You've already forked opentelemetry-go
mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-07-03 00:27:03 +02:00
Add and refine metrics examples (#4504)
This commit is contained in:
@ -30,7 +30,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
instrumentationName = "github.com/instrumentron"
|
instrumentationName = "github.com/instrumentron"
|
||||||
instrumentationVersion = "v0.1.0"
|
instrumentationVersion = "0.1.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -41,7 +41,7 @@ var (
|
|||||||
Resource: res,
|
Resource: res,
|
||||||
ScopeMetrics: []metricdata.ScopeMetrics{
|
ScopeMetrics: []metricdata.ScopeMetrics{
|
||||||
{
|
{
|
||||||
Scope: instrumentation.Scope{Name: "example", Version: "v0.0.1"},
|
Scope: instrumentation.Scope{Name: "example", Version: "0.0.1"},
|
||||||
Metrics: []metricdata.Metrics{
|
Metrics: []metricdata.Metrics{
|
||||||
{
|
{
|
||||||
Name: "requests",
|
Name: "requests",
|
||||||
@ -173,7 +173,7 @@ func Example() {
|
|||||||
// {
|
// {
|
||||||
// "Scope": {
|
// "Scope": {
|
||||||
// "Name": "example",
|
// "Name": "example",
|
||||||
// "Version": "v0.0.1",
|
// "Version": "0.0.1",
|
||||||
// "SchemaURL": ""
|
// "SchemaURL": ""
|
||||||
// },
|
// },
|
||||||
// "Metrics": [
|
// "Metrics": [
|
||||||
|
@ -29,7 +29,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
instrumentationName = "github.com/instrumentron"
|
instrumentationName = "github.com/instrumentron"
|
||||||
instrumentationVersion = "v0.1.0"
|
instrumentationVersion = "0.1.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -16,18 +16,23 @@ package metric_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.opentelemetry.io/otel"
|
"go.opentelemetry.io/otel"
|
||||||
"go.opentelemetry.io/otel/attribute"
|
"go.opentelemetry.io/otel/attribute"
|
||||||
"go.opentelemetry.io/otel/metric"
|
"go.opentelemetry.io/otel/metric"
|
||||||
|
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var meter = otel.Meter("my-service-meter")
|
||||||
|
|
||||||
func ExampleMeter_synchronous() {
|
func ExampleMeter_synchronous() {
|
||||||
// Create a histogram using the global MeterProvider.
|
// Create a histogram using the global MeterProvider.
|
||||||
workDuration, err := otel.Meter("go.opentelemetry.io/otel/metric#SyncExample").Int64Histogram(
|
workDuration, err := meter.Int64Histogram(
|
||||||
"workDuration",
|
"workDuration",
|
||||||
metric.WithUnit("ms"))
|
metric.WithUnit("ms"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -43,8 +48,6 @@ func ExampleMeter_synchronous() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ExampleMeter_asynchronous_single() {
|
func ExampleMeter_asynchronous_single() {
|
||||||
meter := otel.Meter("go.opentelemetry.io/otel/metric#AsyncExample")
|
|
||||||
|
|
||||||
_, err := meter.Int64ObservableGauge(
|
_, err := meter.Int64ObservableGauge(
|
||||||
"DiskUsage",
|
"DiskUsage",
|
||||||
metric.WithUnit("By"),
|
metric.WithUnit("By"),
|
||||||
@ -73,8 +76,6 @@ func ExampleMeter_asynchronous_single() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ExampleMeter_asynchronous_multiple() {
|
func ExampleMeter_asynchronous_multiple() {
|
||||||
meter := otel.Meter("go.opentelemetry.io/otel/metric#MultiAsyncExample")
|
|
||||||
|
|
||||||
// This is just a sample of memory stats to record from the Memstats
|
// This is just a sample of memory stats to record from the Memstats
|
||||||
heapAlloc, err := meter.Int64ObservableUpDownCounter("heapAllocs")
|
heapAlloc, err := meter.Int64ObservableUpDownCounter("heapAllocs")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -106,3 +107,175 @@ func ExampleMeter_asynchronous_multiple() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Counters can be used to measure a non-negative, increasing value.
|
||||||
|
//
|
||||||
|
// Here's how you might report the number of calls for an HTTP handler.
|
||||||
|
func ExampleMeter_counter() {
|
||||||
|
apiCounter, err := meter.Int64Counter(
|
||||||
|
"api.counter",
|
||||||
|
metric.WithDescription("Number of API calls."),
|
||||||
|
metric.WithUnit("{call}"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
apiCounter.Add(r.Context(), 1)
|
||||||
|
|
||||||
|
// do some work in an API call
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpDown counters can increment and decrement, allowing you to observe
|
||||||
|
// a cumulative value that goes up or down.
|
||||||
|
//
|
||||||
|
// Here's how you might report the number of items of some collection.
|
||||||
|
func ExampleMeter_upDownCounter() {
|
||||||
|
var err error
|
||||||
|
itemsCounter, err := meter.Int64UpDownCounter(
|
||||||
|
"items.counter",
|
||||||
|
metric.WithDescription("Number of items."),
|
||||||
|
metric.WithUnit("{item}"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = func() {
|
||||||
|
// code that adds an item to the collection
|
||||||
|
itemsCounter.Add(context.Background(), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = func() {
|
||||||
|
// code that removes an item from the collection
|
||||||
|
itemsCounter.Add(context.Background(), -1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Histograms are used to measure a distribution of values over time.
|
||||||
|
//
|
||||||
|
// Here's how you might report a distribution of response times for an HTTP handler.
|
||||||
|
func ExampleMeter_histogram() {
|
||||||
|
histogram, err := meter.Float64Histogram(
|
||||||
|
"task.duration",
|
||||||
|
metric.WithDescription("The duration of task execution."),
|
||||||
|
metric.WithUnit("s"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
// do some work in an API call
|
||||||
|
|
||||||
|
duration := time.Since(start)
|
||||||
|
histogram.Record(r.Context(), duration.Seconds())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Observable counters can be used to measure an additive, non-negative,
|
||||||
|
// monotonically increasing value.
|
||||||
|
//
|
||||||
|
// Here's how you might report time since the application started.
|
||||||
|
func ExampleMeter_observableCounter() {
|
||||||
|
start := time.Now()
|
||||||
|
if _, err := meter.Float64ObservableCounter(
|
||||||
|
"uptime",
|
||||||
|
metric.WithDescription("The duration since the application started."),
|
||||||
|
metric.WithUnit("s"),
|
||||||
|
metric.WithFloat64Callback(func(_ context.Context, o metric.Float64Observer) error {
|
||||||
|
o.Observe(float64(time.Since(start).Seconds()))
|
||||||
|
return nil
|
||||||
|
}),
|
||||||
|
); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Observable UpDown counters can increment and decrement, allowing you to measure
|
||||||
|
// an additive, non-negative, non-monotonically increasing cumulative value.
|
||||||
|
//
|
||||||
|
// Here's how you might report some database metrics.
|
||||||
|
func ExampleMeter_observableUpDownCounter() {
|
||||||
|
// The function registers asynchronous metrics for the provided db.
|
||||||
|
// Make sure to unregister metric.Registration before closing the provided db.
|
||||||
|
_ = func(db *sql.DB, meter metric.Meter, poolName string) (metric.Registration, error) {
|
||||||
|
max, err := meter.Int64ObservableUpDownCounter(
|
||||||
|
"db.client.connections.max",
|
||||||
|
metric.WithDescription("The maximum number of open connections allowed."),
|
||||||
|
metric.WithUnit("{connection}"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
waitTime, err := meter.Int64ObservableUpDownCounter(
|
||||||
|
"db.client.connections.wait_time",
|
||||||
|
metric.WithDescription("The time it took to obtain an open connection from the pool."),
|
||||||
|
metric.WithUnit("ms"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
reg, err := meter.RegisterCallback(
|
||||||
|
func(_ context.Context, o metric.Observer) error {
|
||||||
|
stats := db.Stats()
|
||||||
|
o.ObserveInt64(max, int64(stats.MaxOpenConnections))
|
||||||
|
o.ObserveInt64(waitTime, int64(stats.WaitDuration))
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
max,
|
||||||
|
waitTime,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return reg, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Observable Gauges should be used to measure non-additive values.
|
||||||
|
//
|
||||||
|
// Here's how you might report memory usage of the heap objects used
|
||||||
|
// in application.
|
||||||
|
func ExampleMeter_observableGauge() {
|
||||||
|
if _, err := meter.Int64ObservableGauge(
|
||||||
|
"memory.heap",
|
||||||
|
metric.WithDescription(
|
||||||
|
"Memory usage of the allocated heap objects.",
|
||||||
|
),
|
||||||
|
metric.WithUnit("By"),
|
||||||
|
metric.WithInt64Callback(func(_ context.Context, o metric.Int64Observer) error {
|
||||||
|
var m runtime.MemStats
|
||||||
|
runtime.ReadMemStats(&m)
|
||||||
|
o.Observe(int64(m.HeapAlloc))
|
||||||
|
return nil
|
||||||
|
}),
|
||||||
|
); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// You can add Attributes by using the [WithAttributeSet] and [WithAttributes] options.
|
||||||
|
//
|
||||||
|
// Here's how you might add the HTTP status code attribute to your recordings.
|
||||||
|
func ExampleMeter_attributes() {
|
||||||
|
apiCounter, err := meter.Int64UpDownCounter(
|
||||||
|
"api.finished.counter",
|
||||||
|
metric.WithDescription("Number of finished API calls."),
|
||||||
|
metric.WithUnit("{call}"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// do some work in an API call and set the response HTTP status code
|
||||||
|
statusCode := http.StatusOK
|
||||||
|
|
||||||
|
apiCounter.Add(r.Context(), 1,
|
||||||
|
metric.WithAttributes(semconv.HTTPStatusCode(statusCode)))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
// Package metric provides an implementation of the OpenTelemetry metric SDK.
|
// Package metric provides an implementation of the OpenTelemetry metrics SDK.
|
||||||
//
|
//
|
||||||
// See https://opentelemetry.io/docs/concepts/signals/metrics/ for information
|
// See https://opentelemetry.io/docs/concepts/signals/metrics/ for information
|
||||||
// about the concept of OpenTelemetry metrics and
|
// about the concept of OpenTelemetry metrics and
|
||||||
@ -27,8 +27,8 @@
|
|||||||
// A MeterProvider needs to be configured to export the measured data, this is
|
// A MeterProvider needs to be configured to export the measured data, this is
|
||||||
// done by configuring it with a Reader implementation (using the WithReader
|
// done by configuring it with a Reader implementation (using the WithReader
|
||||||
// MeterProviderOption). Readers take two forms: ones that push to an endpoint
|
// MeterProviderOption). Readers take two forms: ones that push to an endpoint
|
||||||
// (NewPeriodicReader), and ones that an endpoint pulls from. See the
|
// (NewPeriodicReader), and ones that an endpoint pulls from. See
|
||||||
// go.opentelemetry.io/otel/exporters package for exporters that can be used as
|
// [go.opentelemetry.io/otel/exporters] for exporters that can be used as
|
||||||
// or with these Readers.
|
// or with these Readers.
|
||||||
//
|
//
|
||||||
// Each Reader, when registered with the MeterProvider, can be augmented with a
|
// Each Reader, when registered with the MeterProvider, can be augmented with a
|
||||||
@ -41,4 +41,7 @@
|
|||||||
// should be used to describe the unique runtime environment instrumented code
|
// should be used to describe the unique runtime environment instrumented code
|
||||||
// is being run on. That way when multiple instances of the code are collected
|
// is being run on. That way when multiple instances of the code are collected
|
||||||
// at a single endpoint their origin is decipherable.
|
// at a single endpoint their origin is decipherable.
|
||||||
|
//
|
||||||
|
// See [go.opentelemetry.io/otel/metric] for more information about
|
||||||
|
// the metric API.
|
||||||
package metric // import "go.opentelemetry.io/otel/sdk/metric"
|
package metric // import "go.opentelemetry.io/otel/sdk/metric"
|
||||||
|
@ -16,45 +16,207 @@ package metric_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
"go.opentelemetry.io/otel"
|
"go.opentelemetry.io/otel"
|
||||||
|
"go.opentelemetry.io/otel/sdk/instrumentation"
|
||||||
"go.opentelemetry.io/otel/sdk/metric"
|
"go.opentelemetry.io/otel/sdk/metric"
|
||||||
"go.opentelemetry.io/otel/sdk/resource"
|
"go.opentelemetry.io/otel/sdk/resource"
|
||||||
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
|
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// To enable metrics in your application using the SDK,
|
||||||
|
// you'll need to have an initialized [MeterProvider]
|
||||||
|
// that will let you create a [go.opentelemetry.io/otel/metric.Meter].
|
||||||
|
//
|
||||||
|
// Here's how you might initialize a metrics provider.
|
||||||
func Example() {
|
func Example() {
|
||||||
|
// See [go.opentelemetry.io/otel/sdk/resource] for more
|
||||||
|
// information about how to create and use resources.
|
||||||
|
res, err := resource.Merge(resource.Default(),
|
||||||
|
resource.NewWithAttributes(semconv.SchemaURL,
|
||||||
|
semconv.ServiceName("my-service"),
|
||||||
|
semconv.ServiceVersion("0.1.0"),
|
||||||
|
))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
// This reader is used as a stand-in for a reader that will actually export
|
// This reader is used as a stand-in for a reader that will actually export
|
||||||
// data. See exporters in the go.opentelemetry.io/otel/exporters package
|
// data. See [go.opentelemetry.io/otel/exporters] for exporters
|
||||||
// for more information.
|
// that can be used as or with readers.
|
||||||
reader := metric.NewManualReader()
|
reader := metric.NewManualReader()
|
||||||
|
|
||||||
// See the go.opentelemetry.io/otel/sdk/resource package for more
|
// Create a meter provider.
|
||||||
// information about how to create and use Resources.
|
// You can pass this instance directly to your instrumented code if it
|
||||||
res := resource.NewWithAttributes(
|
// accepts a MeterProvider instance.
|
||||||
semconv.SchemaURL,
|
|
||||||
semconv.ServiceName("my-service"),
|
|
||||||
semconv.ServiceVersion("v0.1.0"),
|
|
||||||
)
|
|
||||||
|
|
||||||
meterProvider := metric.NewMeterProvider(
|
meterProvider := metric.NewMeterProvider(
|
||||||
metric.WithResource(res),
|
metric.WithResource(res),
|
||||||
metric.WithReader(reader),
|
metric.WithReader(reader),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Register as global meter provider so that it can
|
||||||
|
// that can used via [go.opentelemetry.io/otel.Meter]
|
||||||
|
// and accessed using [go.opentelemetry.io/otel.GetMeterProvider].
|
||||||
|
// Most instrumentation libraries use the global meter provider as default.
|
||||||
|
// If the global meter provider is not set then a no-op implementation
|
||||||
|
// is used and which fails to generate data.
|
||||||
otel.SetMeterProvider(meterProvider)
|
otel.SetMeterProvider(meterProvider)
|
||||||
|
|
||||||
|
// Handle shutdown properly so that nothing leaks.
|
||||||
defer func() {
|
defer func() {
|
||||||
err := meterProvider.Shutdown(context.Background())
|
err := meterProvider.Shutdown(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
// The MeterProvider is configured and registered globally. You can now run
|
}
|
||||||
// your code instrumented with the OpenTelemetry API that uses the global
|
|
||||||
// MeterProvider without having to pass this MeterProvider instance. Or,
|
func ExampleView() {
|
||||||
// you can pass this instance directly to your instrumented code if it
|
// The NewView function provides convenient creation of common Views
|
||||||
// accepts a MeterProvider instance.
|
// construction. However, it is limited in what it can create.
|
||||||
//
|
//
|
||||||
// See the go.opentelemetry.io/otel/metric package for more information
|
// When NewView is not able to provide the functionally needed, a custom
|
||||||
// about the metric API.
|
// View can be constructed directly. Here a custom View is constructed that
|
||||||
|
// uses Go's regular expression matching to ensure all data stream names
|
||||||
|
// have a suffix of the units it uses.
|
||||||
|
|
||||||
|
re := regexp.MustCompile(`[._](ms|byte)$`)
|
||||||
|
var view metric.View = func(i metric.Instrument) (metric.Stream, bool) {
|
||||||
|
s := metric.Stream{Name: i.Name, Description: i.Description, Unit: i.Unit}
|
||||||
|
// Any instrument that does not have a unit suffix defined, but has a
|
||||||
|
// dimensional unit defined, update the name with a unit suffix.
|
||||||
|
if re.MatchString(i.Name) {
|
||||||
|
return s, false
|
||||||
|
}
|
||||||
|
switch i.Unit {
|
||||||
|
case "ms":
|
||||||
|
s.Name += ".ms"
|
||||||
|
case "By":
|
||||||
|
s.Name += ".byte"
|
||||||
|
default:
|
||||||
|
return s, false
|
||||||
|
}
|
||||||
|
return s, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// The created view can then be registered with the OpenTelemetry metric
|
||||||
|
// SDK using the WithView option.
|
||||||
|
_ = metric.NewMeterProvider(
|
||||||
|
metric.WithView(view),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Below is an example of how the view will
|
||||||
|
// function in the SDK for certain instruments.
|
||||||
|
stream, _ := view(metric.Instrument{
|
||||||
|
Name: "computation.time.ms",
|
||||||
|
Unit: "ms",
|
||||||
|
})
|
||||||
|
fmt.Println("name:", stream.Name)
|
||||||
|
|
||||||
|
stream, _ = view(metric.Instrument{
|
||||||
|
Name: "heap.size",
|
||||||
|
Unit: "By",
|
||||||
|
})
|
||||||
|
fmt.Println("name:", stream.Name)
|
||||||
|
// Output:
|
||||||
|
// name: computation.time.ms
|
||||||
|
// name: heap.size.byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleNewView() {
|
||||||
|
// Create a view that renames the "latency" instrument from the v0.34.0
|
||||||
|
// version of the "http" instrumentation library as "request.latency".
|
||||||
|
view := metric.NewView(metric.Instrument{
|
||||||
|
Name: "latency",
|
||||||
|
Scope: instrumentation.Scope{
|
||||||
|
Name: "http",
|
||||||
|
Version: "0.34.0",
|
||||||
|
},
|
||||||
|
}, metric.Stream{Name: "request.latency"})
|
||||||
|
|
||||||
|
// The created view can then be registered with the OpenTelemetry metric
|
||||||
|
// SDK using the WithView option.
|
||||||
|
_ = metric.NewMeterProvider(
|
||||||
|
metric.WithView(view),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Below is an example of how the view will
|
||||||
|
// function in the SDK for certain instruments.
|
||||||
|
stream, _ := view(metric.Instrument{
|
||||||
|
Name: "latency",
|
||||||
|
Description: "request latency",
|
||||||
|
Unit: "ms",
|
||||||
|
Kind: metric.InstrumentKindCounter,
|
||||||
|
Scope: instrumentation.Scope{
|
||||||
|
Name: "http",
|
||||||
|
Version: "0.34.0",
|
||||||
|
SchemaURL: "https://opentelemetry.io/schemas/1.0.0",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
fmt.Println("name:", stream.Name)
|
||||||
|
fmt.Println("description:", stream.Description)
|
||||||
|
fmt.Println("unit:", stream.Unit)
|
||||||
|
// Output:
|
||||||
|
// name: request.latency
|
||||||
|
// description: request latency
|
||||||
|
// unit: ms
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleNewView_drop() {
|
||||||
|
// Create a view that sets the drop aggregator for all instrumentation from
|
||||||
|
// the "db" library, effectively turning-off all instrumentation from that
|
||||||
|
// library.
|
||||||
|
view := metric.NewView(
|
||||||
|
metric.Instrument{Scope: instrumentation.Scope{Name: "db"}},
|
||||||
|
metric.Stream{Aggregation: metric.AggregationDrop{}},
|
||||||
|
)
|
||||||
|
|
||||||
|
// The created view can then be registered with the OpenTelemetry metric
|
||||||
|
// SDK using the WithView option.
|
||||||
|
_ = metric.NewMeterProvider(
|
||||||
|
metric.WithView(view),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Below is an example of how the view will
|
||||||
|
// function in the SDK for certain instruments.
|
||||||
|
stream, _ := view(metric.Instrument{
|
||||||
|
Name: "queries",
|
||||||
|
Kind: metric.InstrumentKindCounter,
|
||||||
|
Scope: instrumentation.Scope{Name: "db", Version: "v0.4.0"},
|
||||||
|
})
|
||||||
|
fmt.Println("name:", stream.Name)
|
||||||
|
fmt.Printf("aggregation: %#v", stream.Aggregation)
|
||||||
|
// Output:
|
||||||
|
// name: queries
|
||||||
|
// aggregation: metric.AggregationDrop{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleNewView_wildcard() {
|
||||||
|
// Create a view that sets unit to milliseconds for any instrument with a
|
||||||
|
// name suffix of ".ms".
|
||||||
|
view := metric.NewView(
|
||||||
|
metric.Instrument{Name: "*.ms"},
|
||||||
|
metric.Stream{Unit: "ms"},
|
||||||
|
)
|
||||||
|
|
||||||
|
// The created view can then be registered with the OpenTelemetry metric
|
||||||
|
// SDK using the WithView option.
|
||||||
|
_ = metric.NewMeterProvider(
|
||||||
|
metric.WithView(view),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Below is an example of how the view will
|
||||||
|
// function in the SDK for certain instruments.
|
||||||
|
stream, _ := view(metric.Instrument{
|
||||||
|
Name: "computation.time.ms",
|
||||||
|
Unit: "1",
|
||||||
|
})
|
||||||
|
fmt.Println("name:", stream.Name)
|
||||||
|
fmt.Println("unit:", stream.Unit)
|
||||||
|
// Output:
|
||||||
|
// name: computation.time.ms
|
||||||
|
// unit: ms
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,6 @@
|
|||||||
package metric // import "go.opentelemetry.io/otel/sdk/metric"
|
package metric // import "go.opentelemetry.io/otel/sdk/metric"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
@ -493,134 +491,3 @@ func TestNewViewMultiInstMatchErrorLogged(t *testing.T) {
|
|||||||
})
|
})
|
||||||
assert.Contains(t, got, errMultiInst.Error())
|
assert.Contains(t, got, errMultiInst.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExampleNewView() {
|
|
||||||
// Create a view that renames the "latency" instrument from the v0.34.0
|
|
||||||
// version of the "http" instrumentation library as "request.latency".
|
|
||||||
view := NewView(Instrument{
|
|
||||||
Name: "latency",
|
|
||||||
Scope: instrumentation.Scope{
|
|
||||||
Name: "http",
|
|
||||||
Version: "v0.34.0",
|
|
||||||
},
|
|
||||||
}, Stream{Name: "request.latency"})
|
|
||||||
|
|
||||||
// The created view can then be registered with the OpenTelemetry metric
|
|
||||||
// SDK using the WithView option. Below is an example of how the view will
|
|
||||||
// function in the SDK for certain instruments.
|
|
||||||
|
|
||||||
stream, _ := view(Instrument{
|
|
||||||
Name: "latency",
|
|
||||||
Description: "request latency",
|
|
||||||
Unit: "ms",
|
|
||||||
Kind: InstrumentKindCounter,
|
|
||||||
Scope: instrumentation.Scope{
|
|
||||||
Name: "http",
|
|
||||||
Version: "v0.34.0",
|
|
||||||
SchemaURL: "https://opentelemetry.io/schemas/1.0.0",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
fmt.Println("name:", stream.Name)
|
|
||||||
fmt.Println("description:", stream.Description)
|
|
||||||
fmt.Println("unit:", stream.Unit)
|
|
||||||
// Output:
|
|
||||||
// name: request.latency
|
|
||||||
// description: request latency
|
|
||||||
// unit: ms
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleNewView_drop() {
|
|
||||||
// Create a view that sets the drop aggregator for all instrumentation from
|
|
||||||
// the "db" library, effectively turning-off all instrumentation from that
|
|
||||||
// library.
|
|
||||||
view := NewView(
|
|
||||||
Instrument{Scope: instrumentation.Scope{Name: "db"}},
|
|
||||||
Stream{Aggregation: AggregationDrop{}},
|
|
||||||
)
|
|
||||||
|
|
||||||
// The created view can then be registered with the OpenTelemetry metric
|
|
||||||
// SDK using the WithView option. Below is an example of how the view will
|
|
||||||
// function in the SDK for certain instruments.
|
|
||||||
|
|
||||||
stream, _ := view(Instrument{
|
|
||||||
Name: "queries",
|
|
||||||
Kind: InstrumentKindCounter,
|
|
||||||
Scope: instrumentation.Scope{Name: "db", Version: "v0.4.0"},
|
|
||||||
})
|
|
||||||
fmt.Println("name:", stream.Name)
|
|
||||||
fmt.Printf("aggregation: %#v", stream.Aggregation)
|
|
||||||
// Output:
|
|
||||||
// name: queries
|
|
||||||
// aggregation: metric.AggregationDrop{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleNewView_wildcard() {
|
|
||||||
// Create a view that sets unit to milliseconds for any instrument with a
|
|
||||||
// name suffix of ".ms".
|
|
||||||
view := NewView(
|
|
||||||
Instrument{Name: "*.ms"},
|
|
||||||
Stream{Unit: "ms"},
|
|
||||||
)
|
|
||||||
|
|
||||||
// The created view can then be registered with the OpenTelemetry metric
|
|
||||||
// SDK using the WithView option. Below is an example of how the view
|
|
||||||
// function in the SDK for certain instruments.
|
|
||||||
|
|
||||||
stream, _ := view(Instrument{
|
|
||||||
Name: "computation.time.ms",
|
|
||||||
Unit: "1",
|
|
||||||
})
|
|
||||||
fmt.Println("name:", stream.Name)
|
|
||||||
fmt.Println("unit:", stream.Unit)
|
|
||||||
// Output:
|
|
||||||
// name: computation.time.ms
|
|
||||||
// unit: ms
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleView() {
|
|
||||||
// The NewView function provides convenient creation of common Views
|
|
||||||
// construction. However, it is limited in what it can create.
|
|
||||||
//
|
|
||||||
// When NewView is not able to provide the functionally needed, a custom
|
|
||||||
// View can be constructed directly. Here a custom View is constructed that
|
|
||||||
// uses Go's regular expression matching to ensure all data stream names
|
|
||||||
// have a suffix of the units it uses.
|
|
||||||
|
|
||||||
re := regexp.MustCompile(`[._](ms|byte)$`)
|
|
||||||
var view View = func(i Instrument) (Stream, bool) {
|
|
||||||
s := Stream{Name: i.Name, Description: i.Description, Unit: i.Unit}
|
|
||||||
// Any instrument that does not have a unit suffix defined, but has a
|
|
||||||
// dimensional unit defined, update the name with a unit suffix.
|
|
||||||
if re.MatchString(i.Name) {
|
|
||||||
return s, false
|
|
||||||
}
|
|
||||||
switch i.Unit {
|
|
||||||
case "ms":
|
|
||||||
s.Name += ".ms"
|
|
||||||
case "By":
|
|
||||||
s.Name += ".byte"
|
|
||||||
default:
|
|
||||||
return s, false
|
|
||||||
}
|
|
||||||
return s, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// The created view can then be registered with the OpenTelemetry metric
|
|
||||||
// SDK using the WithView option. Below is an example of how the view will
|
|
||||||
// function in the SDK for certain instruments.
|
|
||||||
|
|
||||||
stream, _ := view(Instrument{
|
|
||||||
Name: "computation.time.ms",
|
|
||||||
Unit: "ms",
|
|
||||||
})
|
|
||||||
fmt.Println("name:", stream.Name)
|
|
||||||
|
|
||||||
stream, _ = view(Instrument{
|
|
||||||
Name: "heap.size",
|
|
||||||
Unit: "By",
|
|
||||||
})
|
|
||||||
fmt.Println("name:", stream.Name)
|
|
||||||
// Output:
|
|
||||||
// name: computation.time.ms
|
|
||||||
// name: heap.size.byte
|
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user