204 lines
5.6 KiB
Go
204 lines
5.6 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 = "conf/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 {
|
|
EnableStdOut *bool `yaml:"enable_std_out"`
|
|
ExtrasFields map[string]interface{} `yaml:"extra_fields"`
|
|
FileConfig *file.ConfigStruct `yaml:"file_config"`
|
|
GelfConfig *gelf.ConfigStruct `yaml:"gelf_config"`
|
|
Level *string `yaml:"level"`
|
|
Providers []ProviderName `yaml:"providers"`
|
|
}
|
|
|
|
func newDefaultConfig() *ConfigStruct {
|
|
return &ConfigStruct{
|
|
Level: convert.ToPointer("debug"),
|
|
EnableStdOut: convert.ToPointer(true),
|
|
Providers: []ProviderName{ProviderName_NONE},
|
|
}
|
|
}
|
|
|
|
func loadConfigFromVault(secret string) (*ConfigStruct, error) {
|
|
_ = secret
|
|
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, "PROVIDERS")); v != "" {
|
|
providersStr := strings.Split(v, ",")
|
|
var providers []ProviderName
|
|
for _, ps := range providersStr {
|
|
providers = append(providers, ProviderName(ps))
|
|
}
|
|
c.Providers = providers
|
|
}
|
|
|
|
// Extra Fields
|
|
if v := os.Getenv(fmt.Sprintf("%s%s", envPrefix, "EXTRA_FIELDS")); v != "" {
|
|
if c.ExtrasFields == nil {
|
|
c.ExtrasFields = make(map[string]interface{})
|
|
}
|
|
|
|
extraFieldsPart := strings.Split(v, ",")
|
|
for _, efp := range extraFieldsPart {
|
|
extraFieldKV := strings.SplitN(efp, ":", 2)
|
|
if len(extraFieldKV) != 2 {
|
|
return errors.NotValidf(fmt.Sprintf("Invalid extra_field %s in environment variable. Should be a key1:value1,key2:value2 format", efp))
|
|
}
|
|
c.ExtrasFields[extraFieldKV[0]] = extraFieldKV[1]
|
|
}
|
|
}
|
|
|
|
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.Providers == nil || len(c.Providers) == 0 {
|
|
c.Providers = defaultConfig.Providers
|
|
}
|
|
}
|
|
|
|
// 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.Providers == nil || len(c.Providers) == 0 {
|
|
return errors.NotValidf("Providers is empty")
|
|
}
|
|
|
|
// Validating configuration for the chosen provider.
|
|
for _, provider := range c.Providers {
|
|
if !provider.IsValid() {
|
|
return errors.NotValidf("Invalid Provider %s. Allowed values: %s", provider.String(), strings.Join(convert.StringerSliceToStringSlice(GetListProviderName()), ", "))
|
|
}
|
|
|
|
switch 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
|
|
}
|