diff --git a/content/en/docs/demo/services/cart/exemplars.png b/content/en/docs/demo/services/cart/exemplars.png new file mode 100644 index 000000000000..6bb7a08973df Binary files /dev/null and b/content/en/docs/demo/services/cart/exemplars.png differ diff --git a/content/en/docs/demo/services/cart.md b/content/en/docs/demo/services/cart/index.md similarity index 53% rename from content/en/docs/demo/services/cart.md rename to content/en/docs/demo/services/cart/index.md index 075f250e838c..29edafef087c 100644 --- a/content/en/docs/demo/services/cart.md +++ b/content/en/docs/demo/services/cart/index.md @@ -31,8 +31,8 @@ Action appResourceBuilder = builder.Services.AddOpenTelemetry() .ConfigureResource(appResourceBuilder) .WithTracing(tracerBuilder => tracerBuilder + .AddSource("OpenTelemetry.Demo.Cart") .AddRedisInstrumentation( - cartStore.GetConnection(), options => options.SetVerboseDatabaseStatements = true) .AddAspNetCoreInstrumentation() .AddGrpcClientInstrumentation() @@ -87,12 +87,85 @@ Action appResourceBuilder = builder.Services.AddOpenTelemetry() .ConfigureResource(appResourceBuilder) .WithMetrics(meterBuilder => meterBuilder + .AddMeter("OpenTelemetry.Demo.Cart") .AddProcessInstrumentation() .AddRuntimeInstrumentation() .AddAspNetCoreInstrumentation() + .SetExemplarFilter(ExemplarFilterType.TraceBased) .AddOtlpExporter()); ``` +### Exemplars + +[Exemplars](/docs/specs/otel/metrics/data-model/#exemplars) are configured in +the Cart service with trace-based exemplar filter, which enables the +OpenTelemetry SDK to attach exemplars to metrics. + +First it creates a `CartActivitySource`, `Meter` and two `Histograms`. The +histogram keeps track from the latency of the methods `AddItem` and `GetCart`, +as those are two important methods in the Cart service. + +Those two methods are critical to the Cart service as users shouldn't wait too +long when adding an item to the cart, or when viewing their cart before moving +to the checkout process. + +```cs +private static readonly ActivitySource CartActivitySource = new("OpenTelemetry.Demo.Cart"); +private static readonly Meter CartMeter = new Meter("OpenTelemetry.Demo.Cart"); +private static readonly Histogram addItemHistogram = CartMeter.CreateHistogram( + "app.cart.add_item.latency", + advice: new InstrumentAdvice + { + HistogramBucketBoundaries = [ 500000, 600000, 700000, 800000, 900000, 1000000, 1100000 ] + }); +private static readonly Histogram getCartHistogram = CartMeter.CreateHistogram( + "app.cart.get_cart.latency", + advice: new InstrumentAdvice + { + HistogramBucketBoundaries = [ 300000, 400000, 500000, 600000, 700000, 800000, 900000 ] + }); +``` + +Note that a custom bucket boundary is also defined, as the default values don't +fit the microseconds results Cart service has. + +Once the variables are defined, the latency of the execution of each method is +tracked with a `StopWatch` as follows: + +```cs +var stopwatch = Stopwatch.StartNew(); + +(method logic) + +addItemHistogram.Record(stopwatch.ElapsedTicks); +``` + +To connect it all together, in the Traces pipeline, it is required to add the +created source. (Already present in the snippet above, but added here to +reference): + +```cs +.AddSource("OpenTelemetry.Demo.Cart") +``` + +And, in the Metrics pipeline, the `Meter` and the `ExemplarFilter`: + +```cs +.AddMeter("OpenTelemetry.Demo.Cart") +.SetExemplarFilter(ExemplarFilterType.TraceBased) +``` + +To visualize the Exemplars, navigate to Grafana + > Dashboards > Demo > Cart Service Exemplars. + +Exemplars appear as special "diamond-shaped dots" on the 95th percentile chart +or as small squares on the heatmap chart. Select any exemplar to view its data, +which includes the timestamp of the measurement, the raw value, and the trace +context at the time of recording. The `trace_id` enables navigation to the +tracing backend (Jaeger, in this case). + +![Cart Service Exemplars](exemplars.png) + ## Logs Logs are configured in the .NET dependency injection container on