diff --git a/docs/metrics/README.md b/docs/metrics/README.md index 20bb5945b30..4499281cdd8 100644 --- a/docs/metrics/README.md +++ b/docs/metrics/README.md @@ -2,20 +2,23 @@ ## Best Practices -- Instruments SHOULD only be created once and reused throughout the application - lifetime. This - [example](../../docs/metrics/getting-started-console/Program.cs) shows how an - instrument is created a `static` field and then used in the application. You - could also look at this ASP.NET Core - [example](../../examples/AspNetCore/Program.cs) which shows a more Dependency - Injection friendly way of doing this by extracting the `Meter` and an - instrument into a dedicated class called - [Instrumentation](../../examples/AspNetCore/Instrumentation.cs) which is then - added as a `Singleton` service. - -- When emitting metrics with tags, DO NOT change the order in which you provide - tags. Changing the order of tag keys would increase the time taken by the SDK - to record the measurement. +### Instruments should be singleton + +Instruments SHOULD only be created once and reused throughout the application +lifetime. This [example](../../docs/metrics/getting-started-console/Program.cs) +shows how an instrument is created as a `static` field and then used in the +application. You could also look at this ASP.NET Core +[example](../../examples/AspNetCore/Program.cs) which shows a more Dependency +Injection friendly way of doing this by extracting the `Meter` and an instrument +into a dedicated class called +[Instrumentation](../../examples/AspNetCore/Instrumentation.cs) which is then +added as a `Singleton` service. + +### Ordering of Tags + +When emitting metrics with tags, DO NOT change the order in which you provide +tags. Changing the order of tag keys would increase the time taken by the SDK to +record the measurement. ```csharp // If you emit the tag keys in this order: name -> color -> taste, stick to this order of tag keys for subsequent measurements. @@ -27,6 +30,8 @@ MyFruitCounter.Add(5, new("name", "apple"), new("color", "red"), new("taste", "s MyFruitCounter.Add(7, new("color", "red"), new("name", "apple"), new("taste", "sweet")); // <--- DON'T DO THIS ``` +### Use TagList where appropriate + For the best performance, it is highly recommended to pass in tags in certain ways so allocations are only happening on the stack rather than the heap, which eliminates pressure on the GC (garbage collector): @@ -49,7 +54,6 @@ var tags = new TagList // Uses a TagList as there are more than three tags counter.Add(100, tags); // <--- DO THIS - // Avoid the below mentioned approaches when there are more than three tags var tag1 = new KeyValuePair("DimName1", "DimValue1"); var tag2 = new KeyValuePair("DimName2", "DimValue2"); @@ -63,11 +67,16 @@ counter.Add(100, readOnlySpanOfTags); // <--- DON'T DO THIS ``` - When emitting metrics with more than eight tags, the SDK allocates memory on - the hot-path. You SHOULD try to keep the number of tags less than or equal to - eight. Check if you can extract any shared tags such as `MachineName`, - `Environment` etc. into `Resource` attributes. Refer to this - [doc](../../docs/metrics/customizing-the-sdk/README.md#resource) for more - information. +the hot-path. You SHOULD try to keep the number of tags less than or equal to +eight. If you are exceeding this, check if you can model some of the tags as +Resource, as [shown here](#modeling-static-tags-as-resource). + +### Modeling static tags as Resource + +Tags such as `MachineName`, `Environment` etc. which are static throughout the +process lifetime should be be modeled as `Resource`, instead of adding them to +each metric measurement. Refer to this +[doc](./customizing-the-sdk/README.md#resource) for details and examples. ## Common issues that lead to missing metrics diff --git a/docs/metrics/customizing-the-sdk/Program.cs b/docs/metrics/customizing-the-sdk/Program.cs index 36539bd6d57..48c9a975311 100644 --- a/docs/metrics/customizing-the-sdk/Program.cs +++ b/docs/metrics/customizing-the-sdk/Program.cs @@ -16,7 +16,12 @@ public class Program public static void Main() { using var meterProvider = Sdk.CreateMeterProviderBuilder() - .ConfigureResource(res => res.AddService("example-service")) + .ConfigureResource(resource => resource.AddAttributes(new List> + { + new KeyValuePair("static-attribute1", "v1"), + new KeyValuePair("static-attribute2", "v2"), + })) + .ConfigureResource(resource => resource.AddService("MyServiceName")) .AddMeter(Meter1.Name) .AddMeter(Meter2.Name) diff --git a/docs/metrics/customizing-the-sdk/README.md b/docs/metrics/customizing-the-sdk/README.md index fb41c28cdd9..148d470f0aa 100644 --- a/docs/metrics/customizing-the-sdk/README.md +++ b/docs/metrics/customizing-the-sdk/README.md @@ -577,14 +577,27 @@ is to use a resource indicating this [Service](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/README.md#service) and [Telemetry SDK](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/README.md#telemetry-sdk). -The `ConfigureResource` method on `MeterProviderBuilder` can be used to set a -configure the resource on the provider. When the provider is built, it -automatically builds the final `Resource` from the configured `ResourceBuilder`. -There can only be a single `Resource` associated with a -provider. It is not possible to change the resource builder *after* the provider -is built, by calling the `Build()` method on the `MeterProviderBuilder`. +The `ConfigureResource` method on `MeterProviderBuilder` can be used to +configure the resource on the provider. `ConfigureResource` accepts an `Action` +to configure the `ResourceBuilder`. Multiple calls to `ConfigureResource` can be +made. When the provider is built, it builds the final `Resource` combining all +the `ConfigureResource` calls. There can only be a single `Resource` associated +with a provider. It is not possible to change the resource builder *after* the +provider is built, by calling the `Build()` method on the +`MeterProviderBuilder`. + `ResourceBuilder` offers various methods to construct resource comprising of -multiple attributes from various sources. +attributes from various sources. For example, `AddService()` adds +[Service](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/README.md#service) +resource. `AddAttributes` can be used to add any additional attributes to the +`Resource`. It also allows adding `ResourceDetector`s. + +It is recommended to model attributes that are static throughout the lifetime of +the process as Resources, instead of adding them as attributes(tags) on each +measurement. + +Follow [this](../../trace/extending-the-sdk/README.md#resource-detector) document +to learn about writing custom resource detectors. The snippet below shows configuring the `Resource` associated with the provider. @@ -594,7 +607,12 @@ using OpenTelemetry.Metrics; using OpenTelemetry.Resources; using var meterProvider = Sdk.CreateMeterProviderBuilder() - .ConfigureResource(r => r.AddService("MyServiceName")) + .ConfigureResource(r => r.AddAttributes(new List> + { + new KeyValuePair("static-attribute1", "v1"), + new KeyValuePair("static-attribute2", "v2"), + })) + .ConfigureResource(resourceBuilder => resourceBuilder.AddService("service-name")) .Build(); ``` diff --git a/docs/trace/README.md b/docs/trace/README.md index e9925cf6565..2ef0ff07340 100644 --- a/docs/trace/README.md +++ b/docs/trace/README.md @@ -2,7 +2,7 @@ ## Best Practices -### ActivitySource singleton +### ActivitySource should be singleton `ActivitySource` SHOULD only be created once and reused throughout the application lifetime. This @@ -31,6 +31,14 @@ care of propagating/restoring the context across process boundaries. If the you need, it is generally recommended to enrich the existing Activity with that information, as opposed to creating a new one. +### Modelling static tags as Resource + +Tags such as `MachineName`, `Environment` etc. which are static throughout the +process lifetime should be be modelled as `Resource`, instead of adding them +to each `Activity`. Refer to this +[doc](./customizing-the-sdk/README.md#resource) for details and +examples. + ## Common issues that lead to missing traces - The `ActivitySource` used to create the `Activity` is not added to the diff --git a/docs/trace/customizing-the-sdk/Program.cs b/docs/trace/customizing-the-sdk/Program.cs index 5da5da584f6..fead3aa0be2 100644 --- a/docs/trace/customizing-the-sdk/Program.cs +++ b/docs/trace/customizing-the-sdk/Program.cs @@ -33,8 +33,12 @@ public static void Main() // The following adds subscription to activities from all Activity Sources // whose name starts with "AbcCompany.XyzProduct.". .AddSource("AbcCompany.XyzProduct.*") - .ConfigureResource(resourceBuilder => resourceBuilder.AddTelemetrySdk()) - .ConfigureResource(r => r.AddService("MyServiceName")) + .ConfigureResource(resource => resource.AddAttributes(new List> + { + new KeyValuePair("static-attribute1", "v1"), + new KeyValuePair("static-attribute2", "v2"), + })) + .ConfigureResource(resource => resource.AddService("MyServiceName")) .AddConsoleExporter() .Build(); diff --git a/docs/trace/customizing-the-sdk/README.md b/docs/trace/customizing-the-sdk/README.md index fd16648c820..76f4145d2e3 100644 --- a/docs/trace/customizing-the-sdk/README.md +++ b/docs/trace/customizing-the-sdk/README.md @@ -303,12 +303,14 @@ provider is built, by calling the `Build()` method on the `TracerProviderBuilder`. `ResourceBuilder` offers various methods to construct resource comprising of -multiple attributes from various sources. Examples include `AddTelemetrySdk()` -which adds [Telemetry -Sdk](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/README.md#telemetry-sdk) -resource, and `AddService()` which adds +attributes from various sources. For example, `AddService()` adds [Service](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/README.md#service) -resource. It also allows adding `ResourceDetector`s. +resource. `AddAttributes` can be used to add any additional attribute to the +`Resource`. It also allows adding `ResourceDetector`s. + +It is recommended to model attributes that are static throughout the lifetime of +the process as Resources, instead of adding them as attributes(tags) on each +`Activity`. Follow [this](../extending-the-sdk/README.md#resource-detector) document to learn about writing custom resource detectors. @@ -321,7 +323,11 @@ using OpenTelemetry.Resources; using OpenTelemetry.Trace; var tracerProvider = Sdk.CreateTracerProviderBuilder() - .ConfigureResource(resourceBuilder => resourceBuilder.AddTelemetrySdk()) + .ConfigureResource(r => r.AddAttributes(new List> + { + new KeyValuePair("static-attribute1", "v1"), + new KeyValuePair("static-attribute2", "v2"), + })) .ConfigureResource(resourceBuilder => resourceBuilder.AddService("service-name")) .Build(); ```