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.New[config.Config]("<prefix>", "<app-name>").
SetDefaults(func(c *config.ConfigReader[config.Config]{
c.SetDefault("int", 32)
}).ReadConfig("main")
config := reader.GetConfig("main")
This creates a standard config reader with defaults from the given config
prototype reading in additional defaults from the <app-name>[-env].yaml
-file
and environment variables.
The defaults provided by the different options 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.New("<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.Setup[Rus|Zero](writer[, logger])
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.New("<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 go-make, which provides default targets for most common tasks, to initialize, build, test, and run the software of this project. Read the go-make manual for more information about targets and configuration options.
The Makefile
depends on a preinstalled go
for version
management, and makes heavy use of GNU tools, i.e. coretils
,
findutils
, '(g)make', (g)awk
, (g)sed
, and
not the least bash
. For certain non-core-features it also requires
docker
/podman
and curl
. On MacOS, it uses
brew to ensure that the latest versions with the exception
docker
/podman
are.
Not: go-make automatically installs pre-commit
and commit-msg
hooks overwriting and deleting pre-existing hooks (see also
Customizing Git - Git Hooks). The pre-commit
hook calls
make commit
as an alias for executing test-go
, test-unit
, lint-<level>
,
and lint-markdown
to enforce successful testing and linting. The commit-msg
hook calls make git-verify message
for validating 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.