Describing the Operation
While Resource attributes describe the application, Span and Metric attributes describe the operation being performed. These are set dynamically, per request or per measurement.
The Semantic Conventions cover specific technology domains to ensure that every team instrumenting the same type of system produces compatible data.
| Domain | Key Attributes | Example Values |
|---|---|---|
| HTTP Server (incoming requests) | http.request.method, http.response.status_code, url.path, url.scheme, server.address, server.port |
"GET", 200, "/api/v1/checkout", "https", "api.example.com", 443 |
| HTTP Client (outgoing requests) | http.request.method, http.response.status_code, url.full, server.address |
"GET", 200, "https://payment.example.com/charge", "payment.example.com" |
| Database | db.system, db.name, db.operation, db.statement, server.address, server.port |
"postgresql", "orders_db", "SELECT", "SELECT * FROM orders WHERE id = ?", "db.internal", 5432 |
| Messaging (Kafka, RabbitMQ, SQS) | messaging.system, messaging.destination.name, messaging.operation |
"kafka", "order-events", "publish" |
Why the exact names matter: If you use db.system=postgresql, your monitoring backend can automatically render a Postgres icon, enable query analysis features, and group all Postgres spans together. If you use database=postgres, the backend treats it as an unknown custom attribute and none of those features activate. The value of conventions is that tooling is built against them — deviating means losing that tooling for free.
Cardinality warning: Never put high-cardinality values (user IDs, order IDs, full URLs with query parameters) into Span attributes that are also used as Metric labels. url.full is fine on a Span (one per request), but catastrophic as a Prometheus label (one time series per unique URL). The convention url.path is preferred for metrics because it excludes query strings.
A common interview scenario: "Your Prometheus cardinality is exploding. You trace it to HTTP instrumentation. What's likely wrong?" The answer: someone used url.full (which includes query parameters like ?user_id=12345) as a metric label instead of url.path or a templated route like /api/users/{id}. The fix is to use the http.route attribute (the parameterized path pattern) for metrics, not the raw URL.