Skip to content
Draft
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
9 changes: 8 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,11 @@
.DS_Store

# rolldice-game node modules
apps/rolldice-game/game_controller/node_modules
apps/rolldice-game/game_controller/node_modules

# Java/Gradle files for rolldice-http-metrics
apps/rolldice-http-metrics/game_controller/.gradle/
apps/rolldice-http-metrics/game_controller/build/
apps/rolldice-http-metrics/game_controller/gradle/wrapper/gradle-wrapper.jar
apps/rolldice-http-metrics/game_controller/opentelemetry-javaagent.jar
apps/rolldice-http-metrics/game_controller/dd-java-agent.jar
32 changes: 32 additions & 0 deletions apps/rolldice-http-metrics/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# W3C Trace Context Example
This project consists of two Flask servers and one Express server instrumented with Opentelemetry on a standalone host. (This is not using k8s or containers)

## Start the Demo
### Option 1 (Standalone Host)
There are a few required steps to get this example working.
1. Install and set up the OpenTelemetry Collector on the host of your choice. https://opentelemetry.io/docs/collector/installation/
2. Set up the Collector configuration. An example collector configuration can be found at [Config File](./config.yml).
* The config.yml is set up to send traces and metrics from OTLP Collector to the Datadog Exporter.
* Update the DATADOG_API_KEY as well.
3. Run this collector ~ `./otelcol-contrib --config=config.yml`
4. Once the collector is up and running. Set up the 3 servers. (Can be found in each of the servers README)

### Option 2 (Docker)
1. Update DATADOG_API_KEY in [Config File](./config.yml).
2. Run docker-compose up

To trigger the service call

### Success
```bash
curl -X POST http://localhost:5002/play_game \
-H "Content-Type: application/json" \
-d '{"player": "John Doe"}'
```
### Error
``` bash
curl -X POST http://localhost:5002/play_game \
-H "Content-Type: application/json" \
-d '{}'
```
View traces & standalone host in app.datadoghq.com
66 changes: 66 additions & 0 deletions apps/rolldice-http-metrics/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
hostmetrics:
# collect metrics every 10 seconds.
collection_interval: 10s
scrapers:
cpu:
disk:
filesystem:
memory:
network:
load:
paging:
processes:

exporters:
debug:
verbosity: detailed
datadog/exporter:
api:
site: datad0g.com
key: ${env:DD_API_KEY}
otlphttp:
headers:
"Dd-Protocol": "otlp"
"Dd-Api-Key": "${env:DD_API_KEY}"

metrics_endpoint: https://trace.agent.datad0g.com/api/v0.2/stats
tls:
insecure: true

connectors:
routing:
default_pipelines: [metrics/datadog]
table:
- context: metric
condition: metric.name == "http.server.request.duration"
pipelines: [metrics/dd_trace_metrics]
- context: metric
condition: metric.name == "http.client.request.duration"
pipelines: [metrics/dd_trace_metrics]

processors:
batch:
cumulativetodelta:
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [datadog/exporter]
metrics:
receivers: [otlp]
exporters: [routing]
metrics/datadog:
receivers: [routing]
exporters: [datadog/exporter]
metrics/dd_trace_metrics:
receivers: [routing]
processors: [cumulativetodelta]
exporters: [debug, datadog/exporter, otlphttp]
75 changes: 75 additions & 0 deletions apps/rolldice-http-metrics/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
version: '3'
services:
game_controller:
build:
context: ./game_controller
dockerfile: Dockerfile
ports:
- "5002:5002"
depends_on:
otelcol:
condition: service_started
rolling:
condition: service_started
scoring:
condition: service_started
environment:
- OTEL_SERVICE_NAME=controller
- OTEL_METRICS_EXPORTER=otlp
- OTEL_LOGS_EXPORTER=otlp
- OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=delta
- OTEL_EXPORTER_OTLP_ENDPOINT=http://otelcol:4317
- OTEL_EXPORTER_OTLP_PROTOCOL=grpc
- OTEL_SEMCONV_STABILITY_OPT_IN=http
- OTEL_RESOURCE_ATTRIBUTES=deployment.environment=demo-env,host.name=demo-host,service.version=v1.0

rolling:
build:
context: ./rolling
dockerfile: Dockerfile
ports:
- "5004:5004"
depends_on:
otelcol:
condition: service_started
environment:
- OTEL_SERVICE_NAME=rolly
- OTEL_EXPORTER_OTLP_ENDPOINT=http://otelcol:4317
- OTEL_EXPORTER_OTLP_PROTOCOL=grpc
- OTEL_SEMCONV_STABILITY_OPT_IN=http
- OTEL_RESOURCE_ATTRIBUTES=deployment.environment=demo-env,host.name=demo-host,service.version=v1.0

