package logger import ( "container/list" "fmt" "io" "log" "os" "strings" "sync" "time" "github.com/influxdata/telegraf" ) type entry struct { timestamp time.Time level telegraf.LogLevel prefix string attributes map[string]interface{} args []interface{} } type handler struct { level telegraf.LogLevel timezone *time.Location impl sink earlysink *log.Logger earlylogs *list.List sync.Mutex } func defaultHandler() *handler { return &handler{ level: telegraf.Info, timezone: time.UTC, earlysink: log.New(os.Stderr, "", 0), earlylogs: list.New(), } } func redirectHandler(w io.Writer) *handler { return &handler{ level: 99, timezone: time.UTC, impl: &redirectLogger{writer: w}, earlysink: log.New(w, "", 0), earlylogs: list.New(), } } func (h *handler) switchSink(impl sink, level telegraf.LogLevel, tz *time.Location, skipEarlyLogs bool) { // Setup the new sink etc h.impl = impl h.level = level h.timezone = tz // Use the new logger to output the early log-messages h.Lock() if !skipEarlyLogs && h.earlylogs.Len() > 0 { current := h.earlylogs.Front() for current != nil { e := current.Value.(*entry) h.impl.Print(e.level, e.timestamp.In(h.timezone), e.prefix, e.attributes, e.args...) next := current.Next() h.earlylogs.Remove(current) current = next } } h.Unlock() } func (h *handler) add(level telegraf.LogLevel, ts time.Time, prefix string, attr map[string]interface{}, args ...interface{}) *entry { e := &entry{ timestamp: ts, level: level, prefix: prefix, attributes: attr, args: args, } h.Lock() h.earlylogs.PushBack(e) h.Unlock() return e } func (h *handler) close() error { if h.impl == nil { return nil } h.Lock() current := h.earlylogs.Front() for current != nil { h.earlylogs.Remove(current) current = h.earlylogs.Front() } h.Unlock() if l, ok := h.impl.(io.Closer); ok { return l.Close() } return nil } // Logger to redirect the logs to an arbitrary writer type redirectLogger struct { writer io.Writer } func (l *redirectLogger) Print(level telegraf.LogLevel, ts time.Time, prefix string, attr map[string]interface{}, args ...interface{}) { var attrMsg string if len(attr) > 0 { var parts []string for k, v := range attr { parts = append(parts, fmt.Sprintf("%s=%v", k, v)) } attrMsg = "(" + strings.Join(parts, ",") + ")" } msg := []interface{}{ts.In(time.UTC).Format(time.RFC3339), level.Indicator()} if prefix+attrMsg != "" { msg = append(msg, prefix+attrMsg) } msg = append(msg, args...) fmt.Fprintln(l.writer, msg...) } func (l *redirectLogger) Close() error { if l.writer == os.Stderr { return nil } if closer, ok := l.writer.(io.Closer); ok { return closer.Close() } return nil }