diff --git a/.gitignore b/.gitignore
index 485dee6..f18e914 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
.idea
+venv/
diff --git a/README.md b/README.md
index 8b6b9cc..26c9486 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@ The Docker image is available on Docker hub: https://hub.docker.com/r/grafana/ot
## Run the Docker image
```sh
-docker run -p 3000:3000 -p 4317:4317 -p 4318:4318 --rm -ti grafana/otel-lgtm
+./run-lgtm.sh
```
## Send OpenTelemetry Data
@@ -72,4 +72,5 @@ Each example uses a different application port (to be able to run all applicatio
|---------|---------------------------------------|
| Java | `curl http://localhost:8080/rolldice` |
| Go | `curl http://localhost:8081/rolldice` |
+| Python | `curl http://localhost:8082/rolldice` |
diff --git a/examples/go/Dockerfile b/examples/go/Dockerfile
index 13549c1..6fb0951 100644
--- a/examples/go/Dockerfile
+++ b/examples/go/Dockerfile
@@ -1,26 +1,15 @@
-# syntax=docker/dockerfile:1
-
FROM golang:1.21
-# Set destination for COPY
WORKDIR /app
-# Download Go modules
COPY go.mod go.sum ./
RUN go mod download
-# Copy the source code. Note the slash at the end, as explained in
-# https://docs.docker.com/engine/reference/builder/#copy
COPY *.go ./
# Build
RUN CGO_ENABLED=0 GOOS=linux go build -o /rolldice
-# Optional:
-# To bind to a TCP port, runtime parameters must be supplied to the docker command.
-# But we can document in the Dockerfile what ports
-# the application is going to listen on by default.
-# https://docs.docker.com/engine/reference/builder/#expose
EXPOSE 8081
# Run
diff --git a/examples/go/run.sh b/examples/go/run.sh
index cad262f..f192e3c 100755
--- a/examples/go/run.sh
+++ b/examples/go/run.sh
@@ -4,5 +4,5 @@ set -euo pipefail
export OTEL_EXPORTER_OTLP_INSECURE="true" # needed because of https://github.com/open-telemetry/opentelemetry-go/issues/4834
export OTEL_METRIC_EXPORT_INTERVAL="5000" # so we don't have to wait 60s for metrics
-export OTEL_RESOURCE_ATTRIBUTES="service.name=example-app,service.instance.id=localhost:8081"
+export OTEL_RESOURCE_ATTRIBUTES="service.name=rolldice,service.instance.id=localhost:8081"
go run .
diff --git a/examples/java/pom.xml b/examples/java/pom.xml
index ec27aa1..20ac1af 100644
--- a/examples/java/pom.xml
+++ b/examples/java/pom.xml
@@ -4,7 +4,7 @@
4.0.0
com.grafana.example
- example-app
+ rolldice
1.0.0-SNAPSHOT
Hello World REST Service
diff --git a/examples/java/run.sh b/examples/java/run.sh
index 89b9b45..77caf57 100755
--- a/examples/java/run.sh
+++ b/examples/java/run.sh
@@ -2,7 +2,7 @@
set -euo pipefail
-if [[ ! -f ./target/example-app.jar ]] ; then
+if [[ ! -f ./target/rolldice.jar ]] ; then
./mvnw clean package
fi
version=v2.0.0
@@ -10,5 +10,5 @@ jar=opentelemetry-javaagent-${version}.jar
if [[ ! -f ./${jar} ]] ; then
curl -sL https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v2.0.0/opentelemetry-javaagent.jar -o ${jar}
fi
-export OTEL_RESOURCE_ATTRIBUTES="service.name=example-app,service.instance.id=localhost:8080"
-java -Dotel.metric.export.interval=500 -Dotel.bsp.schedule.delay=500 -javaagent:${jar} -jar ./target/example-app.jar
+export OTEL_RESOURCE_ATTRIBUTES="service.name=rolldice,service.instance.id=localhost:8080"
+java -Dotel.metric.export.interval=500 -Dotel.bsp.schedule.delay=500 -javaagent:${jar} -jar ./target/rolldice.jar
diff --git a/examples/python/Dockerfile b/examples/python/Dockerfile
new file mode 100644
index 0000000..2bb29f3
--- /dev/null
+++ b/examples/python/Dockerfile
@@ -0,0 +1,25 @@
+FROM python:alpine3.19
+
+WORKDIR /app
+
+COPY requirements.txt .
+
+# How to get the requirements.txt file?
+# 1. Follow https://opentelemetry.io/docs/languages/python/getting-started/
+# 2. Run `pip freeze > requirements.txt` in the same directory as your app.py file
+RUN pip install -r requirements.txt
+
+RUN pip install opentelemetry-distro[otlp]
+RUN opentelemetry-bootstrap -a install
+
+COPY app.py .
+
+# Logging support is still in alpha, so we need to enable it explicitly
+ENV OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true
+
+EXPOSE 8082
+
+CMD ["opentelemetry-instrument", "flask", "run", "--host", "0.0.0.0", "--port", "8082"]
+
+
+
diff --git a/examples/python/app.py b/examples/python/app.py
new file mode 100644
index 0000000..b3897ef
--- /dev/null
+++ b/examples/python/app.py
@@ -0,0 +1,22 @@
+from random import randint
+from flask import Flask, request
+import logging
+
+app = Flask(__name__)
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger(__name__)
+
+
+@app.route("/rolldice")
+def roll_dice():
+ player = request.args.get('player', default=None, type=str)
+ result = str(roll())
+ if player:
+ logger.warning("%s is rolling the dice: %s", player, result)
+ else:
+ logger.warning("Anonymous player is rolling the dice: %s", result)
+ return result
+
+
+def roll():
+ return randint(1, 6)
diff --git a/examples/python/docker-compose.oats.yml b/examples/python/docker-compose.oats.yml
new file mode 100644
index 0000000..9a57965
--- /dev/null
+++ b/examples/python/docker-compose.oats.yml
@@ -0,0 +1,13 @@
+# OATS is an acceptance testing framework for OpenTelemetry - https://github.com/grafana/oats/tree/main/yaml
+version: '3.4'
+
+services:
+ go:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ environment:
+ OTEL_EXPORTER_OTLP_ENDPOINT: http://collector:4317
+ OTEL_METRIC_EXPORT_INTERVAL: "5000" # so we don't have to wait 60s for metrics
+ ports:
+ - "8080:8082"
diff --git a/examples/python/oats.yaml b/examples/python/oats.yaml
new file mode 100644
index 0000000..5ee168b
--- /dev/null
+++ b/examples/python/oats.yaml
@@ -0,0 +1,17 @@
+# OATS is an acceptance testing framework for OpenTelemetry - https://github.com/grafana/oats/tree/main/yaml
+docker-compose:
+ generator: lgtm
+ files:
+ - ./docker-compose.oats.yml
+input:
+ - path: /rolldice
+expected:
+ traces:
+ - traceql: '{ span.http.route = "/rolldice" }'
+ spans:
+ - name: '/rolldice' # should be "GET /rolldice"
+ attributes:
+ otel.library.name: opentelemetry.instrumentation.flask
+ metrics:
+ - promql: 'http_server_active_requests{http_method="GET"}'
+ value: ">= 0"
diff --git a/examples/python/requirements.txt b/examples/python/requirements.txt
new file mode 100644
index 0000000..5a3a34a
--- /dev/null
+++ b/examples/python/requirements.txt
@@ -0,0 +1,7 @@
+blinker==1.7.0
+click==8.1.7
+Flask==2.3.3
+itsdangerous==2.1.2
+Jinja2==3.1.3
+MarkupSafe==2.1.5
+Werkzeug==2.3.8
diff --git a/examples/python/run.sh b/examples/python/run.sh
new file mode 100755
index 0000000..3ea99db
--- /dev/null
+++ b/examples/python/run.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+set -euo pipefail
+
+export OTEL_METRIC_EXPORT_INTERVAL="5000" # so we don't have to wait 60s for metrics
+export OTEL_RESOURCE_ATTRIBUTES="service.name=rolldice,service.instance.id=localhost:8082"
+export OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true
+
+python3 -m venv venv
+source ./venv/bin/activate
+
+# How to get the requirements.txt file?
+# 1. Follow https://opentelemetry.io/docs/languages/python/getting-started/
+# 2. Run `pip freeze > requirements.txt` in the same directory as your app.py file
+pip install -r requirements.txt
+
+pip install opentelemetry-distro[otlp]
+opentelemetry-bootstrap -a install
+
+opentelemetry-instrument flask run -p 8082
diff --git a/generate-traffic.sh b/generate-traffic.sh
index c4c8fad..16dd646 100755
--- a/generate-traffic.sh
+++ b/generate-traffic.sh
@@ -1,3 +1,3 @@
#!/bin/bash
-watch 'curl -s http://localhost:8080/rolldice; curl -s http://localhost:8081/rolldice'
+watch 'curl -s http://localhost:8080/rolldice; curl -s http://localhost:8081/rolldice; curl -s http://localhost:8082/rolldice'
diff --git a/run-lgtm.sh b/run-lgtm.sh
new file mode 100755
index 0000000..176d67b
--- /dev/null
+++ b/run-lgtm.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+docker run -p 3000:3000 -p 4317:4317 -p 4318:4318 --rm -ti grafana/otel-lgtm