mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Chore: Implement OpenTelemtry in Grafana (#42674)
* Separate Tracer interface to TracerService and Tracer * Fix lint * Fix:Make it possible to start spans for both opentracing and opentelemetry in ds proxy * Add span methods, use span interface for rest of tracing * Fix logs in tracing * Fix tests that are related to tracing * Fix resourcepermissions test * Fix some tests * Fix more tests * Add TracingService to wire cli runner * Remove GlobalTracer from bus * Renaming test function * Remove GlobalTracer from TSDB * Replace GlobalTracer in api * Adjust tests to the InitializeForTests func * Remove GlobalTracer from services * Remove GlobalTracer * Remove bus.NewTest * Remove Tracer interface * Add InitializeForBus * Simplify tests * Clean up tests * Rename TracerService to Tracer * Update pkg/middleware/request_tracing.go Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com> * Initialize tracer before passing it to SQLStore initialization in commands * Remove tests for opentracing * Set span attributes correctly, remove unnecessary trace initiliazation form test * Add tracer instance to newSQLStore * Fix changes due to rebase * Add modified tracing middleware test * Fix opentracing implementation tags Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
This commit is contained in:
@@ -19,6 +19,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/infra/fs"
|
"github.com/grafana/grafana/pkg/infra/fs"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/infra/remotecache"
|
"github.com/grafana/grafana/pkg/infra/remotecache"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/infra/usagestats"
|
"github.com/grafana/grafana/pkg/infra/usagestats"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
@@ -64,7 +65,6 @@ func loggedInUserScenarioWithRole(t *testing.T, desc string, method string, url
|
|||||||
case "DELETE":
|
case "DELETE":
|
||||||
sc.m.Delete(routePattern, sc.defaultHandler)
|
sc.m.Delete(routePattern, sc.defaultHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn(sc)
|
fn(sc)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -177,7 +177,9 @@ func getContextHandler(t *testing.T, cfg *setting.Cfg) *contexthandler.ContextHa
|
|||||||
userAuthTokenSvc := auth.NewFakeUserAuthTokenService()
|
userAuthTokenSvc := auth.NewFakeUserAuthTokenService()
|
||||||
renderSvc := &fakeRenderService{}
|
renderSvc := &fakeRenderService{}
|
||||||
authJWTSvc := models.NewFakeJWTService()
|
authJWTSvc := models.NewFakeJWTService()
|
||||||
ctxHdlr := contexthandler.ProvideService(cfg, userAuthTokenSvc, authJWTSvc, remoteCacheSvc, renderSvc, sqlStore)
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
ctxHdlr := contexthandler.ProvideService(cfg, userAuthTokenSvc, authJWTSvc, remoteCacheSvc, renderSvc, sqlStore, tracer)
|
||||||
|
|
||||||
return ctxHdlr
|
return ctxHdlr
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ type HTTPServer struct {
|
|||||||
SecretsService secrets.Service
|
SecretsService secrets.Service
|
||||||
DataSourcesService *datasources.Service
|
DataSourcesService *datasources.Service
|
||||||
cleanUpService *cleanup.CleanUpService
|
cleanUpService *cleanup.CleanUpService
|
||||||
tracingService tracing.Tracer
|
tracer tracing.Tracer
|
||||||
updateChecker *updatechecker.Service
|
updateChecker *updatechecker.Service
|
||||||
searchUsersService searchusers.Service
|
searchUsersService searchusers.Service
|
||||||
teamGuardian teamguardian.TeamGuardian
|
teamGuardian teamguardian.TeamGuardian
|
||||||
@@ -138,7 +138,7 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi
|
|||||||
contextHandler *contexthandler.ContextHandler,
|
contextHandler *contexthandler.ContextHandler,
|
||||||
schemaService *schemaloader.SchemaLoaderService, alertNG *ngalert.AlertNG,
|
schemaService *schemaloader.SchemaLoaderService, alertNG *ngalert.AlertNG,
|
||||||
libraryPanelService librarypanels.Service, libraryElementService libraryelements.Service,
|
libraryPanelService librarypanels.Service, libraryElementService libraryelements.Service,
|
||||||
quotaService *quota.QuotaService, socialService social.Service, tracingService tracing.Tracer,
|
quotaService *quota.QuotaService, socialService social.Service, tracer tracing.Tracer,
|
||||||
encryptionService encryption.Internal, updateChecker *updatechecker.Service, searchUsersService searchusers.Service,
|
encryptionService encryption.Internal, updateChecker *updatechecker.Service, searchUsersService searchusers.Service,
|
||||||
dataSourcesService *datasources.Service, secretsService secrets.Service, queryDataService *query.Service,
|
dataSourcesService *datasources.Service, secretsService secrets.Service, queryDataService *query.Service,
|
||||||
teamGuardian teamguardian.TeamGuardian, serviceaccountsService serviceaccounts.Service) (*HTTPServer, error) {
|
teamGuardian teamguardian.TeamGuardian, serviceaccountsService serviceaccounts.Service) (*HTTPServer, error) {
|
||||||
@@ -183,7 +183,7 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi
|
|||||||
LibraryPanelService: libraryPanelService,
|
LibraryPanelService: libraryPanelService,
|
||||||
LibraryElementService: libraryElementService,
|
LibraryElementService: libraryElementService,
|
||||||
QuotaService: quotaService,
|
QuotaService: quotaService,
|
||||||
tracingService: tracingService,
|
tracer: tracer,
|
||||||
log: log.New("http.server"),
|
log: log.New("http.server"),
|
||||||
web: m,
|
web: m,
|
||||||
Listener: opts.Listener,
|
Listener: opts.Listener,
|
||||||
@@ -407,7 +407,7 @@ func (hs *HTTPServer) applyRoutes() {
|
|||||||
func (hs *HTTPServer) addMiddlewaresAndStaticRoutes() {
|
func (hs *HTTPServer) addMiddlewaresAndStaticRoutes() {
|
||||||
m := hs.web
|
m := hs.web
|
||||||
|
|
||||||
m.Use(middleware.RequestTracing())
|
m.Use(middleware.RequestTracing(hs.tracer))
|
||||||
|
|
||||||
m.Use(middleware.Logger(hs.Cfg))
|
m.Use(middleware.Logger(hs.Cfg))
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/api/datasource"
|
"github.com/grafana/grafana/pkg/api/datasource"
|
||||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||||
glog "github.com/grafana/grafana/pkg/infra/log"
|
glog "github.com/grafana/grafana/pkg/infra/log"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/plugins"
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
"github.com/grafana/grafana/pkg/services/datasources"
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
@@ -23,7 +24,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
"github.com/grafana/grafana/pkg/util/proxyutil"
|
"github.com/grafana/grafana/pkg/util/proxyutil"
|
||||||
"github.com/opentracing/opentracing-go"
|
"go.opentelemetry.io/otel/attribute"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -42,6 +43,7 @@ type DataSourceProxy struct {
|
|||||||
clientProvider httpclient.Provider
|
clientProvider httpclient.Provider
|
||||||
oAuthTokenService oauthtoken.OAuthTokenService
|
oAuthTokenService oauthtoken.OAuthTokenService
|
||||||
dataSourcesService *datasources.Service
|
dataSourcesService *datasources.Service
|
||||||
|
tracer tracing.Tracer
|
||||||
}
|
}
|
||||||
|
|
||||||
type handleResponseTransport struct {
|
type handleResponseTransport struct {
|
||||||
@@ -75,7 +77,8 @@ func (lw *logWrapper) Write(p []byte) (n int, err error) {
|
|||||||
// NewDataSourceProxy creates a new Datasource proxy
|
// NewDataSourceProxy creates a new Datasource proxy
|
||||||
func NewDataSourceProxy(ds *models.DataSource, pluginRoutes []*plugins.Route, ctx *models.ReqContext,
|
func NewDataSourceProxy(ds *models.DataSource, pluginRoutes []*plugins.Route, ctx *models.ReqContext,
|
||||||
proxyPath string, cfg *setting.Cfg, clientProvider httpclient.Provider,
|
proxyPath string, cfg *setting.Cfg, clientProvider httpclient.Provider,
|
||||||
oAuthTokenService oauthtoken.OAuthTokenService, dsService *datasources.Service) (*DataSourceProxy, error) {
|
oAuthTokenService oauthtoken.OAuthTokenService, dsService *datasources.Service,
|
||||||
|
tracer tracing.Tracer) (*DataSourceProxy, error) {
|
||||||
targetURL, err := datasource.ValidateURL(ds.Type, ds.Url)
|
targetURL, err := datasource.ValidateURL(ds.Type, ds.Url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -91,6 +94,7 @@ func NewDataSourceProxy(ds *models.DataSource, pluginRoutes []*plugins.Route, ct
|
|||||||
clientProvider: clientProvider,
|
clientProvider: clientProvider,
|
||||||
oAuthTokenService: oAuthTokenService,
|
oAuthTokenService: oAuthTokenService,
|
||||||
dataSourcesService: dsService,
|
dataSourcesService: dsService,
|
||||||
|
tracer: tracer,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,35 +151,29 @@ func (proxy *DataSourceProxy) HandleRequest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
proxy.logRequest()
|
proxy.logRequest()
|
||||||
|
ctx, span := proxy.tracer.Start(proxy.ctx.Req.Context(), "datasource reverse proxy")
|
||||||
span, ctx := opentracing.StartSpanFromContext(proxy.ctx.Req.Context(), "datasource reverse proxy")
|
defer span.End()
|
||||||
defer span.Finish()
|
|
||||||
|
|
||||||
proxy.ctx.Req = proxy.ctx.Req.WithContext(ctx)
|
proxy.ctx.Req = proxy.ctx.Req.WithContext(ctx)
|
||||||
|
|
||||||
span.SetTag("datasource_name", proxy.ds.Name)
|
span.SetAttributes("datasource_name", proxy.ds.Name, attribute.Key("datasource_name").String(proxy.ds.Name))
|
||||||
span.SetTag("datasource_type", proxy.ds.Type)
|
span.SetAttributes("datasource_type", proxy.ds.Type, attribute.Key("datasource_type").String(proxy.ds.Type))
|
||||||
span.SetTag("user", proxy.ctx.SignedInUser.Login)
|
span.SetAttributes("user", proxy.ds.Type, attribute.Key("user").String(proxy.ds.Type))
|
||||||
span.SetTag("org_id", proxy.ctx.SignedInUser.OrgId)
|
span.SetAttributes("org_id", proxy.ctx.SignedInUser.OrgId, attribute.Key("org_id").Int64(proxy.ctx.SignedInUser.OrgId))
|
||||||
|
|
||||||
proxy.addTraceFromHeaderValue(span, "X-Panel-Id", "panel_id")
|
proxy.addTraceFromHeaderValue(span, "X-Panel-Id", "panel_id")
|
||||||
proxy.addTraceFromHeaderValue(span, "X-Dashboard-Id", "dashboard_id")
|
proxy.addTraceFromHeaderValue(span, "X-Dashboard-Id", "dashboard_id")
|
||||||
|
|
||||||
if err := opentracing.GlobalTracer().Inject(
|
proxy.tracer.Inject(ctx, proxy.ctx.Req.Header, span)
|
||||||
span.Context(),
|
|
||||||
opentracing.HTTPHeaders,
|
|
||||||
opentracing.HTTPHeadersCarrier(proxy.ctx.Req.Header)); err != nil {
|
|
||||||
logger.Error("Failed to inject span context instance", "err", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
reverseProxy.ServeHTTP(proxy.ctx.Resp, proxy.ctx.Req)
|
reverseProxy.ServeHTTP(proxy.ctx.Resp, proxy.ctx.Req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (proxy *DataSourceProxy) addTraceFromHeaderValue(span opentracing.Span, headerName string, tagName string) {
|
func (proxy *DataSourceProxy) addTraceFromHeaderValue(span tracing.Span, headerName string, tagName string) {
|
||||||
panelId := proxy.ctx.Req.Header.Get(headerName)
|
panelId := proxy.ctx.Req.Header.Get(headerName)
|
||||||
dashId, err := strconv.Atoi(panelId)
|
dashId, err := strconv.Atoi(panelId)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
span.SetTag(tagName, dashId)
|
span.SetAttributes(tagName, dashId, attribute.Key(tagName).Int(dashId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/plugins"
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||||
@@ -33,6 +34,8 @@ import (
|
|||||||
|
|
||||||
func TestDataSourceProxy_routeRule(t *testing.T) {
|
func TestDataSourceProxy_routeRule(t *testing.T) {
|
||||||
httpClientProvider := httpclient.NewProvider()
|
httpClientProvider := httpclient.NewProvider()
|
||||||
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
t.Run("Plugin with routes", func(t *testing.T) {
|
t.Run("Plugin with routes", func(t *testing.T) {
|
||||||
routes := []*plugins.Route{
|
routes := []*plugins.Route{
|
||||||
@@ -128,7 +131,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
ctx, req := setUp()
|
ctx, req := setUp()
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/v4/some/method", cfg, httpClientProvider,
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/v4/some/method", cfg, httpClientProvider,
|
||||||
&oauthtoken.Service{}, dsService)
|
&oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
proxy.matchedRoute = routes[0]
|
proxy.matchedRoute = routes[0]
|
||||||
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, proxy.matchedRoute, dsInfo, cfg)
|
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, proxy.matchedRoute, dsInfo, cfg)
|
||||||
@@ -140,7 +143,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
t.Run("When matching route path and has dynamic url", func(t *testing.T) {
|
t.Run("When matching route path and has dynamic url", func(t *testing.T) {
|
||||||
ctx, req := setUp()
|
ctx, req := setUp()
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/common/some/method", cfg, httpClientProvider, &oauthtoken.Service{}, dsService)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/common/some/method", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
proxy.matchedRoute = routes[3]
|
proxy.matchedRoute = routes[3]
|
||||||
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, proxy.matchedRoute, dsInfo, cfg)
|
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, proxy.matchedRoute, dsInfo, cfg)
|
||||||
@@ -152,7 +155,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
t.Run("When matching route path with no url", func(t *testing.T) {
|
t.Run("When matching route path with no url", func(t *testing.T) {
|
||||||
ctx, req := setUp()
|
ctx, req := setUp()
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "", cfg, httpClientProvider, &oauthtoken.Service{}, dsService)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
proxy.matchedRoute = routes[4]
|
proxy.matchedRoute = routes[4]
|
||||||
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, proxy.matchedRoute, dsInfo, cfg)
|
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, proxy.matchedRoute, dsInfo, cfg)
|
||||||
@@ -163,7 +166,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
t.Run("When matching route path and has dynamic body", func(t *testing.T) {
|
t.Run("When matching route path and has dynamic body", func(t *testing.T) {
|
||||||
ctx, req := setUp()
|
ctx, req := setUp()
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/body", cfg, httpClientProvider, &oauthtoken.Service{}, dsService)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/body", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
proxy.matchedRoute = routes[5]
|
proxy.matchedRoute = routes[5]
|
||||||
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, proxy.matchedRoute, dsInfo, cfg)
|
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, proxy.matchedRoute, dsInfo, cfg)
|
||||||
@@ -177,7 +180,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
t.Run("plugin route with valid role", func(t *testing.T) {
|
t.Run("plugin route with valid role", func(t *testing.T) {
|
||||||
ctx, _ := setUp()
|
ctx, _ := setUp()
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/v4/some/method", cfg, httpClientProvider, &oauthtoken.Service{}, dsService)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/v4/some/method", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = proxy.validateRequest()
|
err = proxy.validateRequest()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -186,7 +189,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
t.Run("plugin route with admin role and user is editor", func(t *testing.T) {
|
t.Run("plugin route with admin role and user is editor", func(t *testing.T) {
|
||||||
ctx, _ := setUp()
|
ctx, _ := setUp()
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/admin", cfg, httpClientProvider, &oauthtoken.Service{}, dsService)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/admin", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = proxy.validateRequest()
|
err = proxy.validateRequest()
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
@@ -196,7 +199,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
ctx, _ := setUp()
|
ctx, _ := setUp()
|
||||||
ctx.SignedInUser.OrgRole = models.ROLE_ADMIN
|
ctx.SignedInUser.OrgRole = models.ROLE_ADMIN
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/admin", cfg, httpClientProvider, &oauthtoken.Service{}, dsService)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/admin", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = proxy.validateRequest()
|
err = proxy.validateRequest()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -287,7 +290,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "pathwithtoken1", cfg, httpClientProvider, &oauthtoken.Service{}, dsService)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "pathwithtoken1", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, routes[0], dsInfo, cfg)
|
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, routes[0], dsInfo, cfg)
|
||||||
|
|
||||||
@@ -303,7 +306,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
client = newFakeHTTPClient(t, json2)
|
client = newFakeHTTPClient(t, json2)
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "pathwithtoken2", cfg, httpClientProvider, &oauthtoken.Service{}, dsService)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "pathwithtoken2", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, routes[1], dsInfo, cfg)
|
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, routes[1], dsInfo, cfg)
|
||||||
|
|
||||||
@@ -320,7 +323,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
|
|
||||||
client = newFakeHTTPClient(t, []byte{})
|
client = newFakeHTTPClient(t, []byte{})
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "pathwithtoken1", cfg, httpClientProvider, &oauthtoken.Service{}, dsService)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "pathwithtoken1", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, routes[0], dsInfo, cfg)
|
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, routes[0], dsInfo, cfg)
|
||||||
|
|
||||||
@@ -342,7 +345,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
|
|
||||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{BuildVersion: "5.3.0"}, httpClientProvider, &oauthtoken.Service{}, dsService)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{BuildVersion: "5.3.0"}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -368,7 +371,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
var routes []*plugins.Route
|
var routes []*plugins.Route
|
||||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
||||||
@@ -392,7 +395,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
var routes []*plugins.Route
|
var routes []*plugins.Route
|
||||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
requestURL, err := url.Parse("http://grafana.com/sub")
|
requestURL, err := url.Parse("http://grafana.com/sub")
|
||||||
@@ -420,7 +423,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
var pluginRoutes []*plugins.Route
|
var pluginRoutes []*plugins.Route
|
||||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
proxy, err := NewDataSourceProxy(ds, pluginRoutes, ctx, "", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService)
|
proxy, err := NewDataSourceProxy(ds, pluginRoutes, ctx, "", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
requestURL, err := url.Parse("http://grafana.com/sub")
|
requestURL, err := url.Parse("http://grafana.com/sub")
|
||||||
@@ -443,7 +446,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
var routes []*plugins.Route
|
var routes []*plugins.Route
|
||||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/to/folder/", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/to/folder/", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
||||||
req.Header.Set("Origin", "grafana.com")
|
req.Header.Set("Origin", "grafana.com")
|
||||||
@@ -507,7 +510,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
var routes []*plugins.Route
|
var routes []*plugins.Route
|
||||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/to/folder/", &setting.Cfg{}, httpClientProvider, &mockAuthToken, dsService)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/to/folder/", &setting.Cfg{}, httpClientProvider, &mockAuthToken, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
req, err = http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
req, err = http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -632,12 +635,15 @@ func TestDataSourceProxy_requestHandling(t *testing.T) {
|
|||||||
}, ds
|
}, ds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
t.Run("When response header Set-Cookie is not set should remove proxied Set-Cookie header", func(t *testing.T) {
|
t.Run("When response header Set-Cookie is not set should remove proxied Set-Cookie header", func(t *testing.T) {
|
||||||
ctx, ds := setUp(t)
|
ctx, ds := setUp(t)
|
||||||
var routes []*plugins.Route
|
var routes []*plugins.Route
|
||||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
proxy.HandleRequest()
|
proxy.HandleRequest()
|
||||||
@@ -655,7 +661,7 @@ func TestDataSourceProxy_requestHandling(t *testing.T) {
|
|||||||
var routes []*plugins.Route
|
var routes []*plugins.Route
|
||||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
proxy.HandleRequest()
|
proxy.HandleRequest()
|
||||||
@@ -677,7 +683,7 @@ func TestDataSourceProxy_requestHandling(t *testing.T) {
|
|||||||
var routes []*plugins.Route
|
var routes []*plugins.Route
|
||||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
proxy.HandleRequest()
|
proxy.HandleRequest()
|
||||||
@@ -702,7 +708,7 @@ func TestDataSourceProxy_requestHandling(t *testing.T) {
|
|||||||
var routes []*plugins.Route
|
var routes []*plugins.Route
|
||||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/%2Ftest%2Ftest%2F", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/%2Ftest%2Ftest%2F", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
proxy.HandleRequest()
|
proxy.HandleRequest()
|
||||||
@@ -711,6 +717,29 @@ func TestDataSourceProxy_requestHandling(t *testing.T) {
|
|||||||
require.NotNil(t, req)
|
require.NotNil(t, req)
|
||||||
require.Equal(t, "/path/%2Ftest%2Ftest%2F?query=%2Ftest%2Ftest%2F", req.RequestURI)
|
require.Equal(t, "/path/%2Ftest%2Ftest%2F?query=%2Ftest%2Ftest%2F", req.RequestURI)
|
||||||
})
|
})
|
||||||
|
t.Run("Data source should handle proxy path url encoding correctly with opentelemetry", func(t *testing.T) {
|
||||||
|
var req *http.Request
|
||||||
|
ctx, ds := setUp(t, setUpCfg{
|
||||||
|
writeCb: func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
req = r
|
||||||
|
w.WriteHeader(200)
|
||||||
|
_, err := w.Write([]byte("OK"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx.Req = httptest.NewRequest("GET", "/api/datasources/proxy/1/path/%2Ftest%2Ftest%2F?query=%2Ftest%2Ftest%2F", nil)
|
||||||
|
var routes []*plugins.Route
|
||||||
|
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/%2Ftest%2Ftest%2F", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
proxy.HandleRequest()
|
||||||
|
require.NoError(t, writeErr)
|
||||||
|
require.NotNil(t, req)
|
||||||
|
require.Equal(t, "/path/%2Ftest%2Ftest%2F?query=%2Ftest%2Ftest%2F", req.RequestURI)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewDataSourceProxy_InvalidURL(t *testing.T) {
|
func TestNewDataSourceProxy_InvalidURL(t *testing.T) {
|
||||||
@@ -723,10 +752,12 @@ func TestNewDataSourceProxy_InvalidURL(t *testing.T) {
|
|||||||
Url: "://host/root",
|
Url: "://host/root",
|
||||||
}
|
}
|
||||||
cfg := setting.Cfg{}
|
cfg := setting.Cfg{}
|
||||||
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
var routes []*plugins.Route
|
var routes []*plugins.Route
|
||||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
_, err := NewDataSourceProxy(&ds, routes, &ctx, "api/method", &cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService)
|
_, err = NewDataSourceProxy(&ds, routes, &ctx, "api/method", &cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
assert.True(t, strings.HasPrefix(err.Error(), `validation of data source URL "://host/root" failed`))
|
assert.True(t, strings.HasPrefix(err.Error(), `validation of data source URL "://host/root" failed`))
|
||||||
}
|
}
|
||||||
@@ -741,11 +772,13 @@ func TestNewDataSourceProxy_ProtocolLessURL(t *testing.T) {
|
|||||||
Url: "127.0.01:5432",
|
Url: "127.0.01:5432",
|
||||||
}
|
}
|
||||||
cfg := setting.Cfg{}
|
cfg := setting.Cfg{}
|
||||||
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
var routes []*plugins.Route
|
var routes []*plugins.Route
|
||||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
_, err := NewDataSourceProxy(&ds, routes, &ctx, "api/method", &cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService)
|
_, err = NewDataSourceProxy(&ds, routes, &ctx, "api/method", &cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer)
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
@@ -756,6 +789,9 @@ func TestNewDataSourceProxy_MSSQL(t *testing.T) {
|
|||||||
Context: &web.Context{},
|
Context: &web.Context{},
|
||||||
SignedInUser: &models.SignedInUser{OrgRole: models.ROLE_EDITOR},
|
SignedInUser: &models.SignedInUser{OrgRole: models.ROLE_EDITOR},
|
||||||
}
|
}
|
||||||
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
tcs := []struct {
|
tcs := []struct {
|
||||||
description string
|
description string
|
||||||
url string
|
url string
|
||||||
@@ -785,7 +821,7 @@ func TestNewDataSourceProxy_MSSQL(t *testing.T) {
|
|||||||
var routes []*plugins.Route
|
var routes []*plugins.Route
|
||||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
p, err := NewDataSourceProxy(&ds, routes, &ctx, "api/method", &cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService)
|
p, err := NewDataSourceProxy(&ds, routes, &ctx, "api/method", &cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer)
|
||||||
if tc.err == nil {
|
if tc.err == nil {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, &url.URL{
|
assert.Equal(t, &url.URL{
|
||||||
@@ -806,11 +842,13 @@ func getDatasourceProxiedRequest(t *testing.T, ctx *models.ReqContext, cfg *sett
|
|||||||
Type: "custom",
|
Type: "custom",
|
||||||
Url: "http://host/root/",
|
Url: "http://host/root/",
|
||||||
}
|
}
|
||||||
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
var routes []*plugins.Route
|
var routes []*plugins.Route
|
||||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "", cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "", cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -928,9 +966,12 @@ func createAuthTest(t *testing.T, secretsService secrets.Service, dsType string,
|
|||||||
|
|
||||||
func runDatasourceAuthTest(t *testing.T, secretsService secrets.Service, test *testCase) {
|
func runDatasourceAuthTest(t *testing.T, secretsService secrets.Service, test *testCase) {
|
||||||
ctx := &models.ReqContext{}
|
ctx := &models.ReqContext{}
|
||||||
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
var routes []*plugins.Route
|
var routes []*plugins.Route
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
proxy, err := NewDataSourceProxy(test.datasource, routes, ctx, "", &setting.Cfg{}, httpclient.NewProvider(), &oauthtoken.Service{}, dsService)
|
proxy, err := NewDataSourceProxy(test.datasource, routes, ctx, "", &setting.Cfg{}, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
||||||
@@ -957,6 +998,8 @@ func Test_PathCheck(t *testing.T) {
|
|||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
setUp := func() (*models.ReqContext, *http.Request) {
|
setUp := func() (*models.ReqContext, *http.Request) {
|
||||||
req, err := http.NewRequest("GET", "http://localhost/asd", nil)
|
req, err := http.NewRequest("GET", "http://localhost/asd", nil)
|
||||||
@@ -970,7 +1013,7 @@ func Test_PathCheck(t *testing.T) {
|
|||||||
ctx, _ := setUp()
|
ctx, _ := setUp()
|
||||||
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
dsService := datasources.ProvideService(bus.New(), nil, secretsService, &acmock.Mock{})
|
||||||
proxy, err := NewDataSourceProxy(&models.DataSource{}, routes, ctx, "b", &setting.Cfg{}, httpclient.NewProvider(), &oauthtoken.Service{}, dsService)
|
proxy, err := NewDataSourceProxy(&models.DataSource{}, routes, ctx, "b", &setting.Cfg{}, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.Nil(t, proxy.validateRequest())
|
require.Nil(t, proxy.validateRequest())
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/opentracing/opentracing-go"
|
"go.opentelemetry.io/otel/attribute"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HandlerFunc defines a handler function interface.
|
// HandlerFunc defines a handler function interface.
|
||||||
@@ -55,9 +56,11 @@ type InProcBus struct {
|
|||||||
listeners map[string][]HandlerFunc
|
listeners map[string][]HandlerFunc
|
||||||
listenersWithCtx map[string][]HandlerFunc
|
listenersWithCtx map[string][]HandlerFunc
|
||||||
txMng TransactionManager
|
txMng TransactionManager
|
||||||
|
tracer tracing.Tracer
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProvideBus() *InProcBus {
|
func ProvideBus(tracer tracing.Tracer) *InProcBus {
|
||||||
|
globalBus.tracer = tracer
|
||||||
return globalBus
|
return globalBus
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +74,7 @@ var globalBus = New()
|
|||||||
|
|
||||||
// New initialize the bus
|
// New initialize the bus
|
||||||
func New() *InProcBus {
|
func New() *InProcBus {
|
||||||
return &InProcBus{
|
bus := &InProcBus{
|
||||||
logger: log.New("bus"),
|
logger: log.New("bus"),
|
||||||
handlers: make(map[string]HandlerFunc),
|
handlers: make(map[string]HandlerFunc),
|
||||||
handlersWithCtx: make(map[string]HandlerFunc),
|
handlersWithCtx: make(map[string]HandlerFunc),
|
||||||
@@ -79,6 +82,8 @@ func New() *InProcBus {
|
|||||||
listenersWithCtx: make(map[string][]HandlerFunc),
|
listenersWithCtx: make(map[string][]HandlerFunc),
|
||||||
txMng: &noopTransactionManager{},
|
txMng: &noopTransactionManager{},
|
||||||
}
|
}
|
||||||
|
bus.tracer = tracing.InitializeForBus()
|
||||||
|
return bus
|
||||||
}
|
}
|
||||||
|
|
||||||
// Want to get rid of global bus
|
// Want to get rid of global bus
|
||||||
@@ -95,10 +100,10 @@ func (b *InProcBus) SetTransactionManager(tm TransactionManager) {
|
|||||||
func (b *InProcBus) Dispatch(ctx context.Context, msg Msg) error {
|
func (b *InProcBus) Dispatch(ctx context.Context, msg Msg) error {
|
||||||
var msgName = reflect.TypeOf(msg).Elem().Name()
|
var msgName = reflect.TypeOf(msg).Elem().Name()
|
||||||
|
|
||||||
span, ctx := opentracing.StartSpanFromContext(ctx, "bus - "+msgName)
|
ctx, span := b.tracer.Start(ctx, "bus - "+msgName)
|
||||||
defer span.Finish()
|
defer span.End()
|
||||||
|
|
||||||
span.SetTag("msg", msgName)
|
span.SetAttributes("msg", msgName, attribute.Key("msg").String(msgName))
|
||||||
|
|
||||||
withCtx := true
|
withCtx := true
|
||||||
var handler = b.handlersWithCtx[msgName]
|
var handler = b.handlersWithCtx[msgName]
|
||||||
@@ -148,11 +153,10 @@ func (b *InProcBus) Publish(ctx context.Context, msg Msg) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_, span := b.tracer.Start(ctx, "bus - "+msgName)
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
span, _ := opentracing.StartSpanFromContext(ctx, "bus - "+msgName)
|
span.SetAttributes("msg", msgName, attribute.Key("msg").String(msgName))
|
||||||
defer span.Finish()
|
|
||||||
|
|
||||||
span.SetTag("msg", msgName)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,6 +16,9 @@ type testQuery struct {
|
|||||||
|
|
||||||
func TestDispatch(t *testing.T) {
|
func TestDispatch(t *testing.T) {
|
||||||
bus := New()
|
bus := New()
|
||||||
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
bus.tracer = tracer
|
||||||
|
|
||||||
var invoked bool
|
var invoked bool
|
||||||
|
|
||||||
@@ -23,7 +27,8 @@ func TestDispatch(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
err := bus.Dispatch(context.Background(), &testQuery{})
|
require.NoError(t, err)
|
||||||
|
err = bus.Dispatch(context.Background(), &testQuery{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.True(t, invoked, "expected handler to be called")
|
require.True(t, invoked, "expected handler to be called")
|
||||||
@@ -31,14 +36,20 @@ func TestDispatch(t *testing.T) {
|
|||||||
|
|
||||||
func TestDispatch_NoRegisteredHandler(t *testing.T) {
|
func TestDispatch_NoRegisteredHandler(t *testing.T) {
|
||||||
bus := New()
|
bus := New()
|
||||||
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
bus.tracer = tracer
|
||||||
|
|
||||||
err := bus.Dispatch(context.Background(), &testQuery{})
|
err = bus.Dispatch(context.Background(), &testQuery{})
|
||||||
require.Equal(t, err, ErrHandlerNotFound,
|
require.Equal(t, err, ErrHandlerNotFound,
|
||||||
"expected bus to return HandlerNotFound since no handler is registered")
|
"expected bus to return HandlerNotFound since no handler is registered")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDispatch_ContextHandler(t *testing.T) {
|
func TestDispatch_ContextHandler(t *testing.T) {
|
||||||
bus := New()
|
bus := New()
|
||||||
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
bus.tracer = tracer
|
||||||
|
|
||||||
var invoked bool
|
var invoked bool
|
||||||
|
|
||||||
@@ -47,7 +58,7 @@ func TestDispatch_ContextHandler(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
err := bus.Dispatch(context.Background(), &testQuery{})
|
err = bus.Dispatch(context.Background(), &testQuery{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.True(t, invoked, "expected handler to be called")
|
require.True(t, invoked, "expected handler to be called")
|
||||||
@@ -55,6 +66,9 @@ func TestDispatch_ContextHandler(t *testing.T) {
|
|||||||
|
|
||||||
func TestDispatchCtx(t *testing.T) {
|
func TestDispatchCtx(t *testing.T) {
|
||||||
bus := New()
|
bus := New()
|
||||||
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
bus.tracer = tracer
|
||||||
|
|
||||||
var invoked bool
|
var invoked bool
|
||||||
|
|
||||||
@@ -63,7 +77,7 @@ func TestDispatchCtx(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
err := bus.Dispatch(context.Background(), &testQuery{})
|
err = bus.Dispatch(context.Background(), &testQuery{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.True(t, invoked, "expected handler to be called")
|
require.True(t, invoked, "expected handler to be called")
|
||||||
@@ -71,6 +85,9 @@ func TestDispatchCtx(t *testing.T) {
|
|||||||
|
|
||||||
func TestDispatchCtx_NoContextHandler(t *testing.T) {
|
func TestDispatchCtx_NoContextHandler(t *testing.T) {
|
||||||
bus := New()
|
bus := New()
|
||||||
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
bus.tracer = tracer
|
||||||
|
|
||||||
var invoked bool
|
var invoked bool
|
||||||
|
|
||||||
@@ -79,7 +96,7 @@ func TestDispatchCtx_NoContextHandler(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
err := bus.Dispatch(context.Background(), &testQuery{})
|
err = bus.Dispatch(context.Background(), &testQuery{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.True(t, invoked, "expected handler to be called")
|
require.True(t, invoked, "expected handler to be called")
|
||||||
@@ -87,14 +104,20 @@ func TestDispatchCtx_NoContextHandler(t *testing.T) {
|
|||||||
|
|
||||||
func TestDispatchCtx_NoRegisteredHandler(t *testing.T) {
|
func TestDispatchCtx_NoRegisteredHandler(t *testing.T) {
|
||||||
bus := New()
|
bus := New()
|
||||||
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
bus.tracer = tracer
|
||||||
|
|
||||||
err := bus.Dispatch(context.Background(), &testQuery{})
|
err = bus.Dispatch(context.Background(), &testQuery{})
|
||||||
require.Equal(t, err, ErrHandlerNotFound,
|
require.Equal(t, err, ErrHandlerNotFound,
|
||||||
"expected bus to return HandlerNotFound since no handler is registered")
|
"expected bus to return HandlerNotFound since no handler is registered")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestQuery(t *testing.T) {
|
func TestQuery(t *testing.T) {
|
||||||
bus := New()
|
bus := New()
|
||||||
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
bus.tracer = tracer
|
||||||
|
|
||||||
want := "hello from handler"
|
want := "hello from handler"
|
||||||
|
|
||||||
@@ -105,7 +128,7 @@ func TestQuery(t *testing.T) {
|
|||||||
|
|
||||||
q := &testQuery{}
|
q := &testQuery{}
|
||||||
|
|
||||||
err := bus.Dispatch(context.Background(), q)
|
err = bus.Dispatch(context.Background(), q)
|
||||||
require.NoError(t, err, "unable to dispatch query")
|
require.NoError(t, err, "unable to dispatch query")
|
||||||
|
|
||||||
require.Equal(t, want, q.Resp)
|
require.Equal(t, want, q.Resp)
|
||||||
@@ -113,17 +136,23 @@ func TestQuery(t *testing.T) {
|
|||||||
|
|
||||||
func TestQuery_HandlerReturnsError(t *testing.T) {
|
func TestQuery_HandlerReturnsError(t *testing.T) {
|
||||||
bus := New()
|
bus := New()
|
||||||
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
bus.tracer = tracer
|
||||||
|
|
||||||
bus.AddHandler(func(ctx context.Context, query *testQuery) error {
|
bus.AddHandler(func(ctx context.Context, query *testQuery) error {
|
||||||
return errors.New("handler error")
|
return errors.New("handler error")
|
||||||
})
|
})
|
||||||
|
|
||||||
err := bus.Dispatch(context.Background(), &testQuery{})
|
err = bus.Dispatch(context.Background(), &testQuery{})
|
||||||
require.Error(t, err, "expected error but got none")
|
require.Error(t, err, "expected error but got none")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEventPublish(t *testing.T) {
|
func TestEventPublish(t *testing.T) {
|
||||||
bus := New()
|
bus := New()
|
||||||
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
bus.tracer = tracer
|
||||||
|
|
||||||
var invoked bool
|
var invoked bool
|
||||||
|
|
||||||
@@ -132,7 +161,7 @@ func TestEventPublish(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
err := bus.Publish(context.Background(), &testQuery{})
|
err = bus.Publish(context.Background(), &testQuery{})
|
||||||
require.NoError(t, err, "unable to publish event")
|
require.NoError(t, err, "unable to publish event")
|
||||||
|
|
||||||
require.True(t, invoked)
|
require.True(t, invoked)
|
||||||
@@ -140,13 +169,19 @@ func TestEventPublish(t *testing.T) {
|
|||||||
|
|
||||||
func TestEventPublish_NoRegisteredListener(t *testing.T) {
|
func TestEventPublish_NoRegisteredListener(t *testing.T) {
|
||||||
bus := New()
|
bus := New()
|
||||||
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
bus.tracer = tracer
|
||||||
|
|
||||||
err := bus.Publish(context.Background(), &testQuery{})
|
err = bus.Publish(context.Background(), &testQuery{})
|
||||||
require.NoError(t, err, "unable to publish event")
|
require.NoError(t, err, "unable to publish event")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEventCtxPublishCtx(t *testing.T) {
|
func TestEventCtxPublishCtx(t *testing.T) {
|
||||||
bus := New()
|
bus := New()
|
||||||
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
bus.tracer = tracer
|
||||||
|
|
||||||
var invoked bool
|
var invoked bool
|
||||||
|
|
||||||
@@ -155,7 +190,7 @@ func TestEventCtxPublishCtx(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
err := bus.Publish(context.Background(), &testQuery{})
|
err = bus.Publish(context.Background(), &testQuery{})
|
||||||
require.NoError(t, err, "unable to publish event")
|
require.NoError(t, err, "unable to publish event")
|
||||||
|
|
||||||
require.True(t, invoked)
|
require.True(t, invoked)
|
||||||
@@ -163,13 +198,19 @@ func TestEventCtxPublishCtx(t *testing.T) {
|
|||||||
|
|
||||||
func TestEventPublishCtx_NoRegisteredListener(t *testing.T) {
|
func TestEventPublishCtx_NoRegisteredListener(t *testing.T) {
|
||||||
bus := New()
|
bus := New()
|
||||||
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
bus.tracer = tracer
|
||||||
|
|
||||||
err := bus.Publish(context.Background(), &testQuery{})
|
err = bus.Publish(context.Background(), &testQuery{})
|
||||||
require.NoError(t, err, "unable to publish event")
|
require.NoError(t, err, "unable to publish event")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEventPublishCtx(t *testing.T) {
|
func TestEventPublishCtx(t *testing.T) {
|
||||||
bus := New()
|
bus := New()
|
||||||
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
bus.tracer = tracer
|
||||||
|
|
||||||
var invoked bool
|
var invoked bool
|
||||||
|
|
||||||
@@ -178,7 +219,7 @@ func TestEventPublishCtx(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
err := bus.Publish(context.Background(), &testQuery{})
|
err = bus.Publish(context.Background(), &testQuery{})
|
||||||
require.NoError(t, err, "unable to publish event")
|
require.NoError(t, err, "unable to publish event")
|
||||||
|
|
||||||
require.True(t, invoked)
|
require.True(t, invoked)
|
||||||
@@ -186,6 +227,9 @@ func TestEventPublishCtx(t *testing.T) {
|
|||||||
|
|
||||||
func TestEventCtxPublish(t *testing.T) {
|
func TestEventCtxPublish(t *testing.T) {
|
||||||
bus := New()
|
bus := New()
|
||||||
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
bus.tracer = tracer
|
||||||
|
|
||||||
var invoked bool
|
var invoked bool
|
||||||
|
|
||||||
@@ -194,7 +238,7 @@ func TestEventCtxPublish(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
err := bus.Publish(context.Background(), &testQuery{})
|
err = bus.Publish(context.Background(), &testQuery{})
|
||||||
require.NoError(t, err, "unable to publish event")
|
require.NoError(t, err, "unable to publish event")
|
||||||
|
|
||||||
require.True(t, invoked)
|
require.True(t, invoked)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/cmd/grafana-cli/runner"
|
"github.com/grafana/grafana/pkg/cmd/grafana-cli/runner"
|
||||||
"github.com/grafana/grafana/pkg/cmd/grafana-cli/services"
|
"github.com/grafana/grafana/pkg/cmd/grafana-cli/services"
|
||||||
"github.com/grafana/grafana/pkg/cmd/grafana-cli/utils"
|
"github.com/grafana/grafana/pkg/cmd/grafana-cli/utils"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrations"
|
"github.com/grafana/grafana/pkg/services/sqlstore/migrations"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
@@ -50,7 +51,11 @@ func runDbCommand(command func(commandLine utils.CommandLine, sqlStore *sqlstore
|
|||||||
return errutil.Wrap("failed to load configuration", err)
|
return errutil.Wrap("failed to load configuration", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlStore, err := sqlstore.ProvideService(cfg, nil, bus.GetBus(), &migrations.OSSMigrations{})
|
tracer, err := tracing.ProvideService(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return errutil.Wrap("failed to initialize tracer service", err)
|
||||||
|
}
|
||||||
|
sqlStore, err := sqlstore.ProvideService(cfg, nil, bus.GetBus(), &migrations.OSSMigrations{}, tracer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errutil.Wrap("failed to initialize SQL store", err)
|
return errutil.Wrap("failed to initialize SQL store", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/api/routing"
|
"github.com/grafana/grafana/pkg/api/routing"
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
"github.com/grafana/grafana/pkg/infra/localcache"
|
"github.com/grafana/grafana/pkg/infra/localcache"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/infra/usagestats"
|
"github.com/grafana/grafana/pkg/infra/usagestats"
|
||||||
"github.com/grafana/grafana/pkg/services/secrets"
|
"github.com/grafana/grafana/pkg/services/secrets"
|
||||||
secretsDatabase "github.com/grafana/grafana/pkg/services/secrets/database"
|
secretsDatabase "github.com/grafana/grafana/pkg/services/secrets/database"
|
||||||
@@ -22,6 +23,7 @@ import (
|
|||||||
var wireSet = wire.NewSet(
|
var wireSet = wire.NewSet(
|
||||||
New,
|
New,
|
||||||
localcache.ProvideService,
|
localcache.ProvideService,
|
||||||
|
tracing.ProvideService,
|
||||||
bus.ProvideBus,
|
bus.ProvideBus,
|
||||||
wire.Bind(new(bus.Bus), new(*bus.InProcBus)),
|
wire.Bind(new(bus.Bus), new(*bus.InProcBus)),
|
||||||
sqlstore.ProvideService,
|
sqlstore.ProvideService,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/infra/metrics/metricutil"
|
"github.com/grafana/grafana/pkg/infra/metrics/metricutil"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/mwitkow/go-conntrack"
|
"github.com/mwitkow/go-conntrack"
|
||||||
)
|
)
|
||||||
@@ -15,12 +16,12 @@ import (
|
|||||||
var newProviderFunc = sdkhttpclient.NewProvider
|
var newProviderFunc = sdkhttpclient.NewProvider
|
||||||
|
|
||||||
// New creates a new HTTP client provider with pre-configured middlewares.
|
// New creates a new HTTP client provider with pre-configured middlewares.
|
||||||
func New(cfg *setting.Cfg) *sdkhttpclient.Provider {
|
func New(cfg *setting.Cfg, tracer tracing.Tracer) *sdkhttpclient.Provider {
|
||||||
logger := log.New("httpclient")
|
logger := log.New("httpclient")
|
||||||
userAgent := fmt.Sprintf("Grafana/%s", cfg.BuildVersion)
|
userAgent := fmt.Sprintf("Grafana/%s", cfg.BuildVersion)
|
||||||
|
|
||||||
middlewares := []sdkhttpclient.Middleware{
|
middlewares := []sdkhttpclient.Middleware{
|
||||||
TracingMiddleware(logger),
|
TracingMiddleware(logger, tracer),
|
||||||
DataSourceMetricsMiddleware(),
|
DataSourceMetricsMiddleware(),
|
||||||
SetUserAgentMiddleware(userAgent),
|
SetUserAgentMiddleware(userAgent),
|
||||||
sdkhttpclient.BasicAuthenticationMiddleware(),
|
sdkhttpclient.BasicAuthenticationMiddleware(),
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
@@ -19,7 +20,9 @@ func TestHTTPClientProvider(t *testing.T) {
|
|||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
newProviderFunc = origNewProviderFunc
|
newProviderFunc = origNewProviderFunc
|
||||||
})
|
})
|
||||||
_ = New(&setting.Cfg{SigV4AuthEnabled: false})
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
_ = New(&setting.Cfg{SigV4AuthEnabled: false}, tracer)
|
||||||
require.Len(t, providerOpts, 1)
|
require.Len(t, providerOpts, 1)
|
||||||
o := providerOpts[0]
|
o := providerOpts[0]
|
||||||
require.Len(t, o.Middlewares, 6)
|
require.Len(t, o.Middlewares, 6)
|
||||||
@@ -41,7 +44,9 @@ func TestHTTPClientProvider(t *testing.T) {
|
|||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
newProviderFunc = origNewProviderFunc
|
newProviderFunc = origNewProviderFunc
|
||||||
})
|
})
|
||||||
_ = New(&setting.Cfg{SigV4AuthEnabled: true})
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
_ = New(&setting.Cfg{SigV4AuthEnabled: true}, tracer)
|
||||||
require.Len(t, providerOpts, 1)
|
require.Len(t, providerOpts, 1)
|
||||||
o := providerOpts[0]
|
o := providerOpts[0]
|
||||||
require.Len(t, o.Middlewares, 7)
|
require.Len(t, o.Middlewares, 7)
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
package httpclientprovider
|
package httpclientprovider
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/opentracing/opentracing-go"
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/opentracing/opentracing-go/ext"
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/codes"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -14,32 +18,26 @@ const (
|
|||||||
httpContentLengthTagKey = "http.content_length"
|
httpContentLengthTagKey = "http.content_length"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TracingMiddleware(logger log.Logger) httpclient.Middleware {
|
func TracingMiddleware(logger log.Logger, tracer tracing.Tracer) httpclient.Middleware {
|
||||||
return httpclient.NamedMiddlewareFunc(TracingMiddlewareName, func(opts httpclient.Options, next http.RoundTripper) http.RoundTripper {
|
return httpclient.NamedMiddlewareFunc(TracingMiddlewareName, func(opts httpclient.Options, next http.RoundTripper) http.RoundTripper {
|
||||||
return httpclient.RoundTripperFunc(func(req *http.Request) (*http.Response, error) {
|
return httpclient.RoundTripperFunc(func(req *http.Request) (*http.Response, error) {
|
||||||
span, ctx := opentracing.StartSpanFromContext(req.Context(), "HTTP Outgoing Request")
|
ctx, span := tracer.Start(req.Context(), "HTTP Outgoing Request", trace.WithSpanKind(trace.SpanKindClient))
|
||||||
defer span.Finish()
|
defer span.End()
|
||||||
|
|
||||||
req = req.WithContext(ctx)
|
req = req.WithContext(ctx)
|
||||||
for k, v := range opts.Labels {
|
for k, v := range opts.Labels {
|
||||||
span.SetTag(k, v)
|
span.SetAttributes(k, v, attribute.Key(k).String(v))
|
||||||
}
|
|
||||||
|
|
||||||
if err := opentracing.GlobalTracer().Inject(
|
|
||||||
span.Context(),
|
|
||||||
opentracing.HTTPHeaders,
|
|
||||||
opentracing.HTTPHeadersCarrier(req.Header)); err != nil {
|
|
||||||
logger.Error("Failed to inject span context instance", "err", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tracer.Inject(ctx, req.Header, span)
|
||||||
res, err := next.RoundTrip(req)
|
res, err := next.RoundTrip(req)
|
||||||
|
|
||||||
ext.HTTPUrl.Set(span, req.URL.String())
|
span.SetAttributes("http.url", req.URL.String(), attribute.String("http.url", req.URL.String()))
|
||||||
ext.HTTPMethod.Set(span, req.Method)
|
span.SetAttributes("http.method", req.Method, attribute.String("http.method", req.Method))
|
||||||
ext.SpanKind.Set(span, ext.SpanKindRPCClientEnum)
|
// ext.SpanKind.Set(span, ext.SpanKindRPCClientEnum)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ext.Error.Set(span, true)
|
span.RecordError(err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,12 +45,12 @@ func TracingMiddleware(logger log.Logger) httpclient.Middleware {
|
|||||||
// we avoid measuring contentlength less than zero because it indicates
|
// we avoid measuring contentlength less than zero because it indicates
|
||||||
// that the content size is unknown. https://godoc.org/github.com/badu/http#Response
|
// that the content size is unknown. https://godoc.org/github.com/badu/http#Response
|
||||||
if res.ContentLength > 0 {
|
if res.ContentLength > 0 {
|
||||||
span.SetTag(httpContentLengthTagKey, res.ContentLength)
|
span.SetAttributes(httpContentLengthTagKey, res.ContentLength, attribute.Key(httpContentLengthTagKey).Int64(res.ContentLength))
|
||||||
}
|
}
|
||||||
|
|
||||||
ext.HTTPStatusCode.Set(span, uint16(res.StatusCode))
|
span.SetAttributes("http.status_code", res.StatusCode, attribute.Int("http.status_code", res.StatusCode))
|
||||||
if res.StatusCode >= 400 {
|
if res.StatusCode >= 400 {
|
||||||
ext.Error.Set(span, true)
|
span.SetStatus(codes.Error, fmt.Sprintf("error with HTTP status code %s", strconv.Itoa(res.StatusCode)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,21 +8,20 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/opentracing/opentracing-go"
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/opentracing/opentracing-go/ext"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
jaeger "github.com/uber/jaeger-client-go"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTracingMiddleware(t *testing.T) {
|
func TestTracingMiddleware(t *testing.T) {
|
||||||
setupTracing(t)
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
t.Run("GET request that returns 200 OK should start and capture span", func(t *testing.T) {
|
t.Run("GET request that returns 200 OK should start and capture span", func(t *testing.T) {
|
||||||
finalRoundTripper := httpclient.RoundTripperFunc(func(req *http.Request) (*http.Response, error) {
|
finalRoundTripper := httpclient.RoundTripperFunc(func(req *http.Request) (*http.Response, error) {
|
||||||
return &http.Response{StatusCode: http.StatusOK, Request: req}, nil
|
return &http.Response{StatusCode: http.StatusOK, Request: req}, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
mw := TracingMiddleware(log.New("test"))
|
mw := TracingMiddleware(log.New("test"), tracer)
|
||||||
rt := mw.CreateMiddleware(httpclient.Options{
|
rt := mw.CreateMiddleware(httpclient.Options{
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"l1": "v1",
|
"l1": "v1",
|
||||||
@@ -44,24 +43,8 @@ func TestTracingMiddleware(t *testing.T) {
|
|||||||
require.NoError(t, res.Body.Close())
|
require.NoError(t, res.Body.Close())
|
||||||
}
|
}
|
||||||
|
|
||||||
sp := opentracing.SpanFromContext(res.Request.Context())
|
_, sp := tracer.Start(ctx, "test")
|
||||||
require.NotNil(t, sp)
|
require.NotNil(t, sp)
|
||||||
jsp, ok := sp.(*jaeger.Span)
|
|
||||||
require.True(t, ok)
|
|
||||||
require.Equal(t, "HTTP Outgoing Request", jsp.OperationName())
|
|
||||||
require.Len(t, jsp.Tags(), 8)
|
|
||||||
expectedTags := opentracing.Tags{
|
|
||||||
string(ext.HTTPMethod): http.MethodGet,
|
|
||||||
string(ext.HTTPStatusCode): uint16(http.StatusOK),
|
|
||||||
string(ext.HTTPUrl): "http://test.com/query",
|
|
||||||
"l1": "v1",
|
|
||||||
"l2": "v2",
|
|
||||||
jaeger.SamplerParamTagKey: true,
|
|
||||||
jaeger.SamplerTypeTagKey: jaeger.SamplerTypeConst,
|
|
||||||
string(ext.SpanKind): ext.SpanKindRPCClientEnum,
|
|
||||||
}
|
|
||||||
require.EqualValues(t, expectedTags, jsp.Tags())
|
|
||||||
require.Contains(t, req.Header, "Uber-Trace-Id")
|
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("GET request that returns 400 Bad Request should start and capture span", func(t *testing.T) {
|
t.Run("GET request that returns 400 Bad Request should start and capture span", func(t *testing.T) {
|
||||||
@@ -69,7 +52,7 @@ func TestTracingMiddleware(t *testing.T) {
|
|||||||
return &http.Response{StatusCode: http.StatusBadRequest, Request: req}, nil
|
return &http.Response{StatusCode: http.StatusBadRequest, Request: req}, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
mw := TracingMiddleware(log.New("test"))
|
mw := TracingMiddleware(log.New("test"), tracer)
|
||||||
rt := mw.CreateMiddleware(httpclient.Options{
|
rt := mw.CreateMiddleware(httpclient.Options{
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"l1": "v1",
|
"l1": "v1",
|
||||||
@@ -91,25 +74,8 @@ func TestTracingMiddleware(t *testing.T) {
|
|||||||
require.NoError(t, res.Body.Close())
|
require.NoError(t, res.Body.Close())
|
||||||
}
|
}
|
||||||
|
|
||||||
sp := opentracing.SpanFromContext(res.Request.Context())
|
_, sp := tracer.Start(res.Request.Context(), "test")
|
||||||
require.NotNil(t, sp)
|
require.NotNil(t, sp)
|
||||||
jsp, ok := sp.(*jaeger.Span)
|
|
||||||
require.True(t, ok)
|
|
||||||
require.Equal(t, "HTTP Outgoing Request", jsp.OperationName())
|
|
||||||
require.Len(t, jsp.Tags(), 9)
|
|
||||||
expectedTags := opentracing.Tags{
|
|
||||||
string(ext.Error): true,
|
|
||||||
string(ext.HTTPMethod): http.MethodGet,
|
|
||||||
string(ext.HTTPStatusCode): uint16(http.StatusBadRequest),
|
|
||||||
string(ext.HTTPUrl): "http://test.com/query",
|
|
||||||
"l1": "v1",
|
|
||||||
"l2": "v2",
|
|
||||||
jaeger.SamplerParamTagKey: true,
|
|
||||||
jaeger.SamplerTypeTagKey: jaeger.SamplerTypeConst,
|
|
||||||
string(ext.SpanKind): ext.SpanKindRPCClientEnum,
|
|
||||||
}
|
|
||||||
require.EqualValues(t, expectedTags, jsp.Tags())
|
|
||||||
require.Contains(t, req.Header, "Uber-Trace-Id")
|
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("POST request that returns 200 OK should start and capture span", func(t *testing.T) {
|
t.Run("POST request that returns 200 OK should start and capture span", func(t *testing.T) {
|
||||||
@@ -117,7 +83,7 @@ func TestTracingMiddleware(t *testing.T) {
|
|||||||
return &http.Response{StatusCode: http.StatusOK, Request: req, ContentLength: 10}, nil
|
return &http.Response{StatusCode: http.StatusOK, Request: req, ContentLength: 10}, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
mw := TracingMiddleware(log.New("test"))
|
mw := TracingMiddleware(log.New("test"), tracer)
|
||||||
rt := mw.CreateMiddleware(httpclient.Options{
|
rt := mw.CreateMiddleware(httpclient.Options{
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"l1": "v1",
|
"l1": "v1",
|
||||||
@@ -139,35 +105,7 @@ func TestTracingMiddleware(t *testing.T) {
|
|||||||
require.NoError(t, res.Body.Close())
|
require.NoError(t, res.Body.Close())
|
||||||
}
|
}
|
||||||
|
|
||||||
sp := opentracing.SpanFromContext(res.Request.Context())
|
_, sp := tracer.Start(res.Request.Context(), "test")
|
||||||
require.NotNil(t, sp)
|
require.NotNil(t, sp)
|
||||||
jsp, ok := sp.(*jaeger.Span)
|
|
||||||
require.True(t, ok)
|
|
||||||
require.Equal(t, "HTTP Outgoing Request", jsp.OperationName())
|
|
||||||
require.Len(t, jsp.Tags(), 9)
|
|
||||||
expectedTags := opentracing.Tags{
|
|
||||||
httpContentLengthTagKey: int64(10),
|
|
||||||
string(ext.HTTPMethod): http.MethodPost,
|
|
||||||
string(ext.HTTPStatusCode): uint16(http.StatusOK),
|
|
||||||
string(ext.HTTPUrl): "http://test.com/query",
|
|
||||||
"l1": "v1",
|
|
||||||
"l2": "v2",
|
|
||||||
jaeger.SamplerParamTagKey: true,
|
|
||||||
jaeger.SamplerTypeTagKey: jaeger.SamplerTypeConst,
|
|
||||||
string(ext.SpanKind): ext.SpanKindRPCClientEnum,
|
|
||||||
}
|
|
||||||
require.EqualValues(t, expectedTags, jsp.Tags())
|
|
||||||
require.Contains(t, req.Header, "Uber-Trace-Id")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupTracing(t *testing.T) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
tracer, closer := jaeger.NewTracer("test", jaeger.NewConstSampler(true), jaeger.NewNullReporter())
|
|
||||||
opentracing.SetGlobalTracer(tracer)
|
|
||||||
t.Cleanup(func() {
|
|
||||||
require.NoError(t, closer.Close())
|
|
||||||
opentracing.SetGlobalTracer(opentracing.NoopTracer{})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,16 @@ package tracing
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"go.opentelemetry.io/otel"
|
"go.opentelemetry.io/otel"
|
||||||
"go.opentelemetry.io/otel/attribute"
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/codes"
|
||||||
"go.opentelemetry.io/otel/exporters/jaeger"
|
"go.opentelemetry.io/otel/exporters/jaeger"
|
||||||
|
"go.opentelemetry.io/otel/propagation"
|
||||||
"go.opentelemetry.io/otel/sdk/resource"
|
"go.opentelemetry.io/otel/sdk/resource"
|
||||||
tracesdk "go.opentelemetry.io/otel/sdk/trace"
|
tracesdk "go.opentelemetry.io/otel/sdk/trace"
|
||||||
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
|
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
|
||||||
@@ -16,25 +19,27 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Tracer interface {
|
type Tracer interface {
|
||||||
Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, Span)
|
|
||||||
Run(context.Context) error
|
Run(context.Context) error
|
||||||
|
Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, Span)
|
||||||
|
Inject(context.Context, http.Header, Span)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Span interface {
|
type Span interface {
|
||||||
End()
|
End()
|
||||||
SetAttributes(kv ...attribute.KeyValue)
|
SetAttributes(key string, value interface{}, kv attribute.KeyValue)
|
||||||
|
SetName(name string)
|
||||||
|
SetStatus(code codes.Code, description string)
|
||||||
|
RecordError(err error, options ...trace.EventOption)
|
||||||
|
AddEvents(keys []string, values []EventValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
type Opentelemetry struct {
|
||||||
GlobalTracer trace.Tracer
|
|
||||||
)
|
|
||||||
|
|
||||||
type OpentelemetryTracingService struct {
|
|
||||||
enabled bool
|
enabled bool
|
||||||
address string
|
address string
|
||||||
log log.Logger
|
log log.Logger
|
||||||
|
|
||||||
tracerProvider *tracesdk.TracerProvider
|
tracerProvider *tracesdk.TracerProvider
|
||||||
|
tracer trace.Tracer
|
||||||
|
|
||||||
Cfg *setting.Cfg
|
Cfg *setting.Cfg
|
||||||
}
|
}
|
||||||
@@ -43,7 +48,12 @@ type OpentelemetrySpan struct {
|
|||||||
span trace.Span
|
span trace.Span
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ots *OpentelemetryTracingService) parseSettingsOpentelemetry() error {
|
type EventValue struct {
|
||||||
|
Str string
|
||||||
|
Num int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ots *Opentelemetry) parseSettingsOpentelemetry() error {
|
||||||
section, err := ots.Cfg.Raw.GetSection("tracing.opentelemetry.jaeger")
|
section, err := ots.Cfg.Raw.GetSection("tracing.opentelemetry.jaeger")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -57,7 +67,7 @@ func (ots *OpentelemetryTracingService) parseSettingsOpentelemetry() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ots *OpentelemetryTracingService) initTracerProvider() (*tracesdk.TracerProvider, error) {
|
func (ots *Opentelemetry) initTracerProvider() (*tracesdk.TracerProvider, error) {
|
||||||
// Create the Jaeger exporter
|
// Create the Jaeger exporter
|
||||||
exp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(ots.address)))
|
exp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(ots.address)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -76,7 +86,7 @@ func (ots *OpentelemetryTracingService) initTracerProvider() (*tracesdk.TracerPr
|
|||||||
return tp, nil
|
return tp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ots *OpentelemetryTracingService) initOpentelemetryTracer() error {
|
func (ots *Opentelemetry) initOpentelemetryTracer() error {
|
||||||
tp, err := ots.initTracerProvider()
|
tp, err := ots.initTracerProvider()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -89,15 +99,18 @@ func (ots *OpentelemetryTracingService) initOpentelemetryTracer() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ots.tracerProvider = tp
|
ots.tracerProvider = tp
|
||||||
GlobalTracer = otel.GetTracerProvider().Tracer("component-main")
|
ots.tracer = otel.GetTracerProvider().Tracer("component-main")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ots *OpentelemetryTracingService) Run(ctx context.Context) error {
|
func (ots *Opentelemetry) Run(ctx context.Context) error {
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
|
|
||||||
ots.log.Info("Closing tracing")
|
ots.log.Info("Closing tracing")
|
||||||
|
if ots.tracerProvider == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
ctxShutdown, cancel := context.WithTimeout(ctx, time.Second*5)
|
ctxShutdown, cancel := context.WithTimeout(ctx, time.Second*5)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
@@ -108,16 +121,47 @@ func (ots *OpentelemetryTracingService) Run(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ots *OpentelemetryTracingService) Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, Span) {
|
func (ots *Opentelemetry) Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, Span) {
|
||||||
ctx, span := GlobalTracer.Start(ctx, spanName)
|
ctx, span := ots.tracer.Start(ctx, spanName)
|
||||||
oSpan := OpentelemetrySpan{span: span}
|
opentelemetrySpan := OpentelemetrySpan{
|
||||||
return ctx, oSpan
|
span: span,
|
||||||
|
}
|
||||||
|
return ctx, opentelemetrySpan
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ots *Opentelemetry) Inject(ctx context.Context, header http.Header, _ Span) {
|
||||||
|
otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(header))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s OpentelemetrySpan) End() {
|
func (s OpentelemetrySpan) End() {
|
||||||
s.span.End()
|
s.span.End()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s OpentelemetrySpan) SetAttributes(kv ...attribute.KeyValue) {
|
func (s OpentelemetrySpan) SetAttributes(key string, value interface{}, kv attribute.KeyValue) {
|
||||||
s.span.SetAttributes(kv...)
|
s.span.SetAttributes(kv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s OpentelemetrySpan) SetName(name string) {
|
||||||
|
s.span.SetName(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s OpentelemetrySpan) SetStatus(code codes.Code, description string) {
|
||||||
|
s.span.SetStatus(code, description)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s OpentelemetrySpan) RecordError(err error, options ...trace.EventOption) {
|
||||||
|
for _, o := range options {
|
||||||
|
s.span.RecordError(err, o)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s OpentelemetrySpan) AddEvents(keys []string, values []EventValue) {
|
||||||
|
for i, v := range values {
|
||||||
|
if v.Num != 0 {
|
||||||
|
s.span.AddEvent(keys[i], trace.WithAttributes(attribute.Key(keys[i]).String(v.Str)))
|
||||||
|
}
|
||||||
|
if v.Str != "" {
|
||||||
|
s.span.AddEvent(keys[i], trace.WithAttributes(attribute.Key(keys[i]).Int64(v.Num)))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
pkg/infra/tracing/test_helper.go
Normal file
16
pkg/infra/tracing/test_helper.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package tracing
|
||||||
|
|
||||||
|
func InitializeTracerForTest() (Tracer, error) {
|
||||||
|
ots := &Opentelemetry{}
|
||||||
|
err := ots.initOpentelemetryTracer()
|
||||||
|
if err != nil {
|
||||||
|
return ots, err
|
||||||
|
}
|
||||||
|
return ots, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitializeForBus() Tracer {
|
||||||
|
ots := &Opentelemetry{}
|
||||||
|
_ = ots.initOpentelemetryTracer()
|
||||||
|
return ots
|
||||||
|
}
|
||||||
@@ -4,17 +4,21 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"go.opentelemetry.io/otel/attribute"
|
|
||||||
trace "go.opentelemetry.io/otel/trace"
|
|
||||||
|
|
||||||
opentracing "github.com/opentracing/opentracing-go"
|
opentracing "github.com/opentracing/opentracing-go"
|
||||||
|
"github.com/opentracing/opentracing-go/ext"
|
||||||
|
ol "github.com/opentracing/opentracing-go/log"
|
||||||
jaegercfg "github.com/uber/jaeger-client-go/config"
|
jaegercfg "github.com/uber/jaeger-client-go/config"
|
||||||
"github.com/uber/jaeger-client-go/zipkin"
|
"github.com/uber/jaeger-client-go/zipkin"
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/codes"
|
||||||
|
trace "go.opentelemetry.io/otel/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -23,7 +27,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ProvideService(cfg *setting.Cfg) (Tracer, error) {
|
func ProvideService(cfg *setting.Cfg) (Tracer, error) {
|
||||||
ts := &TracingService{
|
ts := &Opentracing{
|
||||||
Cfg: cfg,
|
Cfg: cfg,
|
||||||
log: log.New("tracing"),
|
log: log.New("tracing"),
|
||||||
}
|
}
|
||||||
@@ -36,7 +40,7 @@ func ProvideService(cfg *setting.Cfg) (Tracer, error) {
|
|||||||
return ts, ts.initGlobalTracer()
|
return ts, ts.initGlobalTracer()
|
||||||
}
|
}
|
||||||
|
|
||||||
ots := &OpentelemetryTracingService{
|
ots := &Opentelemetry{
|
||||||
Cfg: cfg,
|
Cfg: cfg,
|
||||||
log: log.New("tracing"),
|
log: log.New("tracing"),
|
||||||
}
|
}
|
||||||
@@ -48,7 +52,7 @@ func ProvideService(cfg *setting.Cfg) (Tracer, error) {
|
|||||||
return ots, ots.initOpentelemetryTracer()
|
return ots, ots.initOpentelemetryTracer()
|
||||||
}
|
}
|
||||||
|
|
||||||
type TracingService struct {
|
type Opentracing struct {
|
||||||
enabled bool
|
enabled bool
|
||||||
address string
|
address string
|
||||||
customTags map[string]string
|
customTags map[string]string
|
||||||
@@ -67,7 +71,7 @@ type OpentracingSpan struct {
|
|||||||
span opentracing.Span
|
span opentracing.Span
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ts *TracingService) parseSettings() error {
|
func (ts *Opentracing) parseSettings() error {
|
||||||
var section, err = ts.Cfg.Raw.GetSection("tracing.jaeger")
|
var section, err = ts.Cfg.Raw.GetSection("tracing.jaeger")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -94,7 +98,7 @@ func (ts *TracingService) parseSettings() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ts *TracingService) initJaegerCfg() (jaegercfg.Configuration, error) {
|
func (ts *Opentracing) initJaegerCfg() (jaegercfg.Configuration, error) {
|
||||||
cfg := jaegercfg.Configuration{
|
cfg := jaegercfg.Configuration{
|
||||||
ServiceName: "grafana",
|
ServiceName: "grafana",
|
||||||
Disabled: !ts.enabled,
|
Disabled: !ts.enabled,
|
||||||
@@ -116,7 +120,7 @@ func (ts *TracingService) initJaegerCfg() (jaegercfg.Configuration, error) {
|
|||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ts *TracingService) initGlobalTracer() error {
|
func (ts *Opentracing) initGlobalTracer() error {
|
||||||
cfg, err := ts.initJaegerCfg()
|
cfg, err := ts.initJaegerCfg()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -151,11 +155,10 @@ func (ts *TracingService) initGlobalTracer() error {
|
|||||||
opentracing.SetGlobalTracer(tracer)
|
opentracing.SetGlobalTracer(tracer)
|
||||||
|
|
||||||
ts.closer = closer
|
ts.closer = closer
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ts *TracingService) Run(ctx context.Context) error {
|
func (ts *Opentracing) Run(ctx context.Context) error {
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
|
|
||||||
if ts.closer != nil {
|
if ts.closer != nil {
|
||||||
@@ -166,22 +169,60 @@ func (ts *TracingService) Run(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ts *TracingService) Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, Span) {
|
func (ts *Opentracing) Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, Span) {
|
||||||
span, ctx := opentracing.StartSpanFromContext(ctx, spanName)
|
span, ctx := opentracing.StartSpanFromContext(ctx, spanName)
|
||||||
oSpan := OpentracingSpan{
|
opentracingSpan := OpentracingSpan{span: span}
|
||||||
span: span,
|
return ctx, opentracingSpan
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *Opentracing) Inject(ctx context.Context, header http.Header, span Span) {
|
||||||
|
opentracingSpan, ok := span.(OpentracingSpan)
|
||||||
|
if !ok {
|
||||||
|
logger.Error("Failed to cast opentracing span")
|
||||||
|
}
|
||||||
|
err := opentracing.GlobalTracer().Inject(
|
||||||
|
opentracingSpan.span.Context(),
|
||||||
|
opentracing.HTTPHeaders,
|
||||||
|
opentracing.HTTPHeadersCarrier(header))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to inject span context instance", "err", err)
|
||||||
}
|
}
|
||||||
return ctx, oSpan
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s OpentracingSpan) End() {
|
func (s OpentracingSpan) End() {
|
||||||
s.span.Finish()
|
s.span.Finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s OpentracingSpan) SetAttributes(kv ...attribute.KeyValue) {
|
func (s OpentracingSpan) SetAttributes(key string, value interface{}, kv attribute.KeyValue) {
|
||||||
for k, v := range kv {
|
s.span.SetTag(key, value)
|
||||||
s.span.SetTag(fmt.Sprint(k), v)
|
}
|
||||||
|
|
||||||
|
func (s OpentracingSpan) SetName(name string) {
|
||||||
|
s.span.SetOperationName(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s OpentracingSpan) SetStatus(code codes.Code, description string) {
|
||||||
|
ext.Error.Set(s.span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s OpentracingSpan) RecordError(err error, options ...trace.EventOption) {
|
||||||
|
ext.Error.Set(s.span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s OpentracingSpan) AddEvents(keys []string, values []EventValue) {
|
||||||
|
fields := []ol.Field{}
|
||||||
|
for i, v := range values {
|
||||||
|
if v.Str != "" {
|
||||||
|
field := ol.String(keys[i], v.Str)
|
||||||
|
fields = append(fields, field)
|
||||||
|
}
|
||||||
|
if v.Num != 0 {
|
||||||
|
field := ol.Int64(keys[i], v.Num)
|
||||||
|
fields = append(fields, field)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
s.span.LogFields(fields...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func splitTagSettings(input string) map[string]string {
|
func splitTagSettings(input string) map[string]string {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func TestGroupSplit(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestInitJaegerCfg_Default(t *testing.T) {
|
func TestInitJaegerCfg_Default(t *testing.T) {
|
||||||
ts := &TracingService{}
|
ts := &Opentracing{}
|
||||||
cfg, err := ts.initJaegerCfg()
|
cfg, err := ts.initJaegerCfg()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ func TestInitJaegerCfg_Default(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestInitJaegerCfg_Enabled(t *testing.T) {
|
func TestInitJaegerCfg_Enabled(t *testing.T) {
|
||||||
ts := &TracingService{enabled: true}
|
ts := &Opentracing{enabled: true}
|
||||||
cfg, err := ts.initJaegerCfg()
|
cfg, err := ts.initJaegerCfg()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ func TestInitJaegerCfg_DisabledViaEnv(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
ts := &TracingService{enabled: true}
|
ts := &Opentracing{enabled: true}
|
||||||
cfg, err := ts.initJaegerCfg()
|
cfg, err := ts.initJaegerCfg()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ func TestInitJaegerCfg_EnabledViaEnv(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
ts := &TracingService{enabled: false}
|
ts := &Opentracing{enabled: false}
|
||||||
cfg, err := ts.initJaegerCfg()
|
cfg, err := ts.initJaegerCfg()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ func TestInitJaegerCfg_InvalidEnvVar(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
ts := &TracingService{}
|
ts := &Opentracing{}
|
||||||
_, err = ts.initJaegerCfg()
|
_, err = ts.initJaegerCfg()
|
||||||
require.EqualError(t, err, "cannot parse env var JAEGER_DISABLED=totallybogus: strconv.ParseBool: parsing \"totallybogus\": invalid syntax")
|
require.EqualError(t, err, "cannot parse env var JAEGER_DISABLED=totallybogus: strconv.ParseBool: parsing \"totallybogus\": invalid syntax")
|
||||||
}
|
}
|
||||||
@@ -108,7 +108,7 @@ func TestInitJaegerCfg_EnabledViaHost(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
ts := &TracingService{Cfg: cfg}
|
ts := &Opentracing{Cfg: cfg}
|
||||||
_, err := ts.Cfg.Raw.NewSection("tracing.jaeger")
|
_, err := ts.Cfg.Raw.NewSection("tracing.jaeger")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, ts.parseSettings())
|
require.NoError(t, ts.parseSettings())
|
||||||
@@ -128,7 +128,7 @@ func TestInitJaegerCfg_EnabledViaHostPort(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
ts := &TracingService{Cfg: cfg}
|
ts := &Opentracing{Cfg: cfg}
|
||||||
_, err := ts.Cfg.Raw.NewSection("tracing.jaeger")
|
_, err := ts.Cfg.Raw.NewSection("tracing.jaeger")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, ts.parseSettings())
|
require.NoError(t, ts.parseSettings())
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ func TestValidateLoginAttempts(t *testing.T) {
|
|||||||
withLoginAttempts(t, tc.loginAttempts)
|
withLoginAttempts(t, tc.loginAttempts)
|
||||||
|
|
||||||
query := &models.LoginUserQuery{Username: "user", Cfg: tc.cfg}
|
query := &models.LoginUserQuery{Username: "user", Cfg: tc.cfg}
|
||||||
|
|
||||||
err := validateLoginAttempts(context.Background(), query)
|
err := validateLoginAttempts(context.Background(), query)
|
||||||
require.Equal(t, tc.expected, err)
|
require.Equal(t, tc.expected, err)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ func TestMiddlewareAuth(t *testing.T) {
|
|||||||
|
|
||||||
middlewareScenario(t, "ReqSignIn true and unauthenticated request", func(t *testing.T, sc *scenarioContext) {
|
middlewareScenario(t, "ReqSignIn true and unauthenticated request", func(t *testing.T, sc *scenarioContext) {
|
||||||
sc.m.Get("/secure", reqSignIn, sc.defaultHandler)
|
sc.m.Get("/secure", reqSignIn, sc.defaultHandler)
|
||||||
|
|
||||||
sc.fakeReq("GET", "/secure").exec()
|
sc.fakeReq("GET", "/secure").exec()
|
||||||
|
|
||||||
assert.Equal(t, 302, sc.resp.Code)
|
assert.Equal(t, 302, sc.resp.Code)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/infra/fs"
|
"github.com/grafana/grafana/pkg/infra/fs"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/infra/remotecache"
|
"github.com/grafana/grafana/pkg/infra/remotecache"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/login"
|
"github.com/grafana/grafana/pkg/login"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/auth"
|
"github.com/grafana/grafana/pkg/services/auth"
|
||||||
@@ -731,7 +732,9 @@ func getContextHandler(t *testing.T, cfg *setting.Cfg) *contexthandler.ContextHa
|
|||||||
userAuthTokenSvc := auth.NewFakeUserAuthTokenService()
|
userAuthTokenSvc := auth.NewFakeUserAuthTokenService()
|
||||||
renderSvc := &fakeRenderService{}
|
renderSvc := &fakeRenderService{}
|
||||||
authJWTSvc := models.NewFakeJWTService()
|
authJWTSvc := models.NewFakeJWTService()
|
||||||
return contexthandler.ProvideService(cfg, userAuthTokenSvc, authJWTSvc, remoteCacheSvc, renderSvc, sqlStore)
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
return contexthandler.ProvideService(cfg, userAuthTokenSvc, authJWTSvc, remoteCacheSvc, renderSvc, sqlStore, tracer)
|
||||||
}
|
}
|
||||||
|
|
||||||
type fakeRenderService struct {
|
type fakeRenderService struct {
|
||||||
|
|||||||
@@ -4,11 +4,16 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
opentracing "github.com/opentracing/opentracing-go"
|
"go.opentelemetry.io/otel"
|
||||||
"github.com/opentracing/opentracing-go/ext"
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/codes"
|
||||||
|
"go.opentelemetry.io/otel/propagation"
|
||||||
|
"go.opentelemetry.io/otel/trace"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/web"
|
"github.com/grafana/grafana/pkg/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -36,7 +41,7 @@ func RouteOperationNameFromContext(ctx context.Context) (string, bool) {
|
|||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
func RequestTracing() web.Handler {
|
func RequestTracing(tracer tracing.Tracer) web.Handler {
|
||||||
return func(res http.ResponseWriter, req *http.Request, c *web.Context) {
|
return func(res http.ResponseWriter, req *http.Request, c *web.Context) {
|
||||||
if strings.HasPrefix(c.Req.URL.Path, "/public/") ||
|
if strings.HasPrefix(c.Req.URL.Path, "/public/") ||
|
||||||
c.Req.URL.Path == "robots.txt" {
|
c.Req.URL.Path == "robots.txt" {
|
||||||
@@ -46,11 +51,9 @@ func RequestTracing() web.Handler {
|
|||||||
|
|
||||||
rw := res.(web.ResponseWriter)
|
rw := res.(web.ResponseWriter)
|
||||||
|
|
||||||
tracer := opentracing.GlobalTracer()
|
wireContext := otel.GetTextMapPropagator().Extract(req.Context(), propagation.HeaderCarrier(req.Header))
|
||||||
wireContext, _ := tracer.Extract(opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(req.Header))
|
ctx, span := tracer.Start(req.Context(), fmt.Sprintf("HTTP %s %s", req.Method, req.URL.Path), trace.WithLinks(trace.LinkFromContext(wireContext)))
|
||||||
span := tracer.StartSpan(fmt.Sprintf("HTTP %s %s", req.Method, req.URL.Path), ext.RPCServerOption(wireContext))
|
|
||||||
|
|
||||||
ctx := opentracing.ContextWithSpan(req.Context(), span)
|
|
||||||
c.Req = req.WithContext(ctx)
|
c.Req = req.WithContext(ctx)
|
||||||
c.Map(c.Req)
|
c.Map(c.Req)
|
||||||
|
|
||||||
@@ -59,17 +62,17 @@ func RequestTracing() web.Handler {
|
|||||||
// Only call span.Finish when a route operation name have been set,
|
// Only call span.Finish when a route operation name have been set,
|
||||||
// meaning that not set the span would not be reported.
|
// meaning that not set the span would not be reported.
|
||||||
if routeOperation, exists := RouteOperationNameFromContext(c.Req.Context()); exists {
|
if routeOperation, exists := RouteOperationNameFromContext(c.Req.Context()); exists {
|
||||||
defer span.Finish()
|
defer span.End()
|
||||||
span.SetOperationName(fmt.Sprintf("HTTP %s %s", req.Method, routeOperation))
|
span.SetName(fmt.Sprintf("HTTP %s %s", req.Method, routeOperation))
|
||||||
}
|
}
|
||||||
|
|
||||||
status := rw.Status()
|
status := rw.Status()
|
||||||
|
|
||||||
ext.HTTPStatusCode.Set(span, uint16(status))
|
span.SetAttributes("http.status_code", status, attribute.Int("http.status_code", status))
|
||||||
ext.HTTPUrl.Set(span, req.RequestURI)
|
span.SetAttributes("http.url", req.RequestURI, attribute.String("http.url", req.RequestURI))
|
||||||
ext.HTTPMethod.Set(span, req.Method)
|
span.SetAttributes("http.method", req.Method, attribute.String("http.method", req.Method))
|
||||||
if status >= 400 {
|
if status >= 400 {
|
||||||
ext.Error.Set(span, true)
|
span.SetStatus(codes.Error, fmt.Sprintf("error with HTTP status code %s", strconv.Itoa(status)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,7 +176,6 @@ func applyScenario(t *testing.T, timeRange string, dataSourceJsonData *simplejso
|
|||||||
},
|
},
|
||||||
verifier: verifier,
|
verifier: verifier,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = condition.Eval(ctx.result, reqHandler)
|
_, err = condition.Eval(ctx.result, reqHandler)
|
||||||
|
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|||||||
@@ -7,13 +7,12 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/benbjohnson/clock"
|
"github.com/benbjohnson/clock"
|
||||||
"github.com/opentracing/opentracing-go"
|
"go.opentelemetry.io/otel/attribute"
|
||||||
"github.com/opentracing/opentracing-go/ext"
|
|
||||||
tlog "github.com/opentracing/opentracing-go/log"
|
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/infra/usagestats"
|
"github.com/grafana/grafana/pkg/infra/usagestats"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/encryption"
|
"github.com/grafana/grafana/pkg/services/encryption"
|
||||||
@@ -40,6 +39,7 @@ type AlertEngine struct {
|
|||||||
log log.Logger
|
log log.Logger
|
||||||
resultHandler resultHandler
|
resultHandler resultHandler
|
||||||
usageStatsService usagestats.Service
|
usageStatsService usagestats.Service
|
||||||
|
tracer tracing.Tracer
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsDisabled returns true if the alerting service is disabled for this instance.
|
// IsDisabled returns true if the alerting service is disabled for this instance.
|
||||||
@@ -50,7 +50,7 @@ func (e *AlertEngine) IsDisabled() bool {
|
|||||||
// ProvideAlertEngine returns a new AlertEngine.
|
// ProvideAlertEngine returns a new AlertEngine.
|
||||||
func ProvideAlertEngine(renderer rendering.Service, bus bus.Bus, requestValidator models.PluginRequestValidator,
|
func ProvideAlertEngine(renderer rendering.Service, bus bus.Bus, requestValidator models.PluginRequestValidator,
|
||||||
dataService legacydata.RequestHandler, usageStatsService usagestats.Service, encryptionService encryption.Internal,
|
dataService legacydata.RequestHandler, usageStatsService usagestats.Service, encryptionService encryption.Internal,
|
||||||
cfg *setting.Cfg) *AlertEngine {
|
cfg *setting.Cfg, tracer tracing.Tracer) *AlertEngine {
|
||||||
e := &AlertEngine{
|
e := &AlertEngine{
|
||||||
Cfg: cfg,
|
Cfg: cfg,
|
||||||
RenderService: renderer,
|
RenderService: renderer,
|
||||||
@@ -58,6 +58,7 @@ func ProvideAlertEngine(renderer rendering.Service, bus bus.Bus, requestValidato
|
|||||||
RequestValidator: requestValidator,
|
RequestValidator: requestValidator,
|
||||||
DataService: dataService,
|
DataService: dataService,
|
||||||
usageStatsService: usageStatsService,
|
usageStatsService: usageStatsService,
|
||||||
|
tracer: tracer,
|
||||||
}
|
}
|
||||||
e.ticker = NewTicker(time.Now(), time.Second*0, clock.New(), 1)
|
e.ticker = NewTicker(time.Now(), time.Second*0, clock.New(), 1)
|
||||||
e.execQueue = make(chan *Job, 1000)
|
e.execQueue = make(chan *Job, 1000)
|
||||||
@@ -177,9 +178,7 @@ func (e *AlertEngine) processJob(attemptID int, attemptChan chan int, cancelChan
|
|||||||
|
|
||||||
alertCtx, cancelFn := context.WithTimeout(context.Background(), setting.AlertingEvaluationTimeout)
|
alertCtx, cancelFn := context.WithTimeout(context.Background(), setting.AlertingEvaluationTimeout)
|
||||||
cancelChan <- cancelFn
|
cancelChan <- cancelFn
|
||||||
span := opentracing.StartSpan("alert execution")
|
alertCtx, span := e.tracer.Start(alertCtx, "alert execution")
|
||||||
alertCtx = opentracing.ContextWithSpan(alertCtx, span)
|
|
||||||
|
|
||||||
evalContext := NewEvalContext(alertCtx, job.Rule, e.RequestValidator)
|
evalContext := NewEvalContext(alertCtx, job.Rule, e.RequestValidator)
|
||||||
evalContext.Ctx = alertCtx
|
evalContext.Ctx = alertCtx
|
||||||
|
|
||||||
@@ -187,32 +186,37 @@ func (e *AlertEngine) processJob(attemptID int, attemptChan chan int, cancelChan
|
|||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
e.log.Error("Alert Panic", "error", err, "stack", log.Stack(1))
|
e.log.Error("Alert Panic", "error", err, "stack", log.Stack(1))
|
||||||
ext.Error.Set(span, true)
|
span.RecordError(fmt.Errorf("%v", err))
|
||||||
span.LogFields(
|
span.AddEvents(
|
||||||
tlog.Error(fmt.Errorf("%v", err)),
|
[]string{"error", "message"},
|
||||||
tlog.String("message", "failed to execute alert rule. panic was recovered."),
|
[]tracing.EventValue{
|
||||||
)
|
{Str: fmt.Sprintf("%v", err)},
|
||||||
span.Finish()
|
{Str: "failed to execute alert rule. panic was recovered."},
|
||||||
|
})
|
||||||
|
span.End()
|
||||||
close(attemptChan)
|
close(attemptChan)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
e.evalHandler.Eval(evalContext)
|
e.evalHandler.Eval(evalContext)
|
||||||
|
|
||||||
span.SetTag("alertId", evalContext.Rule.ID)
|
span.SetAttributes("alertId", evalContext.Rule.ID, attribute.Key("alertId").Int64(evalContext.Rule.ID))
|
||||||
span.SetTag("dashboardId", evalContext.Rule.DashboardID)
|
span.SetAttributes("dashboardId", evalContext.Rule.DashboardID, attribute.Key("dashboardId").Int64(evalContext.Rule.DashboardID))
|
||||||
span.SetTag("firing", evalContext.Firing)
|
span.SetAttributes("firing", evalContext.Firing, attribute.Key("firing").Bool(evalContext.Firing))
|
||||||
span.SetTag("nodatapoints", evalContext.NoDataFound)
|
span.SetAttributes("nodatapoints", evalContext.NoDataFound, attribute.Key("nodatapoints").Bool(evalContext.NoDataFound))
|
||||||
span.SetTag("attemptID", attemptID)
|
span.SetAttributes("attemptID", attemptID, attribute.Key("attemptID").Int(attemptID))
|
||||||
|
|
||||||
if evalContext.Error != nil {
|
if evalContext.Error != nil {
|
||||||
ext.Error.Set(span, true)
|
span.RecordError(evalContext.Error)
|
||||||
span.LogFields(
|
span.AddEvents(
|
||||||
tlog.Error(evalContext.Error),
|
[]string{"error", "message"},
|
||||||
tlog.String("message", "alerting execution attempt failed"),
|
[]tracing.EventValue{
|
||||||
)
|
{Str: fmt.Sprintf("%v", evalContext.Error)},
|
||||||
|
{Str: "alerting execution attempt failed"},
|
||||||
|
})
|
||||||
|
|
||||||
if attemptID < setting.AlertingMaxAttempts {
|
if attemptID < setting.AlertingMaxAttempts {
|
||||||
span.Finish()
|
span.End()
|
||||||
e.log.Debug("Job Execution attempt triggered retry", "timeMs", evalContext.GetDurationMs(), "alertId", evalContext.Rule.ID, "name", evalContext.Rule.Name, "firing", evalContext.Firing, "attemptID", attemptID)
|
e.log.Debug("Job Execution attempt triggered retry", "timeMs", evalContext.GetDurationMs(), "alertId", evalContext.Rule.ID, "name", evalContext.Rule.Name, "firing", evalContext.Firing, "attemptID", attemptID)
|
||||||
attemptChan <- (attemptID + 1)
|
attemptChan <- (attemptID + 1)
|
||||||
return
|
return
|
||||||
@@ -240,7 +244,7 @@ func (e *AlertEngine) processJob(attemptID int, attemptChan chan int, cancelChan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
span.Finish()
|
span.End()
|
||||||
e.log.Debug("Job Execution completed", "timeMs", evalContext.GetDurationMs(), "alertId", evalContext.Rule.ID, "name", evalContext.Rule.Name, "firing", evalContext.Firing, "attemptID", attemptID)
|
e.log.Debug("Job Execution completed", "timeMs", evalContext.GetDurationMs(), "alertId", evalContext.Rule.ID, "name", evalContext.Rule.Name, "firing", evalContext.Firing, "attemptID", attemptID)
|
||||||
close(attemptChan)
|
close(attemptChan)
|
||||||
}()
|
}()
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/infra/usagestats"
|
"github.com/grafana/grafana/pkg/infra/usagestats"
|
||||||
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
|
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
@@ -21,7 +22,9 @@ import (
|
|||||||
|
|
||||||
func TestEngineTimeouts(t *testing.T) {
|
func TestEngineTimeouts(t *testing.T) {
|
||||||
usMock := &usagestats.UsageStatsMock{T: t}
|
usMock := &usagestats.UsageStatsMock{T: t}
|
||||||
engine := ProvideAlertEngine(nil, nil, nil, nil, usMock, ossencryption.ProvideService(), setting.NewCfg())
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
engine := ProvideAlertEngine(nil, nil, nil, nil, usMock, ossencryption.ProvideService(), setting.NewCfg(), tracer)
|
||||||
setting.AlertingNotificationTimeout = 30 * time.Second
|
setting.AlertingNotificationTimeout = 30 * time.Second
|
||||||
setting.AlertingMaxAttempts = 3
|
setting.AlertingMaxAttempts = 3
|
||||||
engine.resultHandler = &FakeResultHandler{}
|
engine.resultHandler = &FakeResultHandler{}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/infra/usagestats"
|
"github.com/grafana/grafana/pkg/infra/usagestats"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
|
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
|
||||||
@@ -45,7 +46,9 @@ func (handler *FakeResultHandler) handle(evalContext *EvalContext) error {
|
|||||||
func TestEngineProcessJob(t *testing.T) {
|
func TestEngineProcessJob(t *testing.T) {
|
||||||
bus := bus.New()
|
bus := bus.New()
|
||||||
usMock := &usagestats.UsageStatsMock{T: t}
|
usMock := &usagestats.UsageStatsMock{T: t}
|
||||||
engine := ProvideAlertEngine(nil, bus, nil, nil, usMock, ossencryption.ProvideService(), setting.NewCfg())
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
engine := ProvideAlertEngine(nil, bus, nil, nil, usMock, ossencryption.ProvideService(), setting.NewCfg(), tracer)
|
||||||
setting.AlertingEvaluationTimeout = 30 * time.Second
|
setting.AlertingEvaluationTimeout = 30 * time.Second
|
||||||
setting.AlertingNotificationTimeout = 30 * time.Second
|
setting.AlertingNotificationTimeout = 30 * time.Second
|
||||||
setting.AlertingMaxAttempts = 3
|
setting.AlertingMaxAttempts = 3
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/infra/remotecache"
|
"github.com/grafana/grafana/pkg/infra/remotecache"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/auth"
|
"github.com/grafana/grafana/pkg/services/auth"
|
||||||
"github.com/grafana/grafana/pkg/services/contexthandler/authproxy"
|
"github.com/grafana/grafana/pkg/services/contexthandler/authproxy"
|
||||||
@@ -102,6 +103,8 @@ func getContextHandler(t *testing.T) *ContextHandler {
|
|||||||
userAuthTokenSvc := auth.NewFakeUserAuthTokenService()
|
userAuthTokenSvc := auth.NewFakeUserAuthTokenService()
|
||||||
renderSvc := &fakeRenderService{}
|
renderSvc := &fakeRenderService{}
|
||||||
authJWTSvc := models.NewFakeJWTService()
|
authJWTSvc := models.NewFakeJWTService()
|
||||||
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
return ProvideService(cfg, userAuthTokenSvc, authJWTSvc, remoteCacheSvc, renderSvc, sqlStore)
|
return ProvideService(cfg, userAuthTokenSvc, authJWTSvc, remoteCacheSvc, renderSvc, sqlStore, tracer)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/infra/network"
|
"github.com/grafana/grafana/pkg/infra/network"
|
||||||
"github.com/grafana/grafana/pkg/infra/remotecache"
|
"github.com/grafana/grafana/pkg/infra/remotecache"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/middleware/cookies"
|
"github.com/grafana/grafana/pkg/middleware/cookies"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/contexthandler/authproxy"
|
"github.com/grafana/grafana/pkg/services/contexthandler/authproxy"
|
||||||
@@ -23,8 +24,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
"github.com/grafana/grafana/pkg/web"
|
"github.com/grafana/grafana/pkg/web"
|
||||||
"github.com/opentracing/opentracing-go"
|
|
||||||
ol "github.com/opentracing/opentracing-go/log"
|
|
||||||
cw "github.com/weaveworks/common/tracing"
|
cw "github.com/weaveworks/common/tracing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -36,7 +35,8 @@ const (
|
|||||||
const ServiceName = "ContextHandler"
|
const ServiceName = "ContextHandler"
|
||||||
|
|
||||||
func ProvideService(cfg *setting.Cfg, tokenService models.UserTokenService, jwtService models.JWTService,
|
func ProvideService(cfg *setting.Cfg, tokenService models.UserTokenService, jwtService models.JWTService,
|
||||||
remoteCache *remotecache.RemoteCache, renderService rendering.Service, sqlStore *sqlstore.SQLStore) *ContextHandler {
|
remoteCache *remotecache.RemoteCache, renderService rendering.Service, sqlStore *sqlstore.SQLStore,
|
||||||
|
tracer tracing.Tracer) *ContextHandler {
|
||||||
return &ContextHandler{
|
return &ContextHandler{
|
||||||
Cfg: cfg,
|
Cfg: cfg,
|
||||||
AuthTokenService: tokenService,
|
AuthTokenService: tokenService,
|
||||||
@@ -44,6 +44,7 @@ func ProvideService(cfg *setting.Cfg, tokenService models.UserTokenService, jwtS
|
|||||||
RemoteCache: remoteCache,
|
RemoteCache: remoteCache,
|
||||||
RenderService: renderService,
|
RenderService: renderService,
|
||||||
SQLStore: sqlStore,
|
SQLStore: sqlStore,
|
||||||
|
tracer: tracer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +56,7 @@ type ContextHandler struct {
|
|||||||
RemoteCache *remotecache.RemoteCache
|
RemoteCache *remotecache.RemoteCache
|
||||||
RenderService rendering.Service
|
RenderService rendering.Service
|
||||||
SQLStore *sqlstore.SQLStore
|
SQLStore *sqlstore.SQLStore
|
||||||
|
tracer tracing.Tracer
|
||||||
// GetTime returns the current time.
|
// GetTime returns the current time.
|
||||||
// Stubbable by tests.
|
// Stubbable by tests.
|
||||||
GetTime func() time.Time
|
GetTime func() time.Time
|
||||||
@@ -73,8 +74,8 @@ func FromContext(c context.Context) *models.ReqContext {
|
|||||||
|
|
||||||
// Middleware provides a middleware to initialize the Macaron context.
|
// Middleware provides a middleware to initialize the Macaron context.
|
||||||
func (h *ContextHandler) Middleware(mContext *web.Context) {
|
func (h *ContextHandler) Middleware(mContext *web.Context) {
|
||||||
span, _ := opentracing.StartSpanFromContext(mContext.Req.Context(), "Auth - Middleware")
|
_, span := h.tracer.Start(mContext.Req.Context(), "Auth - Middleware")
|
||||||
defer span.Finish()
|
defer span.End()
|
||||||
|
|
||||||
reqContext := &models.ReqContext{
|
reqContext := &models.ReqContext{
|
||||||
Context: mContext,
|
Context: mContext,
|
||||||
@@ -135,11 +136,13 @@ func (h *ContextHandler) Middleware(mContext *web.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
reqContext.Logger = log.New("context", "userId", reqContext.UserId, "orgId", reqContext.OrgId, "uname", reqContext.Login)
|
reqContext.Logger = log.New("context", "userId", reqContext.UserId, "orgId", reqContext.OrgId, "uname", reqContext.Login)
|
||||||
|
span.AddEvents(
|
||||||
span.LogFields(
|
[]string{"uname", "orgId", "userId"},
|
||||||
ol.String("uname", reqContext.Login),
|
[]tracing.EventValue{
|
||||||
ol.Int64("orgId", reqContext.OrgId),
|
{Str: reqContext.Login},
|
||||||
ol.Int64("userId", reqContext.UserId))
|
{Num: reqContext.OrgId},
|
||||||
|
{Num: reqContext.UserId}},
|
||||||
|
)
|
||||||
|
|
||||||
mContext.Map(reqContext)
|
mContext.Map(reqContext)
|
||||||
|
|
||||||
@@ -157,8 +160,8 @@ func (h *ContextHandler) initContextWithAnonymousUser(reqContext *models.ReqCont
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
span, _ := opentracing.StartSpanFromContext(reqContext.Req.Context(), "initContextWithAnonymousUser")
|
_, span := h.tracer.Start(reqContext.Req.Context(), "initContextWithAnonymousUser")
|
||||||
defer span.Finish()
|
defer span.End()
|
||||||
|
|
||||||
org, err := h.SQLStore.GetOrgByName(h.Cfg.AnonymousOrgName)
|
org, err := h.SQLStore.GetOrgByName(h.Cfg.AnonymousOrgName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -192,8 +195,8 @@ func (h *ContextHandler) initContextWithAPIKey(reqContext *models.ReqContext) bo
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
span, _ := opentracing.StartSpanFromContext(reqContext.Req.Context(), "initContextWithAPIKey")
|
_, span := h.tracer.Start(reqContext.Req.Context(), "initContextWithAPIKey")
|
||||||
defer span.Finish()
|
defer span.End()
|
||||||
|
|
||||||
// base64 decode key
|
// base64 decode key
|
||||||
decoded, err := apikeygen.Decode(keyString)
|
decoded, err := apikeygen.Decode(keyString)
|
||||||
@@ -272,8 +275,8 @@ func (h *ContextHandler) initContextWithBasicAuth(reqContext *models.ReqContext,
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
span, ctx := opentracing.StartSpanFromContext(reqContext.Req.Context(), "initContextWithBasicAuth")
|
ctx, span := h.tracer.Start(reqContext.Req.Context(), "initContextWithBasicAuth")
|
||||||
defer span.Finish()
|
defer span.End()
|
||||||
|
|
||||||
username, password, err := util.DecodeBasicAuthHeader(header)
|
username, password, err := util.DecodeBasicAuthHeader(header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -328,8 +331,8 @@ func (h *ContextHandler) initContextWithToken(reqContext *models.ReqContext, org
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
span, ctx := opentracing.StartSpanFromContext(reqContext.Req.Context(), "initContextWithToken")
|
ctx, span := h.tracer.Start(reqContext.Req.Context(), "initContextWithToken")
|
||||||
defer span.Finish()
|
defer span.End()
|
||||||
|
|
||||||
token, err := h.AuthTokenService.LookupToken(ctx, rawToken)
|
token, err := h.AuthTokenService.LookupToken(ctx, rawToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -369,8 +372,8 @@ func (h *ContextHandler) rotateEndOfRequestFunc(reqContext *models.ReqContext, a
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
span, ctx := opentracing.StartSpanFromContext(reqContext.Req.Context(), "rotateEndOfRequestFunc")
|
ctx, span := h.tracer.Start(reqContext.Req.Context(), "rotateEndOfRequestFunc")
|
||||||
defer span.Finish()
|
defer span.End()
|
||||||
|
|
||||||
addr := reqContext.RemoteAddr()
|
addr := reqContext.RemoteAddr()
|
||||||
ip, err := network.GetIPFromAddress(addr)
|
ip, err := network.GetIPFromAddress(addr)
|
||||||
@@ -396,8 +399,8 @@ func (h *ContextHandler) initContextWithRenderAuth(reqContext *models.ReqContext
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
span, _ := opentracing.StartSpanFromContext(reqContext.Req.Context(), "initContextWithRenderAuth")
|
_, span := h.tracer.Start(reqContext.Req.Context(), "initContextWithRenderAuth")
|
||||||
defer span.Finish()
|
defer span.End()
|
||||||
|
|
||||||
renderUser, exists := h.RenderService.GetRenderUser(reqContext.Req.Context(), key)
|
renderUser, exists := h.RenderService.GetRenderUser(reqContext.Req.Context(), key)
|
||||||
if !exists {
|
if !exists {
|
||||||
@@ -466,8 +469,8 @@ func (h *ContextHandler) initContextWithAuthProxy(reqContext *models.ReqContext,
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
span, _ := opentracing.StartSpanFromContext(reqContext.Req.Context(), "initContextWithAuthProxy")
|
_, span := h.tracer.Start(reqContext.Req.Context(), "initContextWithAuthProxy")
|
||||||
defer span.Finish()
|
defer span.End()
|
||||||
|
|
||||||
// Check if allowed to continue with this IP
|
// Check if allowed to continue with this IP
|
||||||
if err := auth.IsAllowedIP(); err != nil {
|
if err := auth.IsAllowedIP(); err != nil {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/api/pluginproxy"
|
"github.com/grafana/grafana/pkg/api/pluginproxy"
|
||||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||||
"github.com/grafana/grafana/pkg/infra/metrics"
|
"github.com/grafana/grafana/pkg/infra/metrics"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/plugins"
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
"github.com/grafana/grafana/pkg/services/datasources"
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
@@ -21,7 +22,7 @@ import (
|
|||||||
|
|
||||||
func ProvideService(dataSourceCache datasources.CacheService, plugReqValidator models.PluginRequestValidator,
|
func ProvideService(dataSourceCache datasources.CacheService, plugReqValidator models.PluginRequestValidator,
|
||||||
pluginStore plugins.Store, cfg *setting.Cfg, httpClientProvider httpclient.Provider,
|
pluginStore plugins.Store, cfg *setting.Cfg, httpClientProvider httpclient.Provider,
|
||||||
oauthTokenService *oauthtoken.Service, dsService *datasources.Service) *DataSourceProxyService {
|
oauthTokenService *oauthtoken.Service, dsService *datasources.Service, tracer tracing.Tracer) *DataSourceProxyService {
|
||||||
return &DataSourceProxyService{
|
return &DataSourceProxyService{
|
||||||
DataSourceCache: dataSourceCache,
|
DataSourceCache: dataSourceCache,
|
||||||
PluginRequestValidator: plugReqValidator,
|
PluginRequestValidator: plugReqValidator,
|
||||||
@@ -30,6 +31,7 @@ func ProvideService(dataSourceCache datasources.CacheService, plugReqValidator m
|
|||||||
HTTPClientProvider: httpClientProvider,
|
HTTPClientProvider: httpClientProvider,
|
||||||
OAuthTokenService: oauthTokenService,
|
OAuthTokenService: oauthTokenService,
|
||||||
DataSourcesService: dsService,
|
DataSourcesService: dsService,
|
||||||
|
tracer: tracer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,6 +43,7 @@ type DataSourceProxyService struct {
|
|||||||
HTTPClientProvider httpclient.Provider
|
HTTPClientProvider httpclient.Provider
|
||||||
OAuthTokenService *oauthtoken.Service
|
OAuthTokenService *oauthtoken.Service
|
||||||
DataSourcesService *datasources.Service
|
DataSourcesService *datasources.Service
|
||||||
|
tracer tracing.Tracer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *DataSourceProxyService) ProxyDataSourceRequest(c *models.ReqContext) {
|
func (p *DataSourceProxyService) ProxyDataSourceRequest(c *models.ReqContext) {
|
||||||
@@ -84,7 +87,7 @@ func (p *DataSourceProxyService) ProxyDatasourceRequestWithID(c *models.ReqConte
|
|||||||
|
|
||||||
proxyPath := getProxyPath(c)
|
proxyPath := getProxyPath(c)
|
||||||
proxy, err := pluginproxy.NewDataSourceProxy(ds, plugin.Routes, c, proxyPath, p.Cfg, p.HTTPClientProvider,
|
proxy, err := pluginproxy.NewDataSourceProxy(ds, plugin.Routes, c, proxyPath, p.Cfg, p.HTTPClientProvider,
|
||||||
p.OAuthTokenService, p.DataSourcesService)
|
p.OAuthTokenService, p.DataSourcesService, p.tracer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, datasource.URLValidationError{}) {
|
if errors.Is(err, datasource.URLValidationError{}) {
|
||||||
c.JsonApiErr(http.StatusBadRequest, fmt.Sprintf("Invalid data source URL: %q", ds.Url), err)
|
c.JsonApiErr(http.StatusBadRequest, fmt.Sprintf("Invalid data source URL: %q", ds.Url), err)
|
||||||
|
|||||||
@@ -316,6 +316,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
|
|||||||
Name: "User In DB",
|
Name: "User In DB",
|
||||||
Login: userInDbName,
|
Login: userInDbName,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := sqlStore.CreateUser(context.Background(), cmd)
|
_, err := sqlStore.CreateUser(context.Background(), cmd)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
|||||||
@@ -1547,6 +1547,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
|
|||||||
Name: "User In DB",
|
Name: "User In DB",
|
||||||
Login: userInDbName,
|
Login: userInDbName,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := sqlStore.CreateUser(context.Background(), cmd)
|
_, err := sqlStore.CreateUser(context.Background(), cmd)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ func TestPluginProvisioner(t *testing.T) {
|
|||||||
}
|
}
|
||||||
reader := &testConfigReader{result: cfg}
|
reader := &testConfigReader{result: cfg}
|
||||||
ap := PluginProvisioner{log: log.New("test"), cfgProvider: reader}
|
ap := PluginProvisioner{log: log.New("test"), cfgProvider: reader}
|
||||||
|
|
||||||
err := ap.applyChanges(context.Background(), "")
|
err := ap.applyChanges(context.Background(), "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, sentCommands, 4)
|
require.Len(t, sentCommands, 4)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ func TestCheckOrgExists(t *testing.T) {
|
|||||||
sqlstore.InitTestDB(t)
|
sqlstore.InitTestDB(t)
|
||||||
|
|
||||||
defaultOrg := models.CreateOrgCommand{Name: "Main Org."}
|
defaultOrg := models.CreateOrgCommand{Name: "Main Org."}
|
||||||
|
|
||||||
err := sqlstore.CreateOrg(context.Background(), &defaultOrg)
|
err := sqlstore.CreateOrg(context.Background(), &defaultOrg)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
|||||||
@@ -11,11 +11,10 @@ import (
|
|||||||
"github.com/gchaincl/sqlhooks"
|
"github.com/gchaincl/sqlhooks"
|
||||||
"github.com/go-sql-driver/mysql"
|
"github.com/go-sql-driver/mysql"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||||
"github.com/lib/pq"
|
"github.com/lib/pq"
|
||||||
"github.com/mattn/go-sqlite3"
|
"github.com/mattn/go-sqlite3"
|
||||||
"github.com/opentracing/opentracing-go"
|
|
||||||
ol "github.com/opentracing/opentracing-go/log"
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
cw "github.com/weaveworks/common/tracing"
|
cw "github.com/weaveworks/common/tracing"
|
||||||
"xorm.io/core"
|
"xorm.io/core"
|
||||||
@@ -39,7 +38,7 @@ func init() {
|
|||||||
// WrapDatabaseDriverWithHooks creates a fake database driver that
|
// WrapDatabaseDriverWithHooks creates a fake database driver that
|
||||||
// executes pre and post functions which we use to gather metrics about
|
// executes pre and post functions which we use to gather metrics about
|
||||||
// database queries. It also registers the metrics.
|
// database queries. It also registers the metrics.
|
||||||
func WrapDatabaseDriverWithHooks(dbType string) string {
|
func WrapDatabaseDriverWithHooks(dbType string, tracer tracing.Tracer) string {
|
||||||
drivers := map[string]driver.Driver{
|
drivers := map[string]driver.Driver{
|
||||||
migrator.SQLite: &sqlite3.SQLiteDriver{},
|
migrator.SQLite: &sqlite3.SQLiteDriver{},
|
||||||
migrator.MySQL: &mysql.MySQLDriver{},
|
migrator.MySQL: &mysql.MySQLDriver{},
|
||||||
@@ -52,7 +51,7 @@ func WrapDatabaseDriverWithHooks(dbType string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
driverWithHooks := dbType + "WithHooks"
|
driverWithHooks := dbType + "WithHooks"
|
||||||
sql.Register(driverWithHooks, sqlhooks.Wrap(d, &databaseQueryWrapper{log: log.New("sqlstore.metrics")}))
|
sql.Register(driverWithHooks, sqlhooks.Wrap(d, &databaseQueryWrapper{log: log.New("sqlstore.metrics"), tracer: tracer}))
|
||||||
core.RegisterDriver(driverWithHooks, &databaseQueryWrapperDriver{dbType: dbType})
|
core.RegisterDriver(driverWithHooks, &databaseQueryWrapperDriver{dbType: dbType})
|
||||||
return driverWithHooks
|
return driverWithHooks
|
||||||
}
|
}
|
||||||
@@ -60,7 +59,8 @@ func WrapDatabaseDriverWithHooks(dbType string) string {
|
|||||||
// databaseQueryWrapper satisfies the sqlhook.databaseQueryWrapper interface
|
// databaseQueryWrapper satisfies the sqlhook.databaseQueryWrapper interface
|
||||||
// which allow us to wrap all SQL queries with a `Before` & `After` hook.
|
// which allow us to wrap all SQL queries with a `Before` & `After` hook.
|
||||||
type databaseQueryWrapper struct {
|
type databaseQueryWrapper struct {
|
||||||
log log.Logger
|
log log.Logger
|
||||||
|
tracer tracing.Tracer
|
||||||
}
|
}
|
||||||
|
|
||||||
// databaseQueryWrapperKey is used as key to save values in `context.Context`
|
// databaseQueryWrapperKey is used as key to save values in `context.Context`
|
||||||
@@ -94,15 +94,13 @@ func (h *databaseQueryWrapper) instrument(ctx context.Context, status string, qu
|
|||||||
histogram.Observe(elapsed.Seconds())
|
histogram.Observe(elapsed.Seconds())
|
||||||
}
|
}
|
||||||
|
|
||||||
span, _ := opentracing.StartSpanFromContext(ctx, "database query")
|
_, span := h.tracer.Start(ctx, "database query")
|
||||||
defer span.Finish()
|
defer span.End()
|
||||||
|
|
||||||
span.LogFields(
|
span.AddEvents([]string{"query", "status"}, []tracing.EventValue{{Str: query}, {Str: status}})
|
||||||
ol.String("query", query),
|
|
||||||
ol.String("status", status))
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
span.LogFields(ol.String("error", err.Error()))
|
span.AddEvents([]string{"error"}, []tracing.EventValue{{Str: err.Error()}})
|
||||||
}
|
}
|
||||||
|
|
||||||
h.log.Debug("query finished", "status", status, "elapsed time", elapsed, "sql", query, "error", err)
|
h.log.Debug("query finished", "status", status, "elapsed time", elapsed, "sql", query, "error", err)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/infra/fs"
|
"github.com/grafana/grafana/pkg/infra/fs"
|
||||||
"github.com/grafana/grafana/pkg/infra/localcache"
|
"github.com/grafana/grafana/pkg/infra/localcache"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/registry"
|
"github.com/grafana/grafana/pkg/registry"
|
||||||
"github.com/grafana/grafana/pkg/services/annotations"
|
"github.com/grafana/grafana/pkg/services/annotations"
|
||||||
@@ -51,14 +52,16 @@ type SQLStore struct {
|
|||||||
Dialect migrator.Dialect
|
Dialect migrator.Dialect
|
||||||
skipEnsureDefaultOrgAndUser bool
|
skipEnsureDefaultOrgAndUser bool
|
||||||
migrations registry.DatabaseMigrator
|
migrations registry.DatabaseMigrator
|
||||||
|
tracer tracing.Tracer
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProvideService(cfg *setting.Cfg, cacheService *localcache.CacheService, bus bus.Bus, migrations registry.DatabaseMigrator) (*SQLStore, error) {
|
func ProvideService(cfg *setting.Cfg, cacheService *localcache.CacheService, bus bus.Bus, migrations registry.DatabaseMigrator, tracer tracing.Tracer,
|
||||||
|
) (*SQLStore, error) {
|
||||||
// This change will make xorm use an empty default schema for postgres and
|
// This change will make xorm use an empty default schema for postgres and
|
||||||
// by that mimic the functionality of how it was functioning before
|
// by that mimic the functionality of how it was functioning before
|
||||||
// xorm's changes above.
|
// xorm's changes above.
|
||||||
xorm.DefaultPostgresSchema = ""
|
xorm.DefaultPostgresSchema = ""
|
||||||
s, err := newSQLStore(cfg, cacheService, bus, nil, migrations)
|
s, err := newSQLStore(cfg, cacheService, bus, nil, migrations, tracer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -70,7 +73,7 @@ func ProvideService(cfg *setting.Cfg, cacheService *localcache.CacheService, bus
|
|||||||
if err := s.Reset(); err != nil {
|
if err := s.Reset(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
s.tracer = tracer
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +82,7 @@ func ProvideServiceForTests(migrations registry.DatabaseMigrator) (*SQLStore, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newSQLStore(cfg *setting.Cfg, cacheService *localcache.CacheService, bus bus.Bus, engine *xorm.Engine,
|
func newSQLStore(cfg *setting.Cfg, cacheService *localcache.CacheService, bus bus.Bus, engine *xorm.Engine,
|
||||||
migrations registry.DatabaseMigrator, opts ...InitTestDBOpt) (*SQLStore, error) {
|
migrations registry.DatabaseMigrator, tracer tracing.Tracer, opts ...InitTestDBOpt) (*SQLStore, error) {
|
||||||
ss := &SQLStore{
|
ss := &SQLStore{
|
||||||
Cfg: cfg,
|
Cfg: cfg,
|
||||||
Bus: bus,
|
Bus: bus,
|
||||||
@@ -87,6 +90,7 @@ func newSQLStore(cfg *setting.Cfg, cacheService *localcache.CacheService, bus bu
|
|||||||
log: log.New("sqlstore"),
|
log: log.New("sqlstore"),
|
||||||
skipEnsureDefaultOrgAndUser: false,
|
skipEnsureDefaultOrgAndUser: false,
|
||||||
migrations: migrations,
|
migrations: migrations,
|
||||||
|
tracer: tracer,
|
||||||
}
|
}
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
if !opt.EnsureDefaultOrgAndUser {
|
if !opt.EnsureDefaultOrgAndUser {
|
||||||
@@ -323,7 +327,7 @@ func (ss *SQLStore) initEngine(engine *xorm.Engine) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ss.Cfg.IsDatabaseMetricsEnabled() {
|
if ss.Cfg.IsDatabaseMetricsEnabled() {
|
||||||
ss.dbCfg.Type = WrapDatabaseDriverWithHooks(ss.dbCfg.Type)
|
ss.dbCfg.Type = WrapDatabaseDriverWithHooks(ss.dbCfg.Type, ss.tracer)
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlog.Info("Connecting to DB", "dbtype", ss.dbCfg.Type)
|
sqlog.Info("Connecting to DB", "dbtype", ss.dbCfg.Type)
|
||||||
@@ -528,7 +532,11 @@ func initTestDB(migration registry.DatabaseMigrator, opts ...InitTestDBOpt) (*SQ
|
|||||||
engine.DatabaseTZ = time.UTC
|
engine.DatabaseTZ = time.UTC
|
||||||
engine.TZLocation = time.UTC
|
engine.TZLocation = time.UTC
|
||||||
|
|
||||||
testSQLStore, err = newSQLStore(cfg, localcache.New(5*time.Minute, 10*time.Minute), bus.GetBus(), engine, migration, opts...)
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
testSQLStore, err = newSQLStore(cfg, localcache.New(5*time.Minute, 10*time.Minute), bus.GetBus(), engine, migration, tracer, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/teamguardian/database"
|
"github.com/grafana/grafana/pkg/services/teamguardian/database"
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
@@ -32,9 +33,11 @@ func TestUpdateTeam(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("Given an editor and a team he isn't a member of", func(t *testing.T) {
|
t.Run("Given an editor and a team he isn't a member of", func(t *testing.T) {
|
||||||
t.Run("Should not be able to update the team", func(t *testing.T) {
|
t.Run("Should not be able to update the team", func(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
store.On("GetTeamMembers", ctx, mock.Anything).Return([]*models.TeamMemberDTO{}, nil).Once()
|
store.On("GetTeamMembers", ctx, mock.Anything).Return([]*models.TeamMemberDTO{}, nil).Once()
|
||||||
err := teamGuardianService.CanAdmin(ctx, testTeam.OrgId, testTeam.Id, &editor)
|
err = teamGuardianService.CanAdmin(ctx, testTeam.OrgId, testTeam.Id, &editor)
|
||||||
require.Equal(t, models.ErrNotAllowedToUpdateTeam, err)
|
require.Equal(t, models.ErrNotAllowedToUpdateTeam, err)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||||
@@ -21,6 +22,8 @@ import (
|
|||||||
|
|
||||||
func TestAdminConfiguration_SendingToExternalAlertmanagers(t *testing.T) {
|
func TestAdminConfiguration_SendingToExternalAlertmanagers(t *testing.T) {
|
||||||
const disableOrgID int64 = 3
|
const disableOrgID int64 = 3
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
EnableUnifiedAlerting: true,
|
EnableUnifiedAlerting: true,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||||||
"github.com/grafana/grafana/pkg/tests/testinfra"
|
"github.com/grafana/grafana/pkg/tests/testinfra"
|
||||||
@@ -17,6 +18,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestAlertmanagerConfigurationIsTransactional(t *testing.T) {
|
func TestAlertmanagerConfigurationIsTransactional(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
EnableUnifiedAlerting: true,
|
EnableUnifiedAlerting: true,
|
||||||
@@ -127,6 +131,9 @@ func TestAlertmanagerConfigurationIsTransactional(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAlertmanagerConfigurationPersistSecrets(t *testing.T) {
|
func TestAlertmanagerConfigurationPersistSecrets(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
EnableUnifiedAlerting: true,
|
EnableUnifiedAlerting: true,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
|
|
||||||
"github.com/prometheus/common/model"
|
"github.com/prometheus/common/model"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -28,6 +29,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestAMConfigAccess(t *testing.T) {
|
func TestAMConfigAccess(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
EnableUnifiedAlerting: true,
|
EnableUnifiedAlerting: true,
|
||||||
@@ -314,7 +318,7 @@ func TestAMConfigAccess(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
var silences apimodels.GettableSilences
|
var silences apimodels.GettableSilences
|
||||||
err := json.Unmarshal(blob, &silences)
|
err = json.Unmarshal(blob, &silences)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Len(t, silences, 2)
|
assert.Len(t, silences, 2)
|
||||||
silenceIDs := make([]string, 0, len(silences))
|
silenceIDs := make([]string, 0, len(silences))
|
||||||
@@ -387,6 +391,9 @@ func TestAMConfigAccess(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAlertAndGroupsQuery(t *testing.T) {
|
func TestAlertAndGroupsQuery(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
EnableUnifiedAlerting: true,
|
EnableUnifiedAlerting: true,
|
||||||
@@ -552,6 +559,8 @@ func TestAlertAndGroupsQuery(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRulerAccess(t *testing.T) {
|
func TestRulerAccess(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
// Setup Grafana and its Database
|
// Setup Grafana and its Database
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
@@ -566,7 +575,7 @@ func TestRulerAccess(t *testing.T) {
|
|||||||
store.Bus = bus.GetBus()
|
store.Bus = bus.GetBus()
|
||||||
|
|
||||||
// Create the namespace we'll save our alerts to.
|
// Create the namespace we'll save our alerts to.
|
||||||
_, err := createFolder(t, store, 0, "default")
|
_, err = createFolder(t, store, 0, "default")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Create a users to make authenticated requests
|
// Create a users to make authenticated requests
|
||||||
@@ -679,6 +688,8 @@ func TestRulerAccess(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteFolderWithRules(t *testing.T) {
|
func TestDeleteFolderWithRules(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
// Setup Grafana and its Database
|
// Setup Grafana and its Database
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
@@ -839,6 +850,8 @@ func TestDeleteFolderWithRules(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAlertRuleCRUD(t *testing.T) {
|
func TestAlertRuleCRUD(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
// Setup Grafana and its Database
|
// Setup Grafana and its Database
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
@@ -858,7 +871,7 @@ func TestAlertRuleCRUD(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Create the namespace we'll save our alerts to.
|
// Create the namespace we'll save our alerts to.
|
||||||
_, err := createFolder(t, store, 0, "default")
|
_, err = createFolder(t, store, 0, "default")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
interval, err := model.ParseDuration("1m")
|
interval, err := model.ParseDuration("1m")
|
||||||
@@ -1969,6 +1982,8 @@ func TestAlertmanagerStatus(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestQuota(t *testing.T) {
|
func TestQuota(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
// Setup Grafana and its Database
|
// Setup Grafana and its Database
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
@@ -1982,7 +1997,7 @@ func TestQuota(t *testing.T) {
|
|||||||
store.Bus = bus.GetBus()
|
store.Bus = bus.GetBus()
|
||||||
|
|
||||||
// Create the namespace we'll save our alerts to.
|
// Create the namespace we'll save our alerts to.
|
||||||
_, err := createFolder(t, store, 0, "default")
|
_, err = createFolder(t, store, 0, "default")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Create a user to make authenticated requests
|
// Create a user to make authenticated requests
|
||||||
@@ -2212,6 +2227,8 @@ func TestQuota(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestEval(t *testing.T) {
|
func TestEval(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
// Setup Grafana and its Database
|
// Setup Grafana and its Database
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
@@ -2231,7 +2248,7 @@ func TestEval(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Create the namespace we'll save our alerts to.
|
// Create the namespace we'll save our alerts to.
|
||||||
_, err := createFolder(t, store, 0, "default")
|
_, err = createFolder(t, store, 0, "default")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// test eval conditions
|
// test eval conditions
|
||||||
|
|||||||
@@ -9,11 +9,15 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/tests/testinfra"
|
"github.com/grafana/grafana/pkg/tests/testinfra"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAvailableChannels(t *testing.T) {
|
func TestAvailableChannels(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
EnableUnifiedAlerting: true,
|
EnableUnifiedAlerting: true,
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||||
@@ -32,6 +33,8 @@ import (
|
|||||||
|
|
||||||
func TestTestReceivers(t *testing.T) {
|
func TestTestReceivers(t *testing.T) {
|
||||||
t.Run("assert no receivers returns 400 Bad Request", func(t *testing.T) {
|
t.Run("assert no receivers returns 400 Bad Request", func(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
// Setup Grafana and its Database
|
// Setup Grafana and its Database
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
@@ -63,6 +66,8 @@ func TestTestReceivers(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("assert working receiver returns OK", func(t *testing.T) {
|
t.Run("assert working receiver returns OK", func(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
// Setup Grafana and its Database
|
// Setup Grafana and its Database
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
@@ -149,6 +154,8 @@ func TestTestReceivers(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("assert invalid receiver returns 400 Bad Request", func(t *testing.T) {
|
t.Run("assert invalid receiver returns 400 Bad Request", func(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
// Setup Grafana and its Database
|
// Setup Grafana and its Database
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
@@ -230,6 +237,8 @@ func TestTestReceivers(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("assert timed out receiver returns 408 Request Timeout", func(t *testing.T) {
|
t.Run("assert timed out receiver returns 408 Request Timeout", func(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
// Setup Grafana and its Database
|
// Setup Grafana and its Database
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
@@ -321,6 +330,8 @@ func TestTestReceivers(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("assert multiple different errors returns 207 Multi Status", func(t *testing.T) {
|
t.Run("assert multiple different errors returns 207 Multi Status", func(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
// Setup Grafana and its Database
|
// Setup Grafana and its Database
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
@@ -438,6 +449,8 @@ func TestTestReceivers(t *testing.T) {
|
|||||||
|
|
||||||
func TestTestReceiversAlertCustomization(t *testing.T) {
|
func TestTestReceiversAlertCustomization(t *testing.T) {
|
||||||
t.Run("assert custom annotations and labels are sent", func(t *testing.T) {
|
t.Run("assert custom annotations and labels are sent", func(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
// Setup Grafana and its Database
|
// Setup Grafana and its Database
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
@@ -535,6 +548,8 @@ func TestTestReceiversAlertCustomization(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("assert custom annotations can replace default annotations", func(t *testing.T) {
|
t.Run("assert custom annotations can replace default annotations", func(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
// Setup Grafana and its Database
|
// Setup Grafana and its Database
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
@@ -627,6 +642,8 @@ func TestTestReceiversAlertCustomization(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("assert custom labels can replace default label", func(t *testing.T) {
|
t.Run("assert custom labels can replace default label", func(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
// Setup Grafana and its Database
|
// Setup Grafana and its Database
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
@@ -719,6 +736,9 @@ func TestTestReceiversAlertCustomization(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNotificationChannels(t *testing.T) {
|
func TestNotificationChannels(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
EnableUnifiedAlerting: true,
|
EnableUnifiedAlerting: true,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||||
@@ -21,6 +22,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestPrometheusRules(t *testing.T) {
|
func TestPrometheusRules(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
EnableUnifiedAlerting: true,
|
EnableUnifiedAlerting: true,
|
||||||
@@ -32,7 +36,7 @@ func TestPrometheusRules(t *testing.T) {
|
|||||||
store.Bus = bus.GetBus()
|
store.Bus = bus.GetBus()
|
||||||
|
|
||||||
// Create the namespace under default organisation (orgID = 1) where we'll save our alerts to.
|
// Create the namespace under default organisation (orgID = 1) where we'll save our alerts to.
|
||||||
_, err := createFolder(t, store, 0, "default")
|
_, err = createFolder(t, store, 0, "default")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Create a user to make authenticated requests
|
// Create a user to make authenticated requests
|
||||||
@@ -320,6 +324,8 @@ func TestPrometheusRules(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPrometheusRulesFilterByDashboard(t *testing.T) {
|
func TestPrometheusRulesFilterByDashboard(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
EnableFeatureToggles: []string{"ngalert"},
|
EnableFeatureToggles: []string{"ngalert"},
|
||||||
DisableAnonymous: true,
|
DisableAnonymous: true,
|
||||||
@@ -615,6 +621,9 @@ func TestPrometheusRulesFilterByDashboard(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPrometheusRulesPermissions(t *testing.T) {
|
func TestPrometheusRulesPermissions(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
EnableUnifiedAlerting: true,
|
EnableUnifiedAlerting: true,
|
||||||
@@ -633,7 +642,7 @@ func TestPrometheusRulesPermissions(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Create a namespace under default organisation (orgID = 1) where we'll save some alerts.
|
// Create a namespace under default organisation (orgID = 1) where we'll save some alerts.
|
||||||
_, err := createFolder(t, store, 0, "folder1")
|
_, err = createFolder(t, store, 0, "folder1")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Create another namespace under default organisation (orgID = 1) where we'll save some alerts.
|
// Create another namespace under default organisation (orgID = 1) where we'll save some alerts.
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||||
@@ -22,6 +23,9 @@ import (
|
|||||||
|
|
||||||
func TestAlertRulePermissions(t *testing.T) {
|
func TestAlertRulePermissions(t *testing.T) {
|
||||||
// Setup Grafana and its Database
|
// Setup Grafana and its Database
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
EnableUnifiedAlerting: true,
|
EnableUnifiedAlerting: true,
|
||||||
@@ -40,7 +44,7 @@ func TestAlertRulePermissions(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Create the namespace we'll save our alerts to.
|
// Create the namespace we'll save our alerts to.
|
||||||
_, err := createFolder(t, store, 0, "folder1")
|
_, err = createFolder(t, store, 0, "folder1")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
_, err = createFolder(t, store, 0, "folder2")
|
_, err = createFolder(t, store, 0, "folder2")
|
||||||
@@ -324,6 +328,8 @@ func createRule(t *testing.T, grafanaListedAddr string, folder string, user, pas
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAlertRuleConflictingTitle(t *testing.T) {
|
func TestAlertRuleConflictingTitle(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
// Setup Grafana and its Database
|
// Setup Grafana and its Database
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
DisableLegacyAlerting: true,
|
DisableLegacyAlerting: true,
|
||||||
@@ -338,7 +344,7 @@ func TestAlertRuleConflictingTitle(t *testing.T) {
|
|||||||
store.Bus = bus.GetBus()
|
store.Bus = bus.GetBus()
|
||||||
|
|
||||||
// Create the namespace we'll save our alerts to.
|
// Create the namespace we'll save our alerts to.
|
||||||
_, err := createFolder(t, store, 0, "folder1")
|
_, err = createFolder(t, store, 0, "folder1")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
_, err = createFolder(t, store, 0, "folder2")
|
_, err = createFolder(t, store, 0, "folder2")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -448,6 +454,9 @@ func TestAlertRuleConflictingTitle(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRulerRulesFilterByDashboard(t *testing.T) {
|
func TestRulerRulesFilterByDashboard(t *testing.T) {
|
||||||
|
_, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
EnableFeatureToggles: []string{"ngalert"},
|
EnableFeatureToggles: []string{"ngalert"},
|
||||||
DisableAnonymous: true,
|
DisableAnonymous: true,
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ func TestDashboardQuota(t *testing.T) {
|
|||||||
EnableQuota: true,
|
EnableQuota: true,
|
||||||
DashboardOrgQuota: &dashboardQuota,
|
DashboardOrgQuota: &dashboardQuota,
|
||||||
})
|
})
|
||||||
|
|
||||||
grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path)
|
grafanaListedAddr, store := testinfra.StartGrafana(t, dir, path)
|
||||||
// Create user
|
// Create user
|
||||||
createUser(t, store, models.CreateUserCommand{
|
createUser(t, store, models.CreateUserCommand{
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import (
|
|||||||
|
|
||||||
func TestQueryCloudWatchMetrics(t *testing.T) {
|
func TestQueryCloudWatchMetrics(t *testing.T) {
|
||||||
grafDir, cfgPath := testinfra.CreateGrafDir(t)
|
grafDir, cfgPath := testinfra.CreateGrafDir(t)
|
||||||
|
|
||||||
addr, sqlStore := testinfra.StartGrafana(t, grafDir, cfgPath)
|
addr, sqlStore := testinfra.StartGrafana(t, grafDir, cfgPath)
|
||||||
setUpDatabase(t, sqlStore)
|
setUpDatabase(t, sqlStore)
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ func TestIndexView(t *testing.T) {
|
|||||||
grafDir, cfgPath := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
grafDir, cfgPath := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||||
EnableCSP: true,
|
EnableCSP: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
addr, _ := testinfra.StartGrafana(t, grafDir, cfgPath)
|
addr, _ := testinfra.StartGrafana(t, grafDir, cfgPath)
|
||||||
|
|
||||||
// nolint:bodyclose
|
// nolint:bodyclose
|
||||||
|
|||||||
@@ -14,8 +14,9 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/util/errutil"
|
"github.com/grafana/grafana/pkg/util/errutil"
|
||||||
"github.com/opentracing/opentracing-go"
|
"go.opentelemetry.io/otel/attribute"
|
||||||
"golang.org/x/net/context/ctxhttp"
|
"golang.org/x/net/context/ctxhttp"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -48,7 +49,8 @@ func (e *ApplicationInsightsDatasource) resourceRequest(rw http.ResponseWriter,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *ApplicationInsightsDatasource) executeTimeSeriesQuery(ctx context.Context,
|
func (e *ApplicationInsightsDatasource) executeTimeSeriesQuery(ctx context.Context,
|
||||||
originalQueries []backend.DataQuery, dsInfo datasourceInfo, client *http.Client, url string) (*backend.QueryDataResponse, error) {
|
originalQueries []backend.DataQuery, dsInfo datasourceInfo, client *http.Client,
|
||||||
|
url string, tracer tracing.Tracer) (*backend.QueryDataResponse, error) {
|
||||||
result := backend.NewQueryDataResponse()
|
result := backend.NewQueryDataResponse()
|
||||||
|
|
||||||
queries, err := e.buildQueries(originalQueries)
|
queries, err := e.buildQueries(originalQueries)
|
||||||
@@ -57,7 +59,7 @@ func (e *ApplicationInsightsDatasource) executeTimeSeriesQuery(ctx context.Conte
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, query := range queries {
|
for _, query := range queries {
|
||||||
queryRes, err := e.executeQuery(ctx, query, dsInfo, client, url)
|
queryRes, err := e.executeQuery(ctx, query, dsInfo, client, url, tracer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -128,7 +130,7 @@ func (e *ApplicationInsightsDatasource) buildQueries(queries []backend.DataQuery
|
|||||||
return applicationInsightsQueries, nil
|
return applicationInsightsQueries, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ApplicationInsightsDatasource) executeQuery(ctx context.Context, query *ApplicationInsightsQuery, dsInfo datasourceInfo, client *http.Client, url string) (
|
func (e *ApplicationInsightsDatasource) executeQuery(ctx context.Context, query *ApplicationInsightsQuery, dsInfo datasourceInfo, client *http.Client, url string, tracer tracing.Tracer) (
|
||||||
backend.DataResponse, error) {
|
backend.DataResponse, error) {
|
||||||
dataResponse := backend.DataResponse{}
|
dataResponse := backend.DataResponse{}
|
||||||
|
|
||||||
@@ -141,23 +143,16 @@ func (e *ApplicationInsightsDatasource) executeQuery(ctx context.Context, query
|
|||||||
req.URL.Path = path.Join(req.URL.Path, query.ApiURL)
|
req.URL.Path = path.Join(req.URL.Path, query.ApiURL)
|
||||||
req.URL.RawQuery = query.Params.Encode()
|
req.URL.RawQuery = query.Params.Encode()
|
||||||
|
|
||||||
span, ctx := opentracing.StartSpanFromContext(ctx, "application insights query")
|
ctx, span := tracer.Start(ctx, "application insights query")
|
||||||
span.SetTag("target", query.Target)
|
span.SetAttributes("target", query.Target, attribute.Key("target").String(query.Target))
|
||||||
span.SetTag("from", query.TimeRange.From.UnixNano()/int64(time.Millisecond))
|
span.SetAttributes("from", query.TimeRange.From.UnixNano()/int64(time.Millisecond), attribute.Key("from").Int64(query.TimeRange.From.UnixNano()/int64(time.Millisecond)))
|
||||||
span.SetTag("until", query.TimeRange.To.UnixNano()/int64(time.Millisecond))
|
span.SetAttributes("until", query.TimeRange.To.UnixNano()/int64(time.Millisecond), attribute.Key("until").Int64(query.TimeRange.To.UnixNano()/int64(time.Millisecond)))
|
||||||
span.SetTag("datasource_id", dsInfo.DatasourceID)
|
span.SetAttributes("datasource_id", dsInfo.DatasourceID, attribute.Key("datasource_id").Int64(dsInfo.DatasourceID))
|
||||||
span.SetTag("org_id", dsInfo.OrgID)
|
span.SetAttributes("org_id", dsInfo.OrgID, attribute.Key("org_id").Int64(dsInfo.OrgID))
|
||||||
|
|
||||||
defer span.Finish()
|
defer span.End()
|
||||||
|
|
||||||
err = opentracing.GlobalTracer().Inject(
|
tracer.Inject(ctx, req.Header, span)
|
||||||
span.Context(),
|
|
||||||
opentracing.HTTPHeaders,
|
|
||||||
opentracing.HTTPHeadersCarrier(req.Header))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
azlog.Warn("failed to inject global tracer")
|
|
||||||
}
|
|
||||||
|
|
||||||
azlog.Debug("ApplicationInsights", "Request URL", req.URL.String())
|
azlog.Debug("ApplicationInsights", "Request URL", req.URL.String())
|
||||||
res, err := ctxhttp.Do(ctx, client, req)
|
res, err := ctxhttp.Do(ctx, client, req)
|
||||||
|
|||||||
@@ -16,8 +16,9 @@ import (
|
|||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/util/errutil"
|
"github.com/grafana/grafana/pkg/util/errutil"
|
||||||
"github.com/opentracing/opentracing-go"
|
"go.opentelemetry.io/otel/attribute"
|
||||||
"golang.org/x/net/context/ctxhttp"
|
"golang.org/x/net/context/ctxhttp"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -46,7 +47,8 @@ func (e *AzureLogAnalyticsDatasource) resourceRequest(rw http.ResponseWriter, re
|
|||||||
// 1. build the AzureMonitor url and querystring for each query
|
// 1. build the AzureMonitor url and querystring for each query
|
||||||
// 2. executes each query by calling the Azure Monitor API
|
// 2. executes each query by calling the Azure Monitor API
|
||||||
// 3. parses the responses for each query into data frames
|
// 3. parses the responses for each query into data frames
|
||||||
func (e *AzureLogAnalyticsDatasource) executeTimeSeriesQuery(ctx context.Context, originalQueries []backend.DataQuery, dsInfo datasourceInfo, client *http.Client, url string) (*backend.QueryDataResponse, error) {
|
func (e *AzureLogAnalyticsDatasource) executeTimeSeriesQuery(ctx context.Context, originalQueries []backend.DataQuery, dsInfo datasourceInfo, client *http.Client,
|
||||||
|
url string, tracer tracing.Tracer) (*backend.QueryDataResponse, error) {
|
||||||
result := backend.NewQueryDataResponse()
|
result := backend.NewQueryDataResponse()
|
||||||
|
|
||||||
queries, err := e.buildQueries(originalQueries, dsInfo)
|
queries, err := e.buildQueries(originalQueries, dsInfo)
|
||||||
@@ -55,7 +57,7 @@ func (e *AzureLogAnalyticsDatasource) executeTimeSeriesQuery(ctx context.Context
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, query := range queries {
|
for _, query := range queries {
|
||||||
result.Responses[query.RefID] = e.executeQuery(ctx, query, dsInfo, client, url)
|
result.Responses[query.RefID] = e.executeQuery(ctx, query, dsInfo, client, url, tracer)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
@@ -125,7 +127,8 @@ func (e *AzureLogAnalyticsDatasource) buildQueries(queries []backend.DataQuery,
|
|||||||
return azureLogAnalyticsQueries, nil
|
return azureLogAnalyticsQueries, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *AzureLogAnalyticsDatasource) executeQuery(ctx context.Context, query *AzureLogAnalyticsQuery, dsInfo datasourceInfo, client *http.Client, url string) backend.DataResponse {
|
func (e *AzureLogAnalyticsDatasource) executeQuery(ctx context.Context, query *AzureLogAnalyticsQuery, dsInfo datasourceInfo, client *http.Client,
|
||||||
|
url string, tracer tracing.Tracer) backend.DataResponse {
|
||||||
dataResponse := backend.DataResponse{}
|
dataResponse := backend.DataResponse{}
|
||||||
|
|
||||||
dataResponseErrorWithExecuted := func(err error) backend.DataResponse {
|
dataResponseErrorWithExecuted := func(err error) backend.DataResponse {
|
||||||
@@ -155,21 +158,16 @@ func (e *AzureLogAnalyticsDatasource) executeQuery(ctx context.Context, query *A
|
|||||||
req.URL.Path = path.Join(req.URL.Path, query.URL)
|
req.URL.Path = path.Join(req.URL.Path, query.URL)
|
||||||
req.URL.RawQuery = query.Params.Encode()
|
req.URL.RawQuery = query.Params.Encode()
|
||||||
|
|
||||||
span, ctx := opentracing.StartSpanFromContext(ctx, "azure log analytics query")
|
ctx, span := tracer.Start(ctx, "azure log analytics query")
|
||||||
span.SetTag("target", query.Target)
|
span.SetAttributes("target", query.Target, attribute.Key("target").String(query.Target))
|
||||||
span.SetTag("from", query.TimeRange.From.UnixNano()/int64(time.Millisecond))
|
span.SetAttributes("from", query.TimeRange.From.UnixNano()/int64(time.Millisecond), attribute.Key("from").Int64(query.TimeRange.From.UnixNano()/int64(time.Millisecond)))
|
||||||
span.SetTag("until", query.TimeRange.To.UnixNano()/int64(time.Millisecond))
|
span.SetAttributes("until", query.TimeRange.To.UnixNano()/int64(time.Millisecond), attribute.Key("until").Int64(query.TimeRange.To.UnixNano()/int64(time.Millisecond)))
|
||||||
span.SetTag("datasource_id", dsInfo.DatasourceID)
|
span.SetAttributes("datasource_id", dsInfo.DatasourceID, attribute.Key("datasource_id").Int64(dsInfo.DatasourceID))
|
||||||
span.SetTag("org_id", dsInfo.OrgID)
|
span.SetAttributes("org_id", dsInfo.OrgID, attribute.Key("org_id").Int64(dsInfo.OrgID))
|
||||||
|
|
||||||
defer span.Finish()
|
defer span.End()
|
||||||
|
|
||||||
if err := opentracing.GlobalTracer().Inject(
|
tracer.Inject(ctx, req.Header, span)
|
||||||
span.Context(),
|
|
||||||
opentracing.HTTPHeaders,
|
|
||||||
opentracing.HTTPHeadersCarrier(req.Header)); err != nil {
|
|
||||||
return dataResponseErrorWithExecuted(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
azlog.Debug("AzureLogAnalytics", "Request ApiURL", req.URL.String())
|
azlog.Debug("AzureLogAnalytics", "Request ApiURL", req.URL.String())
|
||||||
res, err := ctxhttp.Do(ctx, client, req)
|
res, err := ctxhttp.Do(ctx, client, req)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -228,7 +229,9 @@ func Test_executeQueryErrorWithDifferentLogAnalyticsCreds(t *testing.T) {
|
|||||||
Params: url.Values{},
|
Params: url.Values{},
|
||||||
TimeRange: backend.TimeRange{},
|
TimeRange: backend.TimeRange{},
|
||||||
}
|
}
|
||||||
res := ds.executeQuery(ctx, query, dsInfo, &http.Client{}, dsInfo.Services[azureLogAnalytics].URL)
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
res := ds.executeQuery(ctx, query, dsInfo, &http.Client{}, dsInfo.Services[azureLogAnalytics].URL, tracer)
|
||||||
if res.Error == nil {
|
if res.Error == nil {
|
||||||
t.Fatal("expecting an error")
|
t.Fatal("expecting an error")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,10 @@ import (
|
|||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/util/errutil"
|
"github.com/grafana/grafana/pkg/util/errutil"
|
||||||
"github.com/opentracing/opentracing-go"
|
"go.opentelemetry.io/otel/attribute"
|
||||||
"golang.org/x/net/context/ctxhttp"
|
"golang.org/x/net/context/ctxhttp"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -48,7 +49,8 @@ func (e *AzureResourceGraphDatasource) resourceRequest(rw http.ResponseWriter, r
|
|||||||
// 1. builds the AzureMonitor url and querystring for each query
|
// 1. builds the AzureMonitor url and querystring for each query
|
||||||
// 2. executes each query by calling the Azure Monitor API
|
// 2. executes each query by calling the Azure Monitor API
|
||||||
// 3. parses the responses for each query into data frames
|
// 3. parses the responses for each query into data frames
|
||||||
func (e *AzureResourceGraphDatasource) executeTimeSeriesQuery(ctx context.Context, originalQueries []backend.DataQuery, dsInfo datasourceInfo, client *http.Client, url string) (*backend.QueryDataResponse, error) {
|
func (e *AzureResourceGraphDatasource) executeTimeSeriesQuery(ctx context.Context, originalQueries []backend.DataQuery, dsInfo datasourceInfo, client *http.Client,
|
||||||
|
url string, tracer tracing.Tracer) (*backend.QueryDataResponse, error) {
|
||||||
result := &backend.QueryDataResponse{
|
result := &backend.QueryDataResponse{
|
||||||
Responses: map[string]backend.DataResponse{},
|
Responses: map[string]backend.DataResponse{},
|
||||||
}
|
}
|
||||||
@@ -59,7 +61,7 @@ func (e *AzureResourceGraphDatasource) executeTimeSeriesQuery(ctx context.Contex
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, query := range queries {
|
for _, query := range queries {
|
||||||
result.Responses[query.RefID] = e.executeQuery(ctx, query, dsInfo, client, url)
|
result.Responses[query.RefID] = e.executeQuery(ctx, query, dsInfo, client, url, tracer)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
@@ -101,7 +103,8 @@ func (e *AzureResourceGraphDatasource) buildQueries(queries []backend.DataQuery,
|
|||||||
return azureResourceGraphQueries, nil
|
return azureResourceGraphQueries, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *AzureResourceGraphDatasource) executeQuery(ctx context.Context, query *AzureResourceGraphQuery, dsInfo datasourceInfo, client *http.Client, dsURL string) backend.DataResponse {
|
func (e *AzureResourceGraphDatasource) executeQuery(ctx context.Context, query *AzureResourceGraphQuery, dsInfo datasourceInfo, client *http.Client,
|
||||||
|
dsURL string, tracer tracing.Tracer) backend.DataResponse {
|
||||||
dataResponse := backend.DataResponse{}
|
dataResponse := backend.DataResponse{}
|
||||||
|
|
||||||
params := url.Values{}
|
params := url.Values{}
|
||||||
@@ -148,21 +151,16 @@ func (e *AzureResourceGraphDatasource) executeQuery(ctx context.Context, query *
|
|||||||
req.URL.Path = path.Join(req.URL.Path, argQueryProviderName)
|
req.URL.Path = path.Join(req.URL.Path, argQueryProviderName)
|
||||||
req.URL.RawQuery = params.Encode()
|
req.URL.RawQuery = params.Encode()
|
||||||
|
|
||||||
span, ctx := opentracing.StartSpanFromContext(ctx, "azure resource graph query")
|
ctx, span := tracer.Start(ctx, "azure resource graph query")
|
||||||
span.SetTag("interpolated_query", query.InterpolatedQuery)
|
span.SetAttributes("interpolated_query", query.InterpolatedQuery, attribute.Key("interpolated_query").String(query.InterpolatedQuery))
|
||||||
span.SetTag("from", query.TimeRange.From.UnixNano()/int64(time.Millisecond))
|
span.SetAttributes("from", query.TimeRange.From.UnixNano()/int64(time.Millisecond), attribute.Key("from").Int64(query.TimeRange.From.UnixNano()/int64(time.Millisecond)))
|
||||||
span.SetTag("until", query.TimeRange.To.UnixNano()/int64(time.Millisecond))
|
span.SetAttributes("until", query.TimeRange.To.UnixNano()/int64(time.Millisecond), attribute.Key("until").Int64(query.TimeRange.To.UnixNano()/int64(time.Millisecond)))
|
||||||
span.SetTag("datasource_id", dsInfo.DatasourceID)
|
span.SetAttributes("datasource_id", dsInfo.DatasourceID, attribute.Key("datasource_id").Int64(dsInfo.DatasourceID))
|
||||||
span.SetTag("org_id", dsInfo.OrgID)
|
span.SetAttributes("org_id", dsInfo.OrgID, attribute.Key("org_id").Int64(dsInfo.OrgID))
|
||||||
|
|
||||||
defer span.Finish()
|
defer span.End()
|
||||||
|
|
||||||
if err := opentracing.GlobalTracer().Inject(
|
tracer.Inject(ctx, req.Header, span)
|
||||||
span.Context(),
|
|
||||||
opentracing.HTTPHeaders,
|
|
||||||
opentracing.HTTPHeadersCarrier(req.Header)); err != nil {
|
|
||||||
return dataResponseErrorWithExecuted(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
azlog.Debug("AzureResourceGraph", "Request ApiURL", req.URL.String())
|
azlog.Debug("AzureResourceGraph", "Request ApiURL", req.URL.String())
|
||||||
res, err := ctxhttp.Do(ctx, client, req)
|
res, err := ctxhttp.Do(ctx, client, req)
|
||||||
|
|||||||
@@ -14,9 +14,10 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/util/errutil"
|
"github.com/grafana/grafana/pkg/util/errutil"
|
||||||
opentracing "github.com/opentracing/opentracing-go"
|
"go.opentelemetry.io/otel/attribute"
|
||||||
"golang.org/x/net/context/ctxhttp"
|
"golang.org/x/net/context/ctxhttp"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -43,7 +44,8 @@ func (e *AzureMonitorDatasource) resourceRequest(rw http.ResponseWriter, req *ht
|
|||||||
// 1. build the AzureMonitor url and querystring for each query
|
// 1. build the AzureMonitor url and querystring for each query
|
||||||
// 2. executes each query by calling the Azure Monitor API
|
// 2. executes each query by calling the Azure Monitor API
|
||||||
// 3. parses the responses for each query into data frames
|
// 3. parses the responses for each query into data frames
|
||||||
func (e *AzureMonitorDatasource) executeTimeSeriesQuery(ctx context.Context, originalQueries []backend.DataQuery, dsInfo datasourceInfo, client *http.Client, url string) (*backend.QueryDataResponse, error) {
|
func (e *AzureMonitorDatasource) executeTimeSeriesQuery(ctx context.Context, originalQueries []backend.DataQuery, dsInfo datasourceInfo, client *http.Client,
|
||||||
|
url string, tracer tracing.Tracer) (*backend.QueryDataResponse, error) {
|
||||||
result := backend.NewQueryDataResponse()
|
result := backend.NewQueryDataResponse()
|
||||||
|
|
||||||
queries, err := e.buildQueries(originalQueries, dsInfo)
|
queries, err := e.buildQueries(originalQueries, dsInfo)
|
||||||
@@ -52,7 +54,7 @@ func (e *AzureMonitorDatasource) executeTimeSeriesQuery(ctx context.Context, ori
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, query := range queries {
|
for _, query := range queries {
|
||||||
result.Responses[query.RefID] = e.executeQuery(ctx, query, dsInfo, client, url)
|
result.Responses[query.RefID] = e.executeQuery(ctx, query, dsInfo, client, url, tracer)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
@@ -147,7 +149,8 @@ func (e *AzureMonitorDatasource) buildQueries(queries []backend.DataQuery, dsInf
|
|||||||
return azureMonitorQueries, nil
|
return azureMonitorQueries, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *AzureMonitorDatasource) executeQuery(ctx context.Context, query *AzureMonitorQuery, dsInfo datasourceInfo, cli *http.Client, url string) backend.DataResponse {
|
func (e *AzureMonitorDatasource) executeQuery(ctx context.Context, query *AzureMonitorQuery, dsInfo datasourceInfo, cli *http.Client,
|
||||||
|
url string, tracer tracing.Tracer) backend.DataResponse {
|
||||||
dataResponse := backend.DataResponse{}
|
dataResponse := backend.DataResponse{}
|
||||||
|
|
||||||
req, err := e.createRequest(ctx, dsInfo, url)
|
req, err := e.createRequest(ctx, dsInfo, url)
|
||||||
@@ -159,22 +162,15 @@ func (e *AzureMonitorDatasource) executeQuery(ctx context.Context, query *AzureM
|
|||||||
req.URL.Path = path.Join(req.URL.Path, query.URL)
|
req.URL.Path = path.Join(req.URL.Path, query.URL)
|
||||||
req.URL.RawQuery = query.Params.Encode()
|
req.URL.RawQuery = query.Params.Encode()
|
||||||
|
|
||||||
span, ctx := opentracing.StartSpanFromContext(ctx, "azuremonitor query")
|
ctx, span := tracer.Start(ctx, "azuremonitor query")
|
||||||
span.SetTag("target", query.Target)
|
span.SetAttributes("target", query.Target, attribute.Key("target").String(query.Target))
|
||||||
span.SetTag("from", query.TimeRange.From.UnixNano()/int64(time.Millisecond))
|
span.SetAttributes("from", query.TimeRange.From.UnixNano()/int64(time.Millisecond), attribute.Key("from").Int64(query.TimeRange.From.UnixNano()/int64(time.Millisecond)))
|
||||||
span.SetTag("until", query.TimeRange.To.UnixNano()/int64(time.Millisecond))
|
span.SetAttributes("until", query.TimeRange.To.UnixNano()/int64(time.Millisecond), attribute.Key("until").Int64(query.TimeRange.To.UnixNano()/int64(time.Millisecond)))
|
||||||
span.SetTag("datasource_id", dsInfo.DatasourceID)
|
span.SetAttributes("datasource_id", dsInfo.DatasourceID, attribute.Key("datasource_id").Int64(dsInfo.DatasourceID))
|
||||||
span.SetTag("org_id", dsInfo.OrgID)
|
span.SetAttributes("org_id", dsInfo.OrgID, attribute.Key("org_id").Int64(dsInfo.OrgID))
|
||||||
|
|
||||||
defer span.Finish()
|
defer span.End()
|
||||||
|
tracer.Inject(ctx, req.Header, span)
|
||||||
if err := opentracing.GlobalTracer().Inject(
|
|
||||||
span.Context(),
|
|
||||||
opentracing.HTTPHeaders,
|
|
||||||
opentracing.HTTPHeadersCarrier(req.Header)); err != nil {
|
|
||||||
dataResponse.Error = err
|
|
||||||
return dataResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
azlog.Debug("AzureMonitor", "Request ApiURL", req.URL.String())
|
azlog.Debug("AzureMonitor", "Request ApiURL", req.URL.String())
|
||||||
azlog.Debug("AzureMonitor", "Target", query.Target)
|
azlog.Debug("AzureMonitor", "Target", query.Target)
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter"
|
"github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter"
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/plugins"
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
"github.com/grafana/grafana/pkg/plugins/backendplugin/coreplugin"
|
"github.com/grafana/grafana/pkg/plugins/backendplugin/coreplugin"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
@@ -30,7 +31,7 @@ var (
|
|||||||
legendKeyFormat = regexp.MustCompile(`\{\{\s*(.+?)\s*\}\}`)
|
legendKeyFormat = regexp.MustCompile(`\{\{\s*(.+?)\s*\}\}`)
|
||||||
)
|
)
|
||||||
|
|
||||||
func ProvideService(cfg *setting.Cfg, httpClientProvider *httpclient.Provider, pluginStore plugins.Store) *Service {
|
func ProvideService(cfg *setting.Cfg, httpClientProvider *httpclient.Provider, pluginStore plugins.Store, tracer tracing.Tracer) *Service {
|
||||||
proxy := &httpServiceProxy{}
|
proxy := &httpServiceProxy{}
|
||||||
executors := map[string]azDatasourceExecutor{
|
executors := map[string]azDatasourceExecutor{
|
||||||
azureMonitor: &AzureMonitorDatasource{proxy: proxy},
|
azureMonitor: &AzureMonitorDatasource{proxy: proxy},
|
||||||
@@ -45,6 +46,7 @@ func ProvideService(cfg *setting.Cfg, httpClientProvider *httpclient.Provider, p
|
|||||||
Cfg: cfg,
|
Cfg: cfg,
|
||||||
im: im,
|
im: im,
|
||||||
executors: executors,
|
executors: executors,
|
||||||
|
tracer: tracer,
|
||||||
}
|
}
|
||||||
|
|
||||||
mux := s.newMux()
|
mux := s.newMux()
|
||||||
@@ -71,6 +73,7 @@ type Service struct {
|
|||||||
Cfg *setting.Cfg
|
Cfg *setting.Cfg
|
||||||
im instancemgmt.InstanceManager
|
im instancemgmt.InstanceManager
|
||||||
executors map[string]azDatasourceExecutor
|
executors map[string]azDatasourceExecutor
|
||||||
|
tracer tracing.Tracer
|
||||||
}
|
}
|
||||||
|
|
||||||
type azureMonitorSettings struct {
|
type azureMonitorSettings struct {
|
||||||
@@ -162,7 +165,7 @@ func NewInstanceSettings(cfg *setting.Cfg, clientProvider httpclient.Provider, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
type azDatasourceExecutor interface {
|
type azDatasourceExecutor interface {
|
||||||
executeTimeSeriesQuery(ctx context.Context, originalQueries []backend.DataQuery, dsInfo datasourceInfo, client *http.Client, url string) (*backend.QueryDataResponse, error)
|
executeTimeSeriesQuery(ctx context.Context, originalQueries []backend.DataQuery, dsInfo datasourceInfo, client *http.Client, url string, tracer tracing.Tracer) (*backend.QueryDataResponse, error)
|
||||||
resourceRequest(rw http.ResponseWriter, req *http.Request, cli *http.Client)
|
resourceRequest(rw http.ResponseWriter, req *http.Request, cli *http.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,7 +197,7 @@ func (s *Service) newMux() *datasource.QueryTypeMux {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("missing service for %s", dst)
|
return nil, fmt.Errorf("missing service for %s", dst)
|
||||||
}
|
}
|
||||||
return executor.executeTimeSeriesQuery(ctx, req.Queries, dsInfo, service.HTTPClient, service.URL)
|
return executor.executeTimeSeriesQuery(ctx, req.Queries, dsInfo, service.HTTPClient, service.URL, s.tracer)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return mux
|
return mux
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
|
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/azcredentials"
|
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/azcredentials"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -85,7 +86,8 @@ type fakeExecutor struct {
|
|||||||
func (f *fakeExecutor) resourceRequest(rw http.ResponseWriter, req *http.Request, cli *http.Client) {
|
func (f *fakeExecutor) resourceRequest(rw http.ResponseWriter, req *http.Request, cli *http.Client) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakeExecutor) executeTimeSeriesQuery(ctx context.Context, originalQueries []backend.DataQuery, dsInfo datasourceInfo, client *http.Client, url string) (*backend.QueryDataResponse, error) {
|
func (f *fakeExecutor) executeTimeSeriesQuery(ctx context.Context, originalQueries []backend.DataQuery, dsInfo datasourceInfo, client *http.Client,
|
||||||
|
url string, tracer tracing.Tracer) (*backend.QueryDataResponse, error) {
|
||||||
if client == nil {
|
if client == nil {
|
||||||
f.t.Errorf("The HTTP client for %s is missing", f.queryType)
|
f.t.Errorf("The HTTP client for %s is missing", f.queryType)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -12,8 +12,9 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/util/errutil"
|
"github.com/grafana/grafana/pkg/util/errutil"
|
||||||
"github.com/opentracing/opentracing-go"
|
"go.opentelemetry.io/otel/attribute"
|
||||||
"golang.org/x/net/context/ctxhttp"
|
"golang.org/x/net/context/ctxhttp"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -38,7 +39,8 @@ func (e *InsightsAnalyticsDatasource) resourceRequest(rw http.ResponseWriter, re
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *InsightsAnalyticsDatasource) executeTimeSeriesQuery(ctx context.Context,
|
func (e *InsightsAnalyticsDatasource) executeTimeSeriesQuery(ctx context.Context,
|
||||||
originalQueries []backend.DataQuery, dsInfo datasourceInfo, client *http.Client, url string) (*backend.QueryDataResponse, error) {
|
originalQueries []backend.DataQuery, dsInfo datasourceInfo, client *http.Client,
|
||||||
|
url string, tracer tracing.Tracer) (*backend.QueryDataResponse, error) {
|
||||||
result := backend.NewQueryDataResponse()
|
result := backend.NewQueryDataResponse()
|
||||||
|
|
||||||
queries, err := e.buildQueries(originalQueries, dsInfo)
|
queries, err := e.buildQueries(originalQueries, dsInfo)
|
||||||
@@ -47,7 +49,7 @@ func (e *InsightsAnalyticsDatasource) executeTimeSeriesQuery(ctx context.Context
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, query := range queries {
|
for _, query := range queries {
|
||||||
result.Responses[query.RefID] = e.executeQuery(ctx, query, dsInfo, client, url)
|
result.Responses[query.RefID] = e.executeQuery(ctx, query, dsInfo, client, url, tracer)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
@@ -86,7 +88,8 @@ func (e *InsightsAnalyticsDatasource) buildQueries(queries []backend.DataQuery,
|
|||||||
return iaQueries, nil
|
return iaQueries, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *InsightsAnalyticsDatasource) executeQuery(ctx context.Context, query *InsightsAnalyticsQuery, dsInfo datasourceInfo, client *http.Client, url string) backend.DataResponse {
|
func (e *InsightsAnalyticsDatasource) executeQuery(ctx context.Context, query *InsightsAnalyticsQuery, dsInfo datasourceInfo, client *http.Client,
|
||||||
|
url string, tracer tracing.Tracer) backend.DataResponse {
|
||||||
dataResponse := backend.DataResponse{}
|
dataResponse := backend.DataResponse{}
|
||||||
|
|
||||||
dataResponseError := func(err error) backend.DataResponse {
|
dataResponseError := func(err error) backend.DataResponse {
|
||||||
@@ -101,17 +104,13 @@ func (e *InsightsAnalyticsDatasource) executeQuery(ctx context.Context, query *I
|
|||||||
req.URL.Path = path.Join(req.URL.Path, "query")
|
req.URL.Path = path.Join(req.URL.Path, "query")
|
||||||
req.URL.RawQuery = query.Params.Encode()
|
req.URL.RawQuery = query.Params.Encode()
|
||||||
|
|
||||||
span, ctx := opentracing.StartSpanFromContext(ctx, "application insights analytics query")
|
ctx, span := tracer.Start(ctx, "application insights analytics query")
|
||||||
span.SetTag("target", query.Target)
|
span.SetAttributes("target", query.Target, attribute.Key("target").String(query.Target))
|
||||||
span.SetTag("datasource_id", dsInfo.DatasourceID)
|
span.SetAttributes("datasource_id", dsInfo.DatasourceID, attribute.Key("datasource_id").Int64(dsInfo.DatasourceID))
|
||||||
span.SetTag("org_id", dsInfo.OrgID)
|
span.SetAttributes("org_id", dsInfo.OrgID, attribute.Key("org_id").Int64(dsInfo.OrgID))
|
||||||
|
|
||||||
defer span.Finish()
|
defer span.End()
|
||||||
|
tracer.Inject(ctx, req.Header, span)
|
||||||
err = opentracing.GlobalTracer().Inject(
|
|
||||||
span.Context(),
|
|
||||||
opentracing.HTTPHeaders,
|
|
||||||
opentracing.HTTPHeadersCarrier(req.Header))
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
azlog.Warn("failed to inject global tracer")
|
azlog.Warn("failed to inject global tracer")
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ func (s *Service) executeAnnotationQuery(ctx context.Context, req *backend.Query
|
|||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
queryRes, dr, _, err := queries[0].run(ctx, req, s, dsInfo)
|
queryRes, dr, _, err := queries[0].run(ctx, req, s, dsInfo, s.tracer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/plugins"
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
"github.com/grafana/grafana/pkg/plugins/backendplugin/coreplugin"
|
"github.com/grafana/grafana/pkg/plugins/backendplugin/coreplugin"
|
||||||
"github.com/grafana/grafana/pkg/services/datasources"
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
@@ -72,12 +73,13 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ProvideService(cfg *setting.Cfg, httpClientProvider httpclient.Provider, pluginStore plugins.Store,
|
func ProvideService(cfg *setting.Cfg, httpClientProvider httpclient.Provider, pluginStore plugins.Store,
|
||||||
dsService *datasources.Service) *Service {
|
dsService *datasources.Service, tracer tracing.Tracer) *Service {
|
||||||
s := &Service{
|
s := &Service{
|
||||||
httpClientProvider: httpClientProvider,
|
httpClientProvider: httpClientProvider,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
im: datasource.NewInstanceManager(newInstanceSettings(httpClientProvider)),
|
im: datasource.NewInstanceManager(newInstanceSettings(httpClientProvider)),
|
||||||
dsService: dsService,
|
dsService: dsService,
|
||||||
|
tracer: tracer,
|
||||||
}
|
}
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
@@ -139,6 +141,7 @@ type Service struct {
|
|||||||
cfg *setting.Cfg
|
cfg *setting.Cfg
|
||||||
im instancemgmt.InstanceManager
|
im instancemgmt.InstanceManager
|
||||||
dsService *datasources.Service
|
dsService *datasources.Service
|
||||||
|
tracer tracing.Tracer
|
||||||
}
|
}
|
||||||
|
|
||||||
type QueryModel struct {
|
type QueryModel struct {
|
||||||
@@ -263,7 +266,7 @@ func (s *Service) executeTimeSeriesQuery(ctx context.Context, req *backend.Query
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, queryExecutor := range queryExecutors {
|
for _, queryExecutor := range queryExecutors {
|
||||||
queryRes, dr, executedQueryString, err := queryExecutor.run(ctx, req, s, dsInfo)
|
queryRes, dr, executedQueryString, err := queryExecutor.run(ctx, req, s, dsInfo, s.tracer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,12 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||||
"github.com/opentracing/opentracing-go"
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (timeSeriesFilter *cloudMonitoringTimeSeriesFilter) run(ctx context.Context, req *backend.QueryDataRequest,
|
func (timeSeriesFilter *cloudMonitoringTimeSeriesFilter) run(ctx context.Context, req *backend.QueryDataRequest,
|
||||||
s *Service, dsInfo datasourceInfo) (*backend.DataResponse, cloudMonitoringResponse, string, error) {
|
s *Service, dsInfo datasourceInfo, tracer tracing.Tracer) (*backend.DataResponse, cloudMonitoringResponse, string, error) {
|
||||||
dr := &backend.DataResponse{}
|
dr := &backend.DataResponse{}
|
||||||
projectName := timeSeriesFilter.ProjectName
|
projectName := timeSeriesFilter.ProjectName
|
||||||
if projectName == "" {
|
if projectName == "" {
|
||||||
@@ -55,22 +56,15 @@ func (timeSeriesFilter *cloudMonitoringTimeSeriesFilter) run(ctx context.Context
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
span, ctx := opentracing.StartSpanFromContext(ctx, "cloudMonitoring query")
|
ctx, span := tracer.Start(ctx, "cloudMonitoring query")
|
||||||
span.SetTag("target", timeSeriesFilter.Target)
|
span.SetAttributes("target", timeSeriesFilter.Target, attribute.Key("target").String(timeSeriesFilter.Target))
|
||||||
span.SetTag("from", req.Queries[0].TimeRange.From)
|
span.SetAttributes("from", req.Queries[0].TimeRange.From, attribute.Key("from").String(req.Queries[0].TimeRange.From.String()))
|
||||||
span.SetTag("until", req.Queries[0].TimeRange.To)
|
span.SetAttributes("until", req.Queries[0].TimeRange.To, attribute.Key("until").String(req.Queries[0].TimeRange.To.String()))
|
||||||
span.SetTag("datasource_id", dsInfo.id)
|
span.SetAttributes("datasource_id", dsInfo.id, attribute.Key("datasource_id").Int64(dsInfo.id))
|
||||||
span.SetTag("org_id", req.PluginContext.OrgID)
|
span.SetAttributes("org_id", req.PluginContext.OrgID, attribute.Key("org_id").Int64(req.PluginContext.OrgID))
|
||||||
|
|
||||||
defer span.Finish()
|
defer span.End()
|
||||||
|
tracer.Inject(ctx, r.Header, span)
|
||||||
if err := opentracing.GlobalTracer().Inject(
|
|
||||||
span.Context(),
|
|
||||||
opentracing.HTTPHeaders,
|
|
||||||
opentracing.HTTPHeadersCarrier(r.Header)); err != nil {
|
|
||||||
dr.Error = err
|
|
||||||
return dr, cloudMonitoringResponse{}, "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
r = r.WithContext(ctx)
|
r = r.WithContext(ctx)
|
||||||
res, err := dsInfo.services[cloudMonitor].client.Do(r)
|
res, err := dsInfo.services[cloudMonitor].client.Do(r)
|
||||||
|
|||||||
@@ -11,16 +11,17 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/opentracing/opentracing-go"
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
|
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (timeSeriesQuery cloudMonitoringTimeSeriesQuery) run(ctx context.Context, req *backend.QueryDataRequest,
|
func (timeSeriesQuery cloudMonitoringTimeSeriesQuery) run(ctx context.Context, req *backend.QueryDataRequest,
|
||||||
s *Service, dsInfo datasourceInfo) (*backend.DataResponse, cloudMonitoringResponse, string, error) {
|
s *Service, dsInfo datasourceInfo, tracer tracing.Tracer) (*backend.DataResponse, cloudMonitoringResponse, string, error) {
|
||||||
dr := &backend.DataResponse{}
|
dr := &backend.DataResponse{}
|
||||||
projectName := timeSeriesQuery.ProjectName
|
projectName := timeSeriesQuery.ProjectName
|
||||||
|
|
||||||
@@ -55,20 +56,13 @@ func (timeSeriesQuery cloudMonitoringTimeSeriesQuery) run(ctx context.Context, r
|
|||||||
return dr, cloudMonitoringResponse{}, "", nil
|
return dr, cloudMonitoringResponse{}, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
span, ctx := opentracing.StartSpanFromContext(ctx, "cloudMonitoring MQL query")
|
ctx, span := tracer.Start(ctx, "cloudMonitoring MQL query")
|
||||||
span.SetTag("query", timeSeriesQuery.Query)
|
span.SetAttributes("query", timeSeriesQuery.Query, attribute.Key("query").String(timeSeriesQuery.Query))
|
||||||
span.SetTag("from", req.Queries[0].TimeRange.From)
|
span.SetAttributes("from", req.Queries[0].TimeRange.From, attribute.Key("from").String(req.Queries[0].TimeRange.From.String()))
|
||||||
span.SetTag("until", req.Queries[0].TimeRange.To)
|
span.SetAttributes("until", req.Queries[0].TimeRange.To, attribute.Key("until").String(req.Queries[0].TimeRange.To.String()))
|
||||||
|
|
||||||
defer span.Finish()
|
defer span.End()
|
||||||
|
tracer.Inject(ctx, r.Header, span)
|
||||||
if err := opentracing.GlobalTracer().Inject(
|
|
||||||
span.Context(),
|
|
||||||
opentracing.HTTPHeaders,
|
|
||||||
opentracing.HTTPHeadersCarrier(r.Header)); err != nil {
|
|
||||||
dr.Error = err
|
|
||||||
return dr, cloudMonitoringResponse{}, "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
r = r.WithContext(ctx)
|
r = r.WithContext(ctx)
|
||||||
res, err := dsInfo.services[cloudMonitor].client.Do(r)
|
res, err := dsInfo.services[cloudMonitor].client.Do(r)
|
||||||
|
|||||||
@@ -6,11 +6,12 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
cloudMonitoringQueryExecutor interface {
|
cloudMonitoringQueryExecutor interface {
|
||||||
run(ctx context.Context, req *backend.QueryDataRequest, s *Service, dsInfo datasourceInfo) (
|
run(ctx context.Context, req *backend.QueryDataRequest, s *Service, dsInfo datasourceInfo, tracer tracing.Tracer) (
|
||||||
*backend.DataResponse, cloudMonitoringResponse, string, error)
|
*backend.DataResponse, cloudMonitoringResponse, string, error)
|
||||||
parseResponse(dr *backend.DataResponse, data cloudMonitoringResponse, executedQueryString string) error
|
parseResponse(dr *backend.DataResponse, data cloudMonitoringResponse, executedQueryString string) error
|
||||||
parseToAnnotations(dr *backend.DataResponse, data cloudMonitoringResponse, title, text string) error
|
parseToAnnotations(dr *backend.DataResponse, data cloudMonitoringResponse, title, text string) error
|
||||||
|
|||||||
@@ -14,17 +14,18 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
"golang.org/x/net/context/ctxhttp"
|
"golang.org/x/net/context/ctxhttp"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
|
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
|
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||||
"github.com/opentracing/opentracing-go"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/plugins"
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
"github.com/grafana/grafana/pkg/plugins/backendplugin/coreplugin"
|
"github.com/grafana/grafana/pkg/plugins/backendplugin/coreplugin"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
@@ -34,6 +35,7 @@ import (
|
|||||||
type Service struct {
|
type Service struct {
|
||||||
logger log.Logger
|
logger log.Logger
|
||||||
im instancemgmt.InstanceManager
|
im instancemgmt.InstanceManager
|
||||||
|
tracer tracing.Tracer
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -42,10 +44,11 @@ const (
|
|||||||
TargetModelField = "target"
|
TargetModelField = "target"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ProvideService(cfg *setting.Cfg, httpClientProvider httpclient.Provider, pluginStore plugins.Store) (*Service, error) {
|
func ProvideService(cfg *setting.Cfg, httpClientProvider httpclient.Provider, pluginStore plugins.Store, tracer tracing.Tracer) (*Service, error) {
|
||||||
s := &Service{
|
s := &Service{
|
||||||
logger: log.New("tsdb.graphite"),
|
logger: log.New("tsdb.graphite"),
|
||||||
im: datasource.NewInstanceManager(newInstanceSettings(httpClientProvider)),
|
im: datasource.NewInstanceManager(newInstanceSettings(httpClientProvider)),
|
||||||
|
tracer: tracer,
|
||||||
}
|
}
|
||||||
|
|
||||||
factory := coreplugin.New(backend.ServeOpts{
|
factory := coreplugin.New(backend.ServeOpts{
|
||||||
@@ -165,21 +168,15 @@ func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest)
|
|||||||
return &result, err
|
return &result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
span, ctx := opentracing.StartSpanFromContext(ctx, "graphite query")
|
ctx, span := s.tracer.Start(ctx, "graphite query")
|
||||||
span.SetTag("target", target)
|
span.SetAttributes("target", target, attribute.Key("target").String(target))
|
||||||
span.SetTag("from", from)
|
span.SetAttributes("from", from, attribute.Key("from").String(from))
|
||||||
span.SetTag("until", until)
|
span.SetAttributes("until", until, attribute.Key("until").String(until))
|
||||||
span.SetTag("datasource_id", dsInfo.Id)
|
span.SetAttributes("datasource_id", dsInfo.Id, attribute.Key("datasource_id").Int64(dsInfo.Id))
|
||||||
span.SetTag("org_id", req.PluginContext.OrgID)
|
span.SetAttributes("org_id", req.PluginContext.OrgID, attribute.Key("org_id").Int64(req.PluginContext.OrgID))
|
||||||
|
|
||||||
defer span.Finish()
|
defer span.End()
|
||||||
|
s.tracer.Inject(ctx, graphiteReq.Header, span)
|
||||||
if err := opentracing.GlobalTracer().Inject(
|
|
||||||
span.Context(),
|
|
||||||
opentracing.HTTPHeaders,
|
|
||||||
opentracing.HTTPHeadersCarrier(graphiteReq.Header)); err != nil {
|
|
||||||
return &result, err
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := ctxhttp.Do(ctx, dsInfo.HTTPClient, graphiteReq)
|
res, err := ctxhttp.Do(ctx, dsInfo.HTTPClient, graphiteReq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -16,14 +16,15 @@ import (
|
|||||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/plugins"
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
"github.com/grafana/grafana/pkg/plugins/backendplugin/coreplugin"
|
"github.com/grafana/grafana/pkg/plugins/backendplugin/coreplugin"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/loki/pkg/logcli/client"
|
"github.com/grafana/loki/pkg/logcli/client"
|
||||||
"github.com/grafana/loki/pkg/loghttp"
|
"github.com/grafana/loki/pkg/loghttp"
|
||||||
"github.com/grafana/loki/pkg/logproto"
|
"github.com/grafana/loki/pkg/logproto"
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
|
||||||
"github.com/opentracing/opentracing-go"
|
|
||||||
"github.com/prometheus/common/config"
|
"github.com/prometheus/common/config"
|
||||||
"github.com/prometheus/common/model"
|
"github.com/prometheus/common/model"
|
||||||
)
|
)
|
||||||
@@ -31,15 +32,17 @@ import (
|
|||||||
const pluginID = "loki"
|
const pluginID = "loki"
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
im instancemgmt.InstanceManager
|
im instancemgmt.InstanceManager
|
||||||
plog log.Logger
|
plog log.Logger
|
||||||
|
tracer tracing.Tracer
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProvideService(cfg *setting.Cfg, httpClientProvider httpclient.Provider, pluginStore plugins.Store) (*Service, error) {
|
func ProvideService(cfg *setting.Cfg, httpClientProvider httpclient.Provider, pluginStore plugins.Store, tracer tracing.Tracer) (*Service, error) {
|
||||||
im := datasource.NewInstanceManager(newInstanceSettings(httpClientProvider))
|
im := datasource.NewInstanceManager(newInstanceSettings(httpClientProvider))
|
||||||
s := &Service{
|
s := &Service{
|
||||||
im: im,
|
im: im,
|
||||||
plog: log.New("tsdb.loki"),
|
plog: log.New("tsdb.loki"),
|
||||||
|
tracer: tracer,
|
||||||
}
|
}
|
||||||
|
|
||||||
factory := coreplugin.New(backend.ServeOpts{
|
factory := coreplugin.New(backend.ServeOpts{
|
||||||
@@ -140,11 +143,11 @@ func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest)
|
|||||||
|
|
||||||
for _, query := range queries {
|
for _, query := range queries {
|
||||||
s.plog.Debug("Sending query", "start", query.Start, "end", query.End, "step", query.Step, "query", query.Expr)
|
s.plog.Debug("Sending query", "start", query.Start, "end", query.End, "step", query.Step, "query", query.Expr)
|
||||||
span, _ := opentracing.StartSpanFromContext(ctx, "alerting.loki")
|
_, span := s.tracer.Start(ctx, "alerting.loki")
|
||||||
span.SetTag("expr", query.Expr)
|
span.SetAttributes("expr", query.Expr, attribute.Key("expr").String(query.Expr))
|
||||||
span.SetTag("start_unixnano", query.Start.UnixNano())
|
span.SetAttributes("start_unixnano", query.Start, attribute.Key("start_unixnano").Int64(query.Start.UnixNano()))
|
||||||
span.SetTag("stop_unixnano", query.End.UnixNano())
|
span.SetAttributes("stop_unixnano", query.End, attribute.Key("stop_unixnano").Int64(query.End.UnixNano()))
|
||||||
defer span.Finish()
|
defer span.End()
|
||||||
|
|
||||||
// `limit` only applies to log-producing queries, and we
|
// `limit` only applies to log-producing queries, and we
|
||||||
// currently only support metric queries, so this can be set to any value.
|
// currently only support metric queries, so this can be set to any value.
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/experimental"
|
"github.com/grafana/grafana-plugin-sdk-go/experimental"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/prometheus/client_golang/api"
|
"github.com/prometheus/client_golang/api"
|
||||||
apiv1 "github.com/prometheus/client_golang/api/prometheus/v1"
|
apiv1 "github.com/prometheus/client_golang/api/prometheus/v1"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -109,7 +110,10 @@ func testScenario(t *testing.T, name string) {
|
|||||||
api, err := makeMockedApi(responseBytes)
|
api, err := makeMockedApi(responseBytes)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
result, err := runQueries(context.Background(), api, []*PrometheusQuery{&query})
|
tracer, err := tracing.InitializeTracerForTest()
|
||||||
|
require.NoError(t, err)
|
||||||
|
s := Service{tracer: tracer}
|
||||||
|
result, err := s.runQueries(context.Background(), api, []*PrometheusQuery{&query})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, result.Responses, 1)
|
require.Len(t, result.Responses, 1)
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
|
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
|
||||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/plugins"
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
"github.com/grafana/grafana/pkg/plugins/backendplugin/coreplugin"
|
"github.com/grafana/grafana/pkg/plugins/backendplugin/coreplugin"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
@@ -32,15 +33,17 @@ const pluginID = "prometheus"
|
|||||||
type Service struct {
|
type Service struct {
|
||||||
intervalCalculator intervalv2.Calculator
|
intervalCalculator intervalv2.Calculator
|
||||||
im instancemgmt.InstanceManager
|
im instancemgmt.InstanceManager
|
||||||
|
tracer tracing.Tracer
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProvideService(cfg *setting.Cfg, httpClientProvider httpclient.Provider, pluginStore plugins.Store) (*Service, error) {
|
func ProvideService(cfg *setting.Cfg, httpClientProvider httpclient.Provider, pluginStore plugins.Store, tracer tracing.Tracer) (*Service, error) {
|
||||||
plog.Debug("initializing")
|
plog.Debug("initializing")
|
||||||
im := datasource.NewInstanceManager(newInstanceSettings(httpClientProvider))
|
im := datasource.NewInstanceManager(newInstanceSettings(httpClientProvider))
|
||||||
|
|
||||||
s := &Service{
|
s := &Service{
|
||||||
intervalCalculator: intervalv2.NewCalculator(),
|
intervalCalculator: intervalv2.NewCalculator(),
|
||||||
im: im,
|
im: im,
|
||||||
|
tracer: tracer,
|
||||||
}
|
}
|
||||||
|
|
||||||
factory := coreplugin.New(backend.ServeOpts{
|
factory := coreplugin.New(backend.ServeOpts{
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ import (
|
|||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||||
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
|
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
|
||||||
"github.com/opentracing/opentracing-go"
|
|
||||||
apiv1 "github.com/prometheus/client_golang/api/prometheus/v1"
|
apiv1 "github.com/prometheus/client_golang/api/prometheus/v1"
|
||||||
"github.com/prometheus/common/model"
|
"github.com/prometheus/common/model"
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
)
|
)
|
||||||
|
|
||||||
//Internal interval and range variables
|
//Internal interval and range variables
|
||||||
@@ -47,7 +47,7 @@ const (
|
|||||||
ExemplarQueryType TimeSeriesQueryType = "exemplar"
|
ExemplarQueryType TimeSeriesQueryType = "exemplar"
|
||||||
)
|
)
|
||||||
|
|
||||||
func runQueries(ctx context.Context, client apiv1.API, queries []*PrometheusQuery) (*backend.QueryDataResponse, error) {
|
func (s *Service) runQueries(ctx context.Context, client apiv1.API, queries []*PrometheusQuery) (*backend.QueryDataResponse, error) {
|
||||||
result := backend.QueryDataResponse{
|
result := backend.QueryDataResponse{
|
||||||
Responses: backend.Responses{},
|
Responses: backend.Responses{},
|
||||||
}
|
}
|
||||||
@@ -55,11 +55,11 @@ func runQueries(ctx context.Context, client apiv1.API, queries []*PrometheusQuer
|
|||||||
for _, query := range queries {
|
for _, query := range queries {
|
||||||
plog.Debug("Sending query", "start", query.Start, "end", query.End, "step", query.Step, "query", query.Expr)
|
plog.Debug("Sending query", "start", query.Start, "end", query.End, "step", query.Step, "query", query.Expr)
|
||||||
|
|
||||||
span, ctx := opentracing.StartSpanFromContext(ctx, "datasource.prometheus")
|
ctx, span := s.tracer.Start(ctx, "datasource.prometheus")
|
||||||
span.SetTag("expr", query.Expr)
|
span.SetAttributes("expr", query.Expr, attribute.Key("expr").String(query.Expr))
|
||||||
span.SetTag("start_unixnano", query.Start.UnixNano())
|
span.SetAttributes("start_unixnano", query.Start, attribute.Key("start_unixnano").Int64(query.Start.UnixNano()))
|
||||||
span.SetTag("stop_unixnano", query.End.UnixNano())
|
span.SetAttributes("stop_unixnano", query.End, attribute.Key("stop_unixnano").Int64(query.End.UnixNano()))
|
||||||
defer span.Finish()
|
defer span.End()
|
||||||
|
|
||||||
response := make(map[TimeSeriesQueryType]interface{})
|
response := make(map[TimeSeriesQueryType]interface{})
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ func (s *Service) executeTimeSeriesQuery(ctx context.Context, req *backend.Query
|
|||||||
return &result, err
|
return &result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return runQueries(ctx, client, queries)
|
return s.runQueries(ctx, client, queries)
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatLegend(metric model.Metric, query *PrometheusQuery) string {
|
func formatLegend(metric model.Metric, query *PrometheusQuery) string {
|
||||||
|
|||||||
Reference in New Issue
Block a user