Test Backend Integrations¶
This guide covers using motel to verify that an OTLP-compatible backend accepts, stores, and displays traces correctly. The same approach works for initial setup, multi-backend routing, and backend migrations.
Prerequisites¶
- motel installed
- A topology file (see Model your services to create one)
- One or more OTLP-compatible backends running and reachable
Verify a new backend¶
Send a short burst of traces to confirm the backend accepts OTLP data and renders it correctly.
1. Create a test topology¶
Use a small topology that exercises the features you care about — multiple services, varying durations, and some errors:
version: 1
services:
web-gateway:
resource_attributes:
deployment.environment: staging
service.version: 1.0.0
operations:
GET /healthz:
duration: 5ms +/- 2ms
calls:
- api-server.healthcheck
api-server:
resource_attributes:
deployment.environment: staging
service.version: 2.3.1
operations:
healthcheck:
duration: 2ms +/- 1ms
process-order:
duration: 80ms +/- 20ms
error_rate: 5%
calls:
- database.query
database:
resource_attributes:
deployment.environment: staging
db.system: postgresql
operations:
query:
duration: 10ms +/- 3ms
error_rate: 1%
traffic:
rate: 10/s
Save this as backend-test.yaml.
2. Send traces to the backend¶
Point motel at your backend's OTLP endpoint:
motel run --endpoint http://localhost:4318 --protocol http/protobuf \
--duration 10s backend-test.yaml
For gRPC endpoints:
motel run --endpoint localhost:4317 --protocol grpc \
--duration 10s backend-test.yaml
3. Check the results¶
Open your backend's UI and verify:
- All three services appear (web-gateway, api-server, database)
- Traces show the expected call hierarchy: web-gateway calls api-server, which calls database
- Span durations are in the expected ranges
- Some spans on api-server.process-order and database.query are marked as errors
- Resource attributes (
deployment.environment,service.version,db.system) are visible
If traces do not appear, check that the endpoint URL and protocol match your backend's configuration. Use --stdout to confirm motel is generating valid data:
motel run --stdout --duration 2s backend-test.yaml | head -5
Test multi-backend routing¶
A common pattern is routing traces to different backends based on content — for example, sending error traces to a dedicated backend for alerting. motel does not route traces itself, but it generates consistent traffic that you can use to verify your collector's routing rules.
1. Configure your collector¶
Set up an OpenTelemetry Collector with routing logic. For example, a collector config that sends all traces to a primary backend and only error traces to a second backend:
receivers:
otlp:
protocols:
http:
endpoint: 0.0.0.0:4318
exporters:
otlphttp/primary:
endpoint: http://primary-backend:4318
otlphttp/errors:
endpoint: http://errors-backend:4318
processors:
filter/errors-only:
error_mode: ignore
trace_conditions:
- 'span.status.code != STATUS_CODE_ERROR'
service:
pipelines:
traces/all:
receivers: [otlp]
exporters: [otlphttp/primary]
traces/errors:
receivers: [otlp]
processors: [filter/errors-only]
exporters: [otlphttp/errors]
Both pipelines receive all traffic from the same OTLP receiver. The filter/errors-only processor drops non-error spans, so only error spans reach the errors backend.
2. Send traffic through the collector¶
Point motel at the collector's intake:
motel run --endpoint http://localhost:4318 --protocol http/protobuf \
--duration 30s backend-test.yaml
Use a topology with a meaningful error rate (the example above uses 5% on process-order) so that both backends receive data.
3. Verify routing¶
- Primary backend: should contain all traces
- Errors backend: should contain only traces with error spans
Check that error spans in the errors backend carry the same trace IDs, attributes, and timing as their counterparts in the primary backend.
Verify attribute handling¶
Different backends handle attributes differently — some index specific keys, some have length limits, some drop unknown attribute types. Use motel to send traces with a range of attribute shapes and verify they survive the round trip.
1. Add varied attributes to your topology¶
services:
attribute-test:
resource_attributes:
deployment.environment: production
service.version: 3.1.4
cloud.provider: aws
cloud.region: eu-west-1
operations:
varied-attributes:
duration: 20ms +/- 5ms
attributes:
http.request.method:
value: GET
http.response.status_code:
range: [200, 599]
http.route:
values: {"/api/users": 50, "/api/orders": 30, "/api/products": 20}
request.id:
sequence: "req-{n}"
traffic:
rate: 5/s
2. Send and inspect¶
motel run --endpoint http://localhost:4318 --protocol http/protobuf \
--duration 10s attribute-test.yaml
In your backend, verify:
- Resource attributes appear at the service level (
deployment.environment,cloud.provider) - Span attributes appear on individual spans (
http.request.method,http.response.status_code) - Numeric ranges produce varied integer values, not strings
- Weighted values produce the expected distribution (roughly 50/30/20 across routes)
- Sequence values increment correctly (
req-1,req-2, ...)
Smoke test a backend migration¶
When migrating from one backend to another, use motel to send identical traffic to both and compare the results side by side.
1. Send the same traffic to both backends¶
Run motel twice with the same topology, duration, and seed — once against each backend:
motel run --endpoint http://old-backend:4318 --protocol http/protobuf \
--duration 30s --seed 4242 backend-test.yaml
motel run --endpoint http://new-backend:4318 --protocol http/protobuf \
--duration 30s --seed 4242 backend-test.yaml
2. Compare¶
Check both backends for:
- Same number of services and operations visible
- Consistent attribute rendering (no truncation, no missing keys)
- Similar trace visualisation (waterfall view, service maps)
- Error spans displayed and filterable
The trace IDs will differ between runs, but the fixed seed makes simulation decisions reproducible within the same motel version, so structure, timing distributions, and attribute values should be easier to compare. Seeded runs are for repeatable comparisons, not a cross-version stable output contract. What matters is that both backends handle the same shape of data identically.
3. Use scenarios to stress-test¶
Add a scenario to simulate a latency spike and verify both backends handle it:
scenarios:
- name: database latency spike
at: +5s
duration: 10s
override:
database.query:
duration: 500ms +/- 100ms
error_rate: 15%
Run with the scenario and confirm both backends display the spike correctly in their dashboards and alerting views.
Further reading¶
- Visualise traces — setting up Jaeger, Grafana + Tempo, or hosted backends to view traces
- Model your services — creating and refining topologies
- CLI reference — all CLI flags and output formats