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

stdoutmetric: Add WithWriter and WithPrettyPrint options #4507

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Expand Up @@ -8,9 +8,14 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

## [Unreleased]

### Changed

- `go.opentelemetry.io/otel/exporters/stdout/stdoutmetric` does not prettifies the output by default anymore. (#4507)

### Added

- Add the "Roll the dice" getting started application example in `go.opentelemetry.io/otel/example/dice`. (#4539)
- The `WithWriter` and `WithPrettyPrint` options to `go.opentelemetry.io/otel/exporters/stdout/stdoutmetric` to set a custom `io.Writer`, and allow displaying the output in human-readable JSON (#4507).

## [1.19.0-rc.1/0.42.0-rc.1] 2023-09-14

Expand Down
25 changes: 24 additions & 1 deletion exporters/stdout/stdoutmetric/config.go
Expand Up @@ -15,13 +15,15 @@ package stdoutmetric // import "go.opentelemetry.io/otel/exporters/stdout/stdout

import (
"encoding/json"
"io"
"os"

"go.opentelemetry.io/otel/sdk/metric"
)

// config contains options for the exporter.
type config struct {
prettyPrint bool
encoder *encoderHolder
temporalitySelector metric.TemporalitySelector
aggregationSelector metric.AggregationSelector
Expand All @@ -37,10 +39,15 @@ func newConfig(options ...Option) config {

if cfg.encoder == nil {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", "\t")
cfg.encoder = &encoderHolder{encoder: enc}
}

if cfg.prettyPrint {
if e, ok := cfg.encoder.encoder.(*json.Encoder); ok {
e.SetIndent("", "\t")
}
}

if cfg.temporalitySelector == nil {
cfg.temporalitySelector = metric.DefaultTemporalitySelector
}
Expand Down Expand Up @@ -74,6 +81,22 @@ func WithEncoder(encoder Encoder) Option {
})
}

// WithWriter sets the export stream destination.
// Using this option overrides any previously set encoder.
func WithWriter(w io.Writer) Option {
return WithEncoder(json.NewEncoder(w))
}

// WithPrettyPrint prettifies the emitted output.
// This option only works if the encoder is a *json.Encoder, as is the case
// when using `WithWriter`.
pellared marked this conversation as resolved.
Show resolved Hide resolved
pellared marked this conversation as resolved.
Show resolved Hide resolved
func WithPrettyPrint() Option {
return optionFunc(func(c config) config {
c.prettyPrint = true
return c
})
}

// WithTemporalitySelector sets the TemporalitySelector the exporter will use
// to determine the Temporality of an instrument based on its kind. If this
// option is not used, the exporter will use the DefaultTemporalitySelector
Expand Down
38 changes: 38 additions & 0 deletions exporters/stdout/stdoutmetric/exporter_test.go
Expand Up @@ -15,6 +15,7 @@
package stdoutmetric_test // import "go.opentelemetry.io/otel/exporters/stdout/stdoutmetric"

import (
"bytes"
"context"
"encoding/json"
"io"
Expand Down Expand Up @@ -103,6 +104,43 @@ func deltaSelector(metric.InstrumentKind) metricdata.Temporality {
return metricdata.DeltaTemporality
}

func TestExportWithOptions(t *testing.T) {
var (
data = new(metricdata.ResourceMetrics)
ctx = context.Background()
)

for _, tt := range []struct {
name string
opts []stdoutmetric.Option

expectedData string
}{
{
name: "with no options",
expectedData: "{\"Resource\":null,\"ScopeMetrics\":null}\n",
},
{
name: "with pretty print",
opts: []stdoutmetric.Option{
stdoutmetric.WithPrettyPrint(),
},
expectedData: "{\n\t\"Resource\": null,\n\t\"ScopeMetrics\": null\n}\n",
},
} {
t.Run(tt.name, func(t *testing.T) {
var b bytes.Buffer
opts := append(tt.opts, stdoutmetric.WithWriter(&b))

exp, err := stdoutmetric.New(opts...)
require.NoError(t, err)
require.NoError(t, exp.Export(ctx, data))

assert.Equal(t, tt.expectedData, b.String())
})
}
}

func TestTemporalitySelector(t *testing.T) {
exp, err := stdoutmetric.New(
testEncoderOption(),
Expand Down