Goal of go-config
is to provide an easy to use and extensible
config framework with fluent interface based on Viper for services,
jobs, and commands. It is supporting simple default
-tags and prototype
config to set up and change the reader defaults quickly.
In go-config
you simply create your config as an extension of
the config provided in this package as a base line as follows:
// Import for config prototype and config reader.
import "github.com/tkrop/go-config/config"
// Config root element for configuration.
type Config struct {
config.Config `mapstructure:",squash"`
Int int `default:"31"`
String string `default:"my-value"`
Dur Duration `default:"1m"`
Service *my.ServiceConfig
}
Note: go-config
makes it very simple to reuse the simple
config struct
s provided by other libraries and components, since you can
easily create any hierarchy of struct
s, slice
s, and even map[string]
s
containing native types, based on int
, float
, byte
, rune
, complex
,
and string
. You can also use time.Time
and time.Duration
. However, you
need to add the tag mapstructure:",squash"
, if you want to extend a config.
If you do not flatten access via this tag, the inherited structured creates
a sub-structure named config
.
As usual in Viper, you can create your config using the reader that allows creating multiple configs while applying the setup mechanisms for defaults using the following convenience functions:
reader := config.NewReader[config.Config]("<prefix>", "<app-name>").
SetDefaults(func(c *config.ConfigReader[config.Config]{
c.SetDefault("int", 32)
})
config := reader.ReadConfig("main").GetConfig("main")
// or
config := read.LoadConfig("main")
This creates a standard config reader with defaults from the given config
prototype instance. In the final line it is also reading in additional
defaults from the <app-name>[-env].yaml
-file and analyzing the environment
variables using the ReadConfig
method before assembling the config object.
The collected defaults are overwriting each other in the following order:
- First, the values provided via the
default
-tags are applied. - Second the values provided by the config prototype instance are applied.
- Third the values provided by Viper custom setup calls are applied. This also includes the convenient methods provided in this package.
- Forth the values provided in the
<app-name>[-env].yaml
-file are applied. - And finally the values provided via environment variables are applied taking the highest precedence.
Note: While yo declare the reader with a default config structure, it is still possible to customize the reader arbitrarily, e.g. with flag support, and setup any other config structure by using the original Viper interface functions.
A special feature provided by go-config
is to set up defaults
using a partial or complete config prototype. While in the New
constructor
automatically an empty prototype is constructed and parsed for default
-tags,
you can use th SetDefaultConfig
method to provide any pre-filled (sub-)config
to updated and extend default values.
reader := config.NewReader("<prefix>", "<app-name>")).
SetDefaultConfig("", &config.Config{
Env: "prod",
}, false).
SetDefaultConfig("log", &log.Config{
Level: "debug",
}, false)
The go-config
framework supports to set up a Logger
in
zerolog and logrus using the provided standard options
out-of-the-box as follows:
logger := config.Log.SetupRus(writer, logger)
logger := config.Log.SetupZero(writer).ZeroLogger()
If no logger is provided, the standard logger is configured and returned.
Note: While the config supports zerolog, there is currently no real benefit of using it aside of its having a modern interface. Performance wise, the necessary transformations for pretty printing logs are a heavy burden that likely eats up all performance advantages compared to logrus.
Finally, go-config
in conjunction with go-make
supports a build information to track and access the origin of a command,
service or job. While the build information is also auto-discovered, a full
go-make
integration provides the following variables in the
main.go
-file.
// Build information variables set by `go-make`.
var (
// Path contains the package path (set by `go-make`).
Path string
// Version contains the custom version (set by `go-make`).
Version string
// Build contains the custom build time (set by `go-make`).
Build string
// Revision contains the custom revision (set by `go-make`).
Revision string
// Commit contains the custom commit time (set by `go-make`).
Commit string
// Dirty contains the custom dirty flag (set by `go-make`).
Dirty string // Bool not supported by ldflags `-X`.
)
You can now use this information to set up the default build information in
the config reader by using SetInfo
during creation as follows:
func main() {
reader := config.NewReader("<prefix>", "<app-name>", &Config{}).
SetInfo(info.New(Path, Version, Build, Revision, Commit, Dirty)).
}
If you don't want to use go-make
, you can provide the variable
defaults in the -ldflags="-X main.Path=... -X main.Version=... ...
manually
during your build.
This project is using a custom build system called go-make, that provides default targets for most common tasks. Makefile rules are generated based on the project structure and files for common tasks, to initialize, build, test, and run the components in this repository.
To get started, run one of the following commands.
make help
make show-targets
Read the go-make manual for more information about targets and configuration options.
Not: go-make installs pre-commit
and commit-msg
hooks calling make commit
to enforce successful testing and
linting and make git-verify message
to validate whether the commit message
is following the conventional commit best practice.
This software is open source under the MIT license. You can use it without
restrictions and liabilities. Please give it a star, so that I know. If the
project has more than 25 Stars, I will introduce semantic versions v1
.
If you like to contribute, please create an issue and/or pull request with a proper description of your proposal or contribution. I will review it and provide feedback on it as fast as possible.