Created
November 13, 2023 06:39
-
-
Save ionling/041cab12e8ebf4efce744fac230f524c to your computer and use it in GitHub Desktop.
Service health checkers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package health | |
import ( | |
"context" | |
khttp "github.com/go-kratos/kratos/v2/transport/http" | |
) | |
type Health struct { | |
checkers []Checker | |
} | |
type Result struct { | |
Components []Component | |
} | |
type Component struct { | |
Status string | |
Result any | |
} | |
type Checker interface { | |
Check(context.Context) (any, error) | |
} | |
func New() *Health { | |
return &Health{} | |
} | |
func (h *Health) Add(name string, c Checker) *Health { | |
h.checkers = append(h.checkers, c) | |
return h | |
} | |
func (h *Health) KratosHandler() khttp.HandlerFunc { | |
return func(ctx khttp.Context) (err error) { | |
var res = Result{} | |
for _, c := range h.checkers { | |
status := "OK" | |
r, err := c.Check(ctx) | |
if err != nil { | |
status = err.Error() | |
} | |
res.Components = append(res.Components, Component{ | |
Status: status, | |
Result: r, | |
}) | |
} | |
return ctx.JSON(200, res) | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package sqlh | |
import ( | |
"context" | |
"database/sql" | |
"fmt" | |
"strconv" | |
"time" | |
"health" | |
) | |
type checker struct { | |
db *sql.DB | |
} | |
func NewChecker(db *sql.DB) health.Checker { | |
return &checker{ | |
db: db, | |
} | |
} | |
type PGConf struct { | |
Name string | |
Setting string | |
} | |
type PGResult struct { | |
// Starts the autovacuum subprocess. | |
AutoVacuum bool | |
// Sets the client's character set encoding. | |
ClientEncoding string | |
// Sets the delay in microseconds between transaction commit and flushing WAL to disk. | |
CommitDelay int | |
// Sets the minimum concurrent open transactions before performing commit_delay. | |
CommitSiblings int | |
// Sets the server's data directory. | |
DataDirectory string | |
// Sets the time to wait on a lock before checking for deadlock. | |
DeadlockTimeout time.Duration | |
// Shows the maximum number of index keys. | |
MaxIndexKeys int | |
// Sets the maximum stack depth, in kilobytes. | |
MaxStackDepth string | |
// Sets the WAL size that triggers a checkpoint. | |
MaxWALSize string | |
// Sets the TCP port the server listens on. | |
Port int | |
// Shows the server version. | |
Version string | |
} | |
func (c *checker) Check(ctx context.Context) (any, error) { | |
rows, err := c.db.QueryContext(ctx, "SHOW ALL") | |
if err != nil { | |
return nil, fmt.Errorf("query: %w", err) | |
} | |
var confs []PGConf | |
for rows.Next() { | |
var conf PGConf | |
if err := rows.Scan(&conf.Name, &conf.Setting); err != nil { | |
return nil, fmt.Errorf("scan: %w", err) | |
} | |
confs = append(confs, conf) | |
} | |
var res PGResult | |
for _, conf := range confs { | |
switch v := conf.Setting; conf.Name { | |
case "autovacuum": | |
res.AutoVacuum = v == "on" | |
case "client_encoding": | |
res.ClientEncoding = v | |
case "commit_delay": | |
res.CommitDelay, err = strconv.Atoi(v) | |
case "commit_siblings": | |
res.CommitSiblings, err = strconv.Atoi(v) | |
case "data_directory": | |
res.DataDirectory = v | |
case "deadlock_timeout": | |
res.DeadlockTimeout, err = time.ParseDuration(v) | |
case "max_index_keys": | |
case "max_stack_depth": | |
res.MaxStackDepth = v | |
case "max_wal_size": | |
res.MaxStackDepth = v | |
case "port": | |
res.Port, err = strconv.Atoi(v) | |
case "server_version": | |
res.Version = v | |
} | |
if err != nil { | |
// TODO | |
} | |
} | |
return nil, nil | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package redish | |
import ( | |
"context" | |
"fmt" | |
"strings" | |
"github.com/go-redis/redis/v8" | |
"github.com/mitchellh/mapstructure" | |
"health" | |
) | |
type checker struct { | |
c *redis.Client | |
} | |
func NewChecker(c *redis.Client) health.Checker { | |
return &checker{ | |
c: c, | |
} | |
} | |
type Result struct { | |
Version string `mapstructure:"redis_version"` | |
OS string `mapstructure:"os"` | |
UptimeDays int `mapstructure:"uptime_in_days"` | |
ConnectedClients int `mapstructure:"connected_clients"` | |
UsedMemory string `mapstructure:"used_memory_human"` | |
AOFEnabled bool `mapstructure:"aof_enabled"` | |
} | |
func Parse(s string) (res *Result, err error) { | |
m := map[string]string{} | |
for _, line := range strings.Split(s, "\r\n") { | |
if strings.HasPrefix(line, "#") { | |
continue | |
} | |
kv := strings.SplitN(line, ":", 2) | |
if len(kv) != 2 { | |
continue | |
} | |
m[kv[0]] = kv[1] | |
} | |
res = new(Result) | |
err = mapstructure.WeakDecode(m, res) | |
return | |
} | |
func (c *checker) Check(ctx context.Context) (res any, err error) { | |
cmd := c.c.Info(ctx) | |
if err := cmd.Err(); err != nil { | |
return nil, fmt.Errorf("get: %w", err) | |
} | |
res, err = Parse(cmd.Val()) | |
if err != nil { | |
return nil, fmt.Errorf("parse: %w", err) | |
} | |
return | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment