Skip to content

Commit 2fa5c93

Browse files
committed
feat(examples): add dice roller getting started reference application
Add a dice roller example application as the reference implementation for the OpenTelemetry Getting Started guide, as specified in: https://opentelemetry.io/docs/getting-started/reference-application-specification/ Includes: - Uninstrumented version (baseline Sinatra app) - Instrumented version with OpenTelemetry SDK, traces, metrics and logs - Dockerfile for containerized usage - README with setup and usage instructions - GitHub Actions workflow and composite action for CI Closes #1928 Signed-off-by: Arjun Rajappa <arjun.rajappa@ibm.com>
1 parent 4834e00 commit 2fa5c93

File tree

11 files changed

+804
-0
lines changed

11 files changed

+804
-0
lines changed
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
name: Test Dice Roller Example
2+
description: Verifies that the dice roller reference application builds and runs correctly (both instrumented and uninstrumented versions).
3+
4+
inputs:
5+
version:
6+
description: Which version to test — "instrumented" or "uninstrumented"
7+
required: true
8+
ruby:
9+
description: Ruby version to use
10+
required: true
11+
12+
runs:
13+
using: composite
14+
steps:
15+
- name: Install Ruby ${{ inputs.ruby }}
16+
uses: ruby/setup-ruby@8d27f39a5e7ad39aebbcbd1324f7af020229645c # v1.287.0
17+
with:
18+
ruby-version: "${{ inputs.ruby }}"
19+
working-directory: "examples/dice_roller/${{ inputs.version }}"
20+
bundler: "latest"
21+
bundler-cache: true
22+
23+
- name: Start app (${{ inputs.version }})
24+
shell: bash
25+
working-directory: examples/dice_roller/${{ inputs.version }}
26+
env:
27+
APPLICATION_PORT: "8080"
28+
OTEL_TRACES_EXPORTER: none
29+
OTEL_METRICS_EXPORTER: none
30+
OTEL_LOGS_EXPORTER: none
31+
OTEL_SERVICE_NAME: dice_roller_ci
32+
run: |
33+
# 🎲 Start dice roller (${{ inputs.version }}) 🎲
34+
ruby app.rb &
35+
echo "APP_PID=$!" >> "$GITHUB_ENV"
36+
echo "Waiting for server to be ready..."
37+
for i in $(seq 1 30); do
38+
if curl -sf http://localhost:8080/rolldice > /dev/null 2>&1; then
39+
echo "Server ready after ${i}s"
40+
exit 0
41+
fi
42+
sleep 1
43+
done
44+
echo "Server did not start in time" >&2
45+
exit 1
46+
47+
- name: Verify /rolldice returns a single die value
48+
shell: bash
49+
run: |
50+
# 🎲 Single roll 🎲
51+
RESPONSE=$(curl -sf http://localhost:8080/rolldice)
52+
echo "Response: $RESPONSE"
53+
echo "$RESPONSE" | grep -qE '^[1-6]$'
54+
55+
- name: Verify /rolldice?rolls=3 returns an array of 3 values
56+
shell: bash
57+
run: |
58+
# 🎲 Multiple rolls 🎲
59+
RESPONSE=$(curl -sf "http://localhost:8080/rolldice?rolls=3")
60+
echo "Response: $RESPONSE"
61+
echo "$RESPONSE" | grep -qE '^\[[1-6],[1-6],[1-6]\]$'
62+
63+
- name: Verify /rolldice?player=Alice returns a single die value
64+
shell: bash
65+
run: |
66+
# 🎲 Roll with player name 🎲
67+
RESPONSE=$(curl -sf "http://localhost:8080/rolldice?player=Alice")
68+
echo "Response: $RESPONSE"
69+
echo "$RESPONSE" | grep -qE '^[1-6]$'
70+
71+
- name: Verify /rolldice?rolls=invalid returns HTTP 400
72+
shell: bash
73+
run: |
74+
# ❌ Invalid rolls parameter 🎲
75+
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:8080/rolldice?rolls=invalid")
76+
echo "Status: $STATUS"
77+
[ "$STATUS" = "400" ]
78+
79+
- name: Verify /rolldice?rolls=0 returns HTTP 400
80+
shell: bash
81+
run: |
82+
# ❌ Zero rolls 🎲
83+
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:8080/rolldice?rolls=0")
84+
echo "Status: $STATUS"
85+
[ "$STATUS" = "400" ]
86+
87+
- name: Verify /rolldice?rolls=-1 returns HTTP 400
88+
shell: bash
89+
run: |
90+
# ❌ Negative rolls 🎲
91+
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:8080/rolldice?rolls=-1")
92+
echo "Status: $STATUS"
93+
[ "$STATUS" = "400" ]
94+
95+
- name: Stop app
96+
shell: bash
97+
if: always()
98+
run: |
99+
# 🛑 Stop app 🛑
100+
if [ -n "$APP_PID" ]; then
101+
kill "$APP_PID" || true
102+
fi
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
name: CI - Example Dice Roller
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches:
7+
- main
8+
paths:
9+
- 'examples/dice_roller/**'
10+
- '.github/actions/test_dice_roller/**'
11+
- '.github/workflows/ci-example-dice-roller.yml'
12+
pull_request:
13+
branches:
14+
- main
15+
paths:
16+
- 'examples/dice_roller/**'
17+
- '.github/actions/test_dice_roller/**'
18+
- '.github/workflows/ci-example-dice-roller.yml'
19+
20+
permissions:
21+
contents: read
22+
23+
concurrency:
24+
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
25+
cancel-in-progress: true
26+
27+
jobs:
28+
# ---------------------------------------------------------------------------
29+
# Verify both versions build and run correctly across Ruby versions
30+
# ---------------------------------------------------------------------------
31+
dice-roller:
32+
if: ${{ github.repository == 'open-telemetry/opentelemetry-ruby' }}
33+
name: ${{ matrix.version }} / Ruby ${{ matrix.ruby }}
34+
runs-on: ubuntu-latest
35+
strategy:
36+
fail-fast: false
37+
matrix:
38+
version:
39+
- uninstrumented
40+
- instrumented
41+
ruby:
42+
- "3.2"
43+
- "3.3"
44+
- "3.4"
45+
46+
steps:
47+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
48+
49+
- name: Test Dice Roller (${{ matrix.version }}, Ruby ${{ matrix.ruby }})
50+
uses: ./.github/actions/test_dice_roller
51+
with:
52+
version: ${{ matrix.version }}
53+
ruby: ${{ matrix.ruby }}
54+
55+
# ---------------------------------------------------------------------------
56+
# Verify both Docker images build and the container starts correctly
57+
# ---------------------------------------------------------------------------
58+
dice-roller-docker:
59+
if: ${{ github.repository == 'open-telemetry/opentelemetry-ruby' }}
60+
name: Docker ${{ matrix.version }}
61+
runs-on: ubuntu-latest
62+
strategy:
63+
fail-fast: false
64+
matrix:
65+
version:
66+
- uninstrumented
67+
- instrumented
68+
69+
steps:
70+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
71+
72+
- name: Build Docker image (${{ matrix.version }})
73+
working-directory: examples/dice_roller
74+
run: |
75+
# 🐳 Build ${{ matrix.version }} image 🐳
76+
docker build \
77+
--target ${{ matrix.version }} \
78+
-t dice_roller:${{ matrix.version }} \
79+
.
80+
81+
- name: Run container (${{ matrix.version }})
82+
run: |
83+
# 🐳 Start container 🐳
84+
docker run -d \
85+
--name dice_roller_${{ matrix.version }} \
86+
-p 8080:8080 \
87+
-e OTEL_TRACES_EXPORTER=none \
88+
-e OTEL_METRICS_EXPORTER=none \
89+
-e OTEL_LOGS_EXPORTER=none \
90+
-e OTEL_SERVICE_NAME=dice_roller_ci \
91+
dice_roller:${{ matrix.version }}
92+
echo "Waiting for container to be ready..."
93+
for i in $(seq 1 30); do
94+
if curl -sf http://localhost:8080/rolldice > /dev/null 2>&1; then
95+
echo "Container ready after ${i}s"
96+
exit 0
97+
fi
98+
sleep 1
99+
done
100+
echo "Container did not start in time" >&2
101+
docker logs dice_roller_${{ matrix.version }}
102+
exit 1
103+
104+
- name: Verify /rolldice (single roll)
105+
run: |
106+
RESPONSE=$(curl -sf http://localhost:8080/rolldice)
107+
echo "Response: $RESPONSE"
108+
echo "$RESPONSE" | grep -qE '^[1-6]$'
109+
110+
- name: Verify /rolldice?rolls=2 (multiple rolls)
111+
run: |
112+
RESPONSE=$(curl -sf "http://localhost:8080/rolldice?rolls=2")
113+
echo "Response: $RESPONSE"
114+
echo "$RESPONSE" | grep -qE '^\[[1-6],[1-6]\]$'
115+
116+
- name: Stop and remove container
117+
if: always()
118+
run: |
119+
docker stop dice_roller_${{ matrix.version }} || true
120+
docker rm dice_roller_${{ matrix.version }} || true

examples/dice_roller/Dockerfile

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# syntax=docker/dockerfile:1
2+
3+
# Copyright The OpenTelemetry Authors
4+
#
5+
# SPDX-License-Identifier: Apache-2.0
6+
7+
# ---------------------------------------------------------------------------
8+
# Build argument: set to "instrumented" (default) or "uninstrumented"
9+
# ---------------------------------------------------------------------------
10+
ARG APP_VERSION=instrumented
11+
12+
FROM ruby:3.3-slim AS base
13+
14+
WORKDIR /app
15+
16+
# Install build dependencies
17+
RUN apt-get update -qq && \
18+
apt-get install -y --no-install-recommends build-essential && \
19+
rm -rf /var/lib/apt/lists/*
20+
21+
# ---------------------------------------------------------------------------
22+
# Uninstrumented stage
23+
# ---------------------------------------------------------------------------
24+
FROM base AS uninstrumented
25+
26+
COPY uninstrumented/Gemfile ./Gemfile
27+
RUN bundle install
28+
29+
COPY uninstrumented/app.rb ./app.rb
30+
COPY uninstrumented/dice.rb ./dice.rb
31+
32+
ENV APPLICATION_PORT=8080
33+
EXPOSE 8080
34+
35+
CMD ["ruby", "app.rb"]
36+
37+
# ---------------------------------------------------------------------------
38+
# Instrumented stage
39+
# ---------------------------------------------------------------------------
40+
FROM base AS instrumented
41+
42+
COPY instrumented/Gemfile ./Gemfile
43+
RUN bundle install
44+
45+
COPY instrumented/otel.rb ./otel.rb
46+
COPY instrumented/dice.rb ./dice.rb
47+
COPY instrumented/app.rb ./app.rb
48+
49+
ENV APPLICATION_PORT=8080
50+
# Service name used by OTel SDK (can be overridden at runtime)
51+
ENV OTEL_SERVICE_NAME=dice_roller
52+
# Export to console by default; override with "otlp" to send to a collector
53+
ENV OTEL_TRACES_EXPORTER=console
54+
ENV OTEL_METRICS_EXPORTER=console
55+
ENV OTEL_LOGS_EXPORTER=console
56+
57+
EXPOSE 8080
58+
59+
CMD ["ruby", "app.rb"]

0 commit comments

Comments
 (0)