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:
co-authored by
Yuriy Tseretyan
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
|
||||
|
||||
Reference in New Issue
Block a user