Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ads served counter metric with request and response types #678

Merged
merged 2 commits into from
Jan 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,5 @@ significant modifications will be credited to OpenTelemetry Authors.
([#676](https://github.com/open-telemetry/opentelemetry-demo/pull/676))
* Add resource detectors to product catalog service
([#677](https://github.com/open-telemetry/opentelemetry-demo/pull/677))
* Add custom metrics to ads service
([#678](https://github.com/open-telemetry/opentelemetry-demo/pull/678))
2 changes: 2 additions & 0 deletions docs/manual_span_attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
33 changes: 16 additions & 17 deletions docs/metric_service_features.md
Original file line number Diff line number Diff line change
Expand Up @@ -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: |
36 changes: 34 additions & 2 deletions docs/services/adservice.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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

Expand Down
33 changes: 32 additions & 1 deletion src/adservice/src/main/java/hipstershop/AdService.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<String> adRequestTypeKey = AttributeKey.stringKey("app.ads.ad_request_type");
private static final AttributeKey<String> 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(
Expand Down Expand Up @@ -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 {

/**
Expand All @@ -109,6 +129,8 @@ public void getAds(AdRequest req, StreamObserver<AdResponse> responseObserver) {
Span span = Span.current();
try {
List<Ad> allAds = new ArrayList<>();
AdRequestType adRequestType;
AdResponseType adResponseType;

span.setAttribute("app.ads.contextKeys", req.getContextKeysList().toString());
span.setAttribute("app.ads.contextKeys.count", req.getContextKeysCount());
Expand All @@ -118,14 +140,24 @@ public void getAds(AdRequest req, StreamObserver<AdResponse> responseObserver) {
Collection<Ad> 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();
Expand Down Expand Up @@ -155,7 +187,6 @@ private List<Ad> getRandomAds() {
List<Ad> 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
Expand Down
3 changes: 2 additions & 1 deletion src/otelcollector/otelcol-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ exporters:
logging:
prometheus:
endpoint: "otelcol:9464"

resource_to_telemetry_conversion:
enabled: true
processors:
batch:
spanmetrics:
Expand Down