Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
34 changes: 34 additions & 0 deletions .chloggen/exporterhelper-dropped-items.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Use this changelog template to create an entry for release notes.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. receiver/otlp)
component: pkg/exporterhelper

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Add support for reporting items that an exporter intentionally drops, so they are no longer counted as successfully sent.

# One or more tracking issues or pull requests related to the change
issues: [13643]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext: |
Exporter authors can return `exporterhelper.NewDroppedItemsErr(n, reason)`
from their push function to report that `n` items were intentionally dropped.
The dropped items are subtracted from the `exporter_sent_<signal>` counters
and reported via four new telemetry metrics (`exporter_dropped_log_records`,
`exporter_dropped_metric_points`, `exporter_dropped_profile_samples`,
`exporter_dropped_spans`). At detailed telemetry level the metrics also
include the optional `exporter.dropped.reason` attribute; the attribute is
filtered out at lower levels to bound cardinality.
The new spans emitted by exporterhelper carry an `items.dropped` attribute.

# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Include 'api' if there is a change to a library API.
# Default: '[user]'
change_logs: [user, api]
32 changes: 32 additions & 0 deletions exporter/exporterhelper/documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,38 @@

The following telemetry is emitted by this component.

### otelcol_exporter_dropped_log_records

Number of log records intentionally dropped by the exporter (e.g. unsupported data). At detailed telemetry level, includes attribute: exporter.dropped.reason.

| Unit | Metric Type | Value Type | Monotonic | Stability |
| ---- | ----------- | ---------- | --------- | --------- |
| {record} | Sum | Int | true | Alpha |

### otelcol_exporter_dropped_metric_points

Number of metric points intentionally dropped by the exporter (e.g. unsupported temporality). At detailed telemetry level, includes attribute: exporter.dropped.reason.

| Unit | Metric Type | Value Type | Monotonic | Stability |
| ---- | ----------- | ---------- | --------- | --------- |
| {datapoint} | Sum | Int | true | Alpha |

### otelcol_exporter_dropped_profile_samples

Number of profile samples intentionally dropped by the exporter. At detailed telemetry level, includes attribute: exporter.dropped.reason.

| Unit | Metric Type | Value Type | Monotonic | Stability |
| ---- | ----------- | ---------- | --------- | --------- |
| {sample} | Sum | Int | true | Development |

### otelcol_exporter_dropped_spans

Number of spans intentionally dropped by the exporter (e.g. unsupported data). At detailed telemetry level, includes attribute: exporter.dropped.reason.

| Unit | Metric Type | Value Type | Monotonic | Stability |
| ---- | ----------- | ---------- | --------- | --------- |
| {span} | Sum | Int | true | Alpha |

### otelcol_exporter_enqueue_failed_log_records

Number of log records failed to be added to the sending queue.
Expand Down
26 changes: 26 additions & 0 deletions exporter/exporterhelper/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package exporterhelper // import "go.opentelemetry.io/collector/exporter/exporterhelper"

import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/experr"

// DroppedItemsErr is a non-failure sentinel that an exporter's push function
// can return to signal that it intentionally dropped a number of items rather
// than failing to send them. The error is not propagated to the rest of the
// pipeline. exporterhelper subtracts the dropped count from
// exporter_sent_<signal> and records it on exporter_dropped_<signal> instead.
//
// Typical use is an exporter that receives data it cannot translate to the
// destination format (e.g. the Prometheus exporter dropping non-monotonic
// DELTA sums) and wants the operator's internal telemetry to reflect a drop
// rather than a successful send.
type DroppedItemsErr = experr.DroppedItemsErr

// NewDroppedItemsErr creates a [DroppedItemsErr] for the given count and an
// optional human-readable reason. The reason is recorded as the
// exporter.dropped.reason metric attribute at detailed telemetry level only,
// to keep cardinality bounded at lower levels.
func NewDroppedItemsErr(dropped int, reason string) error {
return experr.NewDroppedItemsErr(dropped, reason)
}
35 changes: 35 additions & 0 deletions exporter/exporterhelper/internal/experr/err.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package experr // import "go.opentelemetry.io/collector/exporter/exporterhelper/

import (
"errors"
"fmt"
)

type shutdownErr struct {
Expand All @@ -27,3 +28,37 @@ func IsShutdownErr(err error) bool {
var sdErr shutdownErr
return errors.As(err, &sdErr)
}

// DroppedItemsErr is a non-failure sentinel that an exporter can return to
// signal that it intentionally dropped a number of items rather than failing
// to send them. The error is not propagated to the pipeline as a failure —
// it is used only to update the dropped-items telemetry counters.
type DroppedItemsErr struct {
// Dropped is the number of items that were intentionally dropped.
Dropped int
// Reason is an optional human-readable description of why the items were
// dropped (e.g. "incompatible temporality").
Reason string
Comment thread
Krishnachaitanyakc marked this conversation as resolved.
}

// NewDroppedItemsErr creates a DroppedItemsErr for the given count and reason.
func NewDroppedItemsErr(dropped int, reason string) error {
return &DroppedItemsErr{Dropped: dropped, Reason: reason}
}

func (d *DroppedItemsErr) Error() string {
if d.Reason != "" {
return fmt.Sprintf("dropped %d items: %s", d.Dropped, d.Reason)
}
return fmt.Sprintf("dropped %d items", d.Dropped)
}

// DroppedItemsFromErr extracts the DroppedItemsErr from err, if present, and
// returns it together with a boolean indicating success.
func DroppedItemsFromErr(err error) (*DroppedItemsErr, bool) {
var d *DroppedItemsErr
if errors.As(err, &d) {
return d, true
}
return nil, false
}
24 changes: 24 additions & 0 deletions exporter/exporterhelper/internal/experr/err_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,27 @@ func TestIsShutdownErr(t *testing.T) {
err = NewShutdownErr(err)
require.True(t, IsShutdownErr(err))
}

func TestNewDroppedItemsErr_WithReason(t *testing.T) {
err := NewDroppedItemsErr(5, "incompatible temporality")
assert.Equal(t, "dropped 5 items: incompatible temporality", err.Error())
}

func TestNewDroppedItemsErr_NoReason(t *testing.T) {
err := NewDroppedItemsErr(3, "")
assert.Equal(t, "dropped 3 items", err.Error())
}

func TestDroppedItemsFromErr(t *testing.T) {
err := NewDroppedItemsErr(7, "some reason")
d, ok := DroppedItemsFromErr(err)
require.True(t, ok)
assert.Equal(t, 7, d.Dropped)
assert.Equal(t, "some reason", d.Reason)

_, ok = DroppedItemsFromErr(errors.New("not a dropped items error"))
assert.False(t, ok)

_, ok = DroppedItemsFromErr(nil)
assert.False(t, ok)
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading