From d0a1bd7e3ed563b83c27e90cf994f237c38c5f74 Mon Sep 17 00:00:00 2001 From: Olivier Poitrey Date: Mon, 15 May 2017 11:16:13 -0700 Subject: [PATCH] Make GlobalLevel and DisableSampling thread safe --- README.md | 6 +++--- field.go | 22 +--------------------- globals.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ log.go | 17 +++-------------- 4 files changed, 61 insertions(+), 38 deletions(-) create mode 100644 globals.go diff --git a/README.md b/README.md index 0eadb36..cbdee3d 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ sublogger.Info().Msg("hello world") ### Level logging ```go -zerolog.GlobalLevel = zerolog.InfoLevel +zerolog.SetGlobalLevel(zerolog.InfoLevel) log.Debug().Msg("filtered out message") log.Info().Msg("routed message") @@ -138,8 +138,8 @@ sampled.Info().Msg("will be logged every 10 messages") Some settings can be changed and will by applied to all loggers: * `log.Logger`: You can set this value to customize the global logger (the one used by package level methods). -* `zerolog.GlobalLevel`: Can raise the mimimum level of all loggers. Set this to `zerolog.Disable` to disable logging altogether (quiet mode). -* `zerolog.SamplingDisable`: If set to `true`, all sampled loggers will stop sampling and issue 100% of their log events. +* `zerolog.SetGlobalLevel`: Can raise the mimimum level of all loggers. Set this to `zerolog.Disable` to disable logging altogether (quiet mode). +* `zerolog.DisableSampling`: If argument is `true`, all sampled loggers will stop sampling and issue 100% of their log events. * `zerolog.TimestampFieldName`: Can be set to customize `Timestamp` field name. * `zerolog.LevelFieldName`: Can be set to customize level field name. * `zerolog.MessageFieldName`: Can be set to customize message field name. diff --git a/field.go b/field.go index 4aca84b..c20e160 100644 --- a/field.go +++ b/field.go @@ -6,27 +6,7 @@ import ( "time" ) -var ( - // TimestampFieldName is the field name used for the timestamp field. - TimestampFieldName = "time" - - // LevelFieldName is the field name used for the level field. - LevelFieldName = "level" - - // MessageFieldName is the field name used for the message field. - MessageFieldName = "message" - - // ErrorFieldName is the field name used for error fields. - ErrorFieldName = "error" - - // SampleFieldName is the name of the field used to report sampling. - SampleFieldName = "sample" - - // TimeFieldFormat defines the time format of the Time field type. - TimeFieldFormat = time.RFC3339 - - now = time.Now -) +var now = time.Now type FieldMode uint8 diff --git a/globals.go b/globals.go new file mode 100644 index 0000000..d600ea5 --- /dev/null +++ b/globals.go @@ -0,0 +1,54 @@ +package zerolog + +import "time" +import "sync/atomic" + +var ( + // TimestampFieldName is the field name used for the timestamp field. + TimestampFieldName = "time" + + // LevelFieldName is the field name used for the level field. + LevelFieldName = "level" + + // MessageFieldName is the field name used for the message field. + MessageFieldName = "message" + + // ErrorFieldName is the field name used for error fields. + ErrorFieldName = "error" + + // SampleFieldName is the name of the field used to report sampling. + SampleFieldName = "sample" + + // TimeFieldFormat defines the time format of the Time field type. + TimeFieldFormat = time.RFC3339 +) + +var ( + gLevel = new(uint32) + disableSampling = new(uint32) +) + +// SetGlobalLevel sets the global override for log level. If this +// values is raised, all Loggers will use at least this value. +// +// To globally disable logs, set GlobalLevel to Disabled. +func SetGlobalLevel(l Level) { + atomic.StoreUint32(gLevel, uint32(l)) +} + +func globalLevel() Level { + return Level(atomic.LoadUint32(gLevel)) +} + +// DisableSampling will disable sampling in all Loggers if true. +func DisableSampling(v bool) { + var i uint32 + if v { + i = 1 + } + atomic.StoreUint32(disableSampling, i) +} + +func samplingDisabled() bool { + return atomic.LoadUint32(gLevel) == 1 +} diff --git a/log.go b/log.go index 0ad0297..88fde42 100644 --- a/log.go +++ b/log.go @@ -30,7 +30,7 @@ // // Level logging // -// zerolog.GlobalLevel = zerolog.InfoLevel +// zerolog.SetGlobalLevel(zerolog.InfoLevel) // // log.Debug().Msg("filtered out message") // log.Info().Msg("routed message") @@ -124,17 +124,6 @@ const ( Rarely = int64(1000) ) -var ( - // GlobalLevel defines the global override for log level. If this - // values is raised, all Loggers will use at least this value. - // - // To globally disable logs, set GlobalLevel to Disabled. - GlobalLevel = DebugLevel - - // DisableSampling will disable sampling in all Loggers if true. - DisableSampling = false -) - // A Logger represents an active logging object that generates lines // of JSON output to an io.Writer. Each logging operation makes a single // call to the Writer's Write method. There is no guaranty on access @@ -270,10 +259,10 @@ func (l Logger) newEvent(level Level, addLevelField bool, done func(string)) Eve // should returns true if the log event should be logged. func (l Logger) should(lvl Level) bool { - if lvl < l.level || lvl < GlobalLevel { + if lvl < l.level || lvl < globalLevel() { return false } - if !DisableSampling && l.sample > 0 && l.counter != nil { + if l.sample > 0 && l.counter != nil && !samplingDisabled() { c := atomic.AddUint32(l.counter, 1) return c%l.sample == 0 }