OTel Studio
Generate realistic OpenTelemetry data for any observability stack
OTel Studio is a Docker-deployable telemetry data generator that produces correlated traces, logs and metrics using realistic service topologies. Point it at any OTel-compatible backend and get production-like data flowing in 60 seconds.
Quick Start
docker run -d --name otel-studio -p 3002:3002 \ -e OTEL_ENDPOINT="http://your-collector:4317" \ -e OTEL_PROTOCOL="grpc" \ -e ADMIN_PASS="your-password" \ otel-studio:latest
Open http://localhost:3002, log in with admin / your password, enable a scenario and click Start.
Navigating the App
OTel Studio uses a slim icon rail on the left to switch between five pages. Each gets the full window width — nothing is squeezed into a sidebar.
The top control bar (Real System Data / Simulation toggles, signal switches, quota timer, Inject Anomaly, global rate multiplier, Start/Stop/Reset) stays visible on every page — these are global controls, not scoped to any one page.
Architecture
Traces, logs and metrics are sent via standard OTLP protocol — works with any OTel-compatible backend
OTel Studio uses the official OpenTelemetry JS SDK. Each scenario creates a BasicTracerProvider per service name, with one BatchSpanProcessor per active endpoint. Logs use LoggerProvider with one BatchLogRecordProcessor per active endpoint. Metrics use a shared MeterProvider with one PeriodicExportingMetricReader per active endpoint — this is what makes multi-endpoint fanout work for all three signal types, not just traces.
All three signals are correlated — logs emitted during a trace span inherit the span's trace ID and span ID via OpenTelemetry context propagation. This means you can search for a trace ID in your backend and see the matching logs and metrics.
Docker Configuration
docker run -d --name otel-studio -p 3002:3002 \ -e OTEL_ENDPOINT="http://otelcol:4317" \ -e OTEL_PROTOCOL="grpc" \ -e SERVICE_NAME="otel-agent" \ -e ENVIRONMENT="production" \ -e ADMIN_PASS="secure-password" \ -e MODE_REAL="true" \ -e MODE_SIM="true" \ -v /var/log:/var/log:ro \ -v /var/run/docker.sock:/var/run/docker.sock \ -v otel-data:/data \ --memory=256m \ otel-studio:latest
JWT_SECRET is optional — if omitted, OTel Studio generates a random one on first boot and persists it in the mounted /data volume, so it stays stable across restarts without needing to be set manually. Pass -e JWT_SECRET="..." explicitly only if you're running multiple replicas that need to share one signing secret.25 Scenarios
Each scenario simulates a realistic service topology with parent-child span relationships, correlated log records per service, and matching metric instrument recordings.
Web App
| Scenario | Services | Description |
|---|---|---|
| E-Commerce | frontend → cart → inventory → payment → search → recommendations | Full shopping flow with checkout, search and product recommendations |
| SaaS Platform | api-gateway → auth → user → billing → feature-flags → payment-gateway | Multi-tenant SaaS with auth, billing, subscription management |
| Media Streaming | cdn-edge → origin → transcoder → queue-worker → storage | Video streaming with CDN cache, transcoding pipeline |
| Banking / FinTech | web-portal → fraud-detection → risk-engine → payment → ledger → audit | Financial transactions with fraud scoring and audit trail |
| Social Network | feed → graph → ranking → media → notification-fanout → cache | Social feed generation with friend graph traversal |
Infrastructure
| Scenario | Services | Description |
|---|---|---|
| Linux Syslog | kernel, sshd, systemd, cron, nginx, postgresql, dockerd | System-level log generation (OOM kills, SSH, service failures) |
| Kubernetes | kube-apiserver → scheduler → kubelet → containerd → coredns → etcd | K8s control plane operations (pod scheduling, image pulls, OOM) |
| Database Cluster | query-router → primary-db → replica-db → wal-archiver → read-cache | Database with replication, slow queries, deadlocks |
| Message Queue | producer → kafka-broker → consumer-group → processor → dead-letter | Kafka pipeline with consumer lag and DLQ routing |
| CI/CD Pipeline | webhook-trigger → build-agent → test-runner → deploy-agent → health-checker | Build/test/deploy with rollback triggers |
APM
| Scenario | Services | Description |
|---|---|---|
| Java / JVM | java-backend → node-api → python-worker → go-proxy → ruby-app | Polyglot APM with GC pauses, heap pressure |
| Node.js Services | express-gateway → auth-middleware → product → mongoose → redis → elastic | Express.js stack with MongoDB, Redis, Elasticsearch |
| Python ML Pipeline | api-server → feature-store → model-server → vector-db → result-cache | ML inference with CUDA OOM, feature lag |
| Go Services | http-proxy → grpc-service → worker-pool → object-store | Go microservices with goroutine monitoring |
| .NET Platform | aspnet-gateway → identity → order → data-service → token-store → cache | ASP.NET with SQL Server connection pooling |
Cloud Native
| Scenario | Services | Description |
|---|---|---|
| IoT / Edge | sensor-hub → edge-gateway → stream-processor → timeseries-db → anomaly-detector | IoT telemetry with edge buffering, anomaly detection |
| Serverless / FaaS | api-gateway → lambda-auth → lambda-process → dynamodb → s3 → sns | Lambda functions with cold starts, timeouts |
| Service Mesh | istio-ingressgateway → envoy-sidecar → service-a → service-b | Istio/Envoy with circuit breakers, mTLS errors |
| Security / SIEM | firewall → ids-engine → siem → alert-manager → notification | Security event pipeline with CVE detection, SOC alerts |
| Mobile Backend | mobile-api → auth → feed-aggregator → content → analytics → event-store | Mobile app backend with biometric auth, push notifications |
Chaos / Stress
| Scenario | Services | Description |
|---|---|---|
| Error Storm | frontend → cart → payment → inventory | 80% forced error rate — tests error alerting |
| Cardinality Burst | api-gateway → data-service | Random user IDs per request — tests high cardinality handling |
| Latency Spike | frontend → product → payment → slow-db | 30% of spans get 2-8 second latency injection |
| Traffic Surge | gateway → order → inventory → billing → shipping | 10× batch multiplier — tests ingestion throughput |
| Cascading Failure | gateway → order → billing → cache | 75% errors with circuit breaker fallback patterns |
Signal Types & Ratios
Per the OpenTelemetry specification, the three signal types have different volume characteristics:
| Signal | Volume | How OTel Studio generates it |
|---|---|---|
| Logs | Highest | One log record per service visited in each trace chain. A 5-service chain produces 5 logs per trace. |
| Traces | Middle | One trace chain per batch item, containing 10-15 spans with parent-child relationships. |
| Metrics | Lowest | Aggregated per export cycle (10s interval). Each cycle exports one data point per unique instrument, regardless of request volume. |
Each of Traces, Logs, and Metrics can be toggled independently in the top control bar — turning a signal off stops it from being generated across every active scenario at once.
Advanced Scenario Controls
Every scenario card has an Advanced Settings panel with telemetrygen-style controls for testing specific pipeline behaviors:
Geo / IP Simulation
Tags the root span and logs of each generated request with a client.address and GeoIP-resolvable attributes (geo.country.iso_code, geo.city.name, geo.location.lat/lon, cloud.region), so requests appear to originate from realistic global locations. Two modes, set globally on the Endpoints page:
| Mode | Behavior |
|---|---|
| Realistic | Real regional cloud IP ranges — resolves to an actual city/country in your backend's GeoIP lookup |
| Safe / TEST-NET | RFC 5737 non-routable ranges (192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24) — guaranteed to never collide with real infrastructure, at the cost of not resolving to a real location |
Synthetic PII
Tags the root span and logs with a synthetic user.id, user.name, and user.email, generated from a fixed name pool and RFC 2606-reserved domains (example.com/.org/.net) — never real people's data. Every synthetic record is marked with pii.synthetic: true so a downstream redaction/DLP pipeline being tested can positively identify it. Recommended for scenarios like Banking, Social Network, and E-Commerce where testing PII handling is relevant.
Custom Attributes
Arbitrary key=value pairs, comma-separated, added to the root span and logs of every request in that scenario — useful for tagging generated data with a team name, region, or any attribute your dashboards filter on.
Span Duration Override
Set a min/max range in milliseconds to override the scenario's natural randomized timing. Leave blank to use built-in realistic chain timing.
Status Code Weights
code:weight pairs, comma-separated (e.g. 200:90,404:5,500:5) — controls the distribution of HTTP status codes on generated spans. When set, this overrides the scenario's plain error-rate slider.
Anomaly Injection
Click ⚡ Inject Anomaly to trigger a burst across all active scenarios. For 30 seconds (or until you click Stop Anomaly):
| Traffic | 10× normal batch count |
| Error rate | Forced to 80% regardless of slider |
| Latency | 30% of spans get 2-8 second duration spikes |
Anomaly state is tracked server-side and stays in sync with the main Start/Stop control — stopping the simulation (manually or via quota expiry) also clears an in-progress anomaly, and the button/timer reflect this on any connected browser tab, not just the one that triggered it.
Sequential Mode
Enable Sequential Mode in the Scenarios panel to run one scenario at a time, rotating through all enabled scenarios on a configurable timer (default 30 seconds each). Useful for sequential load testing — each scenario runs in isolation before rotating to the next.
Time Limit / Quota
Set a time limit (1m / 5m / 10m / 30m / 1h / no limit) before clicking Start. The top bar shows a live countdown; when it reaches zero, sending stops automatically across all signals — including metrics, which export on their own periodic schedule independent of the trace/log generation loop.
Multi-Endpoint Fanout
OTel Studio can send telemetry to multiple collectors simultaneously. On the Endpoints page, each endpoint has its own toggle — check any combination to activate them together; at least one must stay active. The SDK creates one BatchSpanProcessor, one BatchLogRecordProcessor, and one metric reader per active endpoint, so traces, logs, and metrics all fan out identically. Use this to compare two o11y backends side-by-side or to send to both production and staging collectors at once.
TLS / mTLS
Each endpoint supports an optional TLS/mTLS configuration, expandable in the Add/Edit Endpoint form: a CA certificate, a client certificate, a client private key (all PEM format), and an "insecure" toggle to skip certificate verification for testing against self-signed backends.
Stack Presets
One-click endpoint configuration for 12 popular observability backends:
| Backend | Protocol | Default URL |
|---|---|---|
| Grafana Alloy | gRPC / HTTP | http://alloy:4317 or :4318 |
| OpenTelemetry Collector | gRPC | http://otelcol:4317 |
| Elastic APM | HTTP | http://apm-server:8200 |
| Honeycomb | HTTP | https://api.honeycomb.io |
| Jaeger | gRPC | http://jaeger:4317 |
| SigNoz | gRPC | http://otel-collector:4317 |
| OpenObserve | HTTP | http://openobserve:5080 |
| Datadog Agent | HTTP | http://datadog-agent:4318 |
| New Relic | HTTP | https://otlp.nr-data.net |
| Dynatrace | HTTP | https://ENV.live.dynatrace.com/api/v2/otlp |
| Lightstep / ServiceNow | HTTP | https://ingest.lightstep.com |
Webhook on Quota Expire
Set an HTTP endpoint (Slack incoming webhook or any URL) on the Endpoints page. When the time-limit quota expires and sending stops automatically, OTel Studio fires a POST with {event: "quota_expired", ts: "<ISO timestamp>"} — useful for notifying a team channel when an automated test run finishes.
Real System Data
Alongside simulated scenarios, OTel Studio can collect real telemetry from the host it's running on, on the Real Data page:
| Log file tailing | Tail any log files on disk (mount them via -v /var/log:/var/log:ro) and stream new lines as real OTel log records |
| Docker container logs | Poll logs from other containers on the host (requires mounting /var/run/docker.sock) |
| Docker container metrics | CPU/memory usage per container |
| System metrics | Host CPU, memory, load average, and network interface stats |
Real System Data and Simulation are independent toggles — run either alone or both together.
Import / Export
Export your scenario configuration as JSON to share setups with your team. Import a config file to restore a saved setup. Export the activity stream as CSV for offline analysis.
Environment Variables
| Variable | Default | Description |
|---|---|---|
PORT | 3002 | HTTP server port |
OTEL_ENDPOINT | http://localhost:4318 | Default OTel collector endpoint |
OTEL_PROTOCOL | http | Protocol: grpc or http |
SERVICE_NAME | otel-agent | Service name in telemetry resource attributes |
ENVIRONMENT | production | Deployment environment attribute |
ADMIN_USER | admin | Initial admin username |
ADMIN_PASS | admin123 | Initial admin password — change this for any deployment reachable outside your own machine |
JWT_SECRET | (auto-generated) | Secret for signing auth tokens. If not set, a random one is generated on first boot and persisted in the /data volume — stable across restarts, unique per deployment |
DB_PATH | /data/otel-simulator.db | SQLite database path |
MODE_REAL | false | Enable real system data collection |
MODE_SIM | true | Enable simulated telemetry |
SCENARIO | ecommerce | Legacy single-scenario default — the app now primarily uses per-scenario config set from the UI (see Advanced Scenario Controls); this only affects the very first boot before any config is saved |
RATE_MS | 1000 | Legacy default rate for SCENARIO on first boot |
BATCH_SIZE | 1 | Legacy default batch size for SCENARIO on first boot |
ERROR_RATE | 0.05 | Legacy default error rate for SCENARIO on first boot |
LOG_FILES | (empty) | Comma-separated paths to tail for real logs |
DOCKER_LOGS | true | Tail Docker container logs |
DOCKER_METRICS | true | Collect Docker container metrics |
METRICS_INTERVAL | 5000 | System metrics collection interval (ms) |
OTel Studio v2.0 — Built by XplurData