178 lines
4.7 KiB
Go
178 lines
4.7 KiB
Go
|
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
|
||
|
}
|