1package lagerflags 2 3import ( 4 "errors" 5 "flag" 6 "fmt" 7 "os" 8 9 "code.cloudfoundry.org/lager" 10) 11 12const ( 13 DEBUG = "debug" 14 INFO = "info" 15 ERROR = "error" 16 FATAL = "fatal" 17) 18 19type TimeFormat int 20 21const ( 22 FormatUnixEpoch TimeFormat = iota 23 FormatRFC3339 24) 25 26func (t TimeFormat) MarshalJSON() ([]byte, error) { 27 if FormatUnixEpoch <= t && t <= FormatRFC3339 { 28 return []byte(`"` + t.String() + `"`), nil 29 } 30 return nil, fmt.Errorf("invalid TimeFormat: %d", t) 31} 32 33// Set implements the flag.Getter interface 34func (t TimeFormat) Get(s string) interface{} { return t } 35 36// Set implements the flag.Value interface 37func (t *TimeFormat) Set(s string) error { 38 switch s { 39 case "unix-epoch", "0": 40 *t = FormatUnixEpoch 41 case "rfc3339", "1": 42 *t = FormatRFC3339 43 default: 44 return errors.New(`invalid TimeFormat: "` + s + `"`) 45 } 46 return nil 47} 48 49func (t *TimeFormat) UnmarshalJSON(data []byte) error { 50 if string(data) == "null" { 51 return nil 52 } 53 // unqote 54 if len(data) >= 2 && data[0] == '"' && data[len(data)-1] == '"' { 55 data = data[1 : len(data)-1] 56 } 57 return t.Set(string(data)) 58} 59 60func (t TimeFormat) String() string { 61 switch t { 62 case FormatUnixEpoch: 63 return "unix-epoch" 64 case FormatRFC3339: 65 return "rfc3339" 66 } 67 return "invalid" 68} 69 70type LagerConfig struct { 71 LogLevel string `json:"log_level,omitempty"` 72 RedactSecrets bool `json:"redact_secrets,omitempty"` 73 TimeFormat TimeFormat `json:"time_format"` 74} 75 76func DefaultLagerConfig() LagerConfig { 77 return LagerConfig{ 78 LogLevel: string(INFO), 79 RedactSecrets: false, 80 TimeFormat: FormatUnixEpoch, 81 } 82} 83 84var minLogLevel string 85var redactSecrets bool 86var timeFormat TimeFormat 87 88func AddFlags(flagSet *flag.FlagSet) { 89 flagSet.StringVar( 90 &minLogLevel, 91 "logLevel", 92 string(INFO), 93 "log level: debug, info, error or fatal", 94 ) 95 flagSet.BoolVar( 96 &redactSecrets, 97 "redactSecrets", 98 false, 99 "use a redacting log sink to scrub sensitive values from data being logged", 100 ) 101 flagSet.Var( 102 &timeFormat, 103 "timeFormat", 104 `Format for timestamp in component logs. Valid values are "unix-epoch" and "rfc3339".`, 105 ) 106} 107 108func ConfigFromFlags() LagerConfig { 109 return LagerConfig{ 110 LogLevel: minLogLevel, 111 RedactSecrets: redactSecrets, 112 TimeFormat: timeFormat, 113 } 114} 115 116func New(component string) (lager.Logger, *lager.ReconfigurableSink) { 117 return newLogger(component, minLogLevel, lager.NewWriterSink(os.Stdout, lager.DEBUG)) 118} 119 120func NewFromSink(component string, sink lager.Sink) (lager.Logger, *lager.ReconfigurableSink) { 121 return newLogger(component, minLogLevel, sink) 122} 123 124func NewFromConfig(component string, config LagerConfig) (lager.Logger, *lager.ReconfigurableSink) { 125 var sink lager.Sink 126 127 if config.TimeFormat == FormatRFC3339 { 128 sink = lager.NewPrettySink(os.Stdout, lager.DEBUG) 129 } else { 130 sink = lager.NewWriterSink(os.Stdout, lager.DEBUG) 131 } 132 133 if config.RedactSecrets { 134 var err error 135 sink, err = lager.NewRedactingSink(sink, nil, nil) 136 if err != nil { 137 panic(err) 138 } 139 140 } 141 142 return newLogger(component, config.LogLevel, sink) 143} 144 145func newLogger(component, minLogLevel string, inSink lager.Sink) (lager.Logger, *lager.ReconfigurableSink) { 146 var minLagerLogLevel lager.LogLevel 147 148 switch minLogLevel { 149 case DEBUG: 150 minLagerLogLevel = lager.DEBUG 151 case INFO: 152 minLagerLogLevel = lager.INFO 153 case ERROR: 154 minLagerLogLevel = lager.ERROR 155 case FATAL: 156 minLagerLogLevel = lager.FATAL 157 default: 158 panic(fmt.Errorf("unknown log level: %s", minLogLevel)) 159 } 160 161 logger := lager.NewLogger(component) 162 163 sink := lager.NewReconfigurableSink(inSink, minLagerLogLevel) 164 logger.RegisterSink(sink) 165 166 return logger, sink 167} 168