scoring:
build:
context: ./scoring
dockerfile: Dockerfile
ports:
- "5001:5001"
depends_on:
otelcol:
condition: service_started
environment:
- OTEL_SERVICE_NAME=scorey
- OTEL_EXPORTER_OTLP_ENDPOINT=http://otelcol:4317
- OTEL_EXPORTER_OTLP_PROTOCOL=grpc
- OTEL_SEMCONV_STABILITY_OPT_IN=http
- OTEL_RESOURCE_ATTRIBUTES=deployment.environment=demo-env,host.name=demo-host,service.version=v1.0
otelcol:
image: otel/opentelemetry-collector-contrib
deploy:
resources:
limits:
memory: 200M
restart: unless-stopped
command: [ "--config=/etc/otelcol-config.yml"]
volumes:
- ./config.yml:/etc/otelcol-config.yml
ports:
- "4318:4318" # OTLP http receiver
- "4317:4317"
environment:
- DD_API_KEY=${DD_API_KEY}
- DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_GRPC_ENDPOINT=0.0.0.0:4317
- DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_HTTP_ENDPOINT=0.0.0.0:4318


35 changes: 35 additions & 0 deletions apps/rolldice-http-metrics/game_controller/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Use OpenJDK 17 as the base image
FROM openjdk:17-jdk-slim

# Set the working directory
WORKDIR /game_controller

# Copy Gradle wrapper and build files
COPY gradlew .
COPY gradle gradle
COPY build.gradle .
COPY settings.gradle .

# Copy source code
COPY src src

# Make gradlew executable
RUN chmod +x ./gradlew

# Build the application
RUN ./gradlew build -x test

# Install curl and download OpenTelemetry Java agent
RUN apt-get update && apt-get install -y curl && \
curl -L -o opentelemetry-javaagent.jar \
https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar && \
rm -rf /var/lib/apt/lists/*

ENV service_name=controller
ENV logs_exporter=otlp

# Expose port 5002 for the app to be accessible
EXPOSE 5002

# Define the command to run the app with OpenTelemetry agent
CMD ["java", "-javaagent:opentelemetry-javaagent.jar", "-jar", "build/libs/game_controller-0.0.1-SNAPSHOT.jar"]
31 changes: 31 additions & 0 deletions apps/rolldice-http-metrics/game_controller/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Game Controller
This project is a Spring Boot application that uses the OpenTelemetry API for tracing and RestTemplate for HTTP requests.


## Installation
* Java 17 or later
* Gradle (wrapper included)


```bash
./gradlew build
```

## Run the server

### With OpenTelemetry
```bash
./run-otel-local.sh
```

### With Datadog
```bash
./run-dd-local.sh
```

### Docker
```bash
docker build -t game-controller .
docker run -p 5002:5002 game-controller
```

27 changes: 27 additions & 0 deletions apps/rolldice-http-metrics/game_controller/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.0'
id 'io.spring.dependency-management' version '1.1.4'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'

java {
sourceCompatibility = '17'
}

repositories {
mavenCentral()
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-actuator'

testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
useJUnitPlatform()
}
47 changes: 47 additions & 0 deletions apps/rolldice-http-metrics/game_controller/controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const express = require('express');
const axios = require('axios');
const { context, trace, propagation } = require('@opentelemetry/api');
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');

const sdk = new NodeSDK({
instrumentations: [getNodeAutoInstrumentations()],
});

sdk.start();
const app = express();
app.use(express.json());

app.post('/play_game', async (req, res) => {
const tracer = trace.getTracer('express-game-controller');
const span = tracer.startSpan('play_game');

const ctx = trace.setSpan(context.active(), span);

context.with(ctx, async () => {
try {
const player = req.body.player;
const headers = {};
propagation.inject(context.active(), headers);
const diceRollResult = await axios.get(`http://rolling:5004/rolldice?player=${player}`, { headers });
const updateScoreResult = await axios.post('http://scoring:5001/update_score', {
player: player,
result: diceRollResult.data
}, { headers });

span.addEvent('score_updated');
span.end();
res.json(updateScoreResult.data);
} catch (error) {
span.recordException(error);
span.end();
console.error(error);
res.status(500).send('An error occurred');
}
});
});

const PORT = process.env.PORT || 5002;
app.listen(PORT, () => {
console.log(`Game Controller service listening at http://localhost:${PORT}`);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading