-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add back the stdoutmetric exporter (#3057)
* PoC stdoutmetric exporter * Use stringer to generate String for Temporality * Add vanity imports * Update Temporality string expected output * Do not return error from newConfig * Add shutdown unit tests * Fix spelling error * Unify testing of ctx errors and test ForceFlush * Add unit test for Export handle of ctx errs * Clarify documentation about alt OTLP exporter * Remove unused ErrUnrecognized A third party encoder can produce their own errors. This code does nothing unique with this error, therefore, it is removed. * Lint exporter_test.go * Refactor example_test.go removing FIXME * Add test for Export shutdown err * Add a discard encoder for testing * Acknowledged error is returned from Shutdown * Remove unexpected SchemaURL from stdouttrace test * Remove unneeded *testing.T arg from testEncoderOption * Fix the location of now * Revise and edit docs Co-authored-by: Aaron Clawson <3766680+MadVikingGod@users.noreply.github.com>
- Loading branch information
1 parent
eefb277
commit ea8af82
Showing
14 changed files
with
636 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
//go:build go1.18 | ||
// +build go1.18 | ||
|
||
package stdoutmetric // import "go.opentelemetry.io/otel/exporters/stdout/stdoutmetric" | ||
|
||
import ( | ||
"encoding/json" | ||
"os" | ||
) | ||
|
||
// config contains options for the exporter. | ||
type config struct { | ||
encoder *encoderHolder | ||
} | ||
|
||
// newConfig creates a validated config configured with options. | ||
func newConfig(options ...Option) config { | ||
cfg := config{} | ||
for _, opt := range options { | ||
cfg = opt.apply(cfg) | ||
} | ||
|
||
if cfg.encoder == nil { | ||
enc := json.NewEncoder(os.Stdout) | ||
enc.SetIndent("", "\t") | ||
cfg.encoder = &encoderHolder{encoder: enc} | ||
} | ||
|
||
return cfg | ||
} | ||
|
||
// Option sets exporter option values. | ||
type Option interface { | ||
apply(config) config | ||
} | ||
|
||
type optionFunc func(config) config | ||
|
||
func (o optionFunc) apply(c config) config { | ||
return o(c) | ||
} | ||
|
||
// WithEncoder sets the exporter to use encoder to encode all the metric | ||
// data-types to an output. | ||
func WithEncoder(encoder Encoder) Option { | ||
return optionFunc(func(c config) config { | ||
if encoder != nil { | ||
c.encoder = &encoderHolder{encoder: encoder} | ||
} | ||
return c | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
// Package stdoutmetric provides an exporter for OpenTelemetry metric | ||
// telemetry. | ||
// | ||
// The exporter is intended to be used for testing and debugging, it is not | ||
// meant for production use. Additionally, it does not provide an interchange | ||
// format for OpenTelemetry that is supported with any stability or | ||
// compatibility guarantees. If these are needed features, please use the OTLP | ||
// exporter instead. | ||
package stdoutmetric // import "go.opentelemetry.io/otel/exporters/stdout/stdoutmetric" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
//go:build go1.18 | ||
// +build go1.18 | ||
|
||
package stdoutmetric // import "go.opentelemetry.io/otel/exporters/stdout/stdoutmetric" | ||
|
||
import "errors" | ||
|
||
// Encoder encodes and outputs OpenTelemetry metric data-types as human | ||
// readable text. | ||
type Encoder interface { | ||
// Encode handles the encoding and writing of OpenTelemetry metric data. | ||
Encode(v any) error | ||
} | ||
|
||
// encoderHolder is the concrete type used to wrap an Encoder so it can be | ||
// used as a atomic.Value type. | ||
type encoderHolder struct { | ||
encoder Encoder | ||
} | ||
|
||
func (e encoderHolder) Encode(v any) error { return e.encoder.Encode(v) } | ||
|
||
// shutdownEncoder is used when the exporter is shutdown. It always returns | ||
// errShutdown when Encode is called. | ||
type shutdownEncoder struct{} | ||
|
||
var errShutdown = errors.New("exporter shutdown") | ||
|
||
func (shutdownEncoder) Encode(any) error { return errShutdown } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,236 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
//go:build go1.18 | ||
// +build go1.18 | ||
|
||
package stdoutmetric_test | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"os" | ||
"time" | ||
|
||
"go.opentelemetry.io/otel/attribute" | ||
"go.opentelemetry.io/otel/exporters/stdout/stdoutmetric" | ||
"go.opentelemetry.io/otel/metric/unit" | ||
"go.opentelemetry.io/otel/sdk/instrumentation" | ||
"go.opentelemetry.io/otel/sdk/metric" | ||
"go.opentelemetry.io/otel/sdk/metric/metricdata" | ||
"go.opentelemetry.io/otel/sdk/resource" | ||
semconv "go.opentelemetry.io/otel/semconv/v1.10.0" | ||
) | ||
|
||
var ( | ||
// Sat Jan 01 2000 00:00:00 GMT+0000. | ||
now = time.Date(2000, time.January, 01, 0, 0, 0, 0, time.FixedZone("GMT", 0)) | ||
|
||
res = resource.NewSchemaless( | ||
semconv.ServiceNameKey.String("stdoutmetric-example"), | ||
) | ||
|
||
mockData = metricdata.ResourceMetrics{ | ||
Resource: res, | ||
ScopeMetrics: []metricdata.ScopeMetrics{ | ||
{ | ||
Scope: instrumentation.Scope{Name: "example", Version: "v0.0.1"}, | ||
Metrics: []metricdata.Metrics{ | ||
{ | ||
Name: "requests", | ||
Description: "Number of requests received", | ||
Unit: unit.Dimensionless, | ||
Data: metricdata.Sum[int64]{ | ||
IsMonotonic: true, | ||
Temporality: metricdata.DeltaTemporality, | ||
DataPoints: []metricdata.DataPoint[int64]{ | ||
{ | ||
Attributes: attribute.NewSet(attribute.String("server", "central")), | ||
StartTime: now, | ||
Time: now.Add(1 * time.Second), | ||
Value: 5, | ||
}, | ||
}, | ||
}, | ||
}, | ||
{ | ||
Name: "latency", | ||
Description: "Time spend processing received requests", | ||
Unit: unit.Milliseconds, | ||
Data: metricdata.Histogram{ | ||
Temporality: metricdata.DeltaTemporality, | ||
DataPoints: []metricdata.HistogramDataPoint{ | ||
{ | ||
Attributes: attribute.NewSet(attribute.String("server", "central")), | ||
StartTime: now, | ||
Time: now.Add(1 * time.Second), | ||
Count: 10, | ||
Bounds: []float64{1, 5, 10}, | ||
BucketCounts: []uint64{1, 3, 6, 0}, | ||
Sum: 57, | ||
}, | ||
}, | ||
}, | ||
}, | ||
{ | ||
Name: "temperature", | ||
Description: "CPU global temperature", | ||
Unit: unit.Unit("cel(1 K)"), | ||
Data: metricdata.Gauge[float64]{ | ||
DataPoints: []metricdata.DataPoint[float64]{ | ||
{ | ||
Attributes: attribute.NewSet(attribute.String("server", "central")), | ||
Time: now.Add(1 * time.Second), | ||
Value: 32.4, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
) | ||
|
||
func Example() { | ||
// Print with a JSON encoder that indents with two spaces. | ||
enc := json.NewEncoder(os.Stdout) | ||
enc.SetIndent("", " ") | ||
exp, err := stdoutmetric.New(stdoutmetric.WithEncoder(enc)) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
// Register the exporter with an SDK via a periodic reader. | ||
sdk := metric.NewMeterProvider( | ||
metric.WithResource(res), | ||
metric.WithReader(metric.NewPeriodicReader(exp)), | ||
) | ||
|
||
ctx := context.Background() | ||
// This is where the sdk would be used to create a Meter and from that | ||
// instruments that would make measurments of your code. To simulate that | ||
// behavior, call export directly with mocked data. | ||
_ = exp.Export(ctx, mockData) | ||
|
||
// Ensure the periodic reader is cleaned up by shutting down the sdk. | ||
_ = sdk.Shutdown(ctx) | ||
|
||
// Output: | ||
// { | ||
// "Resource": [ | ||
// { | ||
// "Key": "service.name", | ||
// "Value": { | ||
// "Type": "STRING", | ||
// "Value": "stdoutmetric-example" | ||
// } | ||
// } | ||
// ], | ||
// "ScopeMetrics": [ | ||
// { | ||
// "Scope": { | ||
// "Name": "example", | ||
// "Version": "v0.0.1" | ||
// }, | ||
// "Metrics": [ | ||
// { | ||
// "Name": "requests", | ||
// "Description": "Number of requests received", | ||
// "Unit": "1", | ||
// "Data": { | ||
// "DataPoints": [ | ||
// { | ||
// "Attributes": [ | ||
// { | ||
// "Key": "server", | ||
// "Value": { | ||
// "Type": "STRING", | ||
// "Value": "central" | ||
// } | ||
// } | ||
// ], | ||
// "StartTime": "2000-01-01T00:00:00Z", | ||
// "Time": "2000-01-01T00:00:01Z", | ||
// "Value": 5 | ||
// } | ||
// ], | ||
// "Temporality": "DeltaTemporality", | ||
// "IsMonotonic": true | ||
// } | ||
// }, | ||
// { | ||
// "Name": "latency", | ||
// "Description": "Time spend processing received requests", | ||
// "Unit": "ms", | ||
// "Data": { | ||
// "DataPoints": [ | ||
// { | ||
// "Attributes": [ | ||
// { | ||
// "Key": "server", | ||
// "Value": { | ||
// "Type": "STRING", | ||
// "Value": "central" | ||
// } | ||
// } | ||
// ], | ||
// "StartTime": "2000-01-01T00:00:00Z", | ||
// "Time": "2000-01-01T00:00:01Z", | ||
// "Count": 10, | ||
// "Bounds": [ | ||
// 1, | ||
// 5, | ||
// 10 | ||
// ], | ||
// "BucketCounts": [ | ||
// 1, | ||
// 3, | ||
// 6, | ||
// 0 | ||
// ], | ||
// "Sum": 57 | ||
// } | ||
// ], | ||
// "Temporality": "DeltaTemporality" | ||
// } | ||
// }, | ||
// { | ||
// "Name": "temperature", | ||
// "Description": "CPU global temperature", | ||
// "Unit": "cel(1 K)", | ||
// "Data": { | ||
// "DataPoints": [ | ||
// { | ||
// "Attributes": [ | ||
// { | ||
// "Key": "server", | ||
// "Value": { | ||
// "Type": "STRING", | ||
// "Value": "central" | ||
// } | ||
// } | ||
// ], | ||
// "StartTime": "0001-01-01T00:00:00Z", | ||
// "Time": "2000-01-01T00:00:01Z", | ||
// "Value": 32.4 | ||
// } | ||
// ] | ||
// } | ||
// } | ||
// ] | ||
// } | ||
// ] | ||
// } | ||
} |
Oops, something went wrong.