You've already forked opentelemetry-go
							
							
				mirror of
				https://github.com/open-telemetry/opentelemetry-go.git
				synced 2025-10-31 00:07:40 +02:00 
			
		
		
		
	Add and refine metrics examples (#4504)
This commit is contained in:
		| @@ -30,7 +30,7 @@ import ( | ||||
|  | ||||
| const ( | ||||
| 	instrumentationName    = "github.com/instrumentron" | ||||
| 	instrumentationVersion = "v0.1.0" | ||||
| 	instrumentationVersion = "0.1.0" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
|   | ||||
| @@ -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", | ||||
| @@ -173,7 +173,7 @@ func Example() { | ||||
| 	//     { | ||||
| 	//       "Scope": { | ||||
| 	//         "Name": "example", | ||||
| 	//         "Version": "v0.0.1", | ||||
| 	//         "Version": "0.0.1", | ||||
| 	//         "SchemaURL": "" | ||||
| 	//       }, | ||||
| 	//       "Metrics": [ | ||||
|   | ||||
| @@ -29,7 +29,7 @@ import ( | ||||
|  | ||||
| const ( | ||||
| 	instrumentationName    = "github.com/instrumentron" | ||||
| 	instrumentationVersion = "v0.1.0" | ||||
| 	instrumentationVersion = "0.1.0" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
|   | ||||
| @@ -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 { | ||||
| @@ -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"), | ||||
| @@ -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 { | ||||
| @@ -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))) | ||||
| 	}) | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
| @@ -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 | ||||
| @@ -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" | ||||
|   | ||||
| @@ -16,45 +16,207 @@ package metric_test | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"regexp" | ||||
|  | ||||
| 	"go.opentelemetry.io/otel" | ||||
| 	"go.opentelemetry.io/otel/sdk/instrumentation" | ||||
| 	"go.opentelemetry.io/otel/sdk/metric" | ||||
| 	"go.opentelemetry.io/otel/sdk/resource" | ||||
| 	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() { | ||||
| 	// 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 | ||||
| 	// data. See exporters in the go.opentelemetry.io/otel/exporters package | ||||
| 	// for more information. | ||||
| 	// data. See [go.opentelemetry.io/otel/exporters] for exporters | ||||
| 	// that can be used as or with readers. | ||||
| 	reader := metric.NewManualReader() | ||||
|  | ||||
| 	// See the go.opentelemetry.io/otel/sdk/resource package for more | ||||
| 	// information about how to create and use Resources. | ||||
| 	res := resource.NewWithAttributes( | ||||
| 		semconv.SchemaURL, | ||||
| 		semconv.ServiceName("my-service"), | ||||
| 		semconv.ServiceVersion("v0.1.0"), | ||||
| 	) | ||||
|  | ||||
| 	// Create a meter provider. | ||||
| 	// You can pass this instance directly to your instrumented code if it | ||||
| 	// accepts a MeterProvider instance. | ||||
| 	meterProvider := metric.NewMeterProvider( | ||||
| 		metric.WithResource(res), | ||||
| 		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) | ||||
|  | ||||
| 	// Handle shutdown properly so that nothing leaks. | ||||
| 	defer func() { | ||||
| 		err := meterProvider.Shutdown(context.Background()) | ||||
| 		if err != nil { | ||||
| 			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, | ||||
| 	// you can pass this instance directly to your instrumented code if it | ||||
| 	// accepts a MeterProvider instance. | ||||
| 	// | ||||
| 	// See the go.opentelemetry.io/otel/metric package for more information | ||||
| 	// about the metric API. | ||||
| } | ||||
|  | ||||
| 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 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" | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"regexp" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/go-logr/logr" | ||||
| @@ -493,134 +491,3 @@ func TestNewViewMultiInstMatchErrorLogged(t *testing.T) { | ||||
| 	}) | ||||
| 	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