Skip to content

distributor: log truncated oversized attributes with rate limited logger - #6467

Merged
carles-grafana merged 2 commits into
grafana:mainfrom
carles-grafana:attributes_log
Feb 20, 2026
Merged

distributor: log truncated oversized attributes with rate limited logger#6467
carles-grafana merged 2 commits into
grafana:mainfrom
carles-grafana:attributes_log

Conversation

@carles-grafana

@carles-grafana carles-grafana commented Feb 16, 2026

Copy link
Copy Markdown
Contributor

What this PR does:

global rate-limited logger for truncation warnings

The truncation log line is a supplementary diagnostic: it tells operators which attribute was truncated, at what scope, and how large it was. The primary observability channel is metricAttributesTruncated, which fires unconditionally per-tenant on every truncation.

This approach guarantees the first truncation event in any time window is always logged.

Rate-limited logger over sampling because at peak load (e.g. 20k push req/s per tenant), sampling at 0.1% still produces 20 log lines/s per pod. The rate-limited logger caps it at 1/s regardless of load.

The log lines are most useful for the noisiest tenant: the one generating the most truncations is the one operators most need diagnostic detail for. If tenant A dominates at 100k truncations/s, that's the tenant we want to see in logs. A quieter tenant B (10/s) is suppressed from logs but fully visible via per-tenant metrics.

Checklist

  • Tests updated
  • Documentation added
  • CHANGELOG.md updated - the order of entries should be [CHANGE], [FEATURE], [ENHANCEMENT], [BUGFIX]

@javiermolinar javiermolinar left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we are in the good direction bu logging each truncated attribute in the inner loop is too costly for the distributor hot path.

My proposal is sampling plus a single log statement:

  • On the first truncation observed, decide sampling rate of 0.001 if you want to log or not the truncated attributes
  • Keep truncating and counting regardless of sampling outcome
  • Emit one structured log
  • Log the result in PushTraces
Comment thread modules/distributor/distributor.go Outdated
@carles-grafana
carles-grafana force-pushed the attributes_log branch 3 times, most recently from 76dbc06 to 7e01c40 Compare February 18, 2026 10:56
@carles-grafana

carles-grafana commented Feb 18, 2026

Copy link
Copy Markdown
Contributor Author

benchmark comparison with count 8, no significant difference

goos: darwin
goarch: arm64
pkg: github.com/grafana/tempo/modules/distributor
cpu: Apple M3 Pro
                                            │             │
                                            │   sec/op    │
ProcessAttributes/truncation_no_detail-11     54.61µ ± 2%
ProcessAttributes/truncation_with_detail-11   52.16µ ± 2%
geomean                                       53.37µ

                                            │              │
                                            │     B/op     │
ProcessAttributes/truncation_no_detail-11     530.5Ki ± 0%
ProcessAttributes/truncation_with_detail-11   530.5Ki ± 0%
geomean                                       530.5Ki

                                            │            │
                                            │ allocs/op  │
ProcessAttributes/truncation_no_detail-11     400.0 ± 0%
ProcessAttributes/truncation_with_detail-11   400.0 ± 0%
geomean                                       400.0
@carles-grafana carles-grafana changed the title distributor: log truncated oversized attributes with rate limiting Feb 18, 2026
Comment thread modules/distributor/distributor.go Outdated
Comment thread modules/distributor/distributor.go
Comment thread modules/distributor/distributor.go
Comment thread modules/distributor/distributor.go Outdated
@carles-grafana carles-grafana changed the title distributor: log truncated oversized attributes with sampling Feb 18, 2026
@carles-grafana
carles-grafana force-pushed the attributes_log branch 2 times, most recently from 680a76e to fdd85ff Compare February 18, 2026 15:40
Comment thread modules/distributor/distributor.go
Comment thread modules/distributor/distributor_test.go Outdated
const maxAttrSize = 2048
const numAttrs = 100

makeAttrs := func() []*v1_common.KeyValue {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is not reliable since most of the time of the benchmark is crafting the test data. We should do it just once and reuse it between iterations

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It is reliable in relative terms to show no extra allocations and a tiny overhead of nanoseconds. But you are right that ideally it would be done outside, but the problem is that processAttributes truncates the slice values in-place, so we would need to pre-generate millions of slices. Not doable. So I'm going do remove this once, since it's no longer useful and I pasted the benchstat results in the PR.

if len(attr.Key) > maxAttrSize {
origSize := len(attr.Key)
attr.Key = attr.Key[:maxAttrSize]
if truncationExample != nil && truncationExample.origSize == 0 { // only capture the first truncation

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm ok with this. We could also keep a example per scope but we should measure the impact

metricAttributesTruncated.WithLabelValues(userID, "link").Add(float64(truncatedAttributesCount.Link))

if truncationExample != nil {
d.truncationLogger.Log("msg", "attributes truncated",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Since we want to expose this to tenants should we include the insight=true?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We can do this later once we see it's good from our side

Add warn-level logging when attribute keys or values exceed the
configured max_attribute_bytes limit.
@carles-grafana
carles-grafana merged commit 15fa5b4 into grafana:main Feb 20, 2026
24 checks passed
mattdurham pushed a commit to mattdurham/tempo that referenced this pull request Jun 18, 2026
…ger (grafana#6467)

* distributor: log truncated oversized attributes with rate limited logger

Add warn-level logging when attribute keys or values exceed the
configured max_attribute_bytes limit.

* remove benchmark, no longer useful
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

3 participants