Skip to content

Commit

Permalink
[exporter/debug] add option use_internal_logger (#10227)
Browse files Browse the repository at this point in the history
#### Description

Adds a new configuration option `use_internal_logger` to the Debug
exporter, that makes it possible to prevent unwanted side effects of the
exporter using the collector's internal logger.

#### Link to tracking issue

Fixes
#10226

#### Testing

Updated unit tests to cover the new config option.

#### Documentation

Added documentation for the feature.

---------

Co-authored-by: Yang Song <[email protected]>
  • Loading branch information
andrzej-stencel and songy23 committed Jun 27, 2024
1 parent 227fb82 commit f47b9f2
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 37 deletions.
25 changes: 25 additions & 0 deletions .chloggen/debug-exporter-use-internal-logger.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# 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. otlpreceiver)
component: exporter/debug

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Add option `use_internal_logger`

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

# (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:

# 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: []
20 changes: 17 additions & 3 deletions exporter/debugexporter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
[k8s]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-k8s
<!-- end autogenerated section -->

Exports data to the console (stderr) via `zap.Logger`.
Outputs telemetry data to the console for debugging purposes.

See also the [Troubleshooting][troubleshooting_docs] document for examples on using this exporter.

Expand All @@ -35,6 +35,7 @@ The following settings are optional:
To enable sampling, change `sampling_thereafter` to a value higher than `1`.
Refer to [Zap docs](https://godoc.org/go.uber.org/zap/zapcore#NewSampler) for more details
on how sampling parameters impact number of messages.
- `use_internal_logger` (default = `true`): uses the collector's internal logger for output. See [below](#using-the-collectors-internal-logger) for description.

Example configuration:

Expand Down Expand Up @@ -120,8 +121,21 @@ Attributes:
{"kind": "exporter", "data_type": "traces", "name": "debug"}
```

## Using the collector's internal logger

When `use_internal_logger` is set to `true` (the default), the exporter uses the collector's [internal logger][internal_telemetry] for output.
This comes with the following consequences:

- The output from the exporter may be annotated by additional output from the collector's logger.
- The output from the exporter is affected by the collector's [logging configuration][internal_logs_config] specified in `service::telemetry::logs`.

When `use_internal_logger` is set to `false`, the exporter does not use the collector's internal logger.
Changing the values in `service::telemetry::logs` has no effect on the exporter's output.
The exporter's output is sent to `stdout`.

[internal_telemetry]: https://opentelemetry.io/docs/collector/internal-telemetry/
[internal_logs_config]: https://opentelemetry.io/docs/collector/internal-telemetry/#configure-internal-logs

## Warnings

- Unstable Output Format: The output formats for all verbosity levels is not guaranteed and may be changed at any time without a breaking change.

[telemetrygen]: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/cmd/telemetrygen
3 changes: 3 additions & 0 deletions exporter/debugexporter/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ type Config struct {

// SamplingThereafter defines the sampling rate after the initial samples are logged.
SamplingThereafter int `mapstructure:"sampling_thereafter"`

// UseInternalLogger defines whether the exporter sends the output to the collector's internal logger.
UseInternalLogger bool `mapstructure:"use_internal_logger"`
}

var _ component.Config = (*Config)(nil)
Expand Down
90 changes: 63 additions & 27 deletions exporter/debugexporter/exporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,39 +21,51 @@ import (
)

func TestTracesExporterNoErrors(t *testing.T) {
lte, err := createTracesExporter(context.Background(), exportertest.NewNopSettings(), createDefaultConfig())
require.NotNil(t, lte)
assert.NoError(t, err)

assert.NoError(t, lte.ConsumeTraces(context.Background(), ptrace.NewTraces()))
assert.NoError(t, lte.ConsumeTraces(context.Background(), testdata.GenerateTraces(10)))

assert.NoError(t, lte.Shutdown(context.Background()))
for _, tc := range createTestCases() {
t.Run(tc.name, func(t *testing.T) {
lte, err := createTracesExporter(context.Background(), exportertest.NewNopSettings(), tc.config)
require.NotNil(t, lte)
assert.NoError(t, err)

assert.NoError(t, lte.ConsumeTraces(context.Background(), ptrace.NewTraces()))
assert.NoError(t, lte.ConsumeTraces(context.Background(), testdata.GenerateTraces(10)))

assert.NoError(t, lte.Shutdown(context.Background()))
})
}
}

func TestMetricsExporterNoErrors(t *testing.T) {
lme, err := createMetricsExporter(context.Background(), exportertest.NewNopSettings(), createDefaultConfig())
require.NotNil(t, lme)
assert.NoError(t, err)

assert.NoError(t, lme.ConsumeMetrics(context.Background(), pmetric.NewMetrics()))
assert.NoError(t, lme.ConsumeMetrics(context.Background(), testdata.GenerateMetricsAllTypes()))
assert.NoError(t, lme.ConsumeMetrics(context.Background(), testdata.GenerateMetricsAllTypesEmpty()))
assert.NoError(t, lme.ConsumeMetrics(context.Background(), testdata.GenerateMetricsMetricTypeInvalid()))
assert.NoError(t, lme.ConsumeMetrics(context.Background(), testdata.GenerateMetrics(10)))

assert.NoError(t, lme.Shutdown(context.Background()))
for _, tc := range createTestCases() {
t.Run(tc.name, func(t *testing.T) {
lme, err := createMetricsExporter(context.Background(), exportertest.NewNopSettings(), tc.config)
require.NotNil(t, lme)
assert.NoError(t, err)

assert.NoError(t, lme.ConsumeMetrics(context.Background(), pmetric.NewMetrics()))
assert.NoError(t, lme.ConsumeMetrics(context.Background(), testdata.GenerateMetricsAllTypes()))
assert.NoError(t, lme.ConsumeMetrics(context.Background(), testdata.GenerateMetricsAllTypesEmpty()))
assert.NoError(t, lme.ConsumeMetrics(context.Background(), testdata.GenerateMetricsMetricTypeInvalid()))
assert.NoError(t, lme.ConsumeMetrics(context.Background(), testdata.GenerateMetrics(10)))

assert.NoError(t, lme.Shutdown(context.Background()))
})
}
}

func TestLogsExporterNoErrors(t *testing.T) {
lle, err := createLogsExporter(context.Background(), exportertest.NewNopSettings(), createDefaultConfig())
require.NotNil(t, lle)
assert.NoError(t, err)

assert.NoError(t, lle.ConsumeLogs(context.Background(), plog.NewLogs()))
assert.NoError(t, lle.ConsumeLogs(context.Background(), testdata.GenerateLogs(10)))

assert.NoError(t, lle.Shutdown(context.Background()))
for _, tc := range createTestCases() {
t.Run(tc.name, func(t *testing.T) {
lle, err := createLogsExporter(context.Background(), exportertest.NewNopSettings(), createDefaultConfig())
require.NotNil(t, lle)
assert.NoError(t, err)

assert.NoError(t, lle.ConsumeLogs(context.Background(), plog.NewLogs()))
assert.NoError(t, lle.ConsumeLogs(context.Background(), testdata.GenerateLogs(10)))

assert.NoError(t, lle.Shutdown(context.Background()))
})
}
}

func TestExporterErrors(t *testing.T) {
Expand All @@ -69,6 +81,30 @@ func TestExporterErrors(t *testing.T) {
assert.Equal(t, errWant, le.pushLogs(context.Background(), plog.NewLogs()))
}

type testCase struct {
name string
config *Config
}

func createTestCases() []testCase {
return []testCase{
{
name: "default config",
config: func() *Config {
return createDefaultConfig().(*Config)
}(),
},
{
name: "don't use internal logger",
config: func() *Config {
cfg := createDefaultConfig().(*Config)
cfg.UseInternalLogger = false
return cfg
}(),
},
}
}

type errMarshaler struct {
err error
}
Expand Down
41 changes: 34 additions & 7 deletions exporter/debugexporter/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ func createDefaultConfig() component.Config {
Verbosity: configtelemetry.LevelBasic,
SamplingInitial: defaultSamplingInitial,
SamplingThereafter: defaultSamplingThereafter,
UseInternalLogger: true,
}
}

Expand Down Expand Up @@ -83,12 +84,38 @@ func createLogsExporter(ctx context.Context, set exporter.Settings, config compo
}

func createLogger(cfg *Config, logger *zap.Logger) *zap.Logger {
core := zapcore.NewSamplerWithOptions(
logger.Core(),
1*time.Second,
cfg.SamplingInitial,
cfg.SamplingThereafter,
)
var exporterLogger *zap.Logger
if cfg.UseInternalLogger {
core := zapcore.NewSamplerWithOptions(
logger.Core(),
1*time.Second,
cfg.SamplingInitial,
cfg.SamplingThereafter,
)
exporterLogger = zap.New(core)
} else {
exporterLogger = createCustomLogger(cfg)
}
return exporterLogger
}

return zap.New(core)
func createCustomLogger(exporterConfig *Config) *zap.Logger {
encoderConfig := zap.NewDevelopmentEncoderConfig()
// Do not prefix the output with log level (`info`)
encoderConfig.LevelKey = ""
// Do not prefix the output with current timestamp.
encoderConfig.TimeKey = ""
zapConfig := zap.Config{
Level: zap.NewAtomicLevelAt(zap.InfoLevel),
DisableCaller: true,
Sampling: &zap.SamplingConfig{
Initial: exporterConfig.SamplingInitial,
Thereafter: exporterConfig.SamplingThereafter,
},
Encoding: "console",
EncoderConfig: encoderConfig,
// Send exporter's output to stdout. This should be made configurable.
OutputPaths: []string{"stdout"},
}
return zap.Must(zapConfig.Build())
}
1 change: 1 addition & 0 deletions exporter/debugexporter/testdata/config_verbosity.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
verbosity: detailed
sampling_initial: 10
sampling_thereafter: 50
use_internal_logger: false

0 comments on commit f47b9f2

Please sign in to comment.