Skip to content

Commit

Permalink
Add and refine metrics examples (open-telemetry#4504)
Browse files Browse the repository at this point in the history
  • Loading branch information
pellared authored Sep 14, 2023
1 parent bcbee2a commit e3d6c8e
Show file tree
Hide file tree
Showing 7 changed files with 367 additions and 162 deletions.
2 changes: 1 addition & 1 deletion exporters/otlp/otlptrace/otlptracehttp/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (

const (
instrumentationName = "github.com/instrumentron"
instrumentationVersion = "v0.1.0"
instrumentationVersion = "0.1.0"
)

var (
Expand Down
4 changes: 2 additions & 2 deletions exporters/stdout/stdoutmetric/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ var (
Resource: res,
ScopeMetrics: []metricdata.ScopeMetrics{
{
Scope: instrumentation.Scope{Name: "example", Version: "v0.0.1"},
Scope: instrumentation.Scope{Name: "example", Version: "0.0.1"},
Metrics: []metricdata.Metrics{
{
Name: "requests",
Expand Down Expand Up @@ -173,7 +173,7 @@ func Example() {
// {
// "Scope": {
// "Name": "example",
// "Version": "v0.0.1",
// "Version": "0.0.1",
// "SchemaURL": ""
// },
// "Metrics": [
Expand Down
2 changes: 1 addition & 1 deletion exporters/stdout/stdouttrace/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (

const (
instrumentationName = "github.com/instrumentron"
instrumentationVersion = "v0.1.0"
instrumentationVersion = "0.1.0"
)

var (
Expand Down
183 changes: 178 additions & 5 deletions metric/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,23 @@ package metric_test

import (
"context"
"database/sql"
"fmt"
"net/http"
"runtime"
"time"

"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
)

var meter = otel.Meter("my-service-meter")

func ExampleMeter_synchronous() {
// Create a histogram using the global MeterProvider.
workDuration, err := otel.Meter("go.opentelemetry.io/otel/metric#SyncExample").Int64Histogram(
workDuration, err := meter.Int64Histogram(
"workDuration",
metric.WithUnit("ms"))
if err != nil {
Expand All @@ -43,8 +48,6 @@ func ExampleMeter_synchronous() {
}

func ExampleMeter_asynchronous_single() {
meter := otel.Meter("go.opentelemetry.io/otel/metric#AsyncExample")

_, err := meter.Int64ObservableGauge(
"DiskUsage",
metric.WithUnit("By"),
Expand Down Expand Up @@ -73,8 +76,6 @@ func ExampleMeter_asynchronous_single() {
}

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
heapAlloc, err := meter.Int64ObservableUpDownCounter("heapAllocs")
if err != nil {
Expand Down Expand Up @@ -106,3 +107,175 @@ func ExampleMeter_asynchronous_multiple() {
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)))
})
}
9 changes: 6 additions & 3 deletions sdk/metric/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// 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
// about the concept of OpenTelemetry metrics and
Expand All @@ -27,8 +27,8 @@
// A MeterProvider needs to be configured to export the measured data, this is
// done by configuring it with a Reader implementation (using the WithReader
// MeterProviderOption). Readers take two forms: ones that push to an endpoint
// (NewPeriodicReader), and ones that an endpoint pulls from. See the
// go.opentelemetry.io/otel/exporters package for exporters that can be used as
// (NewPeriodicReader), and ones that an endpoint pulls from. See
// [go.opentelemetry.io/otel/exporters] for exporters that can be used as
// or with these Readers.
//
// Each Reader, when registered with the MeterProvider, can be augmented with a
Expand All @@ -41,4 +41,7 @@
// 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
// 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"
Loading

0 comments on commit e3d6c8e

Please sign in to comment.