You've already forked opentelemetry-go
mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-07-17 01:12:45 +02:00
Remove context check on stdout exporters (#5189)
This commit is contained in:
@ -17,6 +17,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- `go.opentelemetry.io/otel/exporters/stdout/stdoutlog` won't print timestamps when `WithoutTimestamps` option is set. (#5241)
|
- `go.opentelemetry.io/otel/exporters/stdout/stdoutlog` won't print timestamps when `WithoutTimestamps` option is set. (#5241)
|
||||||
|
- The `Shutdown` method of `Exporter` in `go.opentelemetry.io/otel/exporters/stdout/stdouttrace` ignores the context cancellation and always returns `nil`. (#5189)
|
||||||
|
- The `ForceFlush` and `Shutdown` methods of the exporter returned by `New` in `go.opentelemetry.io/otel/exporters/stdout/stdoutmetric` ignore the context cancellation and always return `nil`. (#5189)
|
||||||
|
|
||||||
## [1.26.0/0.48.0/0.2.0-alpha] 2024-04-24
|
## [1.26.0/0.48.0/0.2.0-alpha] 2024-04-24
|
||||||
|
|
||||||
|
@ -51,12 +51,8 @@ func (e *exporter) Aggregation(k metric.InstrumentKind) metric.Aggregation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *exporter) Export(ctx context.Context, data *metricdata.ResourceMetrics) error {
|
func (e *exporter) Export(ctx context.Context, data *metricdata.ResourceMetrics) error {
|
||||||
select {
|
if err := ctx.Err(); err != nil {
|
||||||
case <-ctx.Done():
|
return err
|
||||||
// Don't do anything if the context has already timed out.
|
|
||||||
return ctx.Err()
|
|
||||||
default:
|
|
||||||
// Context is still valid, continue.
|
|
||||||
}
|
}
|
||||||
if e.redactTimestamps {
|
if e.redactTimestamps {
|
||||||
redactTimestamps(data)
|
redactTimestamps(data)
|
||||||
@ -67,18 +63,18 @@ func (e *exporter) Export(ctx context.Context, data *metricdata.ResourceMetrics)
|
|||||||
return e.encVal.Load().(encoderHolder).Encode(data)
|
return e.encVal.Load().(encoderHolder).Encode(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *exporter) ForceFlush(ctx context.Context) error {
|
func (e *exporter) ForceFlush(context.Context) error {
|
||||||
// exporter holds no state, nothing to flush.
|
// exporter holds no state, nothing to flush.
|
||||||
return ctx.Err()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *exporter) Shutdown(ctx context.Context) error {
|
func (e *exporter) Shutdown(context.Context) error {
|
||||||
e.shutdownOnce.Do(func() {
|
e.shutdownOnce.Do(func() {
|
||||||
e.encVal.Store(encoderHolder{
|
e.encVal.Store(encoderHolder{
|
||||||
encoder: shutdownEncoder{},
|
encoder: shutdownEncoder{},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
return ctx.Err()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *exporter) MarshalLog() interface{} {
|
func (e *exporter) MarshalLog() interface{} {
|
||||||
|
@ -28,8 +28,7 @@ func testEncoderOption() stdoutmetric.Option {
|
|||||||
func testCtxErrHonored(factory func(*testing.T) func(context.Context) error) func(t *testing.T) {
|
func testCtxErrHonored(factory func(*testing.T) func(context.Context) error) func(t *testing.T) {
|
||||||
return func(t *testing.T) {
|
return func(t *testing.T) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx := context.Background()
|
||||||
t.Cleanup(cancel)
|
|
||||||
|
|
||||||
t.Run("DeadlineExceeded", func(t *testing.T) {
|
t.Run("DeadlineExceeded", func(t *testing.T) {
|
||||||
innerCtx, innerCancel := context.WithTimeout(ctx, time.Nanosecond)
|
innerCtx, innerCancel := context.WithTimeout(ctx, time.Nanosecond)
|
||||||
@ -55,19 +54,27 @@ func testCtxErrHonored(factory func(*testing.T) func(context.Context) error) fun
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExporterHonorsContextErrors(t *testing.T) {
|
func testCtxErrIgnored(factory func(*testing.T) func(context.Context) error) func(t *testing.T) {
|
||||||
t.Run("Shutdown", testCtxErrHonored(func(t *testing.T) func(context.Context) error {
|
return func(t *testing.T) {
|
||||||
exp, err := stdoutmetric.New(testEncoderOption())
|
t.Helper()
|
||||||
require.NoError(t, err)
|
ctx := context.Background()
|
||||||
return exp.Shutdown
|
|
||||||
}))
|
|
||||||
|
|
||||||
t.Run("ForceFlush", testCtxErrHonored(func(t *testing.T) func(context.Context) error {
|
t.Run("Canceled Ignored", func(t *testing.T) {
|
||||||
exp, err := stdoutmetric.New(testEncoderOption())
|
innerCtx, innerCancel := context.WithCancel(ctx)
|
||||||
require.NoError(t, err)
|
innerCancel()
|
||||||
return exp.ForceFlush
|
|
||||||
}))
|
|
||||||
|
|
||||||
|
f := factory(t)
|
||||||
|
assert.NoError(t, f(innerCtx))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("NoError", func(t *testing.T) {
|
||||||
|
f := factory(t)
|
||||||
|
assert.NoError(t, f(ctx))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExporterExportHonorsContextErrors(t *testing.T) {
|
||||||
t.Run("Export", testCtxErrHonored(func(t *testing.T) func(context.Context) error {
|
t.Run("Export", testCtxErrHonored(func(t *testing.T) func(context.Context) error {
|
||||||
exp, err := stdoutmetric.New(testEncoderOption())
|
exp, err := stdoutmetric.New(testEncoderOption())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -78,6 +85,22 @@ func TestExporterHonorsContextErrors(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestExporterForceFlushIgnoresContextErrors(t *testing.T) {
|
||||||
|
t.Run("ForceFlush", testCtxErrIgnored(func(t *testing.T) func(context.Context) error {
|
||||||
|
exp, err := stdoutmetric.New(testEncoderOption())
|
||||||
|
require.NoError(t, err)
|
||||||
|
return exp.ForceFlush
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExporterShutdownIgnoresContextErrors(t *testing.T) {
|
||||||
|
t.Run("Shutdown", testCtxErrIgnored(func(t *testing.T) func(context.Context) error {
|
||||||
|
exp, err := stdoutmetric.New(testEncoderOption())
|
||||||
|
require.NoError(t, err)
|
||||||
|
return exp.Shutdown
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
func TestShutdownExporterReturnsShutdownErrorOnExport(t *testing.T) {
|
func TestShutdownExporterReturnsShutdownErrorOnExport(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
data = new(metricdata.ResourceMetrics)
|
data = new(metricdata.ResourceMetrics)
|
||||||
|
@ -47,6 +47,9 @@ type Exporter struct {
|
|||||||
|
|
||||||
// ExportSpans writes spans in json format to stdout.
|
// ExportSpans writes spans in json format to stdout.
|
||||||
func (e *Exporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) error {
|
func (e *Exporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) error {
|
||||||
|
if err := ctx.Err(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
e.stoppedMu.RLock()
|
e.stoppedMu.RLock()
|
||||||
stopped := e.stopped
|
stopped := e.stopped
|
||||||
e.stoppedMu.RUnlock()
|
e.stoppedMu.RUnlock()
|
||||||
@ -88,11 +91,6 @@ func (e *Exporter) Shutdown(ctx context.Context) error {
|
|||||||
e.stopped = true
|
e.stopped = true
|
||||||
e.stoppedMu.Unlock()
|
e.stoppedMu.Unlock()
|
||||||
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return ctx.Err()
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,30 +60,44 @@ func TestExporterExportSpan(t *testing.T) {
|
|||||||
tests := []struct {
|
tests := []struct {
|
||||||
opts []stdouttrace.Option
|
opts []stdouttrace.Option
|
||||||
expectNow time.Time
|
expectNow time.Time
|
||||||
|
ctx context.Context
|
||||||
|
wantErr error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
opts: []stdouttrace.Option{stdouttrace.WithPrettyPrint()},
|
opts: []stdouttrace.Option{stdouttrace.WithPrettyPrint()},
|
||||||
expectNow: now,
|
expectNow: now,
|
||||||
|
ctx: context.Background(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
opts: []stdouttrace.Option{stdouttrace.WithPrettyPrint(), stdouttrace.WithoutTimestamps()},
|
opts: []stdouttrace.Option{stdouttrace.WithPrettyPrint(), stdouttrace.WithoutTimestamps()},
|
||||||
// expectNow is an empty time.Time
|
// expectNow is an empty time.Time
|
||||||
|
ctx: context.Background(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
opts: []stdouttrace.Option{},
|
||||||
|
ctx: func() context.Context {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
cancel()
|
||||||
|
return ctx
|
||||||
|
}(),
|
||||||
|
wantErr: context.Canceled,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
// write to buffer for testing
|
// write to buffer for testing
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
ex, err := stdouttrace.New(append(tt.opts, stdouttrace.WithWriter(&b))...)
|
ex, err := stdouttrace.New(append(tt.opts, stdouttrace.WithWriter(&b))...)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
err = ex.ExportSpans(ctx, tracetest.SpanStubs{ss, ss}.Snapshots())
|
err = ex.ExportSpans(tt.ctx, tracetest.SpanStubs{ss, ss}.Snapshots())
|
||||||
require.Nil(t, err)
|
assert.Equal(t, tt.wantErr, err)
|
||||||
|
|
||||||
got := b.String()
|
if tt.wantErr == nil {
|
||||||
wantone := expectedJSON(tt.expectNow)
|
got := b.String()
|
||||||
assert.Equal(t, wantone+wantone, got)
|
wantone := expectedJSON(tt.expectNow)
|
||||||
|
assert.Equal(t, wantone+wantone, got)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,23 +195,7 @@ func expectedJSON(now time.Time) string {
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExporterShutdownHonorsTimeout(t *testing.T) {
|
func TestExporterShutdownIgnoresContext(t *testing.T) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
e, err := stdouttrace.New()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to create exporter: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
innerCtx, innerCancel := context.WithTimeout(ctx, time.Nanosecond)
|
|
||||||
defer innerCancel()
|
|
||||||
<-innerCtx.Done()
|
|
||||||
err = e.Shutdown(innerCtx)
|
|
||||||
assert.ErrorIs(t, err, context.DeadlineExceeded)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExporterShutdownHonorsCancel(t *testing.T) {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
@ -209,7 +207,7 @@ func TestExporterShutdownHonorsCancel(t *testing.T) {
|
|||||||
innerCtx, innerCancel := context.WithCancel(ctx)
|
innerCtx, innerCancel := context.WithCancel(ctx)
|
||||||
innerCancel()
|
innerCancel()
|
||||||
err = e.Shutdown(innerCtx)
|
err = e.Shutdown(innerCtx)
|
||||||
assert.ErrorIs(t, err, context.Canceled)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExporterShutdownNoError(t *testing.T) {
|
func TestExporterShutdownNoError(t *testing.T) {
|
||||||
|
Reference in New Issue
Block a user