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

Add back the stdoutmetric exporter #3057

Merged
merged 22 commits into from
Aug 4, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,15 @@ updates:
schedule:
interval: weekly
day: sunday
- package-ecosystem: gomod
directory: /exporters/stdout/stdoutmetric
labels:
- dependencies
- go
- Skip Changelog
schedule:
interval: weekly
day: sunday
- package-ecosystem: gomod
directory: /exporters/stdout/stdouttrace
labels:
Expand Down
66 changes: 66 additions & 0 deletions exporters/stdout/stdoutmetric/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// 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 (
"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, error) {
MrAlias marked this conversation as resolved.
Show resolved Hide resolved
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, nil
}

// 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 ecoder 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
})
}
22 changes: 22 additions & 0 deletions exporters/stdout/stdoutmetric/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// 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 an
// exporter meant for production use. Additionally, it does not provide an
// interchange format for OpenTelemetry that is supported with any stability
// or compatibility guarantees. Please use the OTLP instead.
package stdoutmetric // import "go.opentelemetry.io/otel/exporters/stdout/stdoutmetric"
49 changes: 49 additions & 0 deletions exporters/stdout/stdoutmetric/encoder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// 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 "errors"

var ErrUnrecognized = errors.New("unrecognized metric data")

// Encoder encodes and outputs OpenTelemetry metric data-types as human
// readable text.
type Encoder interface {
// Encode handles the encoding and writing OpenTelemetry metric data-types
// that the exporter will pass to it.
//
// Any data-type that is not recognized by the encoder and not output to
// the user, will have an ErrUnrecognized returned from Encode.
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 }
220 changes: 220 additions & 0 deletions exporters/stdout/stdoutmetric/example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
// 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/metricdata"
"go.opentelemetry.io/otel/sdk/resource"
semconv "go.opentelemetry.io/otel/semconv/v1.10.0"
)

// Sat Jan 01 2000 00:00:00 GMT+0000.
var now = time.Unix(946684800, 0)

var mockData = metricdata.ResourceMetrics{
Resource: resource.NewSchemaless(semconv.ServiceNameKey.String("stdoutmetric-example")),
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)
}
// FIXME: The exporter should be registered with an SDK and the output
// should come from that.
exp.Export(context.Background(), mockData)

// 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": "1999-12-31T16:00:00-08:00",
// "Time": "1999-12-31T16:00:01-08:00",
// "Value": 5
// }
// ],
// "Temporality": "delta",
// "IsMonotonic": true
// }
// },
// {
// "Name": "latency",
// "Description": "Time spend processing received requests",
// "Unit": "ms",
// "Data": {
// "DataPoints": [
// {
// "Attributes": [
// {
// "Key": "server",
// "Value": {
// "Type": "STRING",
// "Value": "central"
// }
// }
// ],
// "StartTime": "1999-12-31T16:00:00-08:00",
// "Time": "1999-12-31T16:00:01-08:00",
// "Count": 10,
// "Bounds": [
// 1,
// 5,
// 10
// ],
// "BucketCounts": [
// 1,
// 3,
// 6,
// 0
// ],
// "Sum": 57
// }
// ],
// "Temporality": "delta"
// }
// },
// {
// "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": "1999-12-31T16:00:01-08:00",
// "Value": 32.4
// }
// ]
// }
// }
// ]
// }
// ]
// }
}
Loading