Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/sources/tempo/configuration/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,9 @@ metrics_generator:
# Enables additional labels for services and virtual nodes.
[enable_virtual_node_label: <bool> | default = false]

# List of attribute names used to identify the database name from span attributes. If it isn't set, the order is peer.service -> server.address -> network.peer.address -> db.name
[database_name_attributes: <list of string> | default = ["db.namespace","db.name","db.system"]]

span_metrics:

# Buckets for the latency histogram in seconds.
Expand Down
1 change: 1 addition & 0 deletions docs/sources/tempo/configuration/manifest.md
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,7 @@ metrics_generator:
- db.system
span_multiplier_key: ""
enable_virtual_node_label: false
database_name_attributes: []
span_metrics:
histogram_buckets:
- 0.002
Expand Down
11 changes: 11 additions & 0 deletions modules/generator/processor/servicegraphs/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (

"github.com/grafana/tempo/modules/generator/registry"
"github.com/prometheus/client_golang/prometheus"
semconv "go.opentelemetry.io/otel/semconv/v1.25.0"
semconvnew "go.opentelemetry.io/otel/semconv/v1.34.0"
)

type Config struct {
Expand Down Expand Up @@ -45,6 +47,9 @@ type Config struct {

// EnableVirtualNodeLabel enables additional labels for uninstrumented services
EnableVirtualNodeLabel bool `yaml:"enable_virtual_node_label"`

// DatabaseNameAttributes the list of attribute names used to identify the database name from span attributes.
DatabaseNameAttributes []string `yaml:"database_name_attributes"`
}

func (cfg *Config) RegisterFlagsAndApplyDefaults(string, *flag.FlagSet) {
Expand All @@ -62,4 +67,10 @@ func (cfg *Config) RegisterFlagsAndApplyDefaults(string, *flag.FlagSet) {
cfg.PeerAttributes = peerAttr

cfg.EnableMessagingSystemLatencyHistogram = false

cfg.DatabaseNameAttributes = []string{
string(semconvnew.DBNamespaceKey),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i nearly commented that these are out of order with the previous checks, but these are in fact correct. the previous logic is just awfully convoluted. nice catch

string(semconv.DBNameKey),
string(semconv.DBSystemKey),
}
}
19 changes: 4 additions & 15 deletions modules/generator/processor/servicegraphs/servicegraphs.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"github.com/prometheus/client_golang/prometheus/promauto"
"go.opentelemetry.io/otel/attribute"
semconv "go.opentelemetry.io/otel/semconv/v1.25.0"
semconvnew "go.opentelemetry.io/otel/semconv/v1.34.0"

gen "github.com/grafana/tempo/modules/generator/processor"
"github.com/grafana/tempo/modules/generator/processor/servicegraphs/store"
Expand Down Expand Up @@ -276,19 +275,11 @@ func (p *Processor) upsertDatabaseRequest(e *store.Edge, resourceAttr []*v1_comm
)

// Check for db.name or db.namespace first. The dbName is set initially to maintain backwards compatbility.
if name, ok := processor_util.FindAttributeValue(string(semconv.DBNameKey), resourceAttr, span.Attributes); ok {
dbName = name
isDatabase = true
}
if name, ok := processor_util.FindAttributeValue(string(semconvnew.DBNamespaceKey), span.Attributes); ok {
dbName = name
isDatabase = true
}

// Check for db.system only if we don't have db.name above
if !isDatabase {
if _, ok := processor_util.FindAttributeValue(string(semconv.DBSystemKey), resourceAttr, span.Attributes); ok {
for _, attrName := range p.Cfg.DatabaseNameAttributes {
if name, ok := processor_util.FindAttributeValue(attrName, resourceAttr, span.Attributes); ok {
dbName = name
isDatabase = true
break
}
}

Expand All @@ -299,8 +290,6 @@ func (p *Processor) upsertDatabaseRequest(e *store.Edge, resourceAttr []*v1_comm
e.ConnectionType = store.Database
e.ServerLatencySec = spanDurationSec(span)

// Set the service name by order of precedence

// Check for peer.service
if name, ok := processor_util.FindAttributeValue(string(semconv.PeerServiceKey), resourceAttr, span.Attributes); ok {
e.ServerService = name
Expand Down
37 changes: 33 additions & 4 deletions modules/generator/processor/servicegraphs/servicegraphs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,15 @@ import (

"github.com/go-kit/log"
"github.com/gogo/protobuf/jsonpb"
"github.com/grafana/tempo/modules/generator/registry"
"github.com/grafana/tempo/pkg/tempopb"
"github.com/grafana/tempo/pkg/util/test"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/prometheus/model/labels"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
semconv "go.opentelemetry.io/otel/semconv/v1.25.0"
semconvnew "go.opentelemetry.io/otel/semconv/v1.34.0"

"github.com/grafana/tempo/modules/generator/registry"
"github.com/grafana/tempo/pkg/tempopb"
"github.com/grafana/tempo/pkg/util/test"
)

// NOTE: This is a way to know if the contents of the semconv package have changed.
Expand Down Expand Up @@ -543,6 +542,36 @@ func TestServiceGraphs_prefixDimensionsAndEnableExtraLabels(t *testing.T) {
assert.Equal(t, 0.0, testRegistry.Query(`traces_service_graph_request_failed_total`, dbSystemSystemLabels))
}

func TestServiceGraphs_DatabaseNameAttributes(t *testing.T) {
testRegistry := registry.NewTestRegistry()

cfg := Config{}
cfg.RegisterFlagsAndApplyDefaults("", nil)

cfg.HistogramBuckets = []float64{0.04}
cfg.Dimensions = []string{"beast", "god"}
cfg.DatabaseNameAttributes = []string{"db.system"}

p := New(cfg, "test", testRegistry, log.NewNopLogger(), prometheus.NewCounter(prometheus.CounterOpts{}))
defer p.Shutdown(context.Background())

request, err := loadTestData("testdata/trace-with-queue-database.json")
require.NoError(t, err)

p.PushSpans(context.Background(), request)

// The server label should be set to the value of db.system
labels := labels.FromMap(map[string]string{
"client": "mythical-server",
"server": "postgresql",
"connection_type": "database",
"beast": "",
"god": "",
})
print(testRegistry.Query(`traces_service_graph_request_total`, labels))
assert.Equal(t, 1.0, testRegistry.Query(`traces_service_graph_request_total`, labels))
}

func BenchmarkServiceGraphs(b *testing.B) {
testRegistry := registry.NewTestRegistry()

Expand Down