From c6067778f4cdbb639d459e8e396381b811a70eb4 Mon Sep 17 00:00:00 2001 From: James Lawrie Date: Fri, 13 Jan 2023 10:20:18 -0500 Subject: [PATCH] Add ads served counter metric with request and response types Update documentation Configure collector's prometheus exporter to convert resource attributes to prometheus labels --- CHANGELOG.md | 2 ++ docs/manual_span_attributes.md | 2 ++ docs/metric_service_features.md | 33 +++++++++-------- docs/services/adservice.md | 36 +++++++++++++++++-- .../src/main/java/hipstershop/AdService.java | 33 ++++++++++++++++- src/otelcollector/otelcol-config.yml | 3 +- 6 files changed, 88 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f65c42f143..0fca06944d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -182,3 +182,5 @@ significant modifications will be credited to OpenTelemetry Authors. ([#674](https://github.com/open-telemetry/opentelemetry-demo/pull/674)) * Add resource detectors to accounting service ([#676](https://github.com/open-telemetry/opentelemetry-demo/pull/676)) +* Add custom metrics to ads service +([#678](https://github.com/open-telemetry/opentelemetry-demo/pull/678)) diff --git a/docs/manual_span_attributes.md b/docs/manual_span_attributes.md index bb8fe232bd..2dfcda9ce4 100644 --- a/docs/manual_span_attributes.md +++ b/docs/manual_span_attributes.md @@ -10,6 +10,8 @@ This document contains the list of manual Span Attributes used throughout the de | `app.ads.contextKeys` | string | Context keys used to find related ads | | `app.ads.contextKeys.count` | number | Count of unique context keys used | | `app.ads.count` | number | Count of ads returned to user | +| `app.ads.ad_request_type` | string | Either `targeted` or `not_targeted` | +| `app.ads.ad_response_type` | string | Either `targeted` or `random` | ## CartService diff --git a/docs/metric_service_features.md b/docs/metric_service_features.md index f261b6a23b..deee90be83 100644 --- a/docs/metric_service_features.md +++ b/docs/metric_service_features.md @@ -6,20 +6,19 @@ Emoji Legend - Not Applicable: :no_bell: - Not Present (Yet): :construction: -| Service | Language | Instrumentation Libraries | Manual Span Creation | Span Data Enrichment | RPC Context Propagation | Span Links | Baggage | Resource Detection | -|--------------------|-----------------|---------------------------|----------------------|----------------------|-------------------------|----------------|----------------|--------------------| -| Accounting Service | Go | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | :100: | -| Ad | Java | :100: | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | -| Cart | .NET | :100: | :construction: | :construction: | :construction: | :construction: | :construction: | :100: | -| Checkout | Go | :100: | :construction: | :construction: | :construction: | :construction: | :construction: | :100: | -| Currency | C++ | :no_bell: | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | -| Email | Ruby | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | -| Feature Flag | Erlang / Elixir | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | -| Fraud Detection | Kotlin | :100: | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | -| Frontend | JavaScript | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | -| Payment | JavaScript | :construction: | :100: | :construction: | :construction: | :construction: | :construction: | :100: | -| Product Catalog | Go | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | -| Recommendation | Python | :100: | :100: | :construction: | :construction: | :construction: | :construction: | :construction: | -| Shipping | Rust | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | -| Recommendation | Python | :100: | :100: | :100: | :no_bell: | :no_bell: | :no_bell: | :construction: | -| Shipping | Rust | :no_bell: | :100: | :100: | :100: | :no_bell: | :no_bell: | :construction: | +| Service | Language | Instrumentation Libraries | Manual Metric Creation | Multiple Manual Metric Instruments | Metric Attributes | Resource Attributes | Exemplars | Views | +|--------------------|-----------------|---------------------------|------------------------|------------------------------------|-------------------|---------------------|----------------|----------------| +| Accounting Service | Go | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | +| Ad | Java | :100: | :100: | :construction: | :100: | :100: | :construction: | :construction: | +| Cart | .NET | :100: | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | +| Checkout | Go | :100: | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | +| Currency | C++ | :no_bell: | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | +| Email | Ruby | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | +| Feature Flag | Erlang / Elixir | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | +| Fraud Detection | Kotlin | :100: | :construction: | :construction: | :construction: | :100: | :construction: | :construction: | +| Frontend | JavaScript | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | +| Payment | JavaScript | :construction: | :100: | :construction: | :construction: | :100: | :construction: | :construction: | +| Product Catalog | Go | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | +| Quote Service | PHP | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | +| Recommendation | Python | :100: | :100: | :construction: | :construction: | :construction: | :construction: | :construction: | +| Shipping | Rust | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | diff --git a/docs/services/adservice.md b/docs/services/adservice.md index d7525915c9..10b10911ee 100644 --- a/docs/services/adservice.md +++ b/docs/services/adservice.md @@ -48,7 +48,7 @@ is caught. ### Setting span status -If the result of the operation is an error, the span status is should be set +If the result of the operation is an error, the span status should be set accordingly using `setStatus` on the span object. In the `getAds` function the span status is set when an exception is caught. @@ -85,7 +85,39 @@ the span. ## Metrics -TBD +### Initializing Metrics + +Similar to creating spans, the first step in creating metrics is initializing a +`Meter` instance, e.g. `GlobalOpenTelemetry.getMeter("adservice")`. From +there, use the various builder methods available on the `Meter` instance to +create the desired metric instrument, e.g.: + +```java +meter + .counterBuilder("app.ads.ad_requests") + .setDescription("Counts ad requests by request and response type") + .build(); +``` + +### Current Metrics Produced + +Note that all the metric names below appear in Prometheus/Grafana with `.` +characters transformed to `_`. + +#### Custom metrics + +The following custom metrics are currently available: + +* `app.ads.ad_requests`: A counter of ad requests with dimensions describing +whether the request was targeted with context keys or not, and whether the +response was targeted or random ads. + +#### Auto-instrumented metrics + +The following auto-instrumented metrics are available for the application: + +* [Runtime metrics for the JVM](https://opentelemetry.io/docs/reference/specification/metrics/semantic_conventions/runtime-environment-metrics/#jvm-metrics). +* [Latency metrics for RPCs](https://opentelemetry.io/docs/reference/specification/metrics/semantic_conventions/rpc-metrics/#rpc-server) ## Logs diff --git a/src/adservice/src/main/java/hipstershop/AdService.java b/src/adservice/src/main/java/hipstershop/AdService.java index 981e509b9c..390451e1c7 100644 --- a/src/adservice/src/main/java/hipstershop/AdService.java +++ b/src/adservice/src/main/java/hipstershop/AdService.java @@ -30,6 +30,8 @@ import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongCounter; +import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.StatusCode; import io.opentelemetry.api.trace.Tracer; @@ -57,6 +59,16 @@ public final class AdService { private HealthStatusManager healthMgr; private static final AdService service = new AdService(); + private static final Tracer tracer = GlobalOpenTelemetry.getTracer("adservice"); + private static final Meter meter = GlobalOpenTelemetry.getMeter("adservice"); + + private static final LongCounter adRequestsCounter = meter + .counterBuilder("app.ads.ad_requests") + .setDescription("Counts ad requests by request and response type") + .build(); + + private static final AttributeKey adRequestTypeKey = AttributeKey.stringKey("app.ads.ad_request_type"); + private static final AttributeKey adResponseTypeKey = AttributeKey.stringKey("app.ads.ad_response_type"); private void start() throws IOException { int port = Integer.parseInt(Optional.ofNullable(System.getenv("AD_SERVICE_PORT")).orElseThrow( @@ -92,6 +104,14 @@ private void stop() { } } + private enum AdRequestType { + TARGETED, NOT_TARGETED + } + + private enum AdResponseType { + TARGETED, RANDOM + } + private static class AdServiceImpl extends hipstershop.AdServiceGrpc.AdServiceImplBase { /** @@ -109,6 +129,8 @@ public void getAds(AdRequest req, StreamObserver responseObserver) { Span span = Span.current(); try { List allAds = new ArrayList<>(); + AdRequestType adRequestType; + AdResponseType adResponseType; span.setAttribute("app.ads.contextKeys", req.getContextKeysList().toString()); span.setAttribute("app.ads.contextKeys.count", req.getContextKeysCount()); @@ -118,14 +140,24 @@ public void getAds(AdRequest req, StreamObserver responseObserver) { Collection ads = service.getAdsByCategory(req.getContextKeys(i)); allAds.addAll(ads); } + adRequestType = AdRequestType.TARGETED; + adResponseType = AdResponseType.TARGETED; } else { allAds = service.getRandomAds(); + adRequestType = AdRequestType.NOT_TARGETED; + adResponseType = AdResponseType.RANDOM; } if (allAds.isEmpty()) { // Serve random ads. allAds = service.getRandomAds(); + adResponseType = AdResponseType.RANDOM; } span.setAttribute("app.ads.count", allAds.size()); + span.setAttribute("app.ads.ad_request_type", adRequestType.name()); + span.setAttribute("app.ads.ad_response_type", adResponseType.name()); + + adRequestsCounter.add(1, Attributes.of(adRequestTypeKey, adRequestType.name(), adResponseTypeKey, adResponseType.name())); + AdResponse reply = AdResponse.newBuilder().addAllAds(allAds).build(); responseObserver.onNext(reply); responseObserver.onCompleted(); @@ -155,7 +187,6 @@ private List getRandomAds() { List ads = new ArrayList<>(MAX_ADS_TO_SERVE); // create and start a new span manually - Tracer tracer = GlobalOpenTelemetry.getTracer("adservice"); Span span = tracer.spanBuilder("getRandomAds").startSpan(); // put the span into context, so if any child span is started the parent will be set properly diff --git a/src/otelcollector/otelcol-config.yml b/src/otelcollector/otelcol-config.yml index b9a77e46a4..fe4c872626 100644 --- a/src/otelcollector/otelcol-config.yml +++ b/src/otelcollector/otelcol-config.yml @@ -16,7 +16,8 @@ exporters: logging: prometheus: endpoint: "otelcol:9464" - + resource_to_telemetry_conversion: + enabled: true processors: batch: spanmetrics: