mirror of
https://github.com/foomo/keel.git
synced 2025-10-16 12:35:34 +00:00
refactor: expose docs through interface
This commit is contained in:
parent
58b482d8ac
commit
2823a97bad
@ -62,7 +62,7 @@ linters:
|
||||
- gosec # (gas): Inspects source code for security problems [fast: false, auto-fix: false]
|
||||
- grouper # An analyzer to analyze expression groups. [fast: true, auto-fix: false]
|
||||
- importas # Enforces consistent import aliases [fast: false, auto-fix: false]
|
||||
- maintidx # maintidx measures the maintainability index of each function. [fast: true, auto-fix: false]
|
||||
#- maintidx # maintidx measures the maintainability index of each function. [fast: true, auto-fix: false]
|
||||
- makezero # Finds slice declarations with non-zero initial length [fast: false, auto-fix: false]
|
||||
- misspell # Finds commonly misspelled English words in comments [fast: true, auto-fix: true]
|
||||
- nakedret # Finds naked returns in functions greater than a specified function length [fast: true, auto-fix: false]
|
||||
|
||||
@ -11,7 +11,9 @@ import (
|
||||
|
||||
// config holds the global configuration
|
||||
var (
|
||||
config *viper.Viper
|
||||
config *viper.Viper
|
||||
requiredKeys []string
|
||||
defaults = map[string]interface{}{}
|
||||
)
|
||||
|
||||
// Init sets up the configuration
|
||||
@ -28,15 +30,13 @@ func Config() *viper.Viper {
|
||||
}
|
||||
|
||||
func GetBool(c *viper.Viper, key string, fallback bool) func() bool {
|
||||
c = ensure(c)
|
||||
c.SetDefault(key, fallback)
|
||||
setDefault(c, key, fallback)
|
||||
return func() bool {
|
||||
return c.GetBool(key)
|
||||
}
|
||||
}
|
||||
|
||||
func MustGetBool(c *viper.Viper, key string, fallback bool) func() bool {
|
||||
c = ensure(c)
|
||||
func MustGetBool(c *viper.Viper, key string) func() bool {
|
||||
must(c, key)
|
||||
return func() bool {
|
||||
return c.GetBool(key)
|
||||
@ -58,15 +58,13 @@ func MustGetInt(c *viper.Viper, key string) func() int {
|
||||
}
|
||||
|
||||
func GetInt32(c *viper.Viper, key string, fallback int32) func() int32 {
|
||||
c = ensure(c)
|
||||
c.SetDefault(key, fallback)
|
||||
setDefault(c, key, fallback)
|
||||
return func() int32 {
|
||||
return c.GetInt32(key)
|
||||
}
|
||||
}
|
||||
|
||||
func MustGetInt32(c *viper.Viper, key string) func() int32 {
|
||||
c = ensure(c)
|
||||
must(c, key)
|
||||
return func() int32 {
|
||||
return c.GetInt32(key)
|
||||
@ -74,15 +72,13 @@ func MustGetInt32(c *viper.Viper, key string) func() int32 {
|
||||
}
|
||||
|
||||
func GetInt64(c *viper.Viper, key string, fallback int64) func() int64 {
|
||||
c = ensure(c)
|
||||
c.SetDefault(key, fallback)
|
||||
setDefault(c, key, fallback)
|
||||
return func() int64 {
|
||||
return c.GetInt64(key)
|
||||
}
|
||||
}
|
||||
|
||||
func MustGetInt64(c *viper.Viper, key string) func() int64 {
|
||||
c = ensure(c)
|
||||
must(c, key)
|
||||
return func() int64 {
|
||||
return c.GetInt64(key)
|
||||
@ -90,15 +86,13 @@ func MustGetInt64(c *viper.Viper, key string) func() int64 {
|
||||
}
|
||||
|
||||
func GetUint(c *viper.Viper, key string, fallback uint) func() uint {
|
||||
c = ensure(c)
|
||||
c.SetDefault(key, fallback)
|
||||
setDefault(c, key, fallback)
|
||||
return func() uint {
|
||||
return c.GetUint(key)
|
||||
}
|
||||
}
|
||||
|
||||
func MustGetUint(c *viper.Viper, key string) func() uint {
|
||||
c = ensure(c)
|
||||
must(c, key)
|
||||
return func() uint {
|
||||
return c.GetUint(key)
|
||||
@ -106,15 +100,13 @@ func MustGetUint(c *viper.Viper, key string) func() uint {
|
||||
}
|
||||
|
||||
func GetUint32(c *viper.Viper, key string, fallback uint32) func() uint32 {
|
||||
c = ensure(c)
|
||||
c.SetDefault(key, fallback)
|
||||
setDefault(c, key, fallback)
|
||||
return func() uint32 {
|
||||
return c.GetUint32(key)
|
||||
}
|
||||
}
|
||||
|
||||
func MustGetUint32(c *viper.Viper, key string) func() uint32 {
|
||||
c = ensure(c)
|
||||
must(c, key)
|
||||
return func() uint32 {
|
||||
return c.GetUint32(key)
|
||||
@ -122,15 +114,13 @@ func MustGetUint32(c *viper.Viper, key string) func() uint32 {
|
||||
}
|
||||
|
||||
func GetUint64(c *viper.Viper, key string, fallback uint64) func() uint64 {
|
||||
c = ensure(c)
|
||||
c.SetDefault(key, fallback)
|
||||
setDefault(c, key, fallback)
|
||||
return func() uint64 {
|
||||
return c.GetUint64(key)
|
||||
}
|
||||
}
|
||||
|
||||
func MustGetUint64(c *viper.Viper, key string) func() uint64 {
|
||||
c = ensure(c)
|
||||
must(c, key)
|
||||
return func() uint64 {
|
||||
return c.GetUint64(key)
|
||||
@ -138,15 +128,13 @@ func MustGetUint64(c *viper.Viper, key string) func() uint64 {
|
||||
}
|
||||
|
||||
func GetFloat64(c *viper.Viper, key string, fallback float64) func() float64 {
|
||||
c = ensure(c)
|
||||
c.SetDefault(key, fallback)
|
||||
setDefault(c, key, fallback)
|
||||
return func() float64 {
|
||||
return c.GetFloat64(key)
|
||||
}
|
||||
}
|
||||
|
||||
func MustGetFloat64(c *viper.Viper, key string) func() float64 {
|
||||
c = ensure(c)
|
||||
must(c, key)
|
||||
return func() float64 {
|
||||
return c.GetFloat64(key)
|
||||
@ -154,15 +142,13 @@ func MustGetFloat64(c *viper.Viper, key string) func() float64 {
|
||||
}
|
||||
|
||||
func GetString(c *viper.Viper, key, fallback string) func() string {
|
||||
c = ensure(c)
|
||||
c.SetDefault(key, fallback)
|
||||
setDefault(c, key, fallback)
|
||||
return func() string {
|
||||
return c.GetString(key)
|
||||
}
|
||||
}
|
||||
|
||||
func MustGetString(c *viper.Viper, key string) func() string {
|
||||
c = ensure(c)
|
||||
must(c, key)
|
||||
return func() string {
|
||||
return c.GetString(key)
|
||||
@ -170,15 +156,13 @@ func MustGetString(c *viper.Viper, key string) func() string {
|
||||
}
|
||||
|
||||
func GetTime(c *viper.Viper, key string, fallback time.Time) func() time.Time {
|
||||
c = ensure(c)
|
||||
c.SetDefault(key, fallback)
|
||||
setDefault(c, key, fallback)
|
||||
return func() time.Time {
|
||||
return c.GetTime(key)
|
||||
}
|
||||
}
|
||||
|
||||
func MustGetTime(c *viper.Viper, key string) func() time.Time {
|
||||
c = ensure(c)
|
||||
must(c, key)
|
||||
return func() time.Time {
|
||||
return c.GetTime(key)
|
||||
@ -186,15 +170,13 @@ func MustGetTime(c *viper.Viper, key string) func() time.Time {
|
||||
}
|
||||
|
||||
func GetDuration(c *viper.Viper, key string, fallback time.Duration) func() time.Duration {
|
||||
c = ensure(c)
|
||||
c.SetDefault(key, fallback)
|
||||
setDefault(c, key, fallback)
|
||||
return func() time.Duration {
|
||||
return c.GetDuration(key)
|
||||
}
|
||||
}
|
||||
|
||||
func MustGetDuration(c *viper.Viper, key string) func() time.Duration {
|
||||
c = ensure(c)
|
||||
must(c, key)
|
||||
return func() time.Duration {
|
||||
return c.GetDuration(key)
|
||||
@ -202,15 +184,13 @@ func MustGetDuration(c *viper.Viper, key string) func() time.Duration {
|
||||
}
|
||||
|
||||
func GetIntSlice(c *viper.Viper, key string, fallback []int) func() []int {
|
||||
c = ensure(c)
|
||||
c.SetDefault(key, fallback)
|
||||
setDefault(c, key, fallback)
|
||||
return func() []int {
|
||||
return c.GetIntSlice(key)
|
||||
}
|
||||
}
|
||||
|
||||
func MustGetIntSlice(c *viper.Viper, key string) func() []int {
|
||||
c = ensure(c)
|
||||
must(c, key)
|
||||
return func() []int {
|
||||
return c.GetIntSlice(key)
|
||||
@ -218,15 +198,13 @@ func MustGetIntSlice(c *viper.Viper, key string) func() []int {
|
||||
}
|
||||
|
||||
func GetStringSlice(c *viper.Viper, key string, fallback []string) func() []string {
|
||||
c = ensure(c)
|
||||
c.SetDefault(key, fallback)
|
||||
setDefault(c, key, fallback)
|
||||
return func() []string {
|
||||
return c.GetStringSlice(key)
|
||||
}
|
||||
}
|
||||
|
||||
func MustGetStringSlice(c *viper.Viper, key string) func() []string {
|
||||
c = ensure(c)
|
||||
must(c, key)
|
||||
return func() []string {
|
||||
return c.GetStringSlice(key)
|
||||
@ -234,15 +212,13 @@ func MustGetStringSlice(c *viper.Viper, key string) func() []string {
|
||||
}
|
||||
|
||||
func GetStringMap(c *viper.Viper, key string, fallback map[string]interface{}) func() map[string]interface{} {
|
||||
c = ensure(c)
|
||||
c.SetDefault(key, fallback)
|
||||
setDefault(c, key, fallback)
|
||||
return func() map[string]interface{} {
|
||||
return c.GetStringMap(key)
|
||||
}
|
||||
}
|
||||
|
||||
func MustGetStringMap(c *viper.Viper, key string) func() map[string]interface{} {
|
||||
c = ensure(c)
|
||||
must(c, key)
|
||||
return func() map[string]interface{} {
|
||||
return c.GetStringMap(key)
|
||||
@ -250,15 +226,13 @@ func MustGetStringMap(c *viper.Viper, key string) func() map[string]interface{}
|
||||
}
|
||||
|
||||
func GetStringMapString(c *viper.Viper, key string, fallback map[string]string) func() map[string]string {
|
||||
c = ensure(c)
|
||||
c.SetDefault(key, fallback)
|
||||
setDefault(c, key, fallback)
|
||||
return func() map[string]string {
|
||||
return c.GetStringMapString(key)
|
||||
}
|
||||
}
|
||||
|
||||
func MustGetStringMapString(c *viper.Viper, key string) func() map[string]string {
|
||||
c = ensure(c)
|
||||
must(c, key)
|
||||
return func() map[string]string {
|
||||
return c.GetStringMapString(key)
|
||||
@ -266,15 +240,13 @@ func MustGetStringMapString(c *viper.Viper, key string) func() map[string]string
|
||||
}
|
||||
|
||||
func GetStringMapStringSlice(c *viper.Viper, key string, fallback map[string][]string) func() map[string][]string {
|
||||
c = ensure(c)
|
||||
c.SetDefault(key, fallback)
|
||||
setDefault(c, key, fallback)
|
||||
return func() map[string][]string {
|
||||
return c.GetStringMapStringSlice(key)
|
||||
}
|
||||
}
|
||||
|
||||
func MustGetStringMapStringSlice(c *viper.Viper, key string) func() map[string][]string {
|
||||
c = ensure(c)
|
||||
must(c, key)
|
||||
return func() map[string][]string {
|
||||
return c.GetStringMapStringSlice(key)
|
||||
@ -316,6 +288,14 @@ func GetStruct(c *viper.Viper, key string, fallback interface{}) (func(v interfa
|
||||
}, nil
|
||||
}
|
||||
|
||||
func RequiredKeys() []string {
|
||||
return requiredKeys
|
||||
}
|
||||
|
||||
func Defaults() map[string]interface{} {
|
||||
return defaults
|
||||
}
|
||||
|
||||
func ensure(c *viper.Viper) *viper.Viper {
|
||||
if c == nil {
|
||||
c = config
|
||||
@ -324,6 +304,8 @@ func ensure(c *viper.Viper) *viper.Viper {
|
||||
}
|
||||
|
||||
func must(c *viper.Viper, key string) {
|
||||
c = ensure(c)
|
||||
requiredKeys = append(requiredKeys, key)
|
||||
if !c.IsSet(key) {
|
||||
panic(fmt.Sprintf("missing required config key: %s", key))
|
||||
}
|
||||
@ -339,3 +321,9 @@ func decode(input, output interface{}) error {
|
||||
}
|
||||
return decoder.Decode(input)
|
||||
}
|
||||
|
||||
func setDefault(c *viper.Viper, key string, fallback any) {
|
||||
c = ensure(c)
|
||||
c.SetDefault(key, fallback)
|
||||
defaults[key] = fallback
|
||||
}
|
||||
|
||||
6
interfaces/documenter.go
Normal file
6
interfaces/documenter.go
Normal file
@ -0,0 +1,6 @@
|
||||
package interfaces
|
||||
|
||||
// Documenter interface
|
||||
type Documenter interface {
|
||||
Docs() string
|
||||
}
|
||||
38
markdown/markdown.go
Normal file
38
markdown/markdown.go
Normal file
@ -0,0 +1,38 @@
|
||||
package markdown
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
markdowntable "github.com/fbiville/markdown-table-formatter/pkg/markdown"
|
||||
)
|
||||
|
||||
type Markdown struct {
|
||||
value string
|
||||
}
|
||||
|
||||
func (s *Markdown) Println(a ...any) {
|
||||
s.value += fmt.Sprintln(a...)
|
||||
}
|
||||
func (s *Markdown) Printf(format string, a ...any) {
|
||||
s.Println(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
func (s *Markdown) Print(a ...any) {
|
||||
s.value += fmt.Sprint(a...)
|
||||
}
|
||||
|
||||
func (s *Markdown) String() string {
|
||||
return s.value
|
||||
}
|
||||
|
||||
func (s *Markdown) Table(headers []string, rows [][]string) {
|
||||
table, err := markdowntable.NewTableFormatterBuilder().
|
||||
WithAlphabeticalSortIn(markdowntable.ASCENDING_ORDER).
|
||||
WithPrettyPrint().
|
||||
Build(headers...).
|
||||
Format(rows)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
s.Print(table)
|
||||
}
|
||||
19
markdown/utils.go
Normal file
19
markdown/utils.go
Normal file
@ -0,0 +1,19 @@
|
||||
package markdown
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func Code(v string) string {
|
||||
if v == "" {
|
||||
return ""
|
||||
}
|
||||
return "`" + v + "`"
|
||||
}
|
||||
|
||||
func String(v any) string {
|
||||
if i, ok := v.(fmt.Stringer); ok {
|
||||
return i.String()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
11
option.go
11
option.go
@ -178,3 +178,14 @@ func WithHTTPHealthzService(enabled bool) Option {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPDocsService option with default value
|
||||
func WithHTTPDocsService(enabled bool) Option {
|
||||
return func(inst *Server) {
|
||||
if config.GetBool(inst.Config(), "service.docs.enabled", enabled)() {
|
||||
svs := service.NewDefaultHTTPDocs(inst.documenter)
|
||||
inst.initServices = append(inst.initServices, svs)
|
||||
inst.AddAlwaysHealthzers(svs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
214
server.go
214
server.go
@ -1,6 +1,3 @@
|
||||
//go:build !docs
|
||||
// +build !docs
|
||||
|
||||
package keel
|
||||
|
||||
import (
|
||||
@ -9,14 +6,19 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"reflect"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/foomo/keel/healthz"
|
||||
"github.com/foomo/keel/interfaces"
|
||||
"github.com/foomo/keel/markdown"
|
||||
"github.com/foomo/keel/service"
|
||||
"github.com/foomo/keel/telemetry/nonrecording"
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/spf13/viper"
|
||||
otelhost "go.opentelemetry.io/contrib/instrumentation/host"
|
||||
otelruntime "go.opentelemetry.io/contrib/instrumentation/runtime"
|
||||
@ -46,6 +48,7 @@ type Server struct {
|
||||
running atomic.Bool
|
||||
closers []interface{}
|
||||
probes map[healthz.Type][]interface{}
|
||||
documenter map[string]interfaces.Documenter
|
||||
ctx context.Context
|
||||
ctxCancel context.Context
|
||||
ctxCancelFn context.CancelFunc
|
||||
@ -60,6 +63,7 @@ func NewServer(opts ...Option) *Server {
|
||||
shutdownTimeout: 30 * time.Second,
|
||||
shutdownSignals: []os.Signal{os.Interrupt, syscall.SIGTERM},
|
||||
probes: map[healthz.Type][]interface{}{},
|
||||
documenter: map[string]interfaces.Documenter{},
|
||||
ctx: context.Background(),
|
||||
c: config.Config(),
|
||||
l: log.Logger(),
|
||||
@ -170,6 +174,7 @@ func NewServer(opts ...Option) *Server {
|
||||
|
||||
// add probe
|
||||
inst.AddAlwaysHealthzers(inst)
|
||||
inst.AddDocumenter("Server", inst)
|
||||
|
||||
// start init services
|
||||
inst.startService(inst.initServices...)
|
||||
@ -263,6 +268,11 @@ func (s *Server) AddClosers(closers ...interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
// AddDocumenter adds a dcoumenter to beadded to the exposed docs
|
||||
func (s *Server) AddDocumenter(name string, documenter interfaces.Documenter) {
|
||||
s.documenter[name] = documenter
|
||||
}
|
||||
|
||||
// AddHealthzer adds a probe to be called on healthz checks
|
||||
func (s *Server) AddHealthzer(typ healthz.Type, probe interface{}) {
|
||||
switch probe.(type) {
|
||||
@ -350,12 +360,204 @@ func (s *Server) Run() {
|
||||
s.l.Info("keel server stopped")
|
||||
}
|
||||
|
||||
func (s *Server) Docs() string {
|
||||
md := &markdown.Markdown{}
|
||||
|
||||
{
|
||||
var rows [][]string
|
||||
keys := s.Config().AllKeys()
|
||||
defaults := config.Defaults()
|
||||
for _, key := range keys {
|
||||
var fallback interface{}
|
||||
if v, ok := defaults[key]; ok {
|
||||
fallback = v
|
||||
}
|
||||
rows = append(rows, []string{
|
||||
markdown.Code(key),
|
||||
"",
|
||||
markdown.Code(fmt.Sprintf("%v", fallback)),
|
||||
})
|
||||
}
|
||||
for _, key := range config.RequiredKeys() {
|
||||
rows = append(rows, []string{
|
||||
markdown.Code(key),
|
||||
markdown.Code("true"),
|
||||
"",
|
||||
})
|
||||
}
|
||||
if len(rows) > 0 {
|
||||
md.Println("## Config")
|
||||
md.Println("")
|
||||
md.Println("List of all registered config variabled with their defaults.")
|
||||
md.Println("")
|
||||
md.Table([]string{"Key", "Default", "Required"}, rows)
|
||||
md.Println("")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var rows [][]string
|
||||
for _, value := range s.initServices {
|
||||
if v, ok := value.(*service.HTTP); ok {
|
||||
t := reflect.TypeOf(v)
|
||||
rows = append(rows, []string{
|
||||
markdown.Code(v.Name()),
|
||||
markdown.Code(t.String()),
|
||||
markdown.String(v),
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(rows) > 0 {
|
||||
md.Println("## Init Services")
|
||||
md.Println("")
|
||||
md.Println("List of all registered init services that are being immediately started.")
|
||||
md.Println("")
|
||||
md.Table([]string{"Name", "Type", "Address"}, rows)
|
||||
md.Println("")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var rows [][]string
|
||||
for _, value := range s.services {
|
||||
if v, ok := value.(*service.HTTP); ok {
|
||||
t := reflect.TypeOf(v)
|
||||
rows = append(rows, []string{
|
||||
markdown.Code(v.Name()),
|
||||
markdown.Code(t.String()),
|
||||
markdown.String(v),
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(rows) > 0 {
|
||||
md.Println("## Services")
|
||||
md.Println("")
|
||||
md.Println("List of all registered services that are being started.")
|
||||
md.Println("")
|
||||
md.Table([]string{"Name", "Type", "Description"}, rows)
|
||||
md.Println("")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var rows [][]string
|
||||
for k, probes := range s.probes {
|
||||
for _, probe := range probes {
|
||||
t := reflect.TypeOf(probe)
|
||||
rows = append(rows, []string{
|
||||
markdown.Code(k.String()),
|
||||
markdown.Code(t.String()),
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(rows) > 0 {
|
||||
md.Println("## Health probes")
|
||||
md.Println("")
|
||||
md.Println("List of all registered healthz probes that are being called during startup and runntime.")
|
||||
md.Println("")
|
||||
md.Table([]string{"Name", "Type"}, rows)
|
||||
md.Println("")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var rows [][]string
|
||||
for _, value := range s.closers {
|
||||
t := reflect.TypeOf(value)
|
||||
var closer string
|
||||
switch value.(type) {
|
||||
case interfaces.Closer:
|
||||
closer = "Closer"
|
||||
case interfaces.ErrorCloser:
|
||||
closer = "ErrorCloser"
|
||||
case interfaces.CloserWithContext:
|
||||
closer = "CloserWithContext"
|
||||
case interfaces.ErrorCloserWithContext:
|
||||
closer = "ErrorCloserWithContext"
|
||||
case interfaces.Shutdowner:
|
||||
closer = "Shutdowner"
|
||||
case interfaces.ErrorShutdowner:
|
||||
closer = "ErrorShutdowner"
|
||||
case interfaces.ShutdownerWithContext:
|
||||
closer = "ShutdownerWithContext"
|
||||
case interfaces.ErrorShutdownerWithContext:
|
||||
closer = "ErrorShutdownerWithContext"
|
||||
case interfaces.Stopper:
|
||||
closer = "Stopper"
|
||||
case interfaces.ErrorStopper:
|
||||
closer = "ErrorStopper"
|
||||
case interfaces.StopperWithContext:
|
||||
closer = "StopperWithContext"
|
||||
case interfaces.ErrorStopperWithContext:
|
||||
closer = "ErrorStopperWithContext"
|
||||
case interfaces.Unsubscriber:
|
||||
closer = "Unsubscriber"
|
||||
case interfaces.ErrorUnsubscriber:
|
||||
closer = "ErrorUnsubscriber"
|
||||
case interfaces.UnsubscriberWithContext:
|
||||
closer = "UnsubscriberWithContext"
|
||||
case interfaces.ErrorUnsubscriberWithContext:
|
||||
closer = "ErrorUnsubscriberWithContext"
|
||||
}
|
||||
rows = append(rows, []string{
|
||||
markdown.Code(t.String()),
|
||||
markdown.Code(closer),
|
||||
})
|
||||
}
|
||||
if len(rows) > 0 {
|
||||
md.Println("## Closers")
|
||||
md.Println("")
|
||||
md.Println("List of all registered closers that are being called during graceful shutdown.")
|
||||
md.Println("")
|
||||
md.Table([]string{"Name", "Type"}, rows)
|
||||
md.Println("")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var rows [][]string
|
||||
s.meter.AsyncFloat64()
|
||||
|
||||
values := nonrecording.Metrics()
|
||||
|
||||
gatherer, _ := prometheus.DefaultRegisterer.(*prometheus.Registry).Gather()
|
||||
for _, value := range gatherer {
|
||||
values = append(values, nonrecording.Metric{
|
||||
Name: value.GetName(),
|
||||
Type: value.GetType().String(),
|
||||
Help: value.GetHelp(),
|
||||
})
|
||||
}
|
||||
for _, value := range values {
|
||||
rows = append(rows, []string{
|
||||
markdown.Code(value.Name),
|
||||
value.Type,
|
||||
value.Help,
|
||||
})
|
||||
}
|
||||
if len(rows) > 0 {
|
||||
md.Println("## Metrics")
|
||||
md.Println("")
|
||||
md.Println("List of all registered metrics than are being exposed.")
|
||||
md.Println("")
|
||||
md.Table([]string{"Name", "Type", "Description"}, rows)
|
||||
md.Println("")
|
||||
}
|
||||
}
|
||||
|
||||
return md.String()
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// ~ Private methods
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
// startService starts the given services
|
||||
func (s *Server) startService(services ...Service) {
|
||||
for _, service := range services {
|
||||
service := service
|
||||
for _, value := range services {
|
||||
value := value
|
||||
s.g.Go(func() error {
|
||||
if err := service.Start(s.ctx); errors.Is(err, http.ErrServerClosed) {
|
||||
if err := value.Start(s.ctx); errors.Is(err, http.ErrServerClosed) {
|
||||
log.WithError(s.l, err).Debug("server has closed")
|
||||
} else if err != nil {
|
||||
log.WithError(s.l, err).Error("failed to start service")
|
||||
|
||||
435
server_docs.go
435
server_docs.go
@ -1,435 +0,0 @@
|
||||
//go:build docs
|
||||
// +build docs
|
||||
|
||||
package keel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
markdowntable "github.com/fbiville/markdown-table-formatter/pkg/markdown"
|
||||
"github.com/foomo/keel/config"
|
||||
"github.com/foomo/keel/healthz"
|
||||
"github.com/foomo/keel/interfaces"
|
||||
"github.com/foomo/keel/log"
|
||||
"github.com/foomo/keel/service"
|
||||
"github.com/foomo/keel/telemetry/nonrecording"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/spf13/viper"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
otelglobal "go.opentelemetry.io/otel/metric/global"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// Server struct
|
||||
type Server struct {
|
||||
services []Service
|
||||
initServices []Service
|
||||
meter metric.Meter
|
||||
meterProvider metric.MeterProvider
|
||||
tracer trace.Tracer
|
||||
traceProvider trace.TracerProvider
|
||||
shutdownSignals []os.Signal
|
||||
shutdownTimeout time.Duration
|
||||
closers []interface{}
|
||||
probes map[healthz.Type][]interface{}
|
||||
ctx context.Context
|
||||
gCtx context.Context
|
||||
l *zap.Logger
|
||||
c *viper.Viper
|
||||
}
|
||||
|
||||
func NewServer(opts ...Option) *Server {
|
||||
inst := &Server{
|
||||
probes: map[healthz.Type][]interface{}{},
|
||||
meterProvider: nonrecording.NewNoopMeterProvider(),
|
||||
traceProvider: trace.NewNoopTracerProvider(),
|
||||
ctx: context.Background(),
|
||||
c: config.Config(),
|
||||
l: log.Logger(),
|
||||
}
|
||||
|
||||
inst.meter = inst.meterProvider.Meter("")
|
||||
otelglobal.SetMeterProvider(inst.meterProvider)
|
||||
inst.tracer = inst.traceProvider.Tracer("")
|
||||
otel.SetTracerProvider(inst.traceProvider)
|
||||
|
||||
// add probe
|
||||
inst.AddAlwaysHealthzers(inst)
|
||||
|
||||
return inst
|
||||
}
|
||||
|
||||
// Logger returns server logger
|
||||
func (s *Server) Logger() *zap.Logger {
|
||||
return s.l
|
||||
}
|
||||
|
||||
// Meter returns the implementation meter
|
||||
func (s *Server) Meter() metric.Meter {
|
||||
return s.meter
|
||||
}
|
||||
|
||||
// Tracer returns the implementation tracer
|
||||
func (s *Server) Tracer() trace.Tracer {
|
||||
return s.tracer
|
||||
}
|
||||
|
||||
// Config returns server config
|
||||
func (s *Server) Config() *viper.Viper {
|
||||
return s.c
|
||||
}
|
||||
|
||||
// Context returns server context
|
||||
func (s *Server) Context() context.Context {
|
||||
return s.ctx
|
||||
}
|
||||
|
||||
// CancelContext returns server's cancel context
|
||||
func (s *Server) CancelContext() context.Context {
|
||||
return s.ctx
|
||||
}
|
||||
|
||||
// AddService add a single service
|
||||
func (s *Server) AddService(service Service) {
|
||||
for _, value := range s.services {
|
||||
if value == service {
|
||||
return
|
||||
}
|
||||
}
|
||||
s.services = append(s.services, service)
|
||||
s.AddAlwaysHealthzers(service)
|
||||
s.AddCloser(service)
|
||||
}
|
||||
|
||||
// AddServices adds multiple service
|
||||
func (s *Server) AddServices(services ...Service) {
|
||||
for _, service := range services {
|
||||
s.AddService(service)
|
||||
}
|
||||
}
|
||||
|
||||
// AddCloser adds a closer to be called on shutdown
|
||||
func (s *Server) AddCloser(closer interface{}) {
|
||||
for _, value := range s.closers {
|
||||
if value == closer {
|
||||
return
|
||||
}
|
||||
}
|
||||
switch closer.(type) {
|
||||
case interfaces.Closer,
|
||||
interfaces.ErrorCloser,
|
||||
interfaces.CloserWithContext,
|
||||
interfaces.ErrorCloserWithContext,
|
||||
interfaces.Shutdowner,
|
||||
interfaces.ErrorShutdowner,
|
||||
interfaces.ShutdownerWithContext,
|
||||
interfaces.ErrorShutdownerWithContext,
|
||||
interfaces.Stopper,
|
||||
interfaces.ErrorStopper,
|
||||
interfaces.StopperWithContext,
|
||||
interfaces.ErrorStopperWithContext,
|
||||
interfaces.Unsubscriber,
|
||||
interfaces.ErrorUnsubscriber,
|
||||
interfaces.UnsubscriberWithContext,
|
||||
interfaces.ErrorUnsubscriberWithContext:
|
||||
s.closers = append(s.closers, closer)
|
||||
default:
|
||||
s.l.Warn("unable to add closer", log.FValue(fmt.Sprintf("%T", closer)))
|
||||
}
|
||||
}
|
||||
|
||||
// AddClosers adds the given closers to be called on shutdown
|
||||
func (s *Server) AddClosers(closers ...interface{}) {
|
||||
for _, closer := range closers {
|
||||
s.AddCloser(closer)
|
||||
}
|
||||
}
|
||||
|
||||
// AddHealthzer adds a probe to be called on healthz checks
|
||||
func (s *Server) AddHealthzer(typ healthz.Type, probe interface{}) {
|
||||
switch probe.(type) {
|
||||
case healthz.BoolHealthzer,
|
||||
healthz.BoolHealthzerWithContext,
|
||||
healthz.ErrorHealthzer,
|
||||
healthz.ErrorHealthzWithContext,
|
||||
interfaces.ErrorPinger,
|
||||
interfaces.ErrorPingerWithContext:
|
||||
s.probes[typ] = append(s.probes[typ], probe)
|
||||
default:
|
||||
s.l.Debug("not a healthz probe", log.FValue(fmt.Sprintf("%T", probe)))
|
||||
}
|
||||
}
|
||||
|
||||
// AddHealthzers adds the given probes to be called on healthz checks
|
||||
func (s *Server) AddHealthzers(typ healthz.Type, probes ...interface{}) {
|
||||
for _, probe := range probes {
|
||||
s.AddHealthzer(typ, probe)
|
||||
}
|
||||
}
|
||||
|
||||
// AddAlwaysHealthzers adds the probes to be called on any healthz checks
|
||||
func (s *Server) AddAlwaysHealthzers(probes ...interface{}) {
|
||||
s.AddHealthzers(healthz.TypeAlways, probes...)
|
||||
}
|
||||
|
||||
// AddStartupHealthzers adds the startup probes to be called on healthz checks
|
||||
func (s *Server) AddStartupHealthzers(probes ...interface{}) {
|
||||
s.AddHealthzers(healthz.TypeStartup, probes...)
|
||||
}
|
||||
|
||||
// AddLivenessHealthzers adds the liveness probes to be called on healthz checks
|
||||
func (s *Server) AddLivenessHealthzers(probes ...interface{}) {
|
||||
s.AddHealthzers(healthz.TypeLiveness, probes...)
|
||||
}
|
||||
|
||||
// AddReadinessHealthzers adds the readiness probes to be called on healthz checks
|
||||
func (s *Server) AddReadinessHealthzers(probes ...interface{}) {
|
||||
s.AddHealthzers(healthz.TypeReadiness, probes...)
|
||||
}
|
||||
|
||||
// IsCanceled returns true if the internal errgroup has been canceled
|
||||
func (s *Server) IsCanceled() bool {
|
||||
return errors.Is(s.gCtx.Err(), context.Canceled)
|
||||
}
|
||||
|
||||
// Healthz returns true if the server is running
|
||||
func (s *Server) Healthz() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run runs the server
|
||||
func (s *Server) Run() {
|
||||
// add init services to closers
|
||||
for _, initService := range s.initServices {
|
||||
s.AddClosers(initService)
|
||||
}
|
||||
|
||||
md := &MD{}
|
||||
|
||||
{
|
||||
var rows [][]string
|
||||
for _, key := range s.Config().AllKeys() {
|
||||
rows = append(rows, []string{
|
||||
code(key),
|
||||
code(s.Config().GetString(key)),
|
||||
})
|
||||
}
|
||||
if len(rows) > 0 {
|
||||
md.Println("## Config")
|
||||
md.Println("")
|
||||
md.Println("List of all registered config variabled with their defaults.")
|
||||
md.Println("")
|
||||
md.Table([]string{"Key", "Default"}, rows)
|
||||
md.Println("")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var rows [][]string
|
||||
for _, value := range s.initServices {
|
||||
if v, ok := value.(*service.HTTP); ok {
|
||||
t := reflect.TypeOf(v)
|
||||
rows = append(rows, []string{
|
||||
code(v.Name()),
|
||||
code(t.String()),
|
||||
stringer(v),
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(rows) > 0 {
|
||||
md.Println("## Init Services")
|
||||
md.Println("")
|
||||
md.Println("List of all registerd init services that are being immediately started.")
|
||||
md.Println("")
|
||||
md.Table([]string{"Name", "Type", "Address"}, rows)
|
||||
md.Println("")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var rows [][]string
|
||||
for _, value := range s.services {
|
||||
if v, ok := value.(*service.HTTP); ok {
|
||||
t := reflect.TypeOf(v)
|
||||
rows = append(rows, []string{
|
||||
code(v.Name()),
|
||||
code(t.String()),
|
||||
stringer(v),
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(rows) > 0 {
|
||||
md.Println("## Services")
|
||||
md.Println("")
|
||||
md.Println("List of all registered services that are being started.")
|
||||
md.Println("")
|
||||
md.Table([]string{"Name", "Type", "Description"}, rows)
|
||||
md.Println("")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var rows [][]string
|
||||
for k, probes := range s.probes {
|
||||
for _, probe := range probes {
|
||||
t := reflect.TypeOf(probe)
|
||||
rows = append(rows, []string{
|
||||
code(k.String()),
|
||||
code(t.String()),
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(rows) > 0 {
|
||||
md.Println("## Health probes")
|
||||
md.Println("")
|
||||
md.Println("List of all registered healthz probes that are being called during startup and runntime.")
|
||||
md.Println("")
|
||||
md.Table([]string{"Name", "Type"}, rows)
|
||||
md.Println("")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var rows [][]string
|
||||
for _, value := range s.closers {
|
||||
t := reflect.TypeOf(value)
|
||||
var closer string
|
||||
switch value.(type) {
|
||||
case interfaces.Closer:
|
||||
closer = "Closer"
|
||||
case interfaces.ErrorCloser:
|
||||
closer = "ErrorCloser"
|
||||
case interfaces.CloserWithContext:
|
||||
closer = "CloserWithContext"
|
||||
case interfaces.ErrorCloserWithContext:
|
||||
closer = "ErrorCloserWithContext"
|
||||
case interfaces.Shutdowner:
|
||||
closer = "Shutdowner"
|
||||
case interfaces.ErrorShutdowner:
|
||||
closer = "ErrorShutdowner"
|
||||
case interfaces.ShutdownerWithContext:
|
||||
closer = "ShutdownerWithContext"
|
||||
case interfaces.ErrorShutdownerWithContext:
|
||||
closer = "ErrorShutdownerWithContext"
|
||||
case interfaces.Stopper:
|
||||
closer = "Stopper"
|
||||
case interfaces.ErrorStopper:
|
||||
closer = "ErrorStopper"
|
||||
case interfaces.StopperWithContext:
|
||||
closer = "StopperWithContext"
|
||||
case interfaces.ErrorStopperWithContext:
|
||||
closer = "ErrorStopperWithContext"
|
||||
case interfaces.Unsubscriber:
|
||||
closer = "Unsubscriber"
|
||||
case interfaces.ErrorUnsubscriber:
|
||||
closer = "ErrorUnsubscriber"
|
||||
case interfaces.UnsubscriberWithContext:
|
||||
closer = "UnsubscriberWithContext"
|
||||
case interfaces.ErrorUnsubscriberWithContext:
|
||||
closer = "ErrorUnsubscriberWithContext"
|
||||
}
|
||||
rows = append(rows, []string{
|
||||
code(t.String()),
|
||||
code(closer),
|
||||
})
|
||||
}
|
||||
if len(rows) > 0 {
|
||||
md.Println("## Closers")
|
||||
md.Println("")
|
||||
md.Println("List of all registered closers that are being called during graceful shutdown.")
|
||||
md.Println("")
|
||||
md.Table([]string{"Name", "Type"}, rows)
|
||||
md.Println("")
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var rows [][]string
|
||||
s.meter.AsyncFloat64()
|
||||
|
||||
var names []string
|
||||
values := map[string]nonrecording.Metric{}
|
||||
for _, value := range nonrecording.Metrics() {
|
||||
names = append(names, value.Name)
|
||||
values[value.Name] = value
|
||||
}
|
||||
|
||||
gatherer, _ := prometheus.DefaultRegisterer.(*prometheus.Registry).Gather()
|
||||
for _, value := range gatherer {
|
||||
names = append(names, value.GetName())
|
||||
values[value.GetName()] = nonrecording.Metric{
|
||||
Name: value.GetName(),
|
||||
Type: value.GetType().String(),
|
||||
Help: value.GetHelp(),
|
||||
}
|
||||
}
|
||||
sort.Strings(names)
|
||||
for _, name := range names {
|
||||
value := values[name]
|
||||
rows = append(rows, []string{
|
||||
code(value.Name),
|
||||
value.Type,
|
||||
value.Help,
|
||||
})
|
||||
}
|
||||
if len(rows) > 0 {
|
||||
md.Println("## Metrics")
|
||||
md.Println("")
|
||||
md.Println("List of all registered metrics than are being exposed.")
|
||||
md.Println("")
|
||||
md.Table([]string{"Name", "Type", "Description"}, rows)
|
||||
md.Println("")
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Print(md.String())
|
||||
}
|
||||
|
||||
type MD struct {
|
||||
value string
|
||||
}
|
||||
|
||||
func (s *MD) Println(a ...any) {
|
||||
s.value += fmt.Sprintln(a...)
|
||||
}
|
||||
|
||||
func (s *MD) Print(a ...any) {
|
||||
s.value += fmt.Sprint(a...)
|
||||
}
|
||||
|
||||
func (s *MD) String() string {
|
||||
return s.value
|
||||
}
|
||||
|
||||
func (s *MD) Table(headers []string, rows [][]string) {
|
||||
table, err := markdowntable.NewTableFormatterBuilder().
|
||||
WithPrettyPrint().
|
||||
Build(headers...).
|
||||
Format(rows)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
s.Print(table)
|
||||
}
|
||||
|
||||
func code(v string) string {
|
||||
if v == "" {
|
||||
return ""
|
||||
}
|
||||
return "`" + v + "`"
|
||||
}
|
||||
|
||||
func stringer(v any) string {
|
||||
if i, ok := v.(fmt.Stringer); ok {
|
||||
return i.String()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
49
service/httpdocs.go
Normal file
49
service/httpdocs.go
Normal file
@ -0,0 +1,49 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/foomo/keel/interfaces"
|
||||
"github.com/foomo/keel/markdown"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/foomo/keel/log"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultHTTPDocsName = "docs"
|
||||
DefaultHTTPDocsAddr = "localhost:9001"
|
||||
DefaultHTTPDocsPath = "/docs"
|
||||
)
|
||||
|
||||
func NewHTTPDocs(l *zap.Logger, name, addr, path string, documenters map[string]interfaces.Documenter) *HTTP {
|
||||
handler := http.NewServeMux()
|
||||
handler.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
l.Info("ping ")
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Header().Add("Content-Type", "text/markdown")
|
||||
md := &markdown.Markdown{}
|
||||
for name, documenter := range documenters {
|
||||
md.Printf("# %s", name)
|
||||
md.Println("")
|
||||
md.Print(documenter.Docs())
|
||||
}
|
||||
_, _ = w.Write([]byte(md.String()))
|
||||
default:
|
||||
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
|
||||
}
|
||||
})
|
||||
return NewHTTP(l, name, addr, handler)
|
||||
}
|
||||
|
||||
func NewDefaultHTTPDocs(documenter map[string]interfaces.Documenter) *HTTP {
|
||||
return NewHTTPDocs(
|
||||
log.Logger(),
|
||||
DefaultHTTPDocsName,
|
||||
DefaultHTTPDocsAddr,
|
||||
DefaultHTTPDocsPath,
|
||||
documenter,
|
||||
)
|
||||
}
|
||||
113
service/httpdocs_test.go
Normal file
113
service/httpdocs_test.go
Normal file
@ -0,0 +1,113 @@
|
||||
package service_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/foomo/keel"
|
||||
"github.com/foomo/keel/config"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func ExampleNewHTTPDocs() {
|
||||
shutdown(3 * time.Second)
|
||||
|
||||
// define vars so it does not panic
|
||||
_ = os.Setenv("EXAMPLE_REQUIRED_BOOL", "true")
|
||||
_ = os.Setenv("EXAMPLE_REQUIRED_STRING", "foo")
|
||||
|
||||
svr := keel.NewServer(
|
||||
keel.WithLogger(zap.NewExample()),
|
||||
keel.WithHTTPDocsService(true),
|
||||
)
|
||||
|
||||
c := svr.Config()
|
||||
// config with fallback
|
||||
_ = config.GetBool(c, "example.bool", false)()
|
||||
_ = config.GetString(c, "example.string", "fallback")()
|
||||
// required configs
|
||||
_ = config.MustGetBool(c, "example.required.bool")()
|
||||
_ = config.MustGetString(c, "example.required.string")()
|
||||
|
||||
{
|
||||
resp, _ := http.Get("http://localhost:9001/docs") //nolint:noctx
|
||||
defer resp.Body.Close() //nolint:govet
|
||||
b, _ := io.ReadAll(resp.Body)
|
||||
fmt.Print(string(b))
|
||||
}
|
||||
|
||||
svr.Run()
|
||||
|
||||
// Output:
|
||||
// # Server
|
||||
//
|
||||
// ## Config
|
||||
//
|
||||
// List of all registered config variabled with their defaults.
|
||||
//
|
||||
// | Key | Default | Required |
|
||||
// | ------------------------- | ------- | ---------- |
|
||||
// | `example.bool` | | `false` |
|
||||
// | `example.required.bool` | `true` | |
|
||||
// | `example.required.string` | `true` | |
|
||||
// | `example.string` | | `fallback` |
|
||||
// | `service.docs.enabled` | | `true` |
|
||||
//
|
||||
// ## Init Services
|
||||
//
|
||||
// List of all registered init services that are being immediately started.
|
||||
//
|
||||
// | Name | Type | Address |
|
||||
// | ------ | --------------- | ------------------------- |
|
||||
// | `docs` | `*service.HTTP` | address: `localhost:9001` |
|
||||
//
|
||||
// ## Health probes
|
||||
//
|
||||
// List of all registered healthz probes that are being called during startup and runntime.
|
||||
//
|
||||
// | Name | Type |
|
||||
// | -------- | --------------- |
|
||||
// | `always` | `*keel.Server` |
|
||||
// | `always` | `*service.HTTP` |
|
||||
//
|
||||
// ## Metrics
|
||||
//
|
||||
// List of all registered metrics than are being exposed.
|
||||
//
|
||||
// | Name | Type | Description |
|
||||
// | ---------------------------------- | ------- | ------------------------------------------------------------------ |
|
||||
// | `go_gc_duration_seconds` | SUMMARY | A summary of the pause duration of garbage collection cycles. |
|
||||
// | `go_goroutines` | GAUGE | Number of goroutines that currently exist. |
|
||||
// | `go_info` | GAUGE | Information about the Go environment. |
|
||||
// | `go_memstats_alloc_bytes_total` | COUNTER | Total number of bytes allocated, even if freed. |
|
||||
// | `go_memstats_alloc_bytes` | GAUGE | Number of bytes allocated and still in use. |
|
||||
// | `go_memstats_buck_hash_sys_bytes` | GAUGE | Number of bytes used by the profiling bucket hash table. |
|
||||
// | `go_memstats_frees_total` | COUNTER | Total number of frees. |
|
||||
// | `go_memstats_gc_sys_bytes` | GAUGE | Number of bytes used for garbage collection system metadata. |
|
||||
// | `go_memstats_heap_alloc_bytes` | GAUGE | Number of heap bytes allocated and still in use. |
|
||||
// | `go_memstats_heap_idle_bytes` | GAUGE | Number of heap bytes waiting to be used. |
|
||||
// | `go_memstats_heap_inuse_bytes` | GAUGE | Number of heap bytes that are in use. |
|
||||
// | `go_memstats_heap_objects` | GAUGE | Number of allocated objects. |
|
||||
// | `go_memstats_heap_released_bytes` | GAUGE | Number of heap bytes released to OS. |
|
||||
// | `go_memstats_heap_sys_bytes` | GAUGE | Number of heap bytes obtained from system. |
|
||||
// | `go_memstats_last_gc_time_seconds` | GAUGE | Number of seconds since 1970 of last garbage collection. |
|
||||
// | `go_memstats_lookups_total` | COUNTER | Total number of pointer lookups. |
|
||||
// | `go_memstats_mallocs_total` | COUNTER | Total number of mallocs. |
|
||||
// | `go_memstats_mcache_inuse_bytes` | GAUGE | Number of bytes in use by mcache structures. |
|
||||
// | `go_memstats_mcache_sys_bytes` | GAUGE | Number of bytes used for mcache structures obtained from system. |
|
||||
// | `go_memstats_mspan_inuse_bytes` | GAUGE | Number of bytes in use by mspan structures. |
|
||||
// | `go_memstats_mspan_sys_bytes` | GAUGE | Number of bytes used for mspan structures obtained from system. |
|
||||
// | `go_memstats_next_gc_bytes` | GAUGE | Number of heap bytes when next garbage collection will take place. |
|
||||
// | `go_memstats_other_sys_bytes` | GAUGE | Number of bytes used for other system allocations. |
|
||||
// | `go_memstats_stack_inuse_bytes` | GAUGE | Number of bytes in use by the stack allocator. |
|
||||
// | `go_memstats_stack_sys_bytes` | GAUGE | Number of bytes obtained from system for stack allocator. |
|
||||
// | `go_memstats_sys_bytes` | GAUGE | Number of bytes obtained from system. |
|
||||
// | `go_threads` | GAUGE | Number of OS threads created. |
|
||||
//
|
||||
// {"level":"info","msg":"starting keel server"}
|
||||
// {"level":"debug","msg":"keel graceful shutdown"}
|
||||
// {"level":"info","msg":"keel server stopped"}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user