SSE: (Instrumentation) Add Tracing (#66700)

spans are prefixed `SSE.`
This commit is contained in:
Kyle Brandt 2023-04-18 08:04:51 -04:00 committed by GitHub
parent f3fcc31277
commit 840fb32ad8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 98 additions and 35 deletions

View File

@ -10,6 +10,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/data" "github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/expr/mathexp" "github.com/grafana/grafana/pkg/expr/mathexp"
"github.com/grafana/grafana/pkg/infra/tracing"
) )
// ConditionsCmd is a command that supports the reduction and comparison of conditions. // ConditionsCmd is a command that supports the reduction and comparison of conditions.
@ -68,7 +69,9 @@ func (cmd *ConditionsCmd) NeedsVars() []string {
// Execute runs the command and returns the results or an error if the command // Execute runs the command and returns the results or an error if the command
// failed to execute. // failed to execute.
func (cmd *ConditionsCmd) Execute(ctx context.Context, t time.Time, vars mathexp.Vars) (mathexp.Results, error) { func (cmd *ConditionsCmd) Execute(ctx context.Context, t time.Time, vars mathexp.Vars, tracer tracing.Tracer) (mathexp.Results, error) {
ctx, span := tracer.Start(ctx, "SSE.ExecuteClassicConditions")
defer span.End()
// isFiring and isNoData contains the outcome of ConditionsCmd, and is derived from the // isFiring and isNoData contains the outcome of ConditionsCmd, and is derived from the
// boolean comparison of isCondFiring and isCondNoData of all conditions in ConditionsCmd // boolean comparison of isCondFiring and isCondNoData of all conditions in ConditionsCmd
var isFiring, isNoData bool var isFiring, isNoData bool

View File

@ -10,6 +10,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/expr/mathexp" "github.com/grafana/grafana/pkg/expr/mathexp"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
) )
@ -598,7 +599,7 @@ func TestConditionsCmd(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
res, err := tt.cmd.Execute(context.Background(), time.Now(), tt.vars) res, err := tt.cmd.Execute(context.Background(), time.Now(), tt.vars, tracing.NewFakeTracer())
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, tt.expected(), res) require.Equal(t, tt.expected(), res)
}) })

View File

