From 06a78a9e59ba7cbc165a6f13ad79a6f0a5419d8c Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Fri, 8 Sep 2023 17:34:52 +0200 Subject: [PATCH] feat: add config types --- config/config.go | 82 +++++++++++++++++++++++----------------- server.go | 18 +++++---- service/httpdocs.go | 2 +- service/httpdocs_test.go | 36 +++++++++--------- 4 files changed, 77 insertions(+), 61 deletions(-) diff --git a/config/config.go b/config/config.go index 8444bfc..195d670 100644 --- a/config/config.go +++ b/config/config.go @@ -14,6 +14,7 @@ var ( config *viper.Viper requiredKeys []string defaults = map[string]interface{}{} + types = map[string]string{} ) // Init sets up the configuration @@ -30,224 +31,224 @@ func Config() *viper.Viper { } func GetBool(c *viper.Viper, key string, fallback bool) func() bool { - setDefault(c, key, fallback) + setDefault(c, key, "bool", fallback) return func() bool { return c.GetBool(key) } } func MustGetBool(c *viper.Viper, key string) func() bool { - must(c, key) + must(c, key, "bool") return func() bool { return c.GetBool(key) } } func GetInt(c *viper.Viper, key string, fallback int) func() int { - c.SetDefault(key, fallback) + setDefault(c, key, "int", fallback) return func() int { return c.GetInt(key) } } func MustGetInt(c *viper.Viper, key string) func() int { - must(c, key) + must(c, key, "int") return func() int { return c.GetInt(key) } } func GetInt32(c *viper.Viper, key string, fallback int32) func() int32 { - setDefault(c, key, fallback) + setDefault(c, key, "int32", fallback) return func() int32 { return c.GetInt32(key) } } func MustGetInt32(c *viper.Viper, key string) func() int32 { - must(c, key) + must(c, key, "int32") return func() int32 { return c.GetInt32(key) } } func GetInt64(c *viper.Viper, key string, fallback int64) func() int64 { - setDefault(c, key, fallback) + setDefault(c, key, "int64", fallback) return func() int64 { return c.GetInt64(key) } } func MustGetInt64(c *viper.Viper, key string) func() int64 { - must(c, key) + must(c, key, "int64") return func() int64 { return c.GetInt64(key) } } func GetUint(c *viper.Viper, key string, fallback uint) func() uint { - setDefault(c, key, fallback) + setDefault(c, key, "uint", fallback) return func() uint { return c.GetUint(key) } } func MustGetUint(c *viper.Viper, key string) func() uint { - must(c, key) + must(c, key, "uint") return func() uint { return c.GetUint(key) } } func GetUint32(c *viper.Viper, key string, fallback uint32) func() uint32 { - setDefault(c, key, fallback) + setDefault(c, key, "uint32", fallback) return func() uint32 { return c.GetUint32(key) } } func MustGetUint32(c *viper.Viper, key string) func() uint32 { - must(c, key) + must(c, key, "uint32") return func() uint32 { return c.GetUint32(key) } } func GetUint64(c *viper.Viper, key string, fallback uint64) func() uint64 { - setDefault(c, key, fallback) + setDefault(c, key, "uint64", fallback) return func() uint64 { return c.GetUint64(key) } } func MustGetUint64(c *viper.Viper, key string) func() uint64 { - must(c, key) + must(c, key, "uint64") return func() uint64 { return c.GetUint64(key) } } func GetFloat64(c *viper.Viper, key string, fallback float64) func() float64 { - setDefault(c, key, fallback) + setDefault(c, key, "float64", fallback) return func() float64 { return c.GetFloat64(key) } } func MustGetFloat64(c *viper.Viper, key string) func() float64 { - must(c, key) + must(c, key, "float64") return func() float64 { return c.GetFloat64(key) } } func GetString(c *viper.Viper, key, fallback string) func() string { - setDefault(c, key, fallback) + setDefault(c, key, "string", fallback) return func() string { return c.GetString(key) } } func MustGetString(c *viper.Viper, key string) func() string { - must(c, key) + must(c, key, "string") return func() string { return c.GetString(key) } } func GetTime(c *viper.Viper, key string, fallback time.Time) func() time.Time { - setDefault(c, key, fallback) + setDefault(c, key, "time.Time", fallback) return func() time.Time { return c.GetTime(key) } } func MustGetTime(c *viper.Viper, key string) func() time.Time { - must(c, key) + must(c, key, "time.Time") return func() time.Time { return c.GetTime(key) } } func GetDuration(c *viper.Viper, key string, fallback time.Duration) func() time.Duration { - setDefault(c, key, fallback) + setDefault(c, key, "time.Duration", fallback) return func() time.Duration { return c.GetDuration(key) } } func MustGetDuration(c *viper.Viper, key string) func() time.Duration { - must(c, key) + must(c, key, "time.Duration") return func() time.Duration { return c.GetDuration(key) } } func GetIntSlice(c *viper.Viper, key string, fallback []int) func() []int { - setDefault(c, key, fallback) + setDefault(c, key, "[]int", fallback) return func() []int { return c.GetIntSlice(key) } } func MustGetIntSlice(c *viper.Viper, key string) func() []int { - must(c, key) + must(c, key, "[]int") return func() []int { return c.GetIntSlice(key) } } func GetStringSlice(c *viper.Viper, key string, fallback []string) func() []string { - setDefault(c, key, fallback) + setDefault(c, key, "[]string", fallback) return func() []string { return c.GetStringSlice(key) } } func MustGetStringSlice(c *viper.Viper, key string) func() []string { - must(c, key) + must(c, key, "[]string") return func() []string { return c.GetStringSlice(key) } } func GetStringMap(c *viper.Viper, key string, fallback map[string]interface{}) func() map[string]interface{} { - setDefault(c, key, fallback) + setDefault(c, key, "map[string]interface{}", fallback) return func() map[string]interface{} { return c.GetStringMap(key) } } func MustGetStringMap(c *viper.Viper, key string) func() map[string]interface{} { - must(c, key) + must(c, key, "map[string]interface{}") return func() map[string]interface{} { return c.GetStringMap(key) } } func GetStringMapString(c *viper.Viper, key string, fallback map[string]string) func() map[string]string { - setDefault(c, key, fallback) + setDefault(c, key, "map[string]string", fallback) return func() map[string]string { return c.GetStringMapString(key) } } func MustGetStringMapString(c *viper.Viper, key string) func() map[string]string { - must(c, key) + must(c, key, "map[string]string") return func() map[string]string { return c.GetStringMapString(key) } } func GetStringMapStringSlice(c *viper.Viper, key string, fallback map[string][]string) func() map[string][]string { - setDefault(c, key, fallback) + setDefault(c, key, "map[string][]string", fallback) return func() map[string][]string { return c.GetStringMapStringSlice(key) } } func MustGetStringMapStringSlice(c *viper.Viper, key string) func() map[string][]string { - must(c, key) + must(c, key, "map[string][]string") return func() map[string][]string { return c.GetStringMapStringSlice(key) } @@ -296,6 +297,17 @@ func Defaults() map[string]interface{} { return defaults } +func Types() map[string]string { + return types +} + +func TypeOf(key string) string { + if v, ok := types[key]; ok { + return v + } + return "" +} + func ensure(c *viper.Viper) *viper.Viper { if c == nil { c = config @@ -303,8 +315,9 @@ func ensure(c *viper.Viper) *viper.Viper { return c } -func must(c *viper.Viper, key string) { +func must(c *viper.Viper, key, typeof string) { c = ensure(c) + types[key] = typeof requiredKeys = append(requiredKeys, key) if !c.IsSet(key) { panic(fmt.Sprintf("missing required config key: %s", key)) @@ -322,8 +335,9 @@ func decode(input, output interface{}) error { return decoder.Decode(input) } -func setDefault(c *viper.Viper, key string, fallback any) { +func setDefault(c *viper.Viper, key, typeof string, fallback any) { c = ensure(c) c.SetDefault(key, fallback) defaults[key] = fallback + types[key] = typeof } diff --git a/server.go b/server.go index 8e78b74..896ef30 100644 --- a/server.go +++ b/server.go @@ -178,7 +178,7 @@ func NewServer(opts ...Option) *Server { // add probe inst.AddAlwaysHealthzers(inst) - inst.AddDocumenter("Server", inst) + inst.AddDocumenter("Keel Server", inst) // start init services inst.startService(inst.initServices...) @@ -381,6 +381,7 @@ func (s *Server) Docs() string { } rows = append(rows, []string{ markdown.Code(key), + markdown.Code(config.TypeOf(key)), "", markdown.Code(fmt.Sprintf("%v", fallback)), }) @@ -388,16 +389,17 @@ func (s *Server) Docs() string { for _, key := range config.RequiredKeys() { rows = append(rows, []string{ markdown.Code(key), + markdown.Code(config.TypeOf(key)), markdown.Code("true"), "", }) } if len(rows) > 0 { - md.Println("## Config") + 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.Table([]string{"Key", "Type", "Required", "Default"}, rows) md.Println("") } } @@ -415,7 +417,7 @@ func (s *Server) Docs() string { } } if len(rows) > 0 { - md.Println("## Init Services") + md.Println("### Init Services") md.Println("") md.Println("List of all registered init services that are being immediately started.") md.Println("") @@ -435,7 +437,7 @@ func (s *Server) Docs() string { }) } if len(rows) > 0 { - md.Println("## Services") + md.Println("### Services") md.Println("") md.Println("List of all registered services that are being started.") md.Println("") @@ -457,7 +459,7 @@ func (s *Server) Docs() string { } } if len(rows) > 0 { - md.Println("## Health probes") + md.Println("### Health probes") md.Println("") md.Println("List of all registered healthz probes that are being called during startup and runntime.") md.Println("") @@ -513,7 +515,7 @@ func (s *Server) Docs() string { }) } if len(rows) > 0 { - md.Println("## Closers") + md.Println("### Closers") md.Println("") md.Println("List of all registered closers that are being called during graceful shutdown.") md.Println("") @@ -544,7 +546,7 @@ func (s *Server) Docs() string { }) } if len(rows) > 0 { - md.Println("## Metrics") + md.Println("### Metrics") md.Println("") md.Println("List of all registered metrics than are being exposed.") md.Println("") diff --git a/service/httpdocs.go b/service/httpdocs.go index 2024bec..44892d3 100644 --- a/service/httpdocs.go +++ b/service/httpdocs.go @@ -23,7 +23,7 @@ func NewHTTPDocs(l *zap.Logger, name, addr, path string, documenters map[string] w.Header().Add("Content-Type", "text/markdown") md := &markdown.Markdown{} for name, documenter := range documenters { - md.Printf("# %s", name) + md.Printf("## %s", name) md.Println("") md.Print(documenter.Docs()) } diff --git a/service/httpdocs_test.go b/service/httpdocs_test.go index 5d619ac..89cf4dc 100644 --- a/service/httpdocs_test.go +++ b/service/httpdocs_test.go @@ -27,11 +27,11 @@ func ExampleNewHTTPDocs() { c := svr.Config() // config with fallback - _ = config.GetBool(c, "example.bool", false)() - _ = config.GetString(c, "example.string", "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")() + _ = config.MustGetBool(c, "example.required.bool") + _ = config.MustGetString(c, "example.required.string") svr.AddService(service.NewHTTP(l, "demp-http", "localhost:8080", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) @@ -53,21 +53,21 @@ func ExampleNewHTTPDocs() { svr.Run() // Output: - // # Server + // ## Keel Server // - // ## Config + // ### 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` | + // | Key | Type | Required | Default | + // | ------------------------- | -------- | -------- | ---------- | + // | `example.bool` | `bool` | | `false` | + // | `example.required.bool` | `bool` | `true` | | + // | `example.required.string` | `string` | `true` | | + // | `example.string` | `string` | | `fallback` | + // | `service.docs.enabled` | `bool` | | `true` | // - // ## Init Services + // ### Init Services // // List of all registered init services that are being immediately started. // @@ -75,7 +75,7 @@ func ExampleNewHTTPDocs() { // | ------ | --------------- | ------------------------------------ | // | `docs` | `*service.HTTP` | `*http.ServeMux` on `localhost:9001` | // - // ## Services + // ### Services // // List of all registered services that are being started. // @@ -84,7 +84,7 @@ func ExampleNewHTTPDocs() { // | `demo-goroutine` | `*service.GoRoutine` | parallel: `1` | // | `demp-http` | `*service.HTTP` | `http.HandlerFunc` on `localhost:8080` | // - // ## Health probes + // ### Health probes // // List of all registered healthz probes that are being called during startup and runntime. // @@ -95,7 +95,7 @@ func ExampleNewHTTPDocs() { // | `always` | `*service.HTTP` | `*http.ServeMux` on `localhost:9001` | // | `always` | `*service.HTTP` | `http.HandlerFunc` on `localhost:8080` | // - // ## Closers + // ### Closers // // List of all registered closers that are being called during graceful shutdown. // @@ -105,7 +105,7 @@ func ExampleNewHTTPDocs() { // | `*service.HTTP` | `ErrorCloserWithContext` | // | `*service.HTTP` | `ErrorCloserWithContext` | // - // ## Metrics + // ### Metrics // // List of all registered metrics than are being exposed. //