gocommon/log/config.go

178 lines
4.7 KiB
Go
Raw Normal View History

2022-11-26 20:45:32 +00:00
package log
import (
"fmt"
"os"
"strconv"
"strings"
"github.com/juju/errors"
"github.com/sirupsen/logrus"
"gopkg.in/yaml.v3"
"git.dev.m-and-m.ovh/mderasse/gocommon/convert"
"git.dev.m-and-m.ovh/mderasse/gocommon/log/hooks/file"
"git.dev.m-and-m.ovh/mderasse/gocommon/log/hooks/gelf"
)
// envPrefix is the prefix that will be used for any environnement variable used to configure the logging system.
const envPrefix = "LOG_"
// CONFIG_FILE is the default file that will be searched to apply configuration from the filesystem.
const defaultConfigFile = "log.yaml"
// SECRET_NAME is the default name of the secret that will be searched in vault.
const defaultSecretName = "log"
// ConfigStruct represent the configuration of our logger system.
type ConfigStruct struct {
Level *string `yaml:"level"`
EnableStdOut *bool `yaml:"ensable_std_out"`
Provider *ProviderName `yaml:"provider"`
FileConfig *file.ConfigStruct `yaml:"file_config"`
GelfConfig *gelf.ConfigStruct `yaml:"gelf_config"`
}
func newDefaultConfig() *ConfigStruct {
return &ConfigStruct{
Level: convert.ToPointer("debug"),
EnableStdOut: convert.ToPointer(true),
Provider: convert.ToPointer(ProviderName_NONE),
}
}
func loadConfigFromVault(secret string) (*ConfigStruct, error) {
return nil, os.ErrNotExist
}
// loadConfigFromFile will read the given file and return a config struct.
func loadConfigFromFile(path string) (*ConfigStruct, error) {
if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) {
return nil, errors.Trace(err)
}
//nolint:gosec // we did compute the file path
f, err := os.ReadFile(path)
if err != nil {
return nil, errors.Trace(err)
}
var config ConfigStruct
if err := yaml.Unmarshal(f, &config); err != nil {
return nil, errors.Trace(err)
}
return &config, nil
}
func loadConfig() (*ConfigStruct, error) {
c, err := loadConfigFromVault(defaultSecretName)
if err != nil && !errors.Is(err, os.ErrNotExist) {
return nil, err
} else if err == nil {
return c, nil
}
c, err = loadConfigFromFile(defaultConfigFile)
if err != nil && !errors.Is(err, os.ErrNotExist) {
return nil, err
} else if err == nil {
return c, nil
}
return newDefaultConfig(), nil
}
// applyEnv will retrieve info from environment variable and overide those got by config / vault.
// validity of the value is not checked here and will be check in a IsValid method.
func (c *ConfigStruct) applyEnv() error {
if v := os.Getenv(fmt.Sprintf("%s%s", envPrefix, "LEVEL")); v != "" {
c.Level = convert.ToPointer(v)
}
if v := os.Getenv(fmt.Sprintf("%s%s", envPrefix, "ENABLE_STDOUT")); v != "" {
b, err := strconv.ParseBool(v)
if err != nil {
return errors.NewNotValid(err, fmt.Sprintf("Invalid %s%s environment variable. Should be a boolean", envPrefix, "ENABLE_STDOUT"))
}
c.EnableStdOut = convert.ToPointer(b)
}
if v := os.Getenv(fmt.Sprintf("%s%s", envPrefix, "PROVIDER")); v != "" {
p := ProviderName(v)
c.Provider = convert.ToPointer(p)
}
return nil
}
// applyDefault will check the gaven config and will apply default on empty field.
func (c *ConfigStruct) applyDefault() {
defaultConfig := newDefaultConfig()
if c.Level == nil || *c.Level == "" {
c.Level = defaultConfig.Level
}
if c.EnableStdOut == nil {
c.EnableStdOut = defaultConfig.EnableStdOut
}
if c.Provider == nil || *c.Provider == "" {
c.Provider = defaultConfig.Provider
}
}
// IsValid will check a config struct.
func (c *ConfigStruct) IsValid() error {
if c.EnableStdOut == nil {
return errors.NotValidf("EnableStdOut is empty")
}
if c.Level == nil {
return errors.NotValidf("Level is empty")
} else if _, err := logrus.ParseLevel(*c.Level); err != nil {
return errors.NotValidf("Invalid Level. Allowed values: %s", strings.Join(convert.StringerSliceToStringSlice(logrus.AllLevels), ", "))
}
if c.Provider == nil {
return errors.NotValidf("Provider is empty")
} else if !c.Provider.IsValid() {
return errors.NotValidf("Invalid Provider. Allowed values: %s", strings.Join(convert.StringerSliceToStringSlice(GetListProviderName()), ", "))
}
// Validating configuration for the chosen provider.
switch *c.Provider {
case ProviderName_FILE:
if c.FileConfig == nil {
return errors.NotValidf("file configuration is empty")
}
err := c.FileConfig.IsValid()
if err != nil {
return errors.Trace(err)
}
case ProviderName_GELF:
if c.GelfConfig == nil {
return errors.NotValidf("GELF configuration is empty")
}
err := c.GelfConfig.IsValid()
if err != nil {
return errors.Trace(err)
}
case ProviderName_NONE:
if !*c.EnableStdOut {
return errors.NotValidf("Provider set to none with StdOut disabled make no sense")
}
default:
return errors.NotValidf("Provider not handled")
}
return nil
}