Frontend logging: Remove Sentry javascript agent support (#67493)

* remove Sentry

* fix sourcemap resolve
This commit is contained in:
Domas
2023-05-02 12:10:56 +03:00
committed by GitHub
parent 9614dc2446
commit 15d4169813
38 changed files with 47 additions and 1288 deletions
-1
View File
@@ -185,7 +185,6 @@ type FrontendSettingsDTO struct {
RendererVersion string `json:"rendererVersion"`
SecretsManagerPluginEnabled bool `json:"secretsManagerPluginEnabled"`
Http2Enabled bool `json:"http2Enabled"`
Sentry setting.Sentry `json:"sentry"`
GrafanaJavascriptAgent setting.GrafanaJavascriptAgent `json:"grafanaJavascriptAgent"`
PluginCatalogURL string `json:"pluginCatalogURL"`
PluginAdminEnabled bool `json:"pluginAdminEnabled"`
-2
View File
@@ -4,7 +4,6 @@ import (
"html/template"
"github.com/grafana/grafana/pkg/services/navtree"
"github.com/grafana/grafana/pkg/setting"
)
type IndexViewData struct {
@@ -27,7 +26,6 @@ type IndexViewData struct {
FavIcon template.URL
AppleTouchIcon template.URL
AppTitle string
Sentry *setting.Sentry
ContentDeliveryURL string
LoadingLogo template.URL
CSPContent string
+5 -71
View File
@@ -4,7 +4,6 @@ import (
"net/http"
"time"
"github.com/getsentry/sentry-go"
"golang.org/x/time/rate"
"github.com/grafana/grafana/pkg/api/frontendlogging"
@@ -16,51 +15,8 @@ var frontendLogger = log.New("frontend")
type frontendLogMessageHandler func(hs *HTTPServer, c *web.Context)
const sentryLogEndpointPath = "/log"
const grafanaJavascriptAgentEndpointPath = "/log-grafana-javascript-agent"
/** @deprecated will be removed in the next major version */
func NewFrontendLogMessageHandler(store *frontendlogging.SourceMapStore) frontendLogMessageHandler {
return func(hs *HTTPServer, c *web.Context) {
event := frontendlogging.FrontendSentryEvent{}
if err := web.Bind(c.Req, &event); err != nil {
c.Resp.WriteHeader(http.StatusBadRequest)
_, err = c.Resp.Write([]byte("bad request data"))
if err != nil {
hs.log.Error("could not write to response", "err", err)
}
return
}
var msg = "unknown"
if len(event.Message) > 0 {
msg = event.Message
} else if event.Exception != nil && len(event.Exception.Values) > 0 {
msg = event.Exception.Values[0].FmtMessage()
}
var ctx = event.ToLogContext(store)
switch event.Level {
case sentry.LevelError:
frontendLogger.Error(msg, ctx...)
case sentry.LevelWarning:
frontendLogger.Warn(msg, ctx...)
case sentry.LevelDebug:
frontendLogger.Debug(msg, ctx...)
default:
frontendLogger.Info(msg, ctx...)
}
c.Resp.WriteHeader(http.StatusAccepted)
_, err := c.Resp.Write([]byte("OK"))
if err != nil {
hs.log.Error("could not write to response", "err", err)
}
}
}
func GrafanaJavascriptAgentLogMessageHandler(store *frontendlogging.SourceMapStore) frontendLogMessageHandler {
return func(hs *HTTPServer, c *web.Context) {
event := frontendlogging.FrontendGrafanaJavascriptAgentEvent{}
@@ -143,9 +99,9 @@ func GrafanaJavascriptAgentLogMessageHandler(store *frontendlogging.SourceMapSto
// this is to avoid reporting errors in case config was changes but there are browser
// sessions still open with older config
func (hs *HTTPServer) frontendLogEndpoints() web.Handler {
if !(hs.Cfg.GrafanaJavascriptAgent.Enabled || hs.Cfg.Sentry.Enabled) {
if !(hs.Cfg.GrafanaJavascriptAgent.Enabled) {
return func(ctx *web.Context) {
if ctx.Req.Method == http.MethodPost && (ctx.Req.URL.Path == sentryLogEndpointPath || ctx.Req.URL.Path == grafanaJavascriptAgentEndpointPath) {
if ctx.Req.Method == http.MethodPost && ctx.Req.URL.Path == grafanaJavascriptAgentEndpointPath {
ctx.Resp.WriteHeader(http.StatusAccepted)
_, err := ctx.Resp.Write([]byte("OK"))
if err != nil {
@@ -156,33 +112,11 @@ func (hs *HTTPServer) frontendLogEndpoints() web.Handler {
}
sourceMapStore := frontendlogging.NewSourceMapStore(hs.Cfg, hs.pluginStaticRouteResolver, frontendlogging.ReadSourceMapFromFS)
var rateLimiter *rate.Limiter
var handler frontendLogMessageHandler
handlerEndpoint := ""
dummyEndpoint := ""
if hs.Cfg.GrafanaJavascriptAgent.Enabled {
rateLimiter = rate.NewLimiter(rate.Limit(hs.Cfg.GrafanaJavascriptAgent.EndpointRPS), hs.Cfg.GrafanaJavascriptAgent.EndpointBurst)
handler = GrafanaJavascriptAgentLogMessageHandler(sourceMapStore)
handlerEndpoint = grafanaJavascriptAgentEndpointPath
dummyEndpoint = sentryLogEndpointPath
} else {
rateLimiter = rate.NewLimiter(rate.Limit(hs.Cfg.Sentry.EndpointRPS), hs.Cfg.Sentry.EndpointBurst)
handler = NewFrontendLogMessageHandler(sourceMapStore)
handlerEndpoint = sentryLogEndpointPath
dummyEndpoint = grafanaJavascriptAgentEndpointPath
}
rateLimiter := rate.NewLimiter(rate.Limit(hs.Cfg.GrafanaJavascriptAgent.EndpointRPS), hs.Cfg.GrafanaJavascriptAgent.EndpointBurst)
handler := GrafanaJavascriptAgentLogMessageHandler(sourceMapStore)
return func(ctx *web.Context) {
if ctx.Req.Method == http.MethodPost && ctx.Req.URL.Path == dummyEndpoint {
ctx.Resp.WriteHeader(http.StatusAccepted)
_, err := ctx.Resp.Write([]byte("OK"))
if err != nil {
hs.log.Error("could not write to response", "err", err)
}
}
if ctx.Req.Method == http.MethodPost && ctx.Req.URL.Path == handlerEndpoint {
if ctx.Req.Method == http.MethodPost && ctx.Req.URL.Path == grafanaJavascriptAgentEndpointPath {
if !rateLimiter.AllowN(time.Now(), 1) {
ctx.Resp.WriteHeader(http.StatusTooManyRequests)
return
+3 -287
View File
@@ -9,7 +9,6 @@ import (
"testing"
"time"
"github.com/getsentry/sentry-go"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/stretchr/testify/assert"
@@ -30,79 +29,6 @@ type SourceMapReadRecord struct {
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) {
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.Swap(level.NewFilter(newfrontendLogger, level.AllowInfo()))
sourceMapReads := []SourceMapReadRecord{}
t.Cleanup(func() {
frontendLogger.Swap(origHandler)
})
sc := setupScenarioContext(t, "/log")
cdnRootURL, e := url.Parse("https://storage.googleapis.com/grafana-static-assets")
require.NoError(t, e)
cfg := &setting.Cfg{
StaticRootPath: "/staticroot",
CDNRootURL: cdnRootURL,
}
readSourceMap := func(dir string, path string) ([]byte, error) {
sourceMapReads = append(sourceMapReads, SourceMapReadRecord{
dir: dir,
path: path,
})
if strings.Contains(path, "error") {
return nil, errors.New("epic hard drive failure")
}
if strings.HasSuffix(path, "foo.js.map") {
f, err := os.ReadFile("./frontendlogging/test-data/foo.js.map")
require.NoError(t, err)
return f, nil
}
return nil, os.ErrNotExist
}
// fake plugin route so we will try to find a source map there
pm := fakePluginStaticRouteResolver{
routes: []*plugins.StaticRoute{
{
Directory: "/usr/local/telepathic-panel",
PluginID: "telepathic",
},
},
}
sourceMapStore := frontendlogging.NewSourceMapStore(cfg, &pm, readSourceMap)
loggingHandler := NewFrontendLogMessageHandler(sourceMapStore)
handler := routing.Wrap(func(c *contextmodel.ReqContext) response.Response {
sc.context = c
c.Req.Body = mockRequestBody(event)
c.Req.Header.Add("Content-Type", "application/json")
loggingHandler(nil, c.Context)
return response.Success("ok")
})
sc.m.Post(sc.url, handler)
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
fn(sc, logcontent, sourceMapReads)
})
}
func logGrafanaJavascriptAgentEventScenario(t *testing.T, desc string, event frontendlogging.FrontendGrafanaJavascriptAgentEvent, fn logScenarioFunc) {
t.Run(desc, func(t *testing.T) {
var logcontent = make(map[string]interface{})
@@ -176,216 +102,6 @@ func logGrafanaJavascriptAgentEventScenario(t *testing.T, desc string, event fro
})
}
func TestFrontendLoggingEndpointSentry(t *testing.T) {
ts, err := time.Parse("2006-01-02T15:04:05.000Z", "2020-10-22T06:29:29.078Z")
require.NoError(t, err)
t.Run("FrontendLoggingEndpoint", func(t *testing.T) {
request := sentry.Request{
URL: "http://localhost:3000/",
Headers: map[string]string{
"User-Agent": "Chrome",
},
}
user := sentry.User{
Email: "geralt@kaermorhen.com",
ID: "45",
}
event := sentry.Event{
EventID: "123",
Level: sentry.LevelError,
Request: &request,
Timestamp: ts,
}
errorEvent := frontendlogging.FrontendSentryEvent{
Event: &event,
Exception: &frontendlogging.FrontendSentryException{
Values: []frontendlogging.FrontendSentryExceptionValue{
{
Type: "UserError",
Value: "Please replace user and try again",
Stacktrace: sentry.Stacktrace{
Frames: []sentry.Frame{
{
Function: "foofn",
Filename: "foo.js",
Lineno: 123,
Colno: 23,
},
{
Function: "barfn",
Filename: "bar.js",
Lineno: 113,
Colno: 231,
},
},
},
},
},
},
}
logSentryEventScenario(t, "Should log received error event", errorEvent,
func(sc *scenarioContext, logs map[string]interface{}, sourceMapReads []SourceMapReadRecord) {
assert.Equal(t, http.StatusAccepted, sc.resp.Code)
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, "context")
})
messageEvent := frontendlogging.FrontendSentryEvent{
Event: &sentry.Event{
EventID: "123",
Level: sentry.LevelInfo,
Request: &request,
Timestamp: ts,
Message: "hello world",
User: user,
},
Exception: nil,
}
logSentryEventScenario(t, "Should log received message event", messageEvent,
func(sc *scenarioContext, logs map[string]interface{}, sourceMapReads []SourceMapReadRecord) {
assert.Equal(t, http.StatusAccepted, sc.resp.Code)
assert.Len(t, logs, 10)
assertContextContains(t, logs, "logger", "frontend")
assertContextContains(t, logs, "msg", "hello world")
assertContextContains(t, logs, level.Key().(string), 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{
Event: &sentry.Event{
EventID: "123",
Level: sentry.LevelInfo,
Request: &request,
Timestamp: ts,
Message: "hello world",
User: user,
Contexts: map[string]interface{}{
"foo": map[string]interface{}{
"one": "two",
"three": 4,
},
"bar": "baz",
},
},
Exception: nil,
}
logSentryEventScenario(t, "Should log event context", eventWithContext,
func(sc *scenarioContext, logs map[string]interface{}, sourceMapReads []SourceMapReadRecord) {
assert.Equal(t, http.StatusAccepted, sc.resp.Code)
assertContextContains(t, logs, "context_foo_one", "two")
assertContextContains(t, logs, "context_foo_three", "4")
assertContextContains(t, logs, "context_bar", "baz")
})
errorEventForSourceMapping := frontendlogging.FrontendSentryEvent{
Event: &event,
Exception: &frontendlogging.FrontendSentryException{
Values: []frontendlogging.FrontendSentryExceptionValue{
{
Type: "UserError",
Value: "Please replace user and try again",
Stacktrace: sentry.Stacktrace{
Frames: []sentry.Frame{
{
Function: "foofn",
Filename: "http://localhost:3000/public/build/moo/foo.js", // source map found and mapped, core
Lineno: 2,
Colno: 5,
},
{
Function: "foofn",
Filename: "http://localhost:3000/public/plugins/telepathic/foo.js", // plugin, source map found and mapped
Lineno: 3,
Colno: 10,
},
{
Function: "explode",
Filename: "http://localhost:3000/public/build/error.js", // reading source map throws error
Lineno: 3,
Colno: 10,
},
{
Function: "wat",
Filename: "http://localhost:3000/public/build/bar.js", // core, but source map not found on fs
Lineno: 3,
Colno: 10,
},
{
Function: "nope",
Filename: "http://localhost:3000/baz.js", // not core or plugin, wont even attempt to get source map
Lineno: 3,
Colno: 10,
},
{
Function: "fake",
Filename: "http://localhost:3000/public/build/../../secrets.txt", // path will be sanitized
Lineno: 3,
Colno: 10,
},
{
Function: "cdn",
Filename: "https://storage.googleapis.com/grafana-static-assets/grafana-oss/pre-releases/7.5.0-11925pre/public/build/foo.js", // source map found and mapped
Lineno: 3,
Colno: 10,
},
},
},
},
},
},
}
logSentryEventScenario(t, "Should load sourcemap and transform stacktrace line when possible",
errorEventForSourceMapping, func(sc *scenarioContext, logs map[string]interface{}, sourceMapReads []SourceMapReadRecord) {
assert.Equal(t, http.StatusAccepted, sc.resp.Code)
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)
at wat (http://localhost:3000/public/build/bar.js:3:10)
at nope (http://localhost:3000/baz.js:3:10)
at fake (http://localhost:3000/public/build/../../secrets.txt:3:10)
at ? (core|webpack:///./some_source.ts:3:2)`)
assert.Len(t, sourceMapReads, 6)
assert.Equal(t, "/staticroot", sourceMapReads[0].dir)
assert.Equal(t, "build/moo/foo.js.map", sourceMapReads[0].path)
assert.Equal(t, "/usr/local/telepathic-panel", sourceMapReads[1].dir)
assert.Equal(t, "/foo.js.map", sourceMapReads[1].path)
assert.Equal(t, "/staticroot", sourceMapReads[2].dir)
assert.Equal(t, "build/error.js.map", sourceMapReads[2].path)
assert.Equal(t, "/staticroot", sourceMapReads[3].dir)
assert.Equal(t, "build/bar.js.map", sourceMapReads[3].path)
assert.Equal(t, "/staticroot", sourceMapReads[4].dir)
assert.Equal(t, "secrets.txt.map", sourceMapReads[4].path)
assert.Equal(t, "/staticroot", sourceMapReads[5].dir)
assert.Equal(t, "build/foo.js.map", sourceMapReads[5].path)
})
})
}
func TestFrontendLoggingEndpointGrafanaJavascriptAgent(t *testing.T) {
ts, err := time.Parse("2006-01-02T15:04:05.000Z", "2020-10-22T06:29:29.078Z")
require.NoError(t, err)
@@ -536,13 +252,13 @@ func TestFrontendLoggingEndpointGrafanaJavascriptAgent(t *testing.T) {
func(sc *scenarioContext, logs map[string]interface{}, sourceMapReads []SourceMapReadRecord) {
assert.Equal(t, http.StatusAccepted, sc.resp.Code)
assertContextContains(t, logs, "stacktrace", `UserError: Please replace user and try again
at ? (webpack:///./some_source.ts:2:2)
at ? (webpack:///./some_source.ts:3:2)
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)
at wat (http://localhost:3000/public/build/bar.js:3:10)
at nope (http://localhost:3000/baz.js:3:10)
at fake (http://localhost:3000/public/build/../../secrets.txt:3:10)
at ? (webpack:///./some_source.ts:3:2)`)
at ? (core|webpack:///./some_source.ts:3:2)`)
assert.Len(t, sourceMapReads, 6)
assert.Equal(t, "/staticroot", sourceMapReads[0].dir)
assert.Equal(t, "build/moo/foo.js.map", sourceMapReads[0].path)
@@ -4,6 +4,8 @@ import (
"fmt"
)
type CtxVector []interface{}
type FrontendGrafanaJavascriptAgentEvent struct {
Exceptions []Exception `json:"exceptions,omitempty"`
Logs []Log `json:"logs,omitempty"`
@@ -1,33 +1,5 @@
package frontendlogging
// ResolveSourceLocation resolves minified source location to original source location
func ResolveSourceLocation(store *SourceMapStore, frame *Frame) (*Frame, error) {
smap, err := store.getSourceMap(frame.Filename)
if err != nil {
return nil, err
}
if smap == nil {
return nil, nil
}
file, function, line, col, ok := smap.consumer.Source(frame.Lineno, frame.Colno)
if !ok {
return nil, nil
}
// unfortunately in many cases go-sourcemap fails to determine the original function name.
// not a big issue as long as file, line and column are correct
if len(function) == 0 {
function = "?"
}
return &Frame{
Filename: file,
Lineno: line,
Colno: col,
Function: function,
}, nil
}
// TransformException will attempt to resolved all monified source locations in the stacktrace with original source locations
func TransformException(ex *Exception, store *SourceMapStore) *Exception {
if ex.Stacktrace == nil {
@@ -37,7 +9,7 @@ func TransformException(ex *Exception, store *SourceMapStore) *Exception {
for _, frame := range ex.Stacktrace.Frames {
frame := frame
mappedFrame, err := ResolveSourceLocation(store, &frame)
mappedFrame, err := store.resolveSourceLocation(frame)
if err != nil {
frames = append(frames, frame)
} else if mappedFrame != nil {
-108
View File
@@ -1,108 +0,0 @@
package frontendlogging
import (
"encoding/json"
"fmt"
"strings"
"github.com/getsentry/sentry-go"
"github.com/grafana/grafana/pkg/infra/log"
)
type CtxVector []interface{}
var logger = log.New("frontendlogging")
type FrontendSentryExceptionValue struct {
Value string `json:"value,omitempty"`
Type string `json:"type,omitempty"`
Stacktrace sentry.Stacktrace `json:"stacktrace,omitempty"`
}
type FrontendSentryException struct {
Values []FrontendSentryExceptionValue `json:"values,omitempty"`
}
type FrontendSentryEvent struct {
*sentry.Event
Exception *FrontendSentryException `json:"exception,omitempty"`
}
func (value *FrontendSentryExceptionValue) FmtMessage() string {
return fmt.Sprintf("%s: %s", value.Type, value.Value)
}
func fmtLine(frame sentry.Frame) string {
module := ""
if len(frame.Module) > 0 {
module = frame.Module + "|"
}
return fmt.Sprintf("\n at %s (%s%s:%v:%v)", frame.Function, module, frame.Filename, frame.Lineno, frame.Colno)
}
func (value *FrontendSentryExceptionValue) FmtStacktrace(store *SourceMapStore) string {
var stacktrace = value.FmtMessage()
for _, frame := range value.Stacktrace.Frames {
mappedFrame, err := store.resolveSourceLocation(frame)
if err != nil {
logger.Error("Error resolving stack trace frame source location", "err", err)
stacktrace += fmtLine(frame) // even if reading source map fails for unexpected reason, still better to log compiled location than nothing at all
} else {
if mappedFrame != nil {
stacktrace += fmtLine(*mappedFrame)
} else {
stacktrace += fmtLine(frame)
}
}
}
return stacktrace
}
func (exception *FrontendSentryException) FmtStacktraces(store *SourceMapStore) string {
stacktraces := make([]string, 0, len(exception.Values))
for _, value := range exception.Values {
stacktraces = append(stacktraces, value.FmtStacktrace(store))
}
return strings.Join(stacktraces, "\n\n")
}
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 = append(*logCtx, prefix, fmt.Sprintf("%v", v))
}
}
}
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 = append(ctx, "stacktrace", event.Exception.FmtStacktraces(store))
}
addEventContextToLogContext("context", &ctx, event.Contexts)
if len(event.User.Email) > 0 {
ctx = append(ctx, "user_email", event.User.Email, "user_id", event.User.ID)
}
return ctx
}
func (event *FrontendSentryEvent) MarshalJSON() ([]byte, error) {
eventJSON, err := json.Marshal(event.Event)
if err != nil {
return nil, err
}
exceptionJSON, err := json.Marshal(map[string]interface{}{"exception": event.Exception})
if err != nil {
return nil, err
}
exceptionJSON[0] = ','
return append(eventJSON[:len(eventJSON)-1], exceptionJSON...), nil
}
+5 -4
View File
@@ -9,13 +9,14 @@ import (
"strings"
"sync"
"github.com/getsentry/sentry-go"
sourcemap "github.com/go-sourcemap/sourcemap"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/setting"
)
var logger = log.New("frontendlogging")
type sourceMapLocation struct {
dir string
path string
@@ -136,7 +137,7 @@ func (store *SourceMapStore) getSourceMap(sourceURL string) (*sourceMap, error)
return smap, nil
}
func (store *SourceMapStore) resolveSourceLocation(frame sentry.Frame) (*sentry.Frame, error) {
func (store *SourceMapStore) resolveSourceLocation(frame Frame) (*Frame, error) {
smap, err := store.getSourceMap(frame.Filename)
if err != nil {
return nil, err
@@ -157,7 +158,7 @@ func (store *SourceMapStore) resolveSourceLocation(frame sentry.Frame) (*sentry.
if len(smap.pluginID) > 0 {
module = smap.pluginID
}
return &sentry.Frame{
return &Frame{
Filename: file,
Lineno: line,
Colno: col,
-1
View File
@@ -184,7 +184,6 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro
RendererVersion: hs.RenderService.Version(),
SecretsManagerPluginEnabled: secretsManagerPluginEnabled,
Http2Enabled: hs.Cfg.Protocol == setting.HTTP2Scheme,
Sentry: hs.Cfg.Sentry,
GrafanaJavascriptAgent: hs.Cfg.GrafanaJavascriptAgent,
PluginCatalogURL: hs.Cfg.PluginCatalogURL,
PluginAdminEnabled: hs.Cfg.PluginAdminEnabled,
-1
View File
@@ -136,7 +136,6 @@ func (hs *HTTPServer) setIndexViewData(c *contextmodel.ReqContext) (*dtos.IndexV
AppleTouchIcon: "public/img/apple-touch-icon.png",
AppTitle: "Grafana",
NavTree: navTree,
Sentry: &hs.Cfg.Sentry,
Nonce: c.RequestNonce,
ContentDeliveryURL: hs.Cfg.GetContentDeliveryURL(hs.License.ContentDeliveryPrefix()),
LoadingLogo: "public/img/grafana_icon.svg",