Skip to content

Commit 9540c55

Browse files
committed
Create a extra sampled logger as part of the telemetry settings
1 parent 310b747 commit 9540c55

File tree

9 files changed

+88
-34
lines changed

9 files changed

+88
-34
lines changed

.chloggen/SampledLoggerTelemetry.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver)
7+
component: service/telemetry exporter/exporterhelper
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: "New sampled logger in the telemetry configuration used to avoid flooding the logs with messages that are repeated frequently."
11+
12+
# One or more tracking issues or pull requests related to the change
13+
issues: [8134]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext: The sampled logger is configured by `LogsSamplingConfig` (`service.telemetry.logs.sampling`).
19+
20+
# Optional: The change log or logs in which this entry should be included.
21+
# e.g. '[user]' or '[user, api]'
22+
# Include 'user' if the change is relevant to end users.
23+
# Include 'api' if there is a change to a library API.
24+
# Default: '[user]'
25+
change_logs: [user]

component/componenttest/nop_telemetry.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
func NewNopTelemetrySettings() component.TelemetrySettings {
1818
return component.TelemetrySettings{
1919
Logger: zap.NewNop(),
20+
SampledLogger: zap.NewNop(),
2021
TracerProvider: trace.NewNoopTracerProvider(),
2122
MeterProvider: noop.NewMeterProvider(),
2223
MetricsLevel: configtelemetry.LevelNone,

component/telemetry.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ type TelemetrySettings struct {
1717
// component to be used later as well.
1818
Logger *zap.Logger
1919

20+
// SampledLogger passed to the created component.
21+
// It will be used to avoid flooding the logs with messages that are repeated frequently.
22+
SampledLogger *zap.Logger
23+
2024
// TracerProvider that the factory can pass to other instrumented third-party libraries.
2125
TracerProvider trace.TracerProvider
2226

exporter/exporterhelper/common.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ func newBaseExporter(set exporter.CreateSettings, bs *baseSettings, signal compo
171171
return nil, err
172172
}
173173

174-
be.qrSender = newQueuedRetrySender(set.ID, signal, bs.queue, bs.RetrySettings, &timeoutSender{cfg: bs.TimeoutSettings}, set.Logger)
174+
be.qrSender = newQueuedRetrySender(set.ID, signal, bs.queue, bs.RetrySettings, &timeoutSender{cfg: bs.TimeoutSettings}, set.SampledLogger)
175175
be.sender = be.qrSender
176176
be.StartFunc = func(ctx context.Context, host component.Host) error {
177177
// First start the wrapped exporter.

exporter/exporterhelper/queued_retry.go

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
"go.opentelemetry.io/otel/attribute"
1515
"go.opentelemetry.io/otel/trace"
1616
"go.uber.org/zap"
17-
"go.uber.org/zap/zapcore"
1817

1918
"go.opentelemetry.io/collector/component"
2019
"go.opentelemetry.io/collector/consumer/consumererror"
@@ -78,9 +77,8 @@ type queuedRetrySender struct {
7877
}
7978

8079
func newQueuedRetrySender(id component.ID, signal component.DataType, queue internal.ProducerConsumerQueue,
81-
rCfg RetrySettings, nextSender requestSender, logger *zap.Logger) *queuedRetrySender {
80+
rCfg RetrySettings, nextSender requestSender, sampledLogger *zap.Logger) *queuedRetrySender {
8281
retryStopCh := make(chan struct{})
83-
sampledLogger := createSampledLogger(logger)
8482
traceAttr := attribute.String(obsmetrics.ExporterKey, id.String())
8583

8684
qrs := &queuedRetrySender{
@@ -217,25 +215,6 @@ func NewDefaultRetrySettings() RetrySettings {
217215
}
218216
}
219217

220-
func createSampledLogger(logger *zap.Logger) *zap.Logger {
221-
if logger.Core().Enabled(zapcore.DebugLevel) {
222-
// Debugging is enabled. Don't do any sampling.
223-
return logger
224-
}
225-
226-
// Create a logger that samples all messages to 1 per 10 seconds initially,
227-
// and 1/100 of messages after that.
228-
opts := zap.WrapCore(func(core zapcore.Core) zapcore.Core {
229-
return zapcore.NewSamplerWithOptions(
230-
core,
231-
10*time.Second,
232-
1,
233-
100,
234-
)
235-
})
236-
return logger.WithOptions(opts)
237-
}
238-
239218
// send implements the requestSender interface
240219
func (qrs *queuedRetrySender) send(req internal.Request) error {
241220
if qrs.queue == nil {

service/service.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ func New(ctx context.Context, set Settings, cfg Config) (*Service, error) {
106106

107107
srv.telemetrySettings = component.TelemetrySettings{
108108
Logger: srv.telemetry.Logger(),
109+
SampledLogger: srv.telemetry.SampledLogger(),
109110
TracerProvider: srv.telemetry.TracerProvider(),
110111
MeterProvider: noop.NewMeterProvider(),
111112
MetricsLevel: cfg.Telemetry.Metrics.Level,

service/service_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,19 @@ func TestNilCollectorEffectiveConfig(t *testing.T) {
403403
require.NoError(t, srv.Shutdown(context.Background()))
404404
}
405405

406+
func TestServiceTelemetryLoggers(t *testing.T) {
407+
srv, err := New(context.Background(), newNopSettings(), newNopConfig())
408+
require.NoError(t, err)
409+
410+
assert.NoError(t, srv.Start(context.Background()))
411+
t.Cleanup(func() {
412+
assert.NoError(t, srv.Shutdown(context.Background()))
413+
})
414+
assert.NotNil(t, srv.telemetrySettings.Logger)
415+
assert.NotNil(t, srv.telemetrySettings.SampledLogger)
416+
assert.NotEqual(t, srv.telemetrySettings.Logger, srv.telemetrySettings.SampledLogger)
417+
}
418+
406419
func assertResourceLabels(t *testing.T, res pcommon.Resource, expectedLabels map[string]labelValue) {
407420
for key, labelValue := range expectedLabels {
408421
lookupKey, ok := prometheusToOtelConv[key]

service/telemetry/config.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package telemetry // import "go.opentelemetry.io/collector/service/telemetry"
55

66
import (
77
"fmt"
8+
"time"
89

910
"go.uber.org/zap/zapcore"
1011

@@ -54,7 +55,11 @@ type LogsConfig struct {
5455
// (default = false)
5556
DisableStacktrace bool `mapstructure:"disable_stacktrace"`
5657

57-
// Sampling sets a sampling policy. A nil SamplingConfig disables sampling.
58+
// Sampling sets a sampling policy for the extra sampled logger.
59+
// Default:
60+
// initial: 1
61+
// thereafter: 100
62+
// tick: 10s
5863
Sampling *LogsSamplingConfig `mapstructure:"sampling"`
5964

6065
// OutputPaths is a list of URLs or file paths to write logging output to.
@@ -87,12 +92,13 @@ type LogsConfig struct {
8792
InitialFields map[string]any `mapstructure:"initial_fields"`
8893
}
8994

90-
// LogsSamplingConfig sets a sampling strategy for the logger. Sampling caps the
95+
// LogsSamplingConfig sets a sampling strategy for the extra sampled logger. Sampling caps the
9196
// global CPU and I/O load that logging puts on your process while attempting
9297
// to preserve a representative subset of your logs.
9398
type LogsSamplingConfig struct {
94-
Initial int `mapstructure:"initial"`
95-
Thereafter int `mapstructure:"thereafter"`
99+
Initial int `mapstructure:"initial"`
100+
Thereafter int `mapstructure:"thereafter"`
101+
Tick time.Duration `mapstructure:"tick"`
96102
}
97103

98104
// MetricsConfig exposes the common Telemetry configuration for one component.

service/telemetry/telemetry.go

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package telemetry // import "go.opentelemetry.io/collector/service/telemetry"
55

66
import (
77
"context"
8+
"time"
89

910
sdktrace "go.opentelemetry.io/otel/sdk/trace"
1011
"go.opentelemetry.io/otel/trace"
@@ -15,6 +16,7 @@ import (
1516

1617
type Telemetry struct {
1718
logger *zap.Logger
19+
sampledLogger *zap.Logger
1820
tracerProvider *sdktrace.TracerProvider
1921
}
2022

@@ -26,6 +28,10 @@ func (t *Telemetry) Logger() *zap.Logger {
2628
return t.logger
2729
}
2830

31+
func (t *Telemetry) SampledLogger() *zap.Logger {
32+
return t.sampledLogger
33+
}
34+
2935
func (t *Telemetry) Shutdown(ctx context.Context) error {
3036
// TODO: Sync logger.
3137
return multierr.Combine(
@@ -44,12 +50,15 @@ func New(_ context.Context, set Settings, cfg Config) (*Telemetry, error) {
4450
if err != nil {
4551
return nil, err
4652
}
53+
sampledLogger := newSampledLogger(cfg.Logs.Sampling, logger)
54+
4755
tp := sdktrace.NewTracerProvider(
4856
// needed for supporting the zpages extension
4957
sdktrace.WithSampler(alwaysRecord()),
5058
)
5159
return &Telemetry{
5260
logger: logger,
61+
sampledLogger: sampledLogger,
5362
tracerProvider: tp,
5463
}, nil
5564
}
@@ -59,7 +68,6 @@ func newLogger(cfg LogsConfig, options []zap.Option) (*zap.Logger, error) {
5968
zapCfg := &zap.Config{
6069
Level: zap.NewAtomicLevelAt(cfg.Level),
6170
Development: cfg.Development,
62-
Sampling: toSamplingConfig(cfg.Sampling),
6371
Encoding: cfg.Encoding,
6472
EncoderConfig: zap.NewProductionEncoderConfig(),
6573
OutputPaths: cfg.OutputPaths,
@@ -82,12 +90,29 @@ func newLogger(cfg LogsConfig, options []zap.Option) (*zap.Logger, error) {
8290
return logger, nil
8391
}
8492

85-
func toSamplingConfig(sc *LogsSamplingConfig) *zap.SamplingConfig {
86-
if sc == nil {
87-
return nil
93+
func newSampledLogger(cfg *LogsSamplingConfig, logger *zap.Logger) *zap.Logger {
94+
if cfg == nil {
95+
cfg = newDefaultLogsSamplingConfig()
8896
}
89-
return &zap.SamplingConfig{
90-
Initial: sc.Initial,
91-
Thereafter: sc.Thereafter,
97+
98+
// Create a logger that samples all messages to "initial" per "tick" initially,
99+
// and cfg.Initial/cfg.Thereafter of messages after that.
100+
opts := zap.WrapCore(func(core zapcore.Core) zapcore.Core {
101+
return zapcore.NewSamplerWithOptions(
102+
core,
103+
cfg.Tick,
104+
cfg.Initial,
105+
cfg.Thereafter,
106+
)
107+
})
108+
return logger.WithOptions(opts)
109+
}
110+
111+
// newDefaultLogsSamplingConfig returns a default LogsSamplingConfig.
112+
func newDefaultLogsSamplingConfig() *LogsSamplingConfig {
113+
return &LogsSamplingConfig{
114+
Initial: 1,
115+
Thereafter: 100,
116+
Tick: 10 * time.Second,
92117
}
93118
}

0 commit comments

Comments
 (0)