@ -9,14 +9,16 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime" "github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
"github.com/grafana/grafana-plugin-sdk-go/data" "github.com/grafana/grafana-plugin-sdk-go/data"
"go.opentelemetry.io/otel/attribute"
"github.com/grafana/grafana/pkg/expr/mathexp" "github.com/grafana/grafana/pkg/expr/mathexp"
"github.com/grafana/grafana/pkg/infra/tracing"
) )
// Command is an interface for all expression commands. // Command is an interface for all expression commands.
type Command interface { type Command interface {
NeedsVars() []string NeedsVars() []string
Execute(ctx context.Context, now time.Time, vars mathexp.Vars) (mathexp.Results, error) Execute(ctx context.Context, now time.Time, vars mathexp.Vars, tracer tracing.Tracer) (mathexp.Results, error)
} }
// MathCommand is a command for a math expression such as "1 + $GA / 2" // MathCommand is a command for a math expression such as "1 + $GA / 2"
@ -66,8 +68,11 @@ func (gm *MathCommand) NeedsVars() []string {
// Execute runs the command and returns the results or an error if the command // Execute runs the command and returns the results or an error if the command
// failed to execute. // failed to execute.
func (gm *MathCommand) Execute(_ context.Context, _ time.Time, vars mathexp.Vars) (mathexp.Results, error) { func (gm *MathCommand) Execute(ctx context.Context, _ time.Time, vars mathexp.Vars, tracer tracing.Tracer) (mathexp.Results, error) {
return gm.Expression.Execute(gm.refID, vars) _, span := tracer.Start(ctx, "SSE.ExecuteMath")
span.SetAttributes("expression", gm.RawExpression, attribute.Key("expression").String(gm.RawExpression))
defer span.End()
return gm.Expression.Execute(gm.refID, vars, tracer)
} }
// ReduceCommand is an expression command for reduction of a timeseries such as a min, mean, or max. // ReduceCommand is an expression command for reduction of a timeseries such as a min, mean, or max.
@ -154,7 +159,12 @@ func (gr *ReduceCommand) NeedsVars() []string {
// Execute runs the command and returns the results or an error if the command // Execute runs the command and returns the results or an error if the command
// failed to execute. // failed to execute.
func (gr *ReduceCommand) Execute(_ context.Context, _ time.Time, vars mathexp.Vars) (mathexp.Results, error) { func (gr *ReduceCommand) Execute(ctx context.Context, _ time.Time, vars mathexp.Vars, tracer tracing.Tracer) (mathexp.Results, error) {
_, span := tracer.Start(ctx, "SSE.ExecuteReduce")
defer span.End()
span.SetAttributes("reducer", gr.Reducer, attribute.Key("reducer").String(gr.Reducer))
newRes := mathexp.Results{} newRes := mathexp.Results{}
for _, val := range vars[gr.VarToReduce].Values { for _, val := range vars[gr.VarToReduce].Values {
switch v := val.(type) { switch v := val.(type) {
@ -262,7 +272,9 @@ func (gr *ResampleCommand) NeedsVars() []string {
// Execute runs the command and returns the results or an error if the command // Execute runs the command and returns the results or an error if the command
// failed to execute. // failed to execute.
func (gr *ResampleCommand) Execute(_ context.Context, now time.Time, vars mathexp.Vars) (mathexp.Results, error) { func (gr *ResampleCommand) Execute(ctx context.Context, now time.Time, vars mathexp.Vars, tracer tracing.Tracer) (mathexp.Results, error) {
_, span := tracer.Start(ctx, "SSE.ExecuteResample")
defer span.End()
newRes := mathexp.Results{} newRes := mathexp.Results{}
timeRange := gr.TimeRange.AbsoluteTime(now) timeRange := gr.TimeRange.AbsoluteTime(now)
for _, val := range vars[gr.VarToResample].Values { for _, val := range vars[gr.VarToResample].Values {

View File

@ -14,6 +14,7 @@ import (
"github.com/grafana/grafana/pkg/expr/mathexp" "github.com/grafana/grafana/pkg/expr/mathexp"
"github.com/grafana/grafana/pkg/expr/mathexp/parse" "github.com/grafana/grafana/pkg/expr/mathexp/parse"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
) )
@ -115,7 +116,7 @@ func TestReduceExecute(t *testing.T) {
}, },
} }
execute, err := cmd.Execute(context.Background(), time.Now(), vars) execute, err := cmd.Execute(context.Background(), time.Now(), vars, tracing.NewFakeTracer())
require.NoError(t, err) require.NoError(t, err)
require.Len(t, execute.Values, len(numbers)) require.Len(t, execute.Values, len(numbers))
@ -150,7 +151,7 @@ func TestReduceExecute(t *testing.T) {
}, },
} }
results, err := cmd.Execute(context.Background(), time.Now(), vars) results, err := cmd.Execute(context.Background(), time.Now(), vars, tracing.NewFakeTracer())
require.NoError(t, err) require.NoError(t, err)
require.Len(t, results.Values, 1) require.Len(t, results.Values, 1)
@ -209,7 +210,7 @@ func TestResampleCommand_Execute(t *testing.T) {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
result, err := cmd.Execute(context.Background(), time.Now(), mathexp.Vars{ result, err := cmd.Execute(context.Background(), time.Now(), mathexp.Vars{
varToReduce: mathexp.Results{Values: mathexp.Values{test.vals}}, varToReduce: mathexp.Results{Values: mathexp.Values{test.vals}},
}) }, tracing.NewFakeTracer())
if test.isError { if test.isError {
require.Error(t, err) require.Error(t, err)
} else { } else {
@ -224,7 +225,7 @@ func TestResampleCommand_Execute(t *testing.T) {
t.Run("should return empty result if input is nil Value", func(t *testing.T) { t.Run("should return empty result if input is nil Value", func(t *testing.T) {
result, err := cmd.Execute(context.Background(), time.Now(), mathexp.Vars{ result, err := cmd.Execute(context.Background(), time.Now(), mathexp.Vars{
varToReduce: mathexp.Results{Values: mathexp.Values{nil}}, varToReduce: mathexp.Results{Values: mathexp.Values{nil}},
}) }, tracing.NewFakeTracer())
require.Empty(t, result.Values) require.Empty(t, result.Values)
require.NoError(t, err) require.NoError(t, err)
}) })

View File

@ -1,6 +1,7 @@
package expr package expr
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
@ -11,6 +12,8 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/data" "github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/expr/mathexp" "github.com/grafana/grafana/pkg/expr/mathexp"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
"go.opentelemetry.io/otel/attribute"
) )
func shouldUseDataplane(frames data.Frames, logger *log.ConcreteLogger, disable bool) (dt data.FrameType, b bool, e error) { func shouldUseDataplane(frames data.Frames, logger *log.ConcreteLogger, disable bool) (dt data.FrameType, b bool, e error) {
@ -55,8 +58,12 @@ func shouldUseDataplane(frames data.Frames, logger *log.ConcreteLogger, disable
return dt, true, nil return dt, true, nil
} }
func handleDataplaneFrames(k data.FrameTypeKind, frames data.Frames) (mathexp.Results, error) { func handleDataplaneFrames(ctx context.Context, tracer tracing.Tracer, t data.FrameType, frames data.Frames) (mathexp.Results, error) {
switch k { _, span := tracer.Start(ctx, "SSE.HandleDataPlaneData")
defer span.End()
span.SetAttributes("dataplane.type", t, attribute.Key("dataplane.type").String(string(t)))
switch t.Kind() {
case data.KindUnknown: case data.KindUnknown:
return mathexp.Results{Values: mathexp.Values{mathexp.NoData{}.New()}}, nil return mathexp.Results{Values: mathexp.Values{mathexp.NoData{}.New()}}, nil
case data.KindTimeSeries: case data.KindTimeSeries:
@ -64,7 +71,7 @@ func handleDataplaneFrames(k data.FrameTypeKind, frames data.Frames) (mathexp.Re
case data.KindNumeric: case data.KindNumeric:
return handleDataplaneNumeric(frames) return handleDataplaneNumeric(frames)
default: default:
return mathexp.Results{}, fmt.Errorf("kind %s not supported by server side expressions", k) return mathexp.Results{}, fmt.Errorf("kind %s (type %s) not supported by server side expressions", t.Kind(), t)
} }
} }

View File

@ -9,6 +9,7 @@ import (
"github.com/grafana/dataplane/examples" "github.com/grafana/dataplane/examples"
"github.com/grafana/grafana-plugin-sdk-go/data" "github.com/grafana/grafana-plugin-sdk-go/data"
"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/datasources" "github.com/grafana/grafana/pkg/services/datasources"
datafakes "github.com/grafana/grafana/pkg/services/datasources/fakes" datafakes "github.com/grafana/grafana/pkg/services/datasources/fakes"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
@ -49,6 +50,7 @@ func framesPassThroughService(t *testing.T, frames data.Frames) (data.Frames, er
dataService: me, dataService: me,
dataSourceService: &datafakes.FakeDataSourceService{}, dataSourceService: &datafakes.FakeDataSourceService{},
features: &featuremgmt.FeatureManager{}, features: &featuremgmt.FeatureManager{},
tracer: tracing.InitializeTracerForTest(),
metrics: newMetrics(nil), metrics: newMetrics(nil),
} }
queries := []Query{{ queries := []Query{{

View File

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"time" "time"
"go.opentelemetry.io/otel/attribute"
"gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/graph/simple"
"gonum.org/v1/gonum/graph/topo" "gonum.org/v1/gonum/graph/topo"
@ -50,6 +51,15 @@ type DataPipeline []Node
func (dp *DataPipeline) execute(c context.Context, now time.Time, s *Service) (mathexp.Vars, error) { func (dp *DataPipeline) execute(c context.Context, now time.Time, s *Service) (mathexp.Vars, error) {
vars := make(mathexp.Vars) vars := make(mathexp.Vars)
for _, node := range *dp { for _, node := range *dp {
c, span := s.tracer.Start(c, "SSE.ExecuteNode")
span.SetAttributes("node.refId", node.RefID(), attribute.Key("node.refId").String(node.RefID()))
if node.NodeType() == TypeCMDNode {
cmdNode := node.(*CMDNode)
inputRefIDs := cmdNode.Command.NeedsVars()
span.SetAttributes("node.inputRefIDs", inputRefIDs, attribute.Key("node.inputRefIDs").StringSlice(inputRefIDs))
}
defer span.End()
res, err := node.Execute(c, now, vars, s) res, err := node.Execute(c, now, vars, s)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -9,6 +9,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/data" "github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/expr/mathexp/parse" "github.com/grafana/grafana/pkg/expr/mathexp/parse"
"github.com/grafana/grafana/pkg/infra/tracing"
) )
// Expr holds a parsed math command expression. // Expr holds a parsed math command expression.
@ -25,6 +26,8 @@ type State struct {
// - Unions (How many result A and many Result B in case A + B are joined) // - Unions (How many result A and many Result B in case A + B are joined)
// - NaN/Null behavior // - NaN/Null behavior
RefID string RefID string
tracer tracing.Tracer
} }
// Vars holds the results of datasource queries or other expression commands. // Vars holds the results of datasource queries or other expression commands.
@ -44,11 +47,13 @@ func New(expr string, funcs ...map[string]parse.Func) (*Expr, error) {
} }
// Execute applies a parse expression to the context and executes it // Execute applies a parse expression to the context and executes it
func (e *Expr) Execute(refID string, vars Vars) (r Results, err error) { func (e *Expr) Execute(refID string, vars Vars, tracer tracing.Tracer) (r Results, err error) {
s := &State{ s := &State{
Expr: e, Expr: e,
Vars: vars, Vars: vars,
RefID: refID, RefID: refID,
tracer: tracer,
} }
return e.executeState(s) return e.executeState(s)
} }

View File

@ -8,6 +8,7 @@ import (
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"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/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -147,7 +148,7 @@ func TestNaN(t *testing.T) {
e, err := New(tt.expr) e, err := New(tt.expr)
tt.newErrIs(t, err) tt.newErrIs(t, err)
if e != nil { if e != nil {
res, err := e.Execute("", tt.vars) res, err := e.Execute("", tt.vars, tracing.NewFakeTracer())
tt.execErrIs(t, err) tt.execErrIs(t, err)
if diff := cmp.Diff(res, tt.results, options...); diff != "" { if diff := cmp.Diff(res, tt.results, options...); diff != "" {
assert.FailNow(t, tt.name, diff) assert.FailNow(t, tt.name, diff)
@ -409,7 +410,7 @@ func TestNullValues(t *testing.T) {
e, err := New(tt.expr) e, err := New(tt.expr)
tt.newErrIs(t, err) tt.newErrIs(t, err)
if e != nil { if e != nil {
res, err := e.Execute("", tt.vars) res, err := e.Execute("", tt.vars, tracing.NewFakeTracer())
tt.execErrIs(t, err) tt.execErrIs(t, err)
if diff := cmp.Diff(tt.results, res, options...); diff != "" { if diff := cmp.Diff(tt.results, res, options...); diff != "" {
t.Errorf("Result mismatch (-want +got):\n%s", diff) t.Errorf("Result mismatch (-want +got):\n%s", diff)
@ -446,7 +447,7 @@ func TestNoData(t *testing.T) {
e, err := New(expr) e, err := New(expr)
require.NoError(t, err) require.NoError(t, err)
if e != nil { if e != nil {
res, err := e.Execute("", vars) res, err := e.Execute("", vars, tracing.NewFakeTracer())
require.NoError(t, err) require.NoError(t, err)
require.Len(t, res.Values, 1) require.Len(t, res.Values, 1)
require.Equal(t, NewNoData(), res.Values[0]) require.Equal(t, NewNoData(), res.Values[0])
@ -487,21 +488,21 @@ func TestNoData(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
if e != nil { if e != nil {
t.Run("$A,$B=nodata", func(t *testing.T) { t.Run("$A,$B=nodata", func(t *testing.T) {
res, err := e.Execute("", makeVars(NewNoData(), NewNoData())) res, err := e.Execute("", makeVars(NewNoData(), NewNoData()), tracing.NewFakeTracer())
require.NoError(t, err) require.NoError(t, err)
require.Len(t, res.Values, 1) require.Len(t, res.Values, 1)
require.Equal(t, NewNoData(), res.Values[0]) require.Equal(t, NewNoData(), res.Values[0])
}) })
t.Run("$A=nodata, $B=series", func(t *testing.T) { t.Run("$A=nodata, $B=series", func(t *testing.T) {
res, err := e.Execute("", makeVars(NewNoData(), series)) res, err := e.Execute("", makeVars(NewNoData(), series), tracing.NewFakeTracer())
require.NoError(t, err) require.NoError(t, err)
require.Len(t, res.Values, 1) require.Len(t, res.Values, 1)
require.Equal(t, NewNoData(), res.Values[0]) require.Equal(t, NewNoData(), res.Values[0])
}) })
t.Run("$A=series, $B=nodata", func(t *testing.T) { t.Run("$A=series, $B=nodata", func(t *testing.T) {
res, err := e.Execute("", makeVars(NewNoData(), series)) res, err := e.Execute("", makeVars(NewNoData(), series), tracing.NewFakeTracer())
require.NoError(t, err) require.NoError(t, err)
require.Len(t, res.Values, 1) require.Len(t, res.Values, 1)
require.Equal(t, NewNoData(), res.Values[0]) require.Equal(t, NewNoData(), res.Values[0])

View File

@ -4,6 +4,7 @@ import (
"math" "math"
"testing" "testing"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -78,7 +79,7 @@ func TestScalarExpr(t *testing.T) {
e, err := New(tt.expr) e, err := New(tt.expr)
tt.newErrIs(t, err) tt.newErrIs(t, err)
if e != nil { if e != nil {
res, err := e.Execute("", tt.vars) res, err := e.Execute("", tt.vars, tracing.NewFakeTracer())
tt.execErrIs(t, err) tt.execErrIs(t, err)
tt.resultIs(t, tt.Results, res) tt.resultIs(t, tt.Results, res)
} }
@ -131,7 +132,7 @@ func TestNumberExpr(t *testing.T) {
e, err := New(tt.expr) e, err := New(tt.expr)
tt.newErrIs(t, err) tt.newErrIs(t, err)
if e != nil { if e != nil {
res, err := e.Execute("", tt.vars) res, err := e.Execute("", tt.vars, tracing.NewFakeTracer())
tt.execErrIs(t, err) tt.execErrIs(t, err)
tt.resultIs(t, tt.results, res) tt.resultIs(t, tt.results, res)
} }

View File

@ -6,6 +6,7 @@ import (
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"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/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -178,7 +179,7 @@ func TestSeriesExpr(t *testing.T) {
e, err := New(tt.expr) e, err := New(tt.expr)
tt.newErrIs(t, err) tt.newErrIs(t, err)
if e != nil { if e != nil {
res, err := e.Execute("", tt.vars) res, err := e.Execute("", tt.vars, tracing.NewFakeTracer())
tt.execErrIs(t, err) tt.execErrIs(t, err)
if diff := cmp.Diff(tt.results, res, data.FrameTestCompareOptions()...); diff != "" { if diff := cmp.Diff(tt.results, res, data.FrameTestCompareOptions()...); diff != "" {
t.Errorf("Result mismatch (-want +got):\n%s", diff) t.Errorf("Result mismatch (-want +got):\n%s", diff)

View File

@ -5,6 +5,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -81,7 +82,7 @@ func TestAbsFunc(t *testing.T) {
e, err := New(tt.expr) e, err := New(tt.expr)
tt.newErrIs(t, err) tt.newErrIs(t, err)
if e != nil { if e != nil {
res, err := e.Execute("", tt.vars) res, err := e.Execute("", tt.vars, tracing.NewFakeTracer())
tt.execErrIs(t, err) tt.execErrIs(t, err)
tt.resultIs(t, tt.results, res) tt.resultIs(t, tt.results, res)
} }
@ -152,7 +153,7 @@ func TestIsNumberFunc(t *testing.T) {
e, err := New(tt.expr) e, err := New(tt.expr)
require.NoError(t, err) require.NoError(t, err)
if e != nil { if e != nil {
res, err := e.Execute("", tt.vars) res, err := e.Execute("", tt.vars, tracing.NewFakeTracer())
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, tt.results, res) require.Equal(t, tt.results, res)
} }

View File

@ -8,6 +8,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/data" "github.com/grafana/grafana-plugin-sdk-go/data"
"go.opentelemetry.io/otel/attribute"
"gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/graph/simple"
"github.com/grafana/grafana/pkg/expr/classic" "github.com/grafana/grafana/pkg/expr/classic"
@ -92,8 +93,8 @@ func (gn *CMDNode) NodeType() NodeType {
// Execute runs the node and adds the results to vars. If the node requires // Execute runs the node and adds the results to vars. If the node requires
// other nodes they must have already been executed and their results must // other nodes they must have already been executed and their results must
// already by in vars. // already by in vars.
func (gn *CMDNode) Execute(ctx context.Context, now time.Time, vars mathexp.Vars, _ *Service) (mathexp.Results, error) { func (gn *CMDNode) Execute(ctx context.Context, now time.Time, vars mathexp.Vars, s *Service) (mathexp.Results, error) {
return gn.Command.Execute(ctx, now, vars) return gn.Command.Execute(ctx, now, vars, s.tracer)
} }
func buildCMDNode(dp *simple.DirectedGraph, rn *rawNode) (*CMDNode, error) { func buildCMDNode(dp *simple.DirectedGraph, rn *rawNode) (*CMDNode, error) {
@ -203,6 +204,9 @@ func (s *Service) buildDSNode(dp *simple.DirectedGraph, rn *rawNode, req *Reques
// already by in vars. // already by in vars.
func (dn *DSNode) Execute(ctx context.Context, now time.Time, _ mathexp.Vars, s *Service) (r mathexp.Results, e error) { func (dn *DSNode) Execute(ctx context.Context, now time.Time, _ mathexp.Vars, s *Service) (r mathexp.Results, e error) {
logger := logger.FromContext(ctx).New("datasourceType", dn.datasource.Type, "queryRefId", dn.refID, "datasourceUid", dn.datasource.UID, "datasourceVersion", dn.datasource.Version) logger := logger.FromContext(ctx).New("datasourceType", dn.datasource.Type, "queryRefId", dn.refID, "datasourceUid", dn.datasource.UID, "datasourceVersion", dn.datasource.Version)
ctx, span := s.tracer.Start(ctx, "SSE.ExecuteDatasourceQuery")
defer span.End()
dsInstanceSettings, err := adapters.ModelToInstanceSettings(dn.datasource, s.decryptSecureJsonDataFn(ctx)) dsInstanceSettings, err := adapters.ModelToInstanceSettings(dn.datasource, s.decryptSecureJsonDataFn(ctx))
if err != nil { if err != nil {
return mathexp.Results{}, fmt.Errorf("%v: %w", "failed to convert datasource instance settings", err) return mathexp.Results{}, fmt.Errorf("%v: %w", "failed to convert datasource instance settings", err)
@ -213,6 +217,7 @@ func (dn *DSNode) Execute(ctx context.Context, now time.Time, _ mathexp.Vars, s
PluginID: dn.datasource.Type, PluginID: dn.datasource.Type,
User: dn.request.User, User: dn.request.User,
} }
span.SetAttributes("datasource.type", dn.datasource.Type, attribute.Key("datasource.type").String(dn.datasource.Type))
req := &backend.QueryDataRequest{ req := &backend.QueryDataRequest{
PluginContext: pc, PluginContext: pc,
@ -268,7 +273,7 @@ func (dn *DSNode) Execute(ctx context.Context, now time.Time, _ mathexp.Vars, s
dt, useDataplane, _ = shouldUseDataplane(response.Frames, logger, s.features.IsEnabled(featuremgmt.FlagDisableSSEDataplane)) dt, useDataplane, _ = shouldUseDataplane(response.Frames, logger, s.features.IsEnabled(featuremgmt.FlagDisableSSEDataplane))
if useDataplane { if useDataplane {
logger.Debug("Handling SSE data source query through dataplane", "datatype", dt) logger.Debug("Handling SSE data source query through dataplane", "datatype", dt)
return handleDataplaneFrames(dt.Kind(), response.Frames) return handleDataplaneFrames(ctx, s.tracer, dt, response.Frames)
} }
dataSource := dn.datasource.Type dataSource := dn.datasource.Type

View File

@ -8,6 +8,7 @@ import (
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"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/plugins" "github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
@ -44,15 +45,17 @@ type Service struct {
dataSourceService datasources.DataSourceService dataSourceService datasources.DataSourceService
features featuremgmt.FeatureToggles features featuremgmt.FeatureToggles
tracer tracing.Tracer
metrics *metrics metrics *metrics
} }
func ProvideService(cfg *setting.Cfg, pluginClient plugins.Client, dataSourceService datasources.DataSourceService, features featuremgmt.FeatureToggles, registerer prometheus.Registerer) *Service { func ProvideService(cfg *setting.Cfg, pluginClient plugins.Client, dataSourceService datasources.DataSourceService, features featuremgmt.FeatureToggles, registerer prometheus.Registerer, tracer tracing.Tracer) *Service {
return &Service{ return &Service{
cfg: cfg, cfg: cfg,
dataService: pluginClient, dataService: pluginClient,
dataSourceService: dataSourceService, dataSourceService: dataSourceService,
features: features, features: features,
tracer: tracer,
metrics: newMetrics(registerer), metrics: newMetrics(registerer),
} }
} }
@ -71,6 +74,8 @@ func (s *Service) BuildPipeline(req *Request) (DataPipeline, error) {
// ExecutePipeline executes an expression pipeline and returns all the results. // ExecutePipeline executes an expression pipeline and returns all the results.
func (s *Service) ExecutePipeline(ctx context.Context, now time.Time, pipeline DataPipeline) (*backend.QueryDataResponse, error) { func (s *Service) ExecutePipeline(ctx context.Context, now time.Time, pipeline DataPipeline) (*backend.QueryDataResponse, error) {
ctx, span := s.tracer.Start(ctx, "SSE.ExecutePipeline")
defer span.End()
res := backend.NewQueryDataResponse() res := backend.NewQueryDataResponse()
vars, err := pipeline.execute(ctx, now, s) vars, err := pipeline.execute(ctx, now, s)
if err != nil { if err != nil {

View File

@ -12,6 +12,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/data" "github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources"
datafakes "github.com/grafana/grafana/pkg/services/datasources/fakes" datafakes "github.com/grafana/grafana/pkg/services/datasources/fakes"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
@ -34,6 +35,7 @@ func TestService(t *testing.T) {
dataService: me, dataService: me,
dataSourceService: &datafakes.FakeDataSourceService{}, dataSourceService: &datafakes.FakeDataSourceService{},
features: &featuremgmt.FeatureManager{}, features: &featuremgmt.FeatureManager{},
tracer: tracing.InitializeTracerForTest(),
metrics: newMetrics(nil), metrics: newMetrics(nil),
} }

View File

@ -8,6 +8,7 @@ import (
"time" "time"
"github.com/grafana/grafana/pkg/expr/mathexp" "github.com/grafana/grafana/pkg/expr/mathexp"
"github.com/grafana/grafana/pkg/infra/tracing"
) )
type ThresholdCommand struct { type ThresholdCommand struct {
@ -89,7 +90,7 @@ func (tc *ThresholdCommand) NeedsVars() []string {
return []string{tc.ReferenceVar} return []string{tc.ReferenceVar}
} }
func (tc *ThresholdCommand) Execute(ctx context.Context, now time.Time, vars mathexp.Vars) (mathexp.Results, error) { func (tc *ThresholdCommand) Execute(ctx context.Context, now time.Time, vars mathexp.Vars, tracer tracing.Tracer) (mathexp.Results, error) {
mathExpression, err := createMathExpression(tc.ReferenceVar, tc.ThresholdFunc, tc.Conditions) mathExpression, err := createMathExpression(tc.ReferenceVar, tc.ThresholdFunc, tc.Conditions)
if err != nil { if err != nil {
return mathexp.Results{}, err return mathexp.Results{}, err
@ -100,7 +101,7 @@ func (tc *ThresholdCommand) Execute(ctx context.Context, now time.Time, vars mat
return mathexp.Results{}, err return mathexp.Results{}, err
} }
return mathCommand.Execute(ctx, now, vars) return mathCommand.Execute(ctx, now, vars, tracer)
} }
// createMathExpression converts all the info we have about a "threshold" expression in to a Math expression // createMathExpression converts all the info we have about a "threshold" expression in to a Math expression

View File

@ -70,6 +70,7 @@ func (s *Service) TransformData(ctx context.Context, now time.Time, req *Request
} }
start := time.Now() start := time.Now()
ctx, span := s.tracer.Start(ctx, "SSE.TransformData")
defer func() { defer func() {
var respStatus string var respStatus string
switch { switch {
@ -80,6 +81,8 @@ func (s *Service) TransformData(ctx context.Context, now time.Time, req *Request
} }
duration := float64(time.Since(start).Nanoseconds()) / float64(time.Millisecond) duration := float64(time.Since(start).Nanoseconds()) / float64(time.Millisecond)
s.metrics.expressionsQuerySummary.WithLabelValues(respStatus).Observe(duration) s.metrics.expressionsQuerySummary.WithLabelValues(respStatus).Observe(duration)
span.End()
}() }()
// Build the pipeline from the request, checking for ordering issues (e.g. loops) // Build the pipeline from the request, checking for ordering issues (e.g. loops)

View File

@ -12,6 +12,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/expr" "github.com/grafana/grafana/pkg/expr"
"github.com/grafana/grafana/pkg/infra/tracing"
"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"
fakes "github.com/grafana/grafana/pkg/services/datasources/fakes" fakes "github.com/grafana/grafana/pkg/services/datasources/fakes"
@ -533,7 +534,7 @@ func TestValidate(t *testing.T) {
pluginsStore: store, pluginsStore: store,
}) })
evaluator := NewEvaluatorFactory(setting.UnifiedAlertingSettings{}, cacheService, expr.ProvideService(&setting.Cfg{ExpressionsEnabled: true}, nil, nil, &featuremgmt.FeatureManager{}, nil), store) evaluator := NewEvaluatorFactory(setting.UnifiedAlertingSettings{}, cacheService, expr.ProvideService(&setting.Cfg{ExpressionsEnabled: true}, nil, nil, &featuremgmt.FeatureManager{}, nil, tracing.InitializeTracerForTest()), store)
evalCtx := NewContext(context.Background(), u) evalCtx := NewContext(context.Background(), u)
err := evaluator.Validate(evalCtx, condition) err := evaluator.Validate(evalCtx, condition)

View File

@ -781,7 +781,7 @@ func setupScheduler(t *testing.T, rs *fakeRulesStore, is *state.FakeInstanceStor
var evaluator = evalMock var evaluator = evalMock
if evalMock == nil { if evalMock == nil {
evaluator = eval.NewEvaluatorFactory(setting.UnifiedAlertingSettings{}, nil, expr.ProvideService(&setting.Cfg{ExpressionsEnabled: true}, nil, nil, &featuremgmt.FeatureManager{}, nil), &plugins.FakePluginStore{}) evaluator = eval.NewEvaluatorFactory(setting.UnifiedAlertingSettings{}, nil, expr.ProvideService(&setting.Cfg{ExpressionsEnabled: true}, nil, nil, &featuremgmt.FeatureManager{}, nil, tracing.InitializeTracerForTest()), &plugins.FakePluginStore{})
} }
if registry == nil { if registry == nil {

View File

@ -17,6 +17,7 @@ import (
"github.com/grafana/grafana/pkg/expr" "github.com/grafana/grafana/pkg/expr"
"github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/infra/db"
"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/roletype" "github.com/grafana/grafana/pkg/models/roletype"
"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"
@ -446,7 +447,7 @@ func setup(t *testing.T) *testContext {
DataSources: nil, DataSources: nil,
SimulatePluginFailure: false, SimulatePluginFailure: false,
} }
exprService := expr.ProvideService(&setting.Cfg{ExpressionsEnabled: true}, pc, fakeDatasourceService, &featuremgmt.FeatureManager{}, nil) exprService := expr.ProvideService(&setting.Cfg{ExpressionsEnabled: true}, pc, fakeDatasourceService, &featuremgmt.FeatureManager{}, nil, tracing.InitializeTracerForTest())
queryService := ProvideService(setting.NewCfg(), dc, exprService, rv, ds, pc) // provider belonging to this package queryService := ProvideService(setting.NewCfg(), dc, exprService, rv, ds, pc) // provider belonging to this package
return &testContext{ return &testContext{
pluginContext: pc, pluginContext: pc,