mirror of https://github.com/grafana/grafana.git
				
				
				
			Logger migration from log15 to gokit/log (#41636)
* migrate log15 to gokit/log * fix console log * update some unittest * fix all unittest * fix the build * Update pkg/infra/log/log.go Co-authored-by: Yuriy Tseretyan <tceretian@gmail.com> * general type vector * correct the level key Co-authored-by: Yuriy Tseretyan <tceretian@gmail.com>
This commit is contained in:
		
							parent
							
								
									8898a5f0a0
								
							
						
					
					
						commit
						a8eef45a44
					
				|  | @ -34,13 +34,13 @@ func NewFrontendLogMessageHandler(store *frontendlogging.SourceMapStore) fronten | |||
| 
 | ||||
| 		switch event.Level { | ||||
| 		case sentry.LevelError: | ||||
| 			frontendLogger.Error(msg, ctx) | ||||
| 			frontendLogger.Error(msg, ctx...) | ||||
| 		case sentry.LevelWarning: | ||||
| 			frontendLogger.Warn(msg, ctx) | ||||
| 			frontendLogger.Warn(msg, ctx...) | ||||
| 		case sentry.LevelDebug: | ||||
| 			frontendLogger.Debug(msg, ctx) | ||||
| 			frontendLogger.Debug(msg, ctx...) | ||||
| 		default: | ||||
| 			frontendLogger.Info(msg, ctx) | ||||
| 			frontendLogger.Info(msg, ctx...) | ||||
| 		} | ||||
| 
 | ||||
| 		return response.Success("ok") | ||||
|  |  | |||
|  | @ -10,13 +10,14 @@ import ( | |||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/getsentry/sentry-go" | ||||
| 	"github.com/go-kit/log" | ||||
| 	"github.com/grafana/grafana/pkg/api/frontendlogging" | ||||
| 	"github.com/grafana/grafana/pkg/api/response" | ||||
| 	"github.com/grafana/grafana/pkg/api/routing" | ||||
| 	"github.com/grafana/grafana/pkg/infra/log/level" | ||||
| 	"github.com/grafana/grafana/pkg/models" | ||||
| 	"github.com/grafana/grafana/pkg/plugins" | ||||
| 	"github.com/grafana/grafana/pkg/setting" | ||||
| 	log "github.com/inconshreveable/log15" | ||||
| 
 | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 	"github.com/stretchr/testify/require" | ||||
|  | @ -27,20 +28,25 @@ type SourceMapReadRecord struct { | |||
| 	path string | ||||
| } | ||||
| 
 | ||||
| type logScenarioFunc func(c *scenarioContext, logs []*log.Record, sourceMapReads []SourceMapReadRecord) | ||||
| type logScenarioFunc func(c *scenarioContext, logs map[string]interface{}, sourceMapReads []SourceMapReadRecord) | ||||
| 
 | ||||
| func logSentryEventScenario(t *testing.T, desc string, event frontendlogging.FrontendSentryEvent, fn logScenarioFunc) { | ||||
| 	t.Run(desc, func(t *testing.T) { | ||||
| 		logs := []*log.Record{} | ||||
| 		sourceMapReads := []SourceMapReadRecord{} | ||||
| 
 | ||||
| 		origHandler := frontendLogger.GetHandler() | ||||
| 		frontendLogger.SetHandler(log.FuncHandler(func(r *log.Record) error { | ||||
| 			logs = append(logs, r) | ||||
| 		var logcontent = make(map[string]interface{}) | ||||
| 		logcontent["logger"] = "frontend" | ||||
| 		newfrontendLogger := log.Logger(log.LoggerFunc(func(keyvals ...interface{}) error { | ||||
| 			for i := 0; i < len(keyvals); i += 2 { | ||||
| 				logcontent[keyvals[i].(string)] = keyvals[i+1] | ||||
| 			} | ||||
| 			return nil | ||||
| 		})) | ||||
| 
 | ||||
| 		origHandler := frontendLogger.GetLogger() | ||||
| 		frontendLogger.AddLogger(newfrontendLogger, "info", map[string]level.Option{}) | ||||
| 		sourceMapReads := []SourceMapReadRecord{} | ||||
| 
 | ||||
| 		t.Cleanup(func() { | ||||
| 			frontendLogger.SetHandler(origHandler) | ||||
| 			frontendLogger.SetLogger(origHandler) | ||||
| 		}) | ||||
| 
 | ||||
| 		sc := setupScenarioContext(t, "/log") | ||||
|  | @ -91,7 +97,7 @@ func logSentryEventScenario(t *testing.T, desc string, event frontendlogging.Fro | |||
| 
 | ||||
| 		sc.m.Post(sc.url, handler) | ||||
| 		sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec() | ||||
| 		fn(sc, logs, sourceMapReads) | ||||
| 		fn(sc, logcontent, sourceMapReads) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
|  | @ -148,18 +154,17 @@ func TestFrontendLoggingEndpoint(t *testing.T) { | |||
| 		} | ||||
| 
 | ||||
| 		logSentryEventScenario(t, "Should log received error event", errorEvent, | ||||
| 			func(sc *scenarioContext, logs []*log.Record, sourceMapReads []SourceMapReadRecord) { | ||||
| 			func(sc *scenarioContext, logs map[string]interface{}, sourceMapReads []SourceMapReadRecord) { | ||||
| 				assert.Equal(t, 200, sc.resp.Code) | ||||
| 				assert.Len(t, logs, 1) | ||||
| 				assertContextContains(t, logs[0], "logger", "frontend") | ||||
| 				assertContextContains(t, logs[0], "url", errorEvent.Request.URL) | ||||
| 				assertContextContains(t, logs[0], "user_agent", errorEvent.Request.Headers["User-Agent"]) | ||||
| 				assertContextContains(t, logs[0], "event_id", errorEvent.EventID) | ||||
| 				assertContextContains(t, logs[0], "original_timestamp", errorEvent.Timestamp) | ||||
| 				assertContextContains(t, logs[0], "stacktrace", `UserError: Please replace user and try again | ||||
| 				assertContextContains(t, logs, "logger", "frontend") | ||||
| 				assertContextContains(t, logs, "url", errorEvent.Request.URL) | ||||
| 				assertContextContains(t, logs, "user_agent", errorEvent.Request.Headers["User-Agent"]) | ||||
| 				assertContextContains(t, logs, "event_id", errorEvent.EventID) | ||||
| 				assertContextContains(t, logs, "original_timestamp", errorEvent.Timestamp) | ||||
| 				assertContextContains(t, logs, "stacktrace", `UserError: Please replace user and try again | ||||
|   at foofn (foo.js:123:23) | ||||
|   at barfn (bar.js:113:231)`) | ||||
| 				assert.NotContains(t, logs[0].Ctx, "context") | ||||
| 				assert.NotContains(t, logs, "context") | ||||
| 			}) | ||||
| 
 | ||||
| 		messageEvent := frontendlogging.FrontendSentryEvent{ | ||||
|  | @ -175,20 +180,21 @@ func TestFrontendLoggingEndpoint(t *testing.T) { | |||
| 		} | ||||
| 
 | ||||
| 		logSentryEventScenario(t, "Should log received message event", messageEvent, | ||||
| 			func(sc *scenarioContext, logs []*log.Record, sourceMapReads []SourceMapReadRecord) { | ||||
| 			func(sc *scenarioContext, logs map[string]interface{}, sourceMapReads []SourceMapReadRecord) { | ||||
| 				assert.Equal(t, 200, sc.resp.Code) | ||||
| 				assert.Len(t, logs, 1) | ||||
| 				assert.Equal(t, "hello world", logs[0].Msg) | ||||
| 				assert.Equal(t, log.LvlInfo, logs[0].Lvl) | ||||
| 				assertContextContains(t, logs[0], "logger", "frontend") | ||||
| 				assertContextContains(t, logs[0], "url", messageEvent.Request.URL) | ||||
| 				assertContextContains(t, logs[0], "user_agent", messageEvent.Request.Headers["User-Agent"]) | ||||
| 				assertContextContains(t, logs[0], "event_id", messageEvent.EventID) | ||||
| 				assertContextContains(t, logs[0], "original_timestamp", messageEvent.Timestamp) | ||||
| 				assert.NotContains(t, logs[0].Ctx, "stacktrace") | ||||
| 				assert.NotContains(t, logs[0].Ctx, "context") | ||||
| 				assertContextContains(t, logs[0], "user_email", user.Email) | ||||
| 				assertContextContains(t, logs[0], "user_id", user.ID) | ||||
| 				assert.Len(t, logs, 10) | ||||
| 				assertContextContains(t, logs, "logger", "frontend") | ||||
| 				assertContextContains(t, logs, "msg", "hello world") | ||||
| 				assertContextContains(t, logs, "lvl", level.InfoValue()) | ||||
| 				assertContextContains(t, logs, "logger", "frontend") | ||||
| 				assertContextContains(t, logs, "url", messageEvent.Request.URL) | ||||
| 				assertContextContains(t, logs, "user_agent", messageEvent.Request.Headers["User-Agent"]) | ||||
| 				assertContextContains(t, logs, "event_id", messageEvent.EventID) | ||||
| 				assertContextContains(t, logs, "original_timestamp", messageEvent.Timestamp) | ||||
| 				assert.NotContains(t, logs, "stacktrace") | ||||
| 				assert.NotContains(t, logs, "context") | ||||
| 				assertContextContains(t, logs, "user_email", user.Email) | ||||
| 				assertContextContains(t, logs, "user_id", user.ID) | ||||
| 			}) | ||||
| 
 | ||||
| 		eventWithContext := frontendlogging.FrontendSentryEvent{ | ||||
|  | @ -211,12 +217,11 @@ func TestFrontendLoggingEndpoint(t *testing.T) { | |||
| 		} | ||||
| 
 | ||||
| 		logSentryEventScenario(t, "Should log event context", eventWithContext, | ||||
| 			func(sc *scenarioContext, logs []*log.Record, sourceMapReads []SourceMapReadRecord) { | ||||
| 			func(sc *scenarioContext, logs map[string]interface{}, sourceMapReads []SourceMapReadRecord) { | ||||
| 				assert.Equal(t, 200, sc.resp.Code) | ||||
| 				assert.Len(t, logs, 1) | ||||
| 				assertContextContains(t, logs[0], "context_foo_one", "two") | ||||
| 				assertContextContains(t, logs[0], "context_foo_three", "4") | ||||
| 				assertContextContains(t, logs[0], "context_bar", "baz") | ||||
| 				assertContextContains(t, logs, "context_foo_one", "two") | ||||
| 				assertContextContains(t, logs, "context_foo_three", "4") | ||||
| 				assertContextContains(t, logs, "context_bar", "baz") | ||||
| 			}) | ||||
| 
 | ||||
| 		errorEventForSourceMapping := frontendlogging.FrontendSentryEvent{ | ||||
|  | @ -278,10 +283,10 @@ func TestFrontendLoggingEndpoint(t *testing.T) { | |||
| 		} | ||||
| 
 | ||||
| 		logSentryEventScenario(t, "Should load sourcemap and transform stacktrace line when possible", | ||||
| 			errorEventForSourceMapping, func(sc *scenarioContext, logs []*log.Record, sourceMapReads []SourceMapReadRecord) { | ||||
| 			errorEventForSourceMapping, func(sc *scenarioContext, logs map[string]interface{}, sourceMapReads []SourceMapReadRecord) { | ||||
| 				assert.Equal(t, 200, sc.resp.Code) | ||||
| 				assert.Len(t, logs, 1) | ||||
| 				assertContextContains(t, logs[0], "stacktrace", `UserError: Please replace user and try again | ||||
| 				assert.Len(t, logs, 9) | ||||
| 				assertContextContains(t, logs, "stacktrace", `UserError: Please replace user and try again | ||||
|   at ? (core|webpack:///./some_source.ts:2:2)
 | ||||
|   at ? (telepathic|webpack:///./some_source.ts:3:2)
 | ||||
|   at explode (http://localhost:3000/public/build/error.js:3:10)
 | ||||
|  | @ -306,17 +311,7 @@ func TestFrontendLoggingEndpoint(t *testing.T) { | |||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func indexOf(arr []interface{}, item string) int { | ||||
| 	for i, elem := range arr { | ||||
| 		if elem == item { | ||||
| 			return i | ||||
| 		} | ||||
| 	} | ||||
| 	return -1 | ||||
| } | ||||
| 
 | ||||
| func assertContextContains(t *testing.T, logRecord *log.Record, label string, value interface{}) { | ||||
| 	assert.Contains(t, logRecord.Ctx, label) | ||||
| 	labelIdx := indexOf(logRecord.Ctx, label) | ||||
| 	assert.Equal(t, value, logRecord.Ctx[labelIdx+1]) | ||||
| func assertContextContains(t *testing.T, logRecord map[string]interface{}, label string, value interface{}) { | ||||
| 	assert.Contains(t, logRecord, label) | ||||
| 	assert.Equal(t, value, logRecord[label]) | ||||
| } | ||||
|  |  | |||
|  | @ -7,9 +7,10 @@ import ( | |||
| 
 | ||||
| 	"github.com/getsentry/sentry-go" | ||||
| 	"github.com/grafana/grafana/pkg/infra/log" | ||||
| 	"github.com/inconshreveable/log15" | ||||
| ) | ||||
| 
 | ||||
| type CtxVector []interface{} | ||||
| 
 | ||||
| var logger = log.New("frontendlogging") | ||||
| 
 | ||||
| type FrontendSentryExceptionValue struct { | ||||
|  | @ -65,31 +66,28 @@ func (exception *FrontendSentryException) FmtStacktraces(store *SourceMapStore) | |||
| 	return strings.Join(stacktraces, "\n\n") | ||||
| } | ||||
| 
 | ||||
| func addEventContextToLogContext(rootPrefix string, logCtx log15.Ctx, eventCtx map[string]interface{}) { | ||||
| func addEventContextToLogContext(rootPrefix string, logCtx *CtxVector, eventCtx map[string]interface{}) { | ||||
| 	for key, element := range eventCtx { | ||||
| 		prefix := fmt.Sprintf("%s_%s", rootPrefix, key) | ||||
| 		switch v := element.(type) { | ||||
| 		case map[string]interface{}: | ||||
| 			addEventContextToLogContext(prefix, logCtx, v) | ||||
| 		default: | ||||
| 			logCtx[prefix] = fmt.Sprintf("%v", v) | ||||
| 			*logCtx = append(*logCtx, prefix, fmt.Sprintf("%v", v)) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (event *FrontendSentryEvent) ToLogContext(store *SourceMapStore) log15.Ctx { | ||||
| 	var ctx = make(log15.Ctx) | ||||
| 	ctx["url"] = event.Request.URL | ||||
| 	ctx["user_agent"] = event.Request.Headers["User-Agent"] | ||||
| 	ctx["event_id"] = event.EventID | ||||
| 	ctx["original_timestamp"] = event.Timestamp | ||||
| func (event *FrontendSentryEvent) ToLogContext(store *SourceMapStore) []interface{} { | ||||
| 	var ctx = CtxVector{"url", event.Request.URL, "user_agent", event.Request.Headers["User-Agent"], | ||||
| 		"event_id", event.EventID, "original_timestamp", event.Timestamp} | ||||
| 
 | ||||
| 	if event.Exception != nil { | ||||
| 		ctx["stacktrace"] = event.Exception.FmtStacktraces(store) | ||||
| 		ctx = append(ctx, "stacktrace", event.Exception.FmtStacktraces(store)) | ||||
| 	} | ||||
| 	addEventContextToLogContext("context", ctx, event.Contexts) | ||||
| 	addEventContextToLogContext("context", &ctx, event.Contexts) | ||||
| 	if len(event.User.Email) > 0 { | ||||
| 		ctx["user_email"] = event.User.Email | ||||
| 		ctx["user_id"] = event.User.ID | ||||
| 		ctx = append(ctx, "user_email", event.User.Email, "user_id", event.User.ID) | ||||
| 	} | ||||
| 
 | ||||
| 	return ctx | ||||
|  |  | |||
|  | @ -15,15 +15,13 @@ import ( | |||
| 	"sync" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/inconshreveable/log15" | ||||
| 	"github.com/go-kit/log" | ||||
| ) | ||||
| 
 | ||||
| // FileLogWriter implements LoggerInterface.
 | ||||
| // It writes messages by lines limit, file size limit, or time frequency.
 | ||||
| type FileLogWriter struct { | ||||
| 	mw *MuxWriter | ||||
| 
 | ||||
| 	Format           log15.Format | ||||
| 	Format           Formatedlogger | ||||
| 	Filename         string | ||||
| 	Maxlines         int | ||||
| 	maxlinesCurlines int | ||||
|  | @ -39,30 +37,28 @@ type FileLogWriter struct { | |||
| 
 | ||||
| 	Rotate    bool | ||||
| 	startLock sync.Mutex | ||||
| } | ||||
| 
 | ||||
| // an *os.File writer with locker.
 | ||||
| type MuxWriter struct { | ||||
| 	logger    log.Logger | ||||
| 	sync.Mutex | ||||
| 	fd *os.File | ||||
| } | ||||
| 
 | ||||
| // write to os.File.
 | ||||
| func (l *MuxWriter) Write(b []byte) (int, error) { | ||||
| 	l.Lock() | ||||
| 	defer l.Unlock() | ||||
| 	return l.fd.Write(b) | ||||
| func (w *FileLogWriter) Write(b []byte) (int, error) { | ||||
| 	w.docheck(len(b)) | ||||
| 	w.Lock() | ||||
| 	defer w.Unlock() | ||||
| 	return w.fd.Write(b) | ||||
| } | ||||
| 
 | ||||
| // set os.File in writer.
 | ||||
| func (l *MuxWriter) setFD(fd *os.File) error { | ||||
| 	if l.fd != nil { | ||||
| 		if err := l.fd.Close(); err != nil && !errors.Is(err, os.ErrClosed) { | ||||
| func (w *FileLogWriter) setFD(fd *os.File) error { | ||||
| 	if w.fd != nil { | ||||
| 		if err := w.fd.Close(); err != nil && !errors.Is(err, os.ErrClosed) { | ||||
| 			return fmt.Errorf("closing old file in MuxWriter failed: %w", err) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	l.fd = fd | ||||
| 	w.fd = fd | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
|  | @ -70,30 +66,31 @@ func (l *MuxWriter) setFD(fd *os.File) error { | |||
| func NewFileWriter() *FileLogWriter { | ||||
| 	w := &FileLogWriter{ | ||||
| 		Filename: "", | ||||
| 		Format:   log15.LogfmtFormat(), | ||||
| 		Format: func(w io.Writer) log.Logger { | ||||
| 			return log.NewLogfmtLogger(w) | ||||
| 		}, | ||||
| 		Maxlines: 1000000, | ||||
| 		Maxsize:  1 << 28, // 256 MB
 | ||||
| 		Daily:    true, | ||||
| 		Maxdays:  7, | ||||
| 		Rotate:   true, | ||||
| 	} | ||||
| 	// use MuxWriter instead direct use os.File for lock write when rotate
 | ||||
| 	w.mw = new(MuxWriter) | ||||
| 	return w | ||||
| } | ||||
| 
 | ||||
| func (w *FileLogWriter) Log(r *log15.Record) error { | ||||
| 	data := w.Format.Format(r) | ||||
| 	w.docheck(len(data)) | ||||
| 	_, err := w.mw.Write(data) | ||||
| 	return err | ||||
| func (w *FileLogWriter) Log(keyvals ...interface{}) error { | ||||
| 	return w.logger.Log(keyvals...) | ||||
| } | ||||
| 
 | ||||
| func (w *FileLogWriter) Init() error { | ||||
| 	if len(w.Filename) == 0 { | ||||
| 		return errors.New("config must have filename") | ||||
| 	} | ||||
| 	return w.StartLogger() | ||||
| 	if err := w.StartLogger(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	w.logger = log.NewLogfmtLogger(log.NewSyncWriter(w)) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // start file logger. create log file and set to locker-inside file writer.
 | ||||
|  | @ -102,7 +99,7 @@ func (w *FileLogWriter) StartLogger() error { | |||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := w.mw.setFD(fd); err != nil { | ||||
| 	if err := w.setFD(fd); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
|  | @ -159,7 +156,7 @@ func (w *FileLogWriter) lineCounter() (int, error) { | |||
| } | ||||
| 
 | ||||
| func (w *FileLogWriter) initFd() error { | ||||
| 	fd := w.mw.fd | ||||
| 	fd := w.fd | ||||
| 	finfo, err := fd.Stat() | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("get stat: %s", err) | ||||
|  | @ -196,10 +193,10 @@ func (w *FileLogWriter) DoRotate() error { | |||
| 		} | ||||
| 
 | ||||
| 		// block Logger's io.Writer
 | ||||
| 		w.mw.Lock() | ||||
| 		defer w.mw.Unlock() | ||||
| 		w.Lock() | ||||
| 		defer w.Unlock() | ||||
| 
 | ||||
| 		fd := w.mw.fd | ||||
| 		fd := w.fd | ||||
| 		if err := fd.Close(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | @ -244,14 +241,14 @@ func (w *FileLogWriter) deleteOldLog() { | |||
| 
 | ||||
| // destroy file logger, close file writer.
 | ||||
| func (w *FileLogWriter) Close() error { | ||||
| 	return w.mw.fd.Close() | ||||
| 	return w.fd.Close() | ||||
| } | ||||
| 
 | ||||
| // flush file logger.
 | ||||
| // there are no buffering messages in file logger in memory.
 | ||||
| // flush file means sync file from disk.
 | ||||
| func (w *FileLogWriter) Flush() { | ||||
| 	if err := w.mw.fd.Sync(); err != nil { | ||||
| 	if err := w.fd.Sync(); err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err) | ||||
| 	} | ||||
| } | ||||
|  | @ -259,11 +256,11 @@ func (w *FileLogWriter) Flush() { | |||
| // Reload file logger
 | ||||
| func (w *FileLogWriter) Reload() error { | ||||
| 	// block Logger's io.Writer
 | ||||
| 	w.mw.Lock() | ||||
| 	defer w.mw.Unlock() | ||||
| 	w.Lock() | ||||
| 	defer w.Unlock() | ||||
| 
 | ||||
| 	// Close
 | ||||
| 	fd := w.mw.fd | ||||
| 	fd := w.fd | ||||
| 	if err := fd.Close(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  |  | |||
|  | @ -10,12 +10,8 @@ import ( | |||
| ) | ||||
| 
 | ||||
| func (w *FileLogWriter) WriteLine(line string) error { | ||||
| 	n, err := w.mw.Write([]byte(line)) | ||||
| 	if err != nil { | ||||
| 	_, err := w.Write([]byte(line)) | ||||
| 	return err | ||||
| 	} | ||||
| 	w.docheck(n) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func TestLogFile(t *testing.T) { | ||||
|  |  | |||
|  | @ -1,7 +1,5 @@ | |||
| package log | ||||
| 
 | ||||
| import "github.com/inconshreveable/log15" | ||||
| 
 | ||||
| type Lvl int | ||||
| 
 | ||||
| const ( | ||||
|  | @ -14,18 +12,13 @@ const ( | |||
| 
 | ||||
| type Logger interface { | ||||
| 	// New returns a new Logger that has this logger's context plus the given context
 | ||||
| 	New(ctx ...interface{}) log15.Logger | ||||
| 	New(ctx ...interface{}) MultiLoggers | ||||
| 
 | ||||
| 	// GetHandler gets the handler associated with the logger.
 | ||||
| 	GetHandler() log15.Handler | ||||
| 
 | ||||
| 	// SetHandler updates the logger to write records to the specified handler.
 | ||||
| 	SetHandler(h log15.Handler) | ||||
| 	Log(keyvals ...interface{}) error | ||||
| 
 | ||||
| 	// Log a message at the given level with context key/value pairs
 | ||||
| 	Debug(msg string, ctx ...interface{}) | ||||
| 	Info(msg string, ctx ...interface{}) | ||||
| 	Warn(msg string, ctx ...interface{}) | ||||
| 	Error(msg string, ctx ...interface{}) | ||||
| 	Crit(msg string, ctx ...interface{}) | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,205 @@ | |||
| package level | ||||
| 
 | ||||
| import "github.com/go-kit/log" | ||||
| 
 | ||||
| // Error returns a logger that includes a Key/ErrorValue pair.
 | ||||
| func Error(logger log.Logger) log.Logger { | ||||
| 	return log.WithPrefix(logger, Key(), ErrorValue()) | ||||
| } | ||||
| 
 | ||||
| // Warn returns a logger that includes a Key/WarnValue pair.
 | ||||
| func Warn(logger log.Logger) log.Logger { | ||||
| 	return log.WithPrefix(logger, Key(), WarnValue()) | ||||
| } | ||||
| 
 | ||||
| // Info returns a logger that includes a Key/InfoValue pair.
 | ||||
| func Info(logger log.Logger) log.Logger { | ||||
| 	return log.WithPrefix(logger, Key(), InfoValue()) | ||||
| } | ||||
| 
 | ||||
| // Debug returns a logger that includes a Key/DebugValue pair.
 | ||||
| func Debug(logger log.Logger) log.Logger { | ||||
| 	return log.WithPrefix(logger, Key(), DebugValue()) | ||||
| } | ||||
| 
 | ||||
| // NewFilter wraps next and implements level filtering. See the commentary on
 | ||||
| // the Option functions for a detailed description of how to configure levels.
 | ||||
| // If no options are provided, all leveled log events created with Debug,
 | ||||
| // Info, Warn or Error helper methods are squelched and non-leveled log
 | ||||
| // events are passed to next unmodified.
 | ||||
| func NewFilter(next log.Logger, options ...Option) log.Logger { | ||||
| 	l := &logger{ | ||||
| 		next: next, | ||||
| 	} | ||||
| 	for _, option := range options { | ||||
| 		option(l) | ||||
| 	} | ||||
| 	return l | ||||
| } | ||||
| 
 | ||||
| type logger struct { | ||||
| 	next           log.Logger | ||||
| 	allowed        level | ||||
| 	squelchNoLevel bool | ||||
| 	errNotAllowed  error | ||||
| 	errNoLevel     error | ||||
| } | ||||
| 
 | ||||
| func (l *logger) Log(keyvals ...interface{}) error { | ||||
| 	var hasLevel, levelAllowed bool | ||||
| 	for i := 1; i < len(keyvals); i += 2 { | ||||
| 		if v, ok := keyvals[i].(*levelValue); ok { | ||||
| 			hasLevel = true | ||||
| 			levelAllowed = l.allowed&v.level != 0 | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	if !hasLevel && l.squelchNoLevel { | ||||
| 		return l.errNoLevel | ||||
| 	} | ||||
| 	if hasLevel && !levelAllowed { | ||||
| 		return l.errNotAllowed | ||||
| 	} | ||||
| 	return l.next.Log(keyvals...) | ||||
| } | ||||
| 
 | ||||
| // Option sets a parameter for the leveled logger.
 | ||||
| type Option func(*logger) | ||||
| 
 | ||||
| // AllowAll is an alias for AllowDebug.
 | ||||
| func AllowAll() Option { | ||||
| 	return AllowDebug() | ||||
| } | ||||
| 
 | ||||
| // AllowDebug allows error, warn, info and debug level log events to pass.
 | ||||
| func AllowDebug() Option { | ||||
| 	return allowed(levelError | levelWarn | levelInfo | levelDebug) | ||||
| } | ||||
| 
 | ||||
| // AllowInfo allows error, warn and info level log events to pass.
 | ||||
| func AllowInfo() Option { | ||||
| 	return allowed(levelError | levelWarn | levelInfo) | ||||
| } | ||||
| 
 | ||||
| // AllowWarn allows error and warn level log events to pass.
 | ||||
| func AllowWarn() Option { | ||||
| 	return allowed(levelError | levelWarn) | ||||
| } | ||||
| 
 | ||||
| // AllowError allows only error level log events to pass.
 | ||||
| func AllowError() Option { | ||||
| 	return allowed(levelError) | ||||
| } | ||||
| 
 | ||||
| // AllowNone allows no leveled log events to pass.
 | ||||
| func AllowNone() Option { | ||||
| 	return allowed(0) | ||||
| } | ||||
| 
 | ||||
| func allowed(allowed level) Option { | ||||
| 	return func(l *logger) { l.allowed = allowed } | ||||
| } | ||||
| 
 | ||||
| // ErrNotAllowed sets the error to return from Log when it squelches a log
 | ||||
| // event disallowed by the configured Allow[Level] option. By default,
 | ||||
| // ErrNotAllowed is nil; in this case the log event is squelched with no
 | ||||
| // error.
 | ||||
| func ErrNotAllowed(err error) Option { | ||||
| 	return func(l *logger) { l.errNotAllowed = err } | ||||
| } | ||||
| 
 | ||||
| // SquelchNoLevel instructs Log to squelch log events with no level, so that
 | ||||
| // they don't proceed through to the wrapped logger. If SquelchNoLevel is set
 | ||||
| // to true and a log event is squelched in this way, the error value
 | ||||
| // configured with ErrNoLevel is returned to the caller.
 | ||||
| func SquelchNoLevel(squelch bool) Option { | ||||
| 	return func(l *logger) { l.squelchNoLevel = squelch } | ||||
| } | ||||
| 
 | ||||
| // ErrNoLevel sets the error to return from Log when it squelches a log event
 | ||||
| // with no level. By default, ErrNoLevel is nil; in this case the log event is
 | ||||
| // squelched with no error.
 | ||||
| func ErrNoLevel(err error) Option { | ||||
| 	return func(l *logger) { l.errNoLevel = err } | ||||
| } | ||||
| 
 | ||||
| // NewInjector wraps next and returns a logger that adds a Key/level pair to
 | ||||
| // the beginning of log events that don't already contain a level. In effect,
 | ||||
| // this gives a default level to logs without a level.
 | ||||
| func NewInjector(next log.Logger, level Value) log.Logger { | ||||
| 	return &injector{ | ||||
| 		next:  next, | ||||
| 		level: level, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| type injector struct { | ||||
| 	next  log.Logger | ||||
| 	level interface{} | ||||
| } | ||||
| 
 | ||||
| func (l *injector) Log(keyvals ...interface{}) error { | ||||
| 	for i := 1; i < len(keyvals); i += 2 { | ||||
| 		if _, ok := keyvals[i].(*levelValue); ok { | ||||
| 			return l.next.Log(keyvals...) | ||||
| 		} | ||||
| 	} | ||||
| 	kvs := make([]interface{}, len(keyvals)+2) | ||||
| 	kvs[0], kvs[1] = key, l.level | ||||
| 	copy(kvs[2:], keyvals) | ||||
| 	return l.next.Log(kvs...) | ||||
| } | ||||
| 
 | ||||
| // Value is the interface that each of the canonical level values implement.
 | ||||
| // It contains unexported methods that prevent types from other packages from
 | ||||
| // implementing it and guaranteeing that NewFilter can distinguish the levels
 | ||||
| // defined in this package from all other values.
 | ||||
| type Value interface { | ||||
| 	String() string | ||||
| 	levelVal() | ||||
| } | ||||
| 
 | ||||
| // Key returns the unique key added to log events by the loggers in this
 | ||||
| // package.
 | ||||
| func Key() interface{} { return key } | ||||
| 
 | ||||
| // ErrorValue returns the unique value added to log events by Error.
 | ||||
| func ErrorValue() Value { return errorValue } | ||||
| 
 | ||||
| // WarnValue returns the unique value added to log events by Warn.
 | ||||
| func WarnValue() Value { return warnValue } | ||||
| 
 | ||||
| // InfoValue returns the unique value added to log events by Info.
 | ||||
| func InfoValue() Value { return infoValue } | ||||
| 
 | ||||
| // DebugValue returns the unique value added to log events by Debug.
 | ||||
| func DebugValue() Value { return debugValue } | ||||
| 
 | ||||
| var ( | ||||
| 	// key is of type interface{} so that it allocates once during package
 | ||||
| 	// initialization and avoids allocating every time the value is added to a
 | ||||
| 	// []interface{} later.
 | ||||
| 	key interface{} = "lvl" | ||||
| 
 | ||||
| 	errorValue = &levelValue{level: levelError, name: "eror"} | ||||
| 	warnValue  = &levelValue{level: levelWarn, name: "warn"} | ||||
| 	infoValue  = &levelValue{level: levelInfo, name: "info"} | ||||
| 	debugValue = &levelValue{level: levelDebug, name: "dbug"} | ||||
| ) | ||||
| 
 | ||||
| type level byte | ||||
| 
 | ||||
| const ( | ||||
| 	levelDebug level = 1 << iota | ||||
| 	levelInfo | ||||
| 	levelWarn | ||||
| 	levelError | ||||
| ) | ||||
| 
 | ||||
| type levelValue struct { | ||||
| 	name string | ||||
| 	level | ||||
| } | ||||
| 
 | ||||
| func (v *levelValue) String() string { return v.name } | ||||
| func (v *levelValue) levelVal()      {} | ||||
|  | @ -6,36 +6,237 @@ package log | |||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
| 	gokitlog "github.com/go-kit/log" | ||||
| 	"github.com/go-kit/log/term" | ||||
| 	"github.com/go-stack/stack" | ||||
| 	"github.com/grafana/grafana/pkg/infra/log/level" | ||||
| 	"github.com/grafana/grafana/pkg/util" | ||||
| 	"github.com/grafana/grafana/pkg/util/errutil" | ||||
| 	"github.com/inconshreveable/log15" | ||||
| 	isatty "github.com/mattn/go-isatty" | ||||
| 	"github.com/mattn/go-isatty" | ||||
| 	"gopkg.in/ini.v1" | ||||
| ) | ||||
| 
 | ||||
| var Root log15.Logger | ||||
| var loggersToClose []DisposableHandler | ||||
| var loggersToReload []ReloadableHandler | ||||
| var filters map[string]log15.Lvl | ||||
| var filters map[string]level.Option | ||||
| var Root MultiLoggers | ||||
| 
 | ||||
| func init() { | ||||
| 	loggersToClose = make([]DisposableHandler, 0) | ||||
| 	loggersToReload = make([]ReloadableHandler, 0) | ||||
| 	filters = map[string]log15.Lvl{} | ||||
| 	Root = log15.Root() | ||||
| 	Root.SetHandler(log15.DiscardHandler()) | ||||
| 	filters = map[string]level.Option{} | ||||
| 	Root.AddLogger(gokitlog.NewLogfmtLogger(os.Stderr), "info", filters) | ||||
| } | ||||
| 
 | ||||
| func New(logger string, ctx ...interface{}) Logger { | ||||
| 	params := append([]interface{}{"logger", logger}, ctx...) | ||||
| 	return Root.New(params...) | ||||
| type LogWithFilters struct { | ||||
| 	val      gokitlog.Logger | ||||
| 	filters  map[string]level.Option | ||||
| 	maxLevel level.Option | ||||
| } | ||||
| 
 | ||||
| type MultiLoggers struct { | ||||
| 	loggers []LogWithFilters | ||||
| } | ||||
| 
 | ||||
| func (ml *MultiLoggers) AddLogger(val gokitlog.Logger, levelName string, filters map[string]level.Option) { | ||||
| 	logger := LogWithFilters{val: val, filters: filters, maxLevel: getLogLevelFromString(levelName)} | ||||
| 	ml.loggers = append(ml.loggers, logger) | ||||
| } | ||||
| 
 | ||||
| func (ml *MultiLoggers) SetLogger(des MultiLoggers) { | ||||
| 	ml.loggers = des.loggers | ||||
| } | ||||
| 
 | ||||
| func (ml *MultiLoggers) GetLogger() MultiLoggers { | ||||
| 	return *ml | ||||
| } | ||||
| 
 | ||||
| func (ml MultiLoggers) Warn(msg string, args ...interface{}) { | ||||
| 	args = append([]interface{}{level.Key(), level.WarnValue(), "msg", msg}, args...) | ||||
| 	err := ml.Log(args...) | ||||
| 	if err != nil { | ||||
| 		_ = level.Error(Root).Log("Logging error", "error", err) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (ml MultiLoggers) Debug(msg string, args ...interface{}) { | ||||
| 	args = append([]interface{}{level.Key(), level.DebugValue(), "msg", msg}, args...) | ||||
| 	err := ml.Log(args...) | ||||
| 	if err != nil { | ||||
| 		_ = level.Error(Root).Log("Logging error", "error", err) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (ml MultiLoggers) Error(msg string, args ...interface{}) { | ||||
| 	args = append([]interface{}{level.Key(), level.ErrorValue(), "msg", msg}, args...) | ||||
| 	err := ml.Log(args...) | ||||
| 	if err != nil { | ||||
| 		_ = level.Error(Root).Log("Logging error", "error", err) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (ml MultiLoggers) Info(msg string, args ...interface{}) { | ||||
| 	args = append([]interface{}{level.Key(), level.InfoValue(), "msg", msg}, args...) | ||||
| 	err := ml.Log(args...) | ||||
| 	if err != nil { | ||||
| 		_ = level.Error(Root).Log("Logging error", "error", err) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (ml MultiLoggers) Log(keyvals ...interface{}) error { | ||||
| 	for _, multilogger := range ml.loggers { | ||||
| 		multilogger.val = gokitlog.With(multilogger.val, "t", gokitlog.TimestampFormat(time.Now, "2006-01-02T15:04:05.99-0700")) | ||||
| 		if err := multilogger.val.Log(keyvals...); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // we need to implement new function for multiloggers
 | ||||
| func (ml MultiLoggers) New(ctx ...interface{}) MultiLoggers { | ||||
| 	var newloger MultiLoggers | ||||
| 	for _, logWithFilter := range ml.loggers { | ||||
| 		logWithFilter.val = gokitlog.With(logWithFilter.val, ctx) | ||||
| 		if len(ctx) > 0 { | ||||
| 			v, ok := logWithFilter.filters[ctx[0].(string)] | ||||
| 			if ok { | ||||
| 				logWithFilter.val = level.NewFilter(logWithFilter.val, v) | ||||
| 			} else { | ||||
| 				logWithFilter.val = level.NewFilter(logWithFilter.val, logWithFilter.maxLevel) | ||||
| 			} | ||||
| 		} | ||||
| 		newloger.loggers = append(newloger.loggers, logWithFilter) | ||||
| 	} | ||||
| 	return newloger | ||||
| } | ||||
| 
 | ||||
| func New(ctx ...interface{}) MultiLoggers { | ||||
| 	if len(ctx) == 0 { | ||||
| 		return Root | ||||
| 	} | ||||
| 	var newloger MultiLoggers | ||||
| 	ctx = append([]interface{}{"logger"}, ctx...) | ||||
| 	for _, logWithFilter := range Root.loggers { | ||||
| 		logWithFilter.val = gokitlog.With(logWithFilter.val, ctx...) | ||||
| 		v, ok := logWithFilter.filters[ctx[0].(string)] | ||||
| 		if ok { | ||||
| 			logWithFilter.val = level.NewFilter(logWithFilter.val, v) | ||||
| 		} else { | ||||
| 			logWithFilter.val = level.NewFilter(logWithFilter.val, logWithFilter.maxLevel) | ||||
| 		} | ||||
| 		newloger.loggers = append(newloger.loggers, logWithFilter) | ||||
| 	} | ||||
| 	return newloger | ||||
| } | ||||
| 
 | ||||
| var logLevels = map[string]level.Option{ | ||||
| 	"trace":    level.AllowDebug(), | ||||
| 	"debug":    level.AllowDebug(), | ||||
| 	"info":     level.AllowInfo(), | ||||
| 	"warn":     level.AllowWarn(), | ||||
| 	"error":    level.AllowError(), | ||||
| 	"critical": level.AllowError(), | ||||
| } | ||||
| 
 | ||||
| func getLogLevelFromConfig(key string, defaultName string, cfg *ini.File) (string, level.Option) { | ||||
| 	levelName := cfg.Section(key).Key("level").MustString(defaultName) | ||||
| 	levelName = strings.ToLower(levelName) | ||||
| 	level := getLogLevelFromString(levelName) | ||||
| 	return levelName, level | ||||
| } | ||||
| 
 | ||||
| func getLogLevelFromString(levelName string) level.Option { | ||||
| 	loglevel, ok := logLevels[levelName] | ||||
| 
 | ||||
| 	if !ok { | ||||
| 		_ = level.Error(Root).Log("Unknown log level", "level", levelName) | ||||
| 		return level.AllowError() | ||||
| 	} | ||||
| 
 | ||||
| 	return loglevel | ||||
| } | ||||
| 
 | ||||
| // the filter is composed with logger name and level
 | ||||
| func getFilters(filterStrArray []string) map[string]level.Option { | ||||
| 	filterMap := make(map[string]level.Option) | ||||
| 
 | ||||
| 	for _, filterStr := range filterStrArray { | ||||
| 		parts := strings.Split(filterStr, ":") | ||||
| 		if len(parts) > 1 { | ||||
| 			filterMap[parts[0]] = getLogLevelFromString(parts[1]) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return filterMap | ||||
| } | ||||
| 
 | ||||
| func Stack(skip int) string { | ||||
| 	call := stack.Caller(skip) | ||||
| 	s := stack.Trace().TrimBelow(call).TrimRuntime() | ||||
| 	return s.String() | ||||
| } | ||||
| 
 | ||||
| type Formatedlogger func(w io.Writer) gokitlog.Logger | ||||
| 
 | ||||
| func terminalColorFn(keyvals ...interface{}) term.FgBgColor { | ||||
| 	for i := 0; i < len(keyvals)-1; i += 2 { | ||||
| 		if keyvals[i] != level.Key() { | ||||
| 			continue | ||||
| 		} | ||||
| 		switch keyvals[i+1] { | ||||
| 		case "trace": | ||||
| 			return term.FgBgColor{Fg: term.Gray} | ||||
| 		case level.DebugValue(): | ||||
| 			return term.FgBgColor{Fg: term.Gray} | ||||
| 		case level.InfoValue(): | ||||
| 			return term.FgBgColor{Fg: term.Green} | ||||
| 		case level.WarnValue(): | ||||
| 			return term.FgBgColor{Fg: term.Yellow} | ||||
| 		case level.ErrorValue(): | ||||
| 			return term.FgBgColor{Fg: term.Red} | ||||
| 		case "crit": | ||||
| 			return term.FgBgColor{Fg: term.Gray, Bg: term.DarkRed} | ||||
| 		default: | ||||
| 			return term.FgBgColor{} | ||||
| 		} | ||||
| 	} | ||||
| 	return term.FgBgColor{} | ||||
| } | ||||
| 
 | ||||
| func getLogFormat(format string) Formatedlogger { | ||||
| 	switch format { | ||||
| 	case "console": | ||||
| 		if isatty.IsTerminal(os.Stdout.Fd()) { | ||||
| 			return func(w io.Writer) gokitlog.Logger { | ||||
| 				return term.NewColorLogger(w, gokitlog.NewLogfmtLogger, terminalColorFn) | ||||
| 			} | ||||
| 		} | ||||
| 		return func(w io.Writer) gokitlog.Logger { | ||||
| 			return gokitlog.NewLogfmtLogger(w) | ||||
| 		} | ||||
| 	case "text": | ||||
| 		return func(w io.Writer) gokitlog.Logger { | ||||
| 			return gokitlog.NewLogfmtLogger(w) | ||||
| 		} | ||||
| 	case "json": | ||||
| 		return func(w io.Writer) gokitlog.Logger { | ||||
| 			return gokitlog.NewJSONLogger(gokitlog.NewSyncWriter(w)) | ||||
| 		} | ||||
| 	default: | ||||
| 		return func(w io.Writer) gokitlog.Logger { | ||||
| 			return gokitlog.NewLogfmtLogger(w) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // this is for file logger only
 | ||||
| func Close() error { | ||||
| 	var err error | ||||
| 	for _, logger := range loggersToClose { | ||||
|  | @ -59,62 +260,6 @@ func Reload() error { | |||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| var logLevels = map[string]log15.Lvl{ | ||||
| 	"trace":    log15.LvlDebug, | ||||
| 	"debug":    log15.LvlDebug, | ||||
| 	"info":     log15.LvlInfo, | ||||
| 	"warn":     log15.LvlWarn, | ||||
| 	"error":    log15.LvlError, | ||||
| 	"critical": log15.LvlCrit, | ||||
| } | ||||
| 
 | ||||
| func getLogLevelFromConfig(key string, defaultName string, cfg *ini.File) (string, log15.Lvl) { | ||||
| 	levelName := cfg.Section(key).Key("level").MustString(defaultName) | ||||
| 	levelName = strings.ToLower(levelName) | ||||
| 	level := getLogLevelFromString(levelName) | ||||
| 	return levelName, level | ||||
| } | ||||
| 
 | ||||
| func getLogLevelFromString(levelName string) log15.Lvl { | ||||
| 	level, ok := logLevels[levelName] | ||||
| 
 | ||||
| 	if !ok { | ||||
| 		Root.Error("Unknown log level", "level", levelName) | ||||
| 		return log15.LvlError | ||||
| 	} | ||||
| 
 | ||||
| 	return level | ||||
| } | ||||
| 
 | ||||
| func getFilters(filterStrArray []string) map[string]log15.Lvl { | ||||
| 	filterMap := make(map[string]log15.Lvl) | ||||
| 
 | ||||
| 	for _, filterStr := range filterStrArray { | ||||
| 		parts := strings.Split(filterStr, ":") | ||||
| 		if len(parts) > 1 { | ||||
| 			filterMap[parts[0]] = getLogLevelFromString(parts[1]) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return filterMap | ||||
| } | ||||
| 
 | ||||
| func getLogFormat(format string) log15.Format { | ||||
| 	switch format { | ||||
| 	case "console": | ||||
| 		if isatty.IsTerminal(os.Stdout.Fd()) { | ||||
| 			return log15.TerminalFormat() | ||||
| 		} | ||||
| 		return log15.LogfmtFormat() | ||||
| 	case "text": | ||||
| 		return log15.LogfmtFormat() | ||||
| 	case "json": | ||||
| 		return log15.JsonFormat() | ||||
| 	default: | ||||
| 		return log15.LogfmtFormat() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func ReadLoggingConfig(modes []string, logsPath string, cfg *ini.File) error { | ||||
| 	if err := Close(); err != nil { | ||||
| 		return err | ||||
|  | @ -123,32 +268,31 @@ func ReadLoggingConfig(modes []string, logsPath string, cfg *ini.File) error { | |||
| 	defaultLevelName, _ := getLogLevelFromConfig("log", "info", cfg) | ||||
| 	defaultFilters := getFilters(util.SplitString(cfg.Section("log").Key("filters").String())) | ||||
| 
 | ||||
| 	handlers := make([]log15.Handler, 0) | ||||
| 
 | ||||
| 	var configLoggers []LogWithFilters | ||||
| 	for _, mode := range modes { | ||||
| 		mode = strings.TrimSpace(mode) | ||||
| 		sec, err := cfg.GetSection("log." + mode) | ||||
| 		if err != nil { | ||||
| 			Root.Error("Unknown log mode", "mode", mode) | ||||
| 			_ = level.Error(Root).Log("Unknown log mode", "mode", mode) | ||||
| 			return errutil.Wrapf(err, "failed to get config section log.%s", mode) | ||||
| 		} | ||||
| 
 | ||||
| 		// Log level.
 | ||||
| 		_, level := getLogLevelFromConfig("log."+mode, defaultLevelName, cfg) | ||||
| 		_, leveloption := getLogLevelFromConfig("log."+mode, defaultLevelName, cfg) | ||||
| 		modeFilters := getFilters(util.SplitString(sec.Key("filters").String())) | ||||
| 
 | ||||
| 		format := getLogFormat(sec.Key("format").MustString("")) | ||||
| 
 | ||||
| 		var handler log15.Handler | ||||
| 		var handler LogWithFilters | ||||
| 
 | ||||
| 		// Generate log configuration.
 | ||||
| 		switch mode { | ||||
| 		case "console": | ||||
| 			handler = log15.StreamHandler(os.Stdout, format) | ||||
| 			handler.val = format(os.Stdout) | ||||
| 		case "file": | ||||
| 			fileName := sec.Key("file_name").MustString(filepath.Join(logsPath, "grafana.log")) | ||||
| 			dpath := filepath.Dir(fileName) | ||||
| 			if err := os.MkdirAll(dpath, os.ModePerm); err != nil { | ||||
| 				Root.Error("Failed to create directory", "dpath", dpath, "err", err) | ||||
| 				_ = level.Error(Root).Log("Failed to create directory", "dpath", dpath, "err", err) | ||||
| 				return errutil.Wrapf(err, "failed to create log directory %q", dpath) | ||||
| 			} | ||||
| 			fileHandler := NewFileWriter() | ||||
|  | @ -160,65 +304,43 @@ func ReadLoggingConfig(modes []string, logsPath string, cfg *ini.File) error { | |||
| 			fileHandler.Daily = sec.Key("daily_rotate").MustBool(true) | ||||
| 			fileHandler.Maxdays = sec.Key("max_days").MustInt64(7) | ||||
| 			if err := fileHandler.Init(); err != nil { | ||||
| 				Root.Error("Failed to initialize file handler", "dpath", dpath, "err", err) | ||||
| 				_ = level.Error(Root).Log("Failed to initialize file handler", "dpath", dpath, "err", err) | ||||
| 				return errutil.Wrapf(err, "failed to initialize file handler") | ||||
| 			} | ||||
| 
 | ||||
| 			loggersToClose = append(loggersToClose, fileHandler) | ||||
| 			loggersToReload = append(loggersToReload, fileHandler) | ||||
| 			handler = fileHandler | ||||
| 			handler.val = fileHandler | ||||
| 		case "syslog": | ||||
| 			sysLogHandler := NewSyslog(sec, format) | ||||
| 
 | ||||
| 			loggersToClose = append(loggersToClose, sysLogHandler) | ||||
| 			handler = sysLogHandler | ||||
| 			handler.val = sysLogHandler.logger | ||||
| 		} | ||||
| 		if handler == nil { | ||||
| 		if handler.val == nil { | ||||
| 			panic(fmt.Sprintf("Handler is uninitialized for mode %q", mode)) | ||||
| 		} | ||||
| 
 | ||||
| 		// join default filters and mode filters together
 | ||||
| 		for key, value := range defaultFilters { | ||||
| 			if _, exist := modeFilters[key]; !exist { | ||||
| 				modeFilters[key] = value | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// copy joined default + mode filters into filters
 | ||||
| 		for key, value := range modeFilters { | ||||
| 			if _, exist := filters[key]; !exist { | ||||
| 				filters[key] = value | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		handler = LogFilterHandler(level, modeFilters, handler) | ||||
| 		handlers = append(handlers, handler) | ||||
| 		handler.filters = modeFilters | ||||
| 		handler.maxLevel = leveloption | ||||
| 		// handler = LogFilterHandler(leveloption, modeFilters, handler)
 | ||||
| 		configLoggers = append(configLoggers, handler) | ||||
| 	} | ||||
| 	if len(configLoggers) > 0 { | ||||
| 		Root.loggers = configLoggers | ||||
| 	} | ||||
| 
 | ||||
| 	Root.SetHandler(log15.MultiHandler(handlers...)) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func LogFilterHandler(maxLevel log15.Lvl, filters map[string]log15.Lvl, h log15.Handler) log15.Handler { | ||||
| 	return log15.FilterHandler(func(r *log15.Record) (pass bool) { | ||||
| 		if len(filters) > 0 { | ||||
| 			for i := 0; i < len(r.Ctx); i += 2 { | ||||
| 				key, ok := r.Ctx[i].(string) | ||||
| 				if ok && key == "logger" { | ||||
| 					loggerName, strOk := r.Ctx[i+1].(string) | ||||
| 					if strOk { | ||||
| 						if filterLevel, ok := filters[loggerName]; ok { | ||||
| 							return r.Lvl <= filterLevel | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return r.Lvl <= maxLevel | ||||
| 	}, h) | ||||
| } | ||||
| 
 | ||||
| func Stack(skip int) string { | ||||
| 	call := stack.Caller(skip) | ||||
| 	s := stack.Trace().TrimBelow(call).TrimRuntime() | ||||
| 	return s.String() | ||||
| } | ||||
|  |  | |||
|  | @ -4,11 +4,12 @@ | |||
| package log | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"log/syslog" | ||||
| 	"os" | ||||
| 
 | ||||
| 	"github.com/inconshreveable/log15" | ||||
| 	"github.com/go-kit/log" | ||||
| 	"github.com/go-kit/log/level" | ||||
| 	gokitsyslog "github.com/go-kit/log/syslog" | ||||
| 	"gopkg.in/ini.v1" | ||||
| ) | ||||
| 
 | ||||
|  | @ -18,13 +19,41 @@ type SysLogHandler struct { | |||
| 	Address  string | ||||
| 	Facility string | ||||
| 	Tag      string | ||||
| 	Format   log15.Format | ||||
| 	Format   Formatedlogger | ||||
| 	logger   log.Logger | ||||
| } | ||||
| 
 | ||||
| func NewSyslog(sec *ini.Section, format log15.Format) *SysLogHandler { | ||||
| 	handler := &SysLogHandler{ | ||||
| 		Format: log15.LogfmtFormat(), | ||||
| var selector = func(keyvals ...interface{}) syslog.Priority { | ||||
| 	for i := 0; i < len(keyvals); i += 2 { | ||||
| 		if keyvals[i] == level.Key() { | ||||
| 			if v, ok := keyvals[i+1].(string); ok { | ||||
| 				switch v { | ||||
| 				case "emergency": | ||||
| 					return syslog.LOG_EMERG | ||||
| 				case "alert": | ||||
| 					return syslog.LOG_ALERT | ||||
| 				case "critical": | ||||
| 					return syslog.LOG_CRIT | ||||
| 				case "error": | ||||
| 					return syslog.LOG_ERR | ||||
| 				case "warning": | ||||
| 					return syslog.LOG_WARNING | ||||
| 				case "notice": | ||||
| 					return syslog.LOG_NOTICE | ||||
| 				case "info": | ||||
| 					return syslog.LOG_INFO | ||||
| 				case "debug": | ||||
| 					return syslog.LOG_DEBUG | ||||
| 				} | ||||
| 				return syslog.LOG_LOCAL0 | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return syslog.LOG_LOCAL0 | ||||
| } | ||||
| 
 | ||||
| func NewSyslog(sec *ini.Section, format Formatedlogger) *SysLogHandler { | ||||
| 	handler := &SysLogHandler{} | ||||
| 
 | ||||
| 	handler.Format = format | ||||
| 	handler.Network = sec.Key("network").MustString("") | ||||
|  | @ -33,18 +62,16 @@ func NewSyslog(sec *ini.Section, format log15.Format) *SysLogHandler { | |||
| 	handler.Tag = sec.Key("tag").MustString("") | ||||
| 
 | ||||
| 	if err := handler.Init(); err != nil { | ||||
| 		Root.Error("Failed to init syslog log handler", "error", err) | ||||
| 		_ = level.Error(Root).Log("Failed to init syslog log handler", "error", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 
 | ||||
| 	handler.logger = gokitsyslog.NewSyslogLogger(handler.syslog, format, gokitsyslog.PrioritySelectorOption(selector)) | ||||
| 	return handler | ||||
| } | ||||
| 
 | ||||
| func (sw *SysLogHandler) Init() error { | ||||
| 	prio, err := parseFacility(sw.Facility) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	// the facility is the origin of the syslog message
 | ||||
| 	prio := parseFacility(sw.Facility) | ||||
| 
 | ||||
| 	w, err := syslog.Dial(sw.Network, sw.Address, prio, sw.Tag) | ||||
| 	if err != nil { | ||||
|  | @ -55,26 +82,8 @@ func (sw *SysLogHandler) Init() error { | |||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (sw *SysLogHandler) Log(r *log15.Record) error { | ||||
| 	var err error | ||||
| 
 | ||||
| 	msg := string(sw.Format.Format(r)) | ||||
| 
 | ||||
| 	switch r.Lvl { | ||||
| 	case log15.LvlDebug: | ||||
| 		err = sw.syslog.Debug(msg) | ||||
| 	case log15.LvlInfo: | ||||
| 		err = sw.syslog.Info(msg) | ||||
| 	case log15.LvlWarn: | ||||
| 		err = sw.syslog.Warning(msg) | ||||
| 	case log15.LvlError: | ||||
| 		err = sw.syslog.Err(msg) | ||||
| 	case log15.LvlCrit: | ||||
| 		err = sw.syslog.Crit(msg) | ||||
| 	default: | ||||
| 		err = errors.New("invalid syslog level") | ||||
| 	} | ||||
| 
 | ||||
| func (sw *SysLogHandler) Log(keyvals ...interface{}) error { | ||||
| 	err := sw.logger.Log(keyvals...) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
|  | @ -95,11 +104,11 @@ var facilities = map[string]syslog.Priority{ | |||
| 	"local7": syslog.LOG_LOCAL7, | ||||
| } | ||||
| 
 | ||||
| func parseFacility(facility string) (syslog.Priority, error) { | ||||
| 	prio, ok := facilities[facility] | ||||
| 	if !ok { | ||||
| 		return syslog.LOG_LOCAL0, errors.New("invalid syslog facility") | ||||
| func parseFacility(facility string) syslog.Priority { | ||||
| 	v, found := facilities[facility] | ||||
| 	if !found { | ||||
| 		// default the facility level to LOG_LOCAL7
 | ||||
| 		return syslog.LOG_LOCAL7 | ||||
| 	} | ||||
| 
 | ||||
| 	return prio, nil | ||||
| 	return v | ||||
| } | ||||
|  |  | |||
|  | @ -4,18 +4,19 @@ | |||
| package log | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/inconshreveable/log15" | ||||
| 	"github.com/go-kit/log" | ||||
| 	"gopkg.in/ini.v1" | ||||
| ) | ||||
| 
 | ||||
| type SysLogHandler struct { | ||||
| 	logger log.Logger | ||||
| } | ||||
| 
 | ||||
| func NewSyslog(sec *ini.Section, format log15.Format) *SysLogHandler { | ||||
| func NewSyslog(sec *ini.Section, format Formatedlogger) *SysLogHandler { | ||||
| 	return &SysLogHandler{} | ||||
| } | ||||
| 
 | ||||
| func (sw *SysLogHandler) Log(r *log15.Record) error { | ||||
| func (sw *SysLogHandler) Log(keyvals ...interface{}) error { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -7,7 +7,8 @@ import ( | |||
| 	"errors" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/grafana/grafana/pkg/infra/log" | ||||
| 	"github.com/go-kit/log" | ||||
| 	glog "github.com/grafana/grafana/pkg/infra/log" | ||||
| 	"github.com/grafana/grafana/pkg/registry" | ||||
| 	"github.com/grafana/grafana/pkg/services/sqlstore" | ||||
| 	"github.com/grafana/grafana/pkg/setting" | ||||
|  | @ -35,7 +36,7 @@ func ProvideService(cfg *setting.Cfg, sqlStore *sqlstore.SQLStore) (*RemoteCache | |||
| 	s := &RemoteCache{ | ||||
| 		SQLStore: sqlStore, | ||||
| 		Cfg:      cfg, | ||||
| 		log:      log.New("cache.remote"), | ||||
| 		log:      glog.New("cache.remote"), | ||||
| 		client:   client, | ||||
| 	} | ||||
| 	return s, nil | ||||
|  |  | |||
|  | @ -23,7 +23,7 @@ type UsageStats struct { | |||
| 	SocialService social.Service | ||||
| 	kvStore       *kvstore.NamespacedKVStore | ||||
| 
 | ||||
| 	log log.Logger | ||||
| 	log log.MultiLoggers | ||||
| 
 | ||||
| 	oauthProviders           map[string]bool | ||||
| 	externalMetrics          []usagestats.MetricsFunc | ||||
|  |  | |||
|  | @ -4,28 +4,19 @@ import ( | |||
| 	"encoding/json" | ||||
| 	"net/http" | ||||
| 	"net/http/httptest" | ||||
| 	"os" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/grafana/grafana/pkg/infra/log" | ||||
| 	"github.com/inconshreveable/log15" | ||||
| 	"github.com/mattn/go-isatty" | ||||
| 	"github.com/grafana/grafana/pkg/infra/log/level" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 	"github.com/stretchr/testify/require" | ||||
| 	"golang.org/x/oauth2" | ||||
| ) | ||||
| 
 | ||||
| func getLogFormat() log15.Format { | ||||
| 	if isatty.IsTerminal(os.Stdout.Fd()) { | ||||
| 		return log15.TerminalFormat() | ||||
| 	} | ||||
| 	return log15.LogfmtFormat() | ||||
| } | ||||
| 
 | ||||
| func newLogger(name string, level log15.Lvl) log.Logger { | ||||
| func newLogger(name string, lev string) log.Logger { | ||||
| 	logger := log.Root.New("logger", name) | ||||
| 	logger.SetHandler(log15.LvlFilterHandler(level, log15.StreamHandler(os.Stdout, getLogFormat()))) | ||||
| 	logger.AddLogger(logger, lev, map[string]level.Option{}) | ||||
| 	return logger | ||||
| } | ||||
| 
 | ||||
|  | @ -33,7 +24,7 @@ func TestSearchJSONForEmail(t *testing.T) { | |||
| 	t.Run("Given a generic OAuth provider", func(t *testing.T) { | ||||
| 		provider := SocialGenericOAuth{ | ||||
| 			SocialBase: &SocialBase{ | ||||
| 				log: newLogger("generic_oauth_test", log15.LvlDebug), | ||||
| 				log: newLogger("generic_oauth_test", "debug"), | ||||
| 			}, | ||||
| 		} | ||||
| 
 | ||||
|  | @ -121,7 +112,7 @@ func TestSearchJSONForGroups(t *testing.T) { | |||
| 	t.Run("Given a generic OAuth provider", func(t *testing.T) { | ||||
| 		provider := SocialGenericOAuth{ | ||||
| 			SocialBase: &SocialBase{ | ||||
| 				log: newLogger("generic_oauth_test", log15.LvlDebug), | ||||
| 				log: newLogger("generic_oauth_test", "debug"), | ||||
| 			}, | ||||
| 		} | ||||
| 
 | ||||
|  | @ -184,7 +175,7 @@ func TestSearchJSONForRole(t *testing.T) { | |||
| 	t.Run("Given a generic OAuth provider", func(t *testing.T) { | ||||
| 		provider := SocialGenericOAuth{ | ||||
| 			SocialBase: &SocialBase{ | ||||
| 				log: newLogger("generic_oauth_test", log15.LvlDebug), | ||||
| 				log: newLogger("generic_oauth_test", "debug"), | ||||
| 			}, | ||||
| 		} | ||||
| 
 | ||||
|  | @ -247,7 +238,7 @@ func TestUserInfoSearchesForEmailAndRole(t *testing.T) { | |||
| 	t.Run("Given a generic OAuth provider", func(t *testing.T) { | ||||
| 		provider := SocialGenericOAuth{ | ||||
| 			SocialBase: &SocialBase{ | ||||
| 				log: newLogger("generic_oauth_test", log15.LvlDebug), | ||||
| 				log: newLogger("generic_oauth_test", "debug"), | ||||
| 			}, | ||||
| 			emailAttributePath: "email", | ||||
| 		} | ||||
|  | @ -456,7 +447,7 @@ func TestUserInfoSearchesForLogin(t *testing.T) { | |||
| 	t.Run("Given a generic OAuth provider", func(t *testing.T) { | ||||
| 		provider := SocialGenericOAuth{ | ||||
| 			SocialBase: &SocialBase{ | ||||
| 				log: newLogger("generic_oauth_test", log15.LvlDebug), | ||||
| 				log: newLogger("generic_oauth_test", "debug"), | ||||
| 			}, | ||||
| 			loginAttributePath: "login", | ||||
| 		} | ||||
|  | @ -551,7 +542,7 @@ func TestUserInfoSearchesForName(t *testing.T) { | |||
| 	t.Run("Given a generic OAuth provider", func(t *testing.T) { | ||||
| 		provider := SocialGenericOAuth{ | ||||
| 			SocialBase: &SocialBase{ | ||||
| 				log: newLogger("generic_oauth_test", log15.LvlDebug), | ||||
| 				log: newLogger("generic_oauth_test", "debug"), | ||||
| 			}, | ||||
| 			nameAttributePath: "name", | ||||
| 		} | ||||
|  | @ -649,7 +640,7 @@ func TestUserInfoSearchesForGroup(t *testing.T) { | |||
| 	t.Run("Given a generic OAuth provider", func(t *testing.T) { | ||||
| 		provider := SocialGenericOAuth{ | ||||
| 			SocialBase: &SocialBase{ | ||||
| 				log: newLogger("generic_oauth_test", log15.LvlDebug), | ||||
| 				log: newLogger("generic_oauth_test", "debug"), | ||||
| 			}, | ||||
| 		} | ||||
| 
 | ||||
|  | @ -717,7 +708,7 @@ func TestUserInfoSearchesForGroup(t *testing.T) { | |||
| func TestPayloadCompression(t *testing.T) { | ||||
| 	provider := SocialGenericOAuth{ | ||||
| 		SocialBase: &SocialBase{ | ||||
| 			log: newLogger("generic_oauth_test", log15.LvlDebug), | ||||
| 			log: newLogger("generic_oauth_test", "debug"), | ||||
| 		}, | ||||
| 		emailAttributePath: "email", | ||||
| 	} | ||||
|  |  | |||
|  | @ -106,7 +106,8 @@ func Recovery(cfg *setting.Cfg) web.Handler { | |||
| 	return func(c *web.Context) { | ||||
| 		defer func() { | ||||
| 			if r := recover(); r != nil { | ||||
| 				panicLogger := log.Root | ||||
| 				var panicLogger log.Logger | ||||
| 				panicLogger = log.Root | ||||
| 				// try to get request logger
 | ||||
| 				ctx := contexthandler.FromContext(c.Req.Context()) | ||||
| 				if ctx != nil { | ||||
|  |  | |||
|  | @ -5,7 +5,6 @@ import ( | |||
| 	"path/filepath" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/inconshreveable/log15" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 
 | ||||
| 	"github.com/grafana/grafana/pkg/infra/log" | ||||
|  | @ -357,11 +356,11 @@ type testPlugin struct { | |||
| } | ||||
| 
 | ||||
| type fakeLogger struct { | ||||
| 	log.Logger | ||||
| 	log.MultiLoggers | ||||
| } | ||||
| 
 | ||||
| func (f fakeLogger) New(_ ...interface{}) log15.Logger { | ||||
| 	return fakeLogger{} | ||||
| func (f fakeLogger) New(_ ...interface{}) log.MultiLoggers { | ||||
| 	return log.MultiLoggers{} | ||||
| } | ||||
| 
 | ||||
| func (f fakeLogger) Warn(_ string, _ ...interface{}) { | ||||
|  |  | |||
|  | @ -1,14 +1,16 @@ | |||
| package loginservice | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/go-kit/log" | ||||
| 	"github.com/grafana/grafana/pkg/bus" | ||||
| 	"github.com/grafana/grafana/pkg/infra/log/level" | ||||
| 	"github.com/grafana/grafana/pkg/models" | ||||
| 	"github.com/grafana/grafana/pkg/services/quota" | ||||
| 	log "github.com/inconshreveable/log15" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 	"github.com/stretchr/testify/require" | ||||
| ) | ||||
|  | @ -43,11 +45,8 @@ func Test_syncOrgRoles_doesNotBreakWhenTryingToRemoveLastOrgAdmin(t *testing.T) | |||
| } | ||||
| 
 | ||||
| func Test_syncOrgRoles_whenTryingToRemoveLastOrgLogsError(t *testing.T) { | ||||
| 	logs := []string{} | ||||
| 	logger.SetHandler(log.FuncHandler(func(r *log.Record) error { | ||||
| 		logs = append(logs, r.Msg) | ||||
| 		return nil | ||||
| 	})) | ||||
| 	buf := &bytes.Buffer{} | ||||
| 	logger.AddLogger(log.NewLogfmtLogger(buf), "info", map[string]level.Option{}) | ||||
| 
 | ||||
| 	user := createSimpleUser() | ||||
| 	externalUser := createSimpleExternalUser() | ||||
|  | @ -57,7 +56,6 @@ func Test_syncOrgRoles_whenTryingToRemoveLastOrgLogsError(t *testing.T) { | |||
| 	defer bus.ClearBusHandlers() | ||||
| 	bus.AddHandler("test", func(ctx context.Context, q *models.GetUserOrgListQuery) error { | ||||
| 		q.Result = createUserOrgDTO() | ||||
| 
 | ||||
| 		return nil | ||||
| 	}) | ||||
| 
 | ||||
|  | @ -74,7 +72,7 @@ func Test_syncOrgRoles_whenTryingToRemoveLastOrgLogsError(t *testing.T) { | |||
| 
 | ||||
| 	err := syncOrgRoles(context.Background(), &user, &externalUser) | ||||
| 	require.NoError(t, err) | ||||
| 	assert.Contains(t, logs, models.ErrLastOrgAdmin.Error()) | ||||
| 	assert.Contains(t, buf.String(), models.ErrLastOrgAdmin.Error()) | ||||
| } | ||||
| 
 | ||||
| type authInfoServiceMock struct { | ||||
|  |  | |||
|  | @ -6,18 +6,17 @@ import ( | |||
| 	"io" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	gokit_log "github.com/go-kit/kit/log" | ||||
| 	"github.com/go-kit/log" | ||||
| 	"github.com/go-kit/log/level" | ||||
| 	"github.com/inconshreveable/log15" | ||||
| 	glog "github.com/grafana/grafana/pkg/infra/log" | ||||
| 	"github.com/grafana/grafana/pkg/infra/log/level" | ||||
| 	"github.com/stretchr/testify/require" | ||||
| ) | ||||
| 
 | ||||
| func Test_GoKitWrapper(t *testing.T) { | ||||
| 	getLogger := func(writer io.Writer) log.Logger { | ||||
| 		log15Logger := log15.New() | ||||
| 		log15Logger.SetHandler(log15.StreamHandler(writer, log15.LogfmtFormat())) | ||||
| 		return NewWrapper(log15Logger) | ||||
| 		gLogger := glog.New() | ||||
| 		gLogger.AddLogger(log.NewLogfmtLogger(writer), "info", map[string]level.Option{}) | ||||
| 		return NewWrapper(gLogger) | ||||
| 	} | ||||
| 
 | ||||
| 	tests := []struct { | ||||
|  | @ -71,20 +70,21 @@ func Test_GoKitWrapper(t *testing.T) { | |||
| } | ||||
| 
 | ||||
| func Benchmark_Baseline(t *testing.B) { | ||||
| 	log15Logger := log15.New() | ||||
| 	gLogger := glog.New() | ||||
| 	var buff bytes.Buffer | ||||
| 	log15Logger.SetHandler(log15.StreamHandler(&buff, log15.LogfmtFormat())) | ||||
| 	gLogger.AddLogger(log.NewLogfmtLogger(&buff), "info", map[string]level.Option{}) | ||||
| 
 | ||||
| 	for i := 0; i < t.N; i++ { | ||||
| 		log15Logger.Info("test", "some", "more", "context", "data") | ||||
| 		gLogger.Info("test", "some", "more", "context", "data") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func Benchmark_WrapperLogger(t *testing.B) { | ||||
| 	log15Logger := log15.New() | ||||
| 	gLogger := glog.New() | ||||
| 	var buff bytes.Buffer | ||||
| 	log15Logger.SetHandler(log15.StreamHandler(&buff, log15.LogfmtFormat())) | ||||
| 	gokit := NewWrapper(log15Logger) | ||||
| 	gLogger.AddLogger(log.NewLogfmtLogger(&buff), "info", map[string]level.Option{}) | ||||
| 
 | ||||
| 	gokit := NewWrapper(gLogger) | ||||
| 
 | ||||
| 	for i := 0; i < t.N; i++ { | ||||
| 		_ = level.Info(gokit).Log("msg", "test", "some", "more", "context", "data") | ||||
|  | @ -92,10 +92,11 @@ func Benchmark_WrapperLogger(t *testing.B) { | |||
| } | ||||
| 
 | ||||
| func Benchmark_WrapperWriter(t *testing.B) { | ||||
| 	log15Logger := log15.New() | ||||
| 	gLogger := glog.New() | ||||
| 	var buff bytes.Buffer | ||||
| 	log15Logger.SetHandler(log15.StreamHandler(&buff, log15.LogfmtFormat())) | ||||
| 	gokit := gokit_log.NewLogfmtLogger(NewWrapper(log15Logger)) | ||||
| 	gLogger.AddLogger(log.NewLogfmtLogger(&buff), "info", map[string]level.Option{}) | ||||
| 	gokit := NewWrapper(gLogger) | ||||
| 
 | ||||
| 	for i := 0; i < t.N; i++ { | ||||
| 		_ = level.Info(gokit).Log("msg", "test", "some", "more", "context", "data") | ||||
| 	} | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue