Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New otelcol.exporter.debug component #5867

Merged
merged 11 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from 9 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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ internal API changes are not present.
Main (unreleased)
-----------------

### Features

- A new `otelcol.exporter.debug` component for printing OTel telemetry from
other `otelcol` components to the console. (@BarunKGP)

v0.41.1 (2024-06-07)
--------------------

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
aliases:
- /docs/grafana-cloud/agent/flow/reference/components/otelcol.exporter.debug/
- /docs/grafana-cloud/monitor-infrastructure/agent/flow/reference/components/otelcol.exporter.debug/
- /docs/grafana-cloud/monitor-infrastructure/integrations/agent/flow/reference/components/otelcol.exporter.debug/
- /docs/grafana-cloud/send-data/agent/flow/reference/components/otelcol.exporter.debug/
canonical: https://grafana.com/docs/agent/latest/flow/reference/components/otelcol.exporter.debug/
description: Learn about otelcol.exporter.debug
labels:
stage: experimental
title: otelcol.exporter.debug
BarunKGP marked this conversation as resolved.
Show resolved Hide resolved
---

# otelcol.exporter.debug

`otelcol.exporter.debug` accepts telemetry data from other `otelcol` components and writes them to the console (stderr).
You can control the verbosity of the logs.

{{< admonition type="note" >}}
`otelcol.exporter.debug` is a wrapper over the upstream OpenTelemetry Collector `debug` exporter.
If necessary, bug reports or feature requests are redirected to the upstream repository.
{{< /admonition >}}

Multiple `otelcol.exporter.debug` components can be specified by giving them different labels.

## Usage

```river
otelcol.exporter.debug "LABEL" { }
```

## Arguments

`otelcol.exporter.debug` supports the following arguments:

Name | Type | Description | Default | Required
---- | ---- | ----------- | ------- | --------
`verbosity` | `string` | Verbosity of the generated logs. | `"normal"` | no
`sampling_initial` | `int` | Number of messages initially logged each second. | `2` | no
`sampling_thereafter` | `int` | Sampling rate after the initial messages are logged. | `500` | no

The `verbosity` argument must be one of `"basic"`, `"normal"`, or `"detailed"`.

## Exported fields

The following fields are exported and can be referenced by other components:

Name | Type | Description
---- | ---- | -----------
`input` | `otelcol.Consumer` | A value that other components can use to send telemetry data to.

`input` accepts `otelcol.Consumer` data for any telemetry signal (metrics,
logs, or traces).

## Component health

`otelcol.exporter.debug` is only reported as unhealthy if given an invalid
configuration.

## Debug information

`otelcol.exporter.debug` does not expose any component-specific debug
information.

## Example

This example scrapes Prometheus UNIX metrics and writes them to the console:

```river
prometheus.exporter.unix "default" { }

prometheus.scrape "default" {
targets = prometheus.exporter.unix.default.targets
forward_to = [otelcol.receiver.prometheus.default.receiver]
}

otelcol.receiver.prometheus "default" {
output {
metrics = [otelcol.exporter.debug.default.input]
}
}

otelcol.exporter.debug "default" {
verbosity = "detailed"
sampling_initial = 1
sampling_thereafter = 1
}
```
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,7 @@ require (
go.opentelemetry.io/collector/confmap/converter/expandconverter v0.96.0
go.opentelemetry.io/collector/confmap/provider/fileprovider v0.96.0
go.opentelemetry.io/collector/confmap/provider/yamlprovider v0.96.0
go.opentelemetry.io/collector/exporter/debugexporter v0.96.0
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.24.0
golang.org/x/crypto/x509roots/fallback v0.0.0-20240208163226-62c9f1799c91
k8s.io/apimachinery v0.29.2
Expand Down
2 changes: 2 additions & 0 deletions go.sum
BarunKGP marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -2348,6 +2348,8 @@ go.opentelemetry.io/collector/consumer v0.96.0 h1:JN4JHelp5EGMGoC2UVelTMG6hyZjgt
go.opentelemetry.io/collector/consumer v0.96.0/go.mod h1:Vn+qzzKgekDFayCVV8peSH5Btx1xrt/bmzD9gTxgidQ=
go.opentelemetry.io/collector/exporter v0.96.0 h1:SmOSaP+zUNq0nl+BcllsCSsYePdUNIIUfW5sXKKaUlI=
go.opentelemetry.io/collector/exporter v0.96.0/go.mod h1:DcuGaxcINhOV2LgojDI56r3830cUtuCsNadINMIU23c=
go.opentelemetry.io/collector/exporter/debugexporter v0.96.0 h1:88v2GWCIuYgd3e4KdwF0JLklIgBzETBw0e3dkEJ7BbI=
go.opentelemetry.io/collector/exporter/debugexporter v0.96.0/go.mod h1:mZjJ0G6Pn6aSS7T4UeEjXSHt3pgslvaZa/4Uam8DKuo=
go.opentelemetry.io/collector/exporter/loggingexporter v0.96.0 h1:fKHt4iTcD7C0utDzeww6ZYVlDYaC0dw9wtzVwLha4CM=
go.opentelemetry.io/collector/exporter/loggingexporter v0.96.0/go.mod h1:vpuKdiIQ6yjwZbKiiAs/MV8rZMKiQfPF55vX8UxO8fk=
go.opentelemetry.io/collector/exporter/otlpexporter v0.96.0 h1:vZEd10B/zj7WkBWSVegDkGOwv7FZhUwyk60E2zkYwL4=
Expand Down
96 changes: 96 additions & 0 deletions internal/component/otelcol/exporter/debug/debug.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package debug

import (
"fmt"

"github.com/grafana/agent/internal/component"
"github.com/grafana/agent/internal/component/otelcol"
"github.com/grafana/agent/internal/component/otelcol/exporter"
"github.com/grafana/agent/internal/featuregate"
otelcomponent "go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config/configtelemetry"
debugexporter "go.opentelemetry.io/collector/exporter/debugexporter"
otelextension "go.opentelemetry.io/collector/extension"
)

func init() {
component.Register(component.Registration{
Name: "otelcol.exporter.debug",
Args: Arguments{},
Exports: otelcol.ConsumerExports{},
Stability: featuregate.StabilityExperimental,

Build: func(opts component.Options, args component.Arguments) (component.Component, error) {
fact := debugexporter.NewFactory()
return exporter.New(opts, fact, args.(Arguments), exporter.TypeAll)
},
})
}

type Arguments struct {
Verbosity string `river:"verbosity,attr,optional"`
SamplingInitial int `river:"sampling_initial,attr,optional"`
SamplingThereafter int `river:"sampling_thereafter,attr,optional"`
}

func (args Arguments) convertVerbosity() (configtelemetry.Level, error) {
var verbosity configtelemetry.Level
switch args.Verbosity {
case "basic":
verbosity = configtelemetry.LevelBasic
case "normal":
verbosity = configtelemetry.LevelNormal
case "detailed":
verbosity = configtelemetry.LevelDetailed
default:
// Invalid verbosity
// debugexporter only supports basic, normal and detailed levels
return verbosity, fmt.Errorf("invalid verbosity %q", args.Verbosity)
}

return verbosity, nil
}

var _ exporter.Arguments = Arguments{}

// DefaultArguments holds default values for Arguments.
var DefaultArguments = Arguments{
Verbosity: "normal",
SamplingInitial: 2,
SamplingThereafter: 500,
}

// SetToDefault implements river.Defaulter.
func (args *Arguments) SetToDefault() {
*args = DefaultArguments
}

// Convert implements exporter.Arguments.
func (args Arguments) Convert() (otelcomponent.Config, error) {
verbosity, err := args.convertVerbosity()
if err != nil {
return nil, fmt.Errorf("error in conversion to config arguments, %v", err)
}

return &debugexporter.Config{
Verbosity: verbosity,
SamplingInitial: args.SamplingInitial,
SamplingThereafter: args.SamplingThereafter,
}, nil
}

// Extensions implements exporter.Arguments.
func (args Arguments) Extensions() map[otelcomponent.ID]otelextension.Extension {
return nil
}

// Exporters implements exporter.Arguments.
func (args Arguments) Exporters() map[otelcomponent.DataType]map[otelcomponent.ID]otelcomponent.Component {
return nil
}

// DebugMetricsConfig implements receiver.Arguments.
func (args Arguments) DebugMetricsConfig() otelcol.DebugMetricsArguments {
var debugMetrics otelcol.DebugMetricsArguments
return debugMetrics
}
79 changes: 79 additions & 0 deletions internal/component/otelcol/exporter/debug/debug_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package debug_test

import (
"fmt"
"testing"

"github.com/grafana/agent/internal/component/otelcol/exporter/debug"
"github.com/grafana/river"
"github.com/stretchr/testify/require"
otelcomponent "go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config/configtelemetry"
debugexporter "go.opentelemetry.io/collector/exporter/debugexporter"
)

func Test(t *testing.T) {
tests := []struct {
testName string
args string
expectedReturn debugexporter.Config
errorMsg string
}{
{
testName: "defaultConfig",
args: ``,
expectedReturn: debugexporter.Config{
Verbosity: configtelemetry.LevelNormal,
SamplingInitial: 2,
SamplingThereafter: 500,
},
},

{
testName: "validConfig",
args: `
verbosity = "detailed"
sampling_initial = 5
sampling_thereafter = 20
`,
expectedReturn: debugexporter.Config{
Verbosity: configtelemetry.LevelDetailed,
SamplingInitial: 5,
SamplingThereafter: 20,
},
},

{
testName: "invalidConfig",
args: `
verbosity = "test"
sampling_initial = 5
sampling_thereafter = 20
`,
errorMsg: "error in conversion to config arguments",
},
}

for _, tc := range tests {
t.Run(tc.testName, func(t *testing.T) {
var args debug.Arguments
err := river.Unmarshal([]byte(tc.args), &args)
require.NoError(t, err)

actualPtr, err := args.Convert()
if tc.errorMsg != "" {
require.ErrorContains(t, err, tc.errorMsg)
return
}

require.NoError(t, err)

actual := actualPtr.(*debugexporter.Config)
fmt.Printf("Passed conversion")

require.NoError(t, otelcomponent.ValidateConfig(actual))

require.Equal(t, tc.expectedReturn, *actual)
})
}
}