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
 | |
| }
 |