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 all commits
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
65 changes: 65 additions & 0 deletions exporters/stdout/stdoutmetric/config.go
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
})
}
23 changes: 23 additions & 0 deletions exporters/stdout/stdoutmetric/doc.go
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"
43 changes: 43 additions & 0 deletions exporters/stdout/stdoutmetric/encoder.go
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 }
236 changes: 236 additions & 0 deletions exporters/stdout/stdoutmetric/example_test.go
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
// }
// ]
// }
// }
// ]
// }
// ]
// }
}
Loading