fix(logs): Small refacto and allow multiple providers at the same time
This commit is contained in:
parent
bef0d38f1e
commit
99bca634d2
@ -28,7 +28,7 @@ const defaultSecretName = "log"
|
|||||||
type ConfigStruct struct {
|
type ConfigStruct struct {
|
||||||
Level *string `yaml:"level"`
|
Level *string `yaml:"level"`
|
||||||
EnableStdOut *bool `yaml:"ensable_std_out"`
|
EnableStdOut *bool `yaml:"ensable_std_out"`
|
||||||
Provider *ProviderName `yaml:"provider"`
|
Providers []ProviderName `yaml:"providers"`
|
||||||
FileConfig *file.ConfigStruct `yaml:"file_config"`
|
FileConfig *file.ConfigStruct `yaml:"file_config"`
|
||||||
GelfConfig *gelf.ConfigStruct `yaml:"gelf_config"`
|
GelfConfig *gelf.ConfigStruct `yaml:"gelf_config"`
|
||||||
}
|
}
|
||||||
@ -37,7 +37,7 @@ func newDefaultConfig() *ConfigStruct {
|
|||||||
return &ConfigStruct{
|
return &ConfigStruct{
|
||||||
Level: convert.ToPointer("debug"),
|
Level: convert.ToPointer("debug"),
|
||||||
EnableStdOut: convert.ToPointer(true),
|
EnableStdOut: convert.ToPointer(true),
|
||||||
Provider: convert.ToPointer(ProviderName_NONE),
|
Providers: []ProviderName{ProviderName_NONE},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,9 +102,13 @@ func (c *ConfigStruct) applyEnv() error {
|
|||||||
c.EnableStdOut = convert.ToPointer(b)
|
c.EnableStdOut = convert.ToPointer(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
if v := os.Getenv(fmt.Sprintf("%s%s", envPrefix, "PROVIDER")); v != "" {
|
if v := os.Getenv(fmt.Sprintf("%s%s", envPrefix, "PROVIDERS")); v != "" {
|
||||||
p := ProviderName(v)
|
providersStr := strings.Split(v, ",")
|
||||||
c.Provider = convert.ToPointer(p)
|
var providers []ProviderName
|
||||||
|
for _, ps := range providersStr {
|
||||||
|
providers = append(providers, ProviderName(ps))
|
||||||
|
}
|
||||||
|
c.Providers = providers
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -123,8 +127,8 @@ func (c *ConfigStruct) applyDefault() {
|
|||||||
c.EnableStdOut = defaultConfig.EnableStdOut
|
c.EnableStdOut = defaultConfig.EnableStdOut
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Provider == nil || *c.Provider == "" {
|
if c.Providers == nil || len(c.Providers) == 0 {
|
||||||
c.Provider = defaultConfig.Provider
|
c.Providers = defaultConfig.Providers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,36 +145,40 @@ func (c *ConfigStruct) IsValid() error {
|
|||||||
return errors.NotValidf("Invalid Level. Allowed values: %s", strings.Join(convert.StringerSliceToStringSlice(logrus.AllLevels), ", "))
|
return errors.NotValidf("Invalid Level. Allowed values: %s", strings.Join(convert.StringerSliceToStringSlice(logrus.AllLevels), ", "))
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Provider == nil {
|
if c.Providers == nil || len(c.Providers) == 0 {
|
||||||
return errors.NotValidf("Provider is empty")
|
return errors.NotValidf("Providers 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.
|
// Validating configuration for the chosen provider.
|
||||||
switch *c.Provider {
|
for _, provider := range c.Providers {
|
||||||
case ProviderName_FILE:
|
if !provider.IsValid() {
|
||||||
if c.FileConfig == nil {
|
return errors.NotValidf("Invalid Provider %s. Allowed values: %s", provider.String(), strings.Join(convert.StringerSliceToStringSlice(GetListProviderName()), ", "))
|
||||||
return errors.NotValidf("file configuration is empty")
|
|
||||||
}
|
}
|
||||||
err := c.FileConfig.IsValid()
|
|
||||||
if err != nil {
|
switch provider {
|
||||||
return errors.Trace(err)
|
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")
|
||||||
}
|
}
|
||||||
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
|
return nil
|
||||||
|
@ -16,6 +16,13 @@ import (
|
|||||||
// be available in the queue.
|
// be available in the queue.
|
||||||
var BufSize uint = 8192
|
var BufSize uint = 8192
|
||||||
|
|
||||||
|
// defaultFormater will be use if no formatter is given.
|
||||||
|
var defaultFormater = &logrus.TextFormatter{
|
||||||
|
DisableColors: true,
|
||||||
|
TimestampFormat: time.RFC3339Nano,
|
||||||
|
QuoteEmptyFields: true,
|
||||||
|
}
|
||||||
|
|
||||||
// Hook will write logs to a file.
|
// Hook will write logs to a file.
|
||||||
type Hook struct {
|
type Hook struct {
|
||||||
Level logrus.Level
|
Level logrus.Level
|
||||||
@ -27,19 +34,21 @@ type Hook struct {
|
|||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX: Maybe just take a formatter in input
|
|
||||||
|
|
||||||
// NewFileHook creates a hook to be added to an instance of logger.
|
// NewFileHook creates a hook to be added to an instance of logger.
|
||||||
func NewFileHook(w io.Writer, of OutputFormat) *Hook {
|
func NewFileHook(w io.Writer, f logrus.Formatter) *Hook {
|
||||||
if w == nil {
|
if w == nil {
|
||||||
logrus.Error("Can't create File Hook with an empty writer")
|
logrus.Error("Can't create File Hook with an empty writer")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if f == nil {
|
||||||
|
f = defaultFormater
|
||||||
|
}
|
||||||
|
|
||||||
hook := &Hook{
|
hook := &Hook{
|
||||||
Level: logrus.DebugLevel,
|
Level: logrus.DebugLevel,
|
||||||
synchronous: true,
|
synchronous: true,
|
||||||
f: handleFormat(of),
|
f: f,
|
||||||
w: w,
|
w: w,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,16 +58,20 @@ func NewFileHook(w io.Writer, of OutputFormat) *Hook {
|
|||||||
// NewAsyncFileHook creates a hook to be added to an instance of logger.
|
// NewAsyncFileHook creates a hook to be added to an instance of logger.
|
||||||
// The hook created will be asynchronous, and it's the responsibility of the user to call the Flush method
|
// The hook created will be asynchronous, and it's the responsibility of the user to call the Flush method
|
||||||
// before exiting to empty the log queue.
|
// before exiting to empty the log queue.
|
||||||
func NewAsyncFileHook(w io.Writer, of OutputFormat) *Hook {
|
func NewAsyncFileHook(w io.Writer, f logrus.Formatter) *Hook {
|
||||||
if w == nil {
|
if w == nil {
|
||||||
logrus.Error("Can't create File Hook with an empty writer")
|
logrus.Error("Can't create File Hook with an empty writer")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if f == nil {
|
||||||
|
f = defaultFormater
|
||||||
|
}
|
||||||
|
|
||||||
hook := &Hook{
|
hook := &Hook{
|
||||||
Level: logrus.DebugLevel,
|
Level: logrus.DebugLevel,
|
||||||
buf: make(chan logrus.Entry, BufSize),
|
buf: make(chan logrus.Entry, BufSize),
|
||||||
f: handleFormat(of),
|
f: f,
|
||||||
w: w,
|
w: w,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,23 +93,6 @@ func (hook *Hook) Flush() {
|
|||||||
hook.wg.Wait()
|
hook.wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleFormat will take a OutputFormat and will transform it in a formatter.
|
|
||||||
func handleFormat(of OutputFormat) logrus.Formatter {
|
|
||||||
|
|
||||||
if of == OutputFormat_JSON {
|
|
||||||
return &logrus.JSONFormatter{
|
|
||||||
PrettyPrint: false,
|
|
||||||
TimestampFormat: time.RFC3339Nano,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &logrus.TextFormatter{
|
|
||||||
DisableColors: true,
|
|
||||||
TimestampFormat: time.RFC3339Nano,
|
|
||||||
QuoteEmptyFields: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fire is called when a log event is fired.
|
// Fire is called when a log event is fired.
|
||||||
// We assume the entry will be altered by another hook,
|
// We assume the entry will be altered by another hook,
|
||||||
// otherwise we might be logging something wrong to Graylog.
|
// otherwise we might be logging something wrong to Graylog.
|
||||||
|
@ -70,7 +70,24 @@ func NewHook(c *ConfigStruct) (logrus.Hook, error) {
|
|||||||
w = fh
|
w = fh
|
||||||
}
|
}
|
||||||
|
|
||||||
h := NewAsyncFileHook(w, outputFormat)
|
h := NewAsyncFileHook(w, handleFormat(outputFormat))
|
||||||
|
|
||||||
return h, nil
|
return h, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handleFormat will take a OutputFormat and will transform it in a formatter.
|
||||||
|
func handleFormat(of OutputFormat) logrus.Formatter {
|
||||||
|
|
||||||
|
if of == OutputFormat_JSON {
|
||||||
|
return &logrus.JSONFormatter{
|
||||||
|
PrettyPrint: false,
|
||||||
|
TimestampFormat: time.RFC3339Nano,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &logrus.TextFormatter{
|
||||||
|
DisableColors: true,
|
||||||
|
TimestampFormat: time.RFC3339Nano,
|
||||||
|
QuoteEmptyFields: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
52
log/log.go
52
log/log.go
@ -11,8 +11,8 @@ import (
|
|||||||
"git.dev.m-and-m.ovh/mderasse/gocommon/log/hooks/gelf"
|
"git.dev.m-and-m.ovh/mderasse/gocommon/log/hooks/gelf"
|
||||||
)
|
)
|
||||||
|
|
||||||
// InitLog will try to initialize logger by trying to retrieve config from multiple source.
|
// Init will try to initialize logger by trying to retrieve config from multiple source.
|
||||||
func InitLog() (*logrus.Logger, error) {
|
func Init() (*logrus.Logger, error) {
|
||||||
|
|
||||||
// loading configuration
|
// loading configuration
|
||||||
c, err := loadConfig()
|
c, err := loadConfig()
|
||||||
@ -23,8 +23,8 @@ func InitLog() (*logrus.Logger, error) {
|
|||||||
return initFromSource(c)
|
return initFromSource(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitLogFromCustomVaultSecret will initialize logger with a vault secret.
|
// InitFromCustomVaultSecret will initialize logger with a vault secret.
|
||||||
func InitLogFromCustomVaultSecret(secret string) (*logrus.Logger, error) {
|
func InitFromCustomVaultSecret(secret string) (*logrus.Logger, error) {
|
||||||
|
|
||||||
c, err := loadConfigFromVault(secret)
|
c, err := loadConfigFromVault(secret)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -34,8 +34,8 @@ func InitLogFromCustomVaultSecret(secret string) (*logrus.Logger, error) {
|
|||||||
return initFromSource(c)
|
return initFromSource(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitLogFromCustomFile will initialize logger with a config file.
|
// InitFromCustomFile will initialize logger with a config file.
|
||||||
func InitLogFromCustomFile(path string) (*logrus.Logger, error) {
|
func InitFromCustomFile(path string) (*logrus.Logger, error) {
|
||||||
|
|
||||||
c, err := loadConfigFromFile(path)
|
c, err := loadConfigFromFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -53,11 +53,11 @@ func initFromSource(c *ConfigStruct) (*logrus.Logger, error) {
|
|||||||
|
|
||||||
c.applyDefault()
|
c.applyDefault()
|
||||||
|
|
||||||
return InitLogFromCustomConfig(c)
|
return InitFromCustomConfig(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitLogFromCustomConfig will initialize logger from a gaven config.
|
// InitFromCustomConfig will initialize logger from a gaven config.
|
||||||
func InitLogFromCustomConfig(c *ConfigStruct) (*logrus.Logger, error) {
|
func InitFromCustomConfig(c *ConfigStruct) (*logrus.Logger, error) {
|
||||||
|
|
||||||
err := c.IsValid()
|
err := c.IsValid()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -79,23 +79,25 @@ func InitLogFromCustomConfig(c *ConfigStruct) (*logrus.Logger, error) {
|
|||||||
log.SetOutput(io.Discard)
|
log.SetOutput(io.Discard)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch *c.Provider {
|
for _, provider := range c.Providers {
|
||||||
case ProviderName_FILE:
|
switch provider {
|
||||||
hook, err := file.NewHook(c.FileConfig)
|
case ProviderName_FILE:
|
||||||
if err != nil {
|
hook, err := file.NewHook(c.FileConfig)
|
||||||
return nil, errors.Trace(err)
|
if err != nil {
|
||||||
|
return nil, errors.Trace(err)
|
||||||
|
}
|
||||||
|
log.AddHook(hook)
|
||||||
|
case ProviderName_GELF:
|
||||||
|
hook, err := gelf.NewHook(c.GelfConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Trace(err)
|
||||||
|
}
|
||||||
|
log.AddHook(hook)
|
||||||
|
case ProviderName_NONE:
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
return nil, errors.BadRequestf("Provider is not handled.")
|
||||||
}
|
}
|
||||||
log.AddHook(hook)
|
|
||||||
case ProviderName_GELF:
|
|
||||||
hook, err := gelf.NewHook(c.GelfConfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Trace(err)
|
|
||||||
}
|
|
||||||
log.AddHook(hook)
|
|
||||||
case ProviderName_NONE:
|
|
||||||
fallthrough
|
|
||||||
default:
|
|
||||||
return nil, errors.BadRequestf("Provider is not handled.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return log, nil
|
return log, nil
|
||||||
|
Loading…
Reference in New Issue
Block a user