1 package ldcomponents 2 3 import ( 4 "time" 5 6 "github.com/launchdarkly/go-sdk-common/v3/ldlog" 7 "github.com/launchdarkly/go-server-sdk/v6/internal" 8 "github.com/launchdarkly/go-server-sdk/v6/subsystems" 9 ) 10 11 // LoggingConfigurationBuilder contains methods for configuring the SDK's logging behavior. 12 // 13 // If you want to set non-default values for any of these properties, create a builder with 14 // ldcomponents.[Logging](), change its properties with the LoggingConfigurationBuilder methods, and 15 // store it in the Logging field of [github.com/launchdarkly/go-server-sdk/v6.Config]: 16 // 17 // config := ld.Config{ 18 // Logging: ldcomponents.Logging().MinLevel(ldlog.Warn), 19 // } 20 type LoggingConfigurationBuilder struct { 21 inited bool 22 config subsystems.LoggingConfiguration 23 } 24 25 // DefaultLogDataSourceOutageAsErrorAfter is the default value for 26 // [LoggingConfigurationBuilder.LogDataSourceOutageAsErrorAfter]: one minute. 27 const DefaultLogDataSourceOutageAsErrorAfter = time.Minute 28 29 // Logging returns a configuration builder for the SDK's logging configuration. 30 // 31 // The default configuration has logging enabled with default settings. If you want to set non-default 32 // values for any of these properties, create a builder with ldcomponents.Logging(), change its properties 33 // with the [LoggingConfigurationBuilder] methods, and store it in Config.Logging: 34 // 35 // config := ld.Config{ 36 // Logging: ldcomponents.Logging().MinLevel(ldlog.Warn), 37 // } 38 func Logging() *LoggingConfigurationBuilder { 39 return &LoggingConfigurationBuilder{} 40 } 41 42 func (b *LoggingConfigurationBuilder) checkValid() bool { 43 if b == nil { 44 internal.LogErrorNilPointerMethod("LoggingConfigurationBuilder") 45 return false 46 } 47 if !b.inited { 48 b.config = subsystems.LoggingConfiguration{ 49 LogDataSourceOutageAsErrorAfter: DefaultLogDataSourceOutageAsErrorAfter, 50 Loggers: ldlog.NewDefaultLoggers(), 51 } 52 b.inited = true 53 } 54 return true 55 } 56 57 // LogDataSourceOutageAsErrorAfter sets the time threshold, if any, after which the SDK will log a data 58 // source outage at Error level instead of Warn level. 59 // 60 // A data source outage means that an error condition, such as a network interruption or an error from 61 // the LaunchDarkly service, is preventing the SDK from receiving feature flag updates. Many outages are 62 // brief and the SDK can recover from them quickly; in that case it may be undesirable to log an 63 // Error line, which might trigger an unwanted automated alert depending on your monitoring 64 // tools. So, by default, the SDK logs such errors at Warn level. However, if the amount of time 65 // specified by this method elapses before the data source starts working again, the SDK will log an 66 // additional message at Error level to indicate that this is a sustained problem. 67 // 68 // The default is [DefaultLogDataSourceOutageAsErrorAfter] (one minute). Setting it to zero will disable 69 // this feature, so you will only get Warn messages. 70 func (b *LoggingConfigurationBuilder) LogDataSourceOutageAsErrorAfter( 71 logDataSourceOutageAsErrorAfter time.Duration, 72 ) *LoggingConfigurationBuilder { 73 if b.checkValid() { 74 b.config.LogDataSourceOutageAsErrorAfter = logDataSourceOutageAsErrorAfter 75 } 76 return b 77 } 78 79 // LogEvaluationErrors sets whether the client should log a warning message whenever a flag cannot be evaluated due 80 // to an error (e.g. there is no flag with that key, or the context properties are invalid). By default, these messages 81 // are not logged, although you can detect such errors programmatically using the VariationDetail methods. The only 82 // exception is that the SDK will always log any error involving invalid flag data, because such data should not be 83 // possible and indicates that LaunchDarkly support assistance may be required. 84 func (b *LoggingConfigurationBuilder) LogEvaluationErrors(logEvaluationErrors bool) *LoggingConfigurationBuilder { 85 if b.checkValid() { 86 b.config.LogEvaluationErrors = logEvaluationErrors 87 } 88 return b 89 } 90 91 // LogContextKeyInErrors sets whether log messages for errors related to a specific evaluation context can include the 92 // context key. By default, they will not, since the key might be considered privileged information. 93 func (b *LoggingConfigurationBuilder) LogContextKeyInErrors(logContextKeyInErrors bool) *LoggingConfigurationBuilder { 94 if b.checkValid() { 95 b.config.LogContextKeyInErrors = logContextKeyInErrors 96 } 97 return b 98 } 99 100 // Loggers specifies an instance of [ldlog.Loggers] to use for SDK logging. The ldlog package contains 101 // methods for customizing the destination and level filtering of log output. 102 func (b *LoggingConfigurationBuilder) Loggers(loggers ldlog.Loggers) *LoggingConfigurationBuilder { 103 if b.checkValid() { 104 b.config.Loggers = loggers 105 } 106 return b 107 } 108 109 // MinLevel specifies the minimum level for log output, where [ldlog.Debug] is the lowest and [ldlog.Error] 110 // is the highest. Log messages at a level lower than this will be suppressed. The default is 111 // [ldlog.Info]. 112 // 113 // This is equivalent to creating an ldlog.Loggers instance, calling SetMinLevel() on it, and then 114 // passing it to LoggingConfigurationBuilder.Loggers(). 115 func (b *LoggingConfigurationBuilder) MinLevel(level ldlog.LogLevel) *LoggingConfigurationBuilder { 116 if b.checkValid() { 117 b.config.Loggers.SetMinLevel(level) 118 } 119 return b 120 } 121 122 // Build is called internally by the SDK. 123 func (b *LoggingConfigurationBuilder) Build( 124 clientContext subsystems.ClientContext, 125 ) (subsystems.LoggingConfiguration, error) { 126 if !b.checkValid() { 127 defaults := LoggingConfigurationBuilder{} 128 return defaults.Build(clientContext) 129 } 130 return b.config, nil 131 } 132 133 // NoLogging returns a configuration object that disables logging. 134 // 135 // config := ld.Config{ 136 // Logging: ldcomponents.NoLogging(), 137 // } 138 func NoLogging() subsystems.ComponentConfigurer[subsystems.LoggingConfiguration] { 139 // Note that we're using the builder type but returning it as just an opaque ComponentConfigurer, so 140 // you can't do something illogical like call MinLevel on it. 141 return Logging().Loggers(ldlog.NewDisabledLoggers()) 142 } 143