Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 27 additions & 21 deletions nconf/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,24 @@ type RootArgs struct {
ConfigFile string
}

func (args *RootArgs) Setup(config interface{}, serviceName, version string) (logrus.FieldLogger, error) {
// first load the logger and BugSnag config
rootConfig := &struct {
Log *LoggingConfig
BugSnag *BugSnagConfig
Metrics metriks.Config
Tracing tracing.Config
FeatureFlag featureflag.Config
}{}
type RootConfig struct {
Log LoggingConfig
BugSnag BugSnagConfig `mapstructure:",squash"`
Metrics metriks.Config `mapstructure:",squash"`
Tracing tracing.Config `mapstructure:",squash"`
FeatureFlag featureflag.Config `mapstructure:",squash"`
}

loader := func(cfg interface{}) error {
return LoadFromEnv(args.Prefix, args.ConfigFile, cfg)
}
if !strings.HasSuffix(args.ConfigFile, ".env") {
loader = func(cfg interface{}) error {
return LoadFromFile(args.ConfigFile, cfg)
}
func (args *RootArgs) Setup(config interface{}, serviceName, version string) (logrus.FieldLogger, error) {
rootConfig := RootConfig{
Log: DefaultLoggingConfig,
}

if err := loader(rootConfig); err != nil {
return nil, errors.Wrap(err, "Failed to load the logging configuration")
if err := args.load(&rootConfig); err != nil {
return nil, errors.Wrap(err, "Failed to load the root configuration")
}

log, err := ConfigureLogging(rootConfig.Log)
log, err := ConfigureLogging(&rootConfig.Log)
if err != nil {
return nil, errors.Wrap(err, "Failed to create the logger")
}
Expand All @@ -50,7 +44,7 @@ func (args *RootArgs) Setup(config interface{}, serviceName, version string) (lo
}
log = log.WithField("version", version)

if err := SetupBugSnag(rootConfig.BugSnag, version); err != nil {
if err := SetupBugSnag(&rootConfig.BugSnag, version); err != nil {
return nil, errors.Wrap(err, "Failed to configure bugsnag")
}

Expand All @@ -71,14 +65,26 @@ func (args *RootArgs) Setup(config interface{}, serviceName, version string) (lo

if config != nil {
// second load the config for this project
if err := loader(config); err != nil {
if err := args.load(config); err != nil {
return log, errors.Wrap(err, "Failed to load the config object")
}
log.Debug("Loaded configuration")
}
return log, nil
}

func (args *RootArgs) load(cfg interface{}) error {
loader := func(cfg interface{}) error {
return LoadFromEnv(args.Prefix, args.ConfigFile, cfg)
}
if !strings.HasSuffix(args.ConfigFile, ".env") {
loader = func(cfg interface{}) error {
return LoadFromFile(args.ConfigFile, cfg)
}
}
return loader(cfg)
}

func (args *RootArgs) MustSetup(config interface{}, serviceName, version string) logrus.FieldLogger {
logger, err := args.Setup(config, serviceName, version)
if err != nil {
Expand Down
43 changes: 43 additions & 0 deletions nconf/args_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package nconf

import (
"io/ioutil"
"os"
"testing"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -67,3 +68,45 @@ func TestArgsAddToCmd(t *testing.T) {
require.NoError(t, cmd.Execute())
assert.Equal(t, 1, called)
}

func TestArgsLoadFromYAML(t *testing.T) {
f, err := ioutil.TempFile("", "test-config-*.yaml")
require.NoError(t, err)
defer os.Remove(f.Name())

args := RootArgs{
ConfigFile: f.Name(),
}

t.Run("empty-file", func(t *testing.T) {
cfg := RootConfig{
Log: DefaultLoggingConfig,
}
require.NoError(t, args.load(&cfg))

assert.True(t, cfg.Log.QuoteEmptyFields)
assert.Equal(t, DefaultLoggingConfig, cfg.Log)
assert.Empty(t, cfg.BugSnag.APIKey)
})

_, err = f.WriteString(`
log:
level: debug
fields:
string: value
int: 4
`)
require.NoError(t, err)

t.Run("set log field", func(t *testing.T) {
cfg := RootConfig{Log: DefaultLoggingConfig}
require.NoError(t, args.load(&cfg))

// retains original value
assert.True(t, cfg.Log.QuoteEmptyFields)
assert.Equal(t, "debug", cfg.Log.Level)
require.Len(t, cfg.Log.Fields, 2)
assert.Equal(t, "value", cfg.Log.Fields["string"])
assert.Equal(t, 4, cfg.Log.Fields["int"])
})
}
26 changes: 12 additions & 14 deletions nconf/configuration.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package nconf

import (
"encoding/json"
"io/ioutil"
"os"
"strings"

"github.com/joho/godotenv"
"github.com/kelseyhightower/envconfig"
"github.com/pkg/errors"
"github.com/spf13/viper"
"gopkg.in/yaml.v3"
)

// LoadFromFile will load the configuration from the specified file based on the file type
Expand All @@ -17,24 +18,21 @@ func LoadFromFile(configFile string, input interface{}) error {
return nil
}

// read in all the bytes
data, err := ioutil.ReadFile(configFile)
if err != nil {
return err
}

switch {
case strings.HasSuffix(configFile, ".json"):
viper.SetConfigType("json")
err = json.Unmarshal(data, input)
case strings.HasSuffix(configFile, ".yaml"):
fallthrough
case strings.HasSuffix(configFile, ".yml"):
viper.SetConfigType("yaml")
err = yaml.Unmarshal(data, input)
}
viper.SetConfigFile(configFile)

if err := viper.ReadInConfig(); err != nil && !os.IsNotExist(err) {
_, ok := err.(viper.ConfigFileNotFoundError)
if !ok {
return errors.Wrap(err, "reading configuration from files")
}
}

return viper.Unmarshal(input)
return err
}

func LoadFromEnv(prefix, filename string, face interface{}) error {
Expand Down
3 changes: 2 additions & 1 deletion nconf/configuration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v3"
)

type testConfig struct {
Expand Down Expand Up @@ -96,7 +97,7 @@ func TestFileLoadJSON(t *testing.T) {

func TestFileLoadYAML(t *testing.T) {
expected := exampleConfig()
bytes, err := json.Marshal(&expected)
bytes, err := yaml.Marshal(&expected)
require.NoError(t, err)
filename := writeTestFile(t, "yaml", bytes)
defer os.Remove(filename)
Expand Down
10 changes: 10 additions & 0 deletions nconf/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,19 @@ type LoggingConfig struct {
UseNewLogger bool `mapstructure:"use_new_logger",split_words:"true"`
}

var DefaultLoggingConfig = LoggingConfig{
Level: "info",
QuoteEmptyFields: true,
Fields: make(map[string]interface{}),
}

func ConfigureLogging(config *LoggingConfig) (*logrus.Entry, error) {
logger := logrus.New()

if config == nil {
config = &DefaultLoggingConfig
}

tsFormat := time.RFC3339Nano
if config.TSFormat != "" {
tsFormat = config.TSFormat
Expand Down