|
| 1 | +--- |
| 2 | +title: How to Name Your Span Attributes |
| 3 | +linkTitle: How to Name Your Span Attributes |
| 4 | +date: 2025-08-27 |
| 5 | +author: >- |
| 6 | + [Juraci Paixão Kröhling](https://github.com/jpkrohling) (OllyGarden) |
| 7 | +canonical_url: https://blog.olly.garden/how-to-name-your-span-attributes |
| 8 | +cSpell:ignore: interoperability jpkrohling OllyGarden shopify |
| 9 | +--- |
| 10 | + |
| 11 | +Welcome to the second installment in our series on OpenTelemetry naming best |
| 12 | +practices. In our [previous post](/blog/2025/how-to-name-your-spans/), we |
| 13 | +explored how to name spans using the `{verb} {object}` pattern. Today, we're |
| 14 | +diving into span attributes—the rich contextual data that transforms your traces |
| 15 | +from simple operation logs into powerful debugging and analysis tools. |
| 16 | + |
| 17 | +This guide targets developers who are: |
| 18 | + |
| 19 | +- **Instrumenting their own applications** with custom spans and attributes |
| 20 | +- **Enriching telemetry** beyond what auto-instrumentation provides |
| 21 | +- **Creating libraries** that others will instrument |
| 22 | + |
| 23 | +The attribute naming decisions you make directly impact the usability and |
| 24 | +maintainability of your observability data. Let's get them right. |
| 25 | + |
| 26 | +## Start with semantic conventions |
| 27 | + |
| 28 | +Here's the most important rule that will save you time and improve |
| 29 | +interoperability: **if an OpenTelemetry |
| 30 | +[semantic convention exists](/docs/specs/semconv/registry/attributes/) and the |
| 31 | +semantics match your use case, use it**. |
| 32 | + |
| 33 | +This isn't just about convenience—it's about building telemetry that integrates |
| 34 | +seamlessly with the broader OpenTelemetry ecosystem. When you use standardized |
| 35 | +attribute names, your data automatically works with existing dashboards, |
| 36 | +alerting rules, and analysis tools. |
| 37 | + |
| 38 | +### When semantics match, use the convention |
| 39 | + |
| 40 | +| Your need | Use this semantic convention | Why | |
| 41 | +| :----------------------- | :--------------------------- | :---------------------------------------------- | |
| 42 | +| HTTP request method | `http.request.method` | Standardized across all HTTP instrumentation | |
| 43 | +| Database collection name | `db.collection.name` | Works with database monitoring tools | |
| 44 | +| Service identification | `service.name` | Core resource attribute for service correlation | |
| 45 | +| Network peer address | `network.peer.address` | Standard for network-level debugging | |
| 46 | +| Error classification | `error.type` | Enables consistent error analysis | |
| 47 | + |
| 48 | +The key principle is **semantic match over naming preference**. Even if you |
| 49 | +prefer `database_table` over `db.collection.name`, use the semantic convention |
| 50 | +when it accurately describes your data. |
| 51 | + |
| 52 | +### When semantics don't match, don't force it |
| 53 | + |
| 54 | +Resist the temptation to misuse semantic conventions: |
| 55 | + |
| 56 | +| Don't do this | Why it's wrong | |
| 57 | +| :----------------------------------------------- | :---------------------------------------------------- | |
| 58 | +| Using `db.collection.name` for a file name | Files and database collections are different concepts | |
| 59 | +| Using `http.request.method` for business actions | "approve_payment" isn't an HTTP method | |
| 60 | +| Using `user.id` for a transaction ID | Users and transactions are different entities | |
| 61 | + |
| 62 | +Misusing semantic conventions is worse than creating custom attributes—it |
| 63 | +creates confusion and breaks tooling that expects the standard semantics. |
| 64 | + |
| 65 | +## The golden rule: Domain first, never company first |
| 66 | + |
| 67 | +When you need custom attributes beyond the semantic conventions, the most |
| 68 | +critical principle is: **start with the domain or technology, never your company |
| 69 | +or application name**. |
| 70 | + |
| 71 | +This principle seems obvious but is consistently violated across the industry. |
| 72 | +Here's why it matters and how to get it right. |
| 73 | + |
| 74 | +### Why company-first naming fails |
| 75 | + |
| 76 | +| Bad attribute name | Problems | |
| 77 | +| :-------------------------- | :--------------------------------------------------- | |
| 78 | +| `og.user.id` | Company prefix pollutes global namespace | |
| 79 | +| `myapp.request.size` | Application-specific, not reusable | |
| 80 | +| `acme.inventory.count` | Makes correlation with standard attributes difficult | |
| 81 | +| `shopify_store.product.sku` | Unnecessarily ties concept to one vendor | |
| 82 | + |
| 83 | +These approaches create attributes that are: |
| 84 | + |
| 85 | +- Difficult to correlate across teams and organizations |
| 86 | +- Impossible to reuse in different contexts |
| 87 | +- Vendor-locked and inflexible |
| 88 | +- Inconsistent with OpenTelemetry's interoperability goals |
| 89 | + |
| 90 | +### Domain-first success stories |
| 91 | + |
| 92 | +| Good attribute name | Why it works | |
| 93 | +| :------------------- | :--------------------------------- | |
| 94 | +| `user.id` | Universal concept, vendor-neutral | |
| 95 | +| `request.size` | Reusable across applications | |
| 96 | +| `inventory.count` | Clear, domain-specific concept | |
| 97 | +| `product.sku` | Standard e-commerce terminology | |
| 98 | +| `workflow.step.name` | Generic process management concept | |
| 99 | + |
| 100 | +This approach creates attributes that are universally understandable, reusable |
| 101 | +by others facing similar problems, and future-proof. |
| 102 | + |
| 103 | +## Understanding the structure: Dots and underscores |
| 104 | + |
| 105 | +OpenTelemetry attribute names follow a specific structural pattern that balances |
| 106 | +readability with consistency. Understanding this pattern helps you create |
| 107 | +attributes that feel natural alongside standard semantic conventions. |
| 108 | + |
| 109 | +### Use dots for hierarchical separation |
| 110 | + |
| 111 | +Dots (`.`) separate hierarchical components, following the pattern: |
| 112 | +`{domain}.{component}.{property}` |
| 113 | + |
| 114 | +Examples from semantic conventions: |
| 115 | + |
| 116 | +- `http.request.method` - HTTP domain, request component, method property |
| 117 | +- `db.collection.name` - Database domain, collection component, name property |
| 118 | +- `service.instance.id` - Service domain, instance component, ID property |
| 119 | + |
| 120 | +### Use underscores for multi-word components |
| 121 | + |
| 122 | +When a single component contains multiple words, use underscores (`_`): |
| 123 | + |
| 124 | +- `http.response.status_code` - "status_code" is one logical component |
| 125 | +- `system.memory.usage_percent` - "usage_percent" is one measurement concept |
| 126 | + |
| 127 | +### Create deeper hierarchies when needed |
| 128 | + |
| 129 | +You can nest further when it adds clarity: |
| 130 | + |
| 131 | +- `http.request.body.size` |
| 132 | +- `k8s.pod.label.{key}` |
| 133 | +- `messaging.kafka.message.key` |
| 134 | + |
| 135 | +Each level should represent a meaningful conceptual boundary. |
| 136 | + |
| 137 | +## Reserved namespaces: What you must never use |
| 138 | + |
| 139 | +Certain namespaces are strictly reserved, and violating these rules can break |
| 140 | +your telemetry data. |
| 141 | + |
| 142 | +### The `otel.*` namespace is off-limits |
| 143 | + |
| 144 | +The `otel.*` prefix is exclusively reserved for the OpenTelemetry specification |
| 145 | +itself. It's used to express OpenTelemetry concepts in telemetry formats that |
| 146 | +don't natively support them. |
| 147 | + |
| 148 | +Reserved `otel.*` attributes include: |
| 149 | + |
| 150 | +- `otel.scope.name` - Instrumentation scope name |
| 151 | +- `otel.status_code` - Span status code |
| 152 | +- `otel.span.sampling_result` - Sampling decision |
| 153 | + |
| 154 | +**Never create attributes starting with `otel.`** Any additions to this |
| 155 | +namespace must be approved as part of the OpenTelemetry specification. |
| 156 | + |
| 157 | +### Other reserved attributes |
| 158 | + |
| 159 | +The specification also reserves these specific attribute names: |
| 160 | + |
| 161 | +- `error.type` |
| 162 | +- `exception.message`, `exception.stacktrace`, `exception.type` |
| 163 | +- `server.address`, `server.port` |
| 164 | +- `service.name` |
| 165 | +- `telemetry.sdk.language`, `telemetry.sdk.name`, `telemetry.sdk.version` |
| 166 | +- `url.scheme` |
| 167 | + |
| 168 | +## Semantic convention patterns |
| 169 | + |
| 170 | +The best way to develop good attribute naming intuition is studying |
| 171 | +OpenTelemetry's semantic conventions. These represent thousands of hours of |
| 172 | +design work by observability experts. |
| 173 | + |
| 174 | +### Domain organization patterns |
| 175 | + |
| 176 | +Notice how semantic conventions organize around clear domains: |
| 177 | + |
| 178 | +#### Infrastructure domains |
| 179 | + |
| 180 | +- `service.*` - Service identity and metadata |
| 181 | +- `host.*` - Host/machine information |
| 182 | +- `container.*` - Container runtime information |
| 183 | +- `process.*` - Operating system processes |
| 184 | + |
| 185 | +#### Communication domains |
| 186 | + |
| 187 | +- `http.*` - HTTP protocol specifics |
| 188 | +- `network.*` - Network layer information |
| 189 | +- `rpc.*` - Remote procedure call attributes |
| 190 | +- `messaging.*` - Message queue systems |
| 191 | + |
| 192 | +#### Data domains |
| 193 | + |
| 194 | +- `db.*` - Database operations |
| 195 | +- `url.*` - URL components |
| 196 | + |
| 197 | +### Universal property patterns |
| 198 | + |
| 199 | +Across all domains, consistent patterns emerge for common properties: |
| 200 | + |
| 201 | +#### Identity properties |
| 202 | + |
| 203 | +- `.name` - Human-readable identifiers (`service.name`, `container.name`) |
| 204 | +- `.id` - System identifiers (`container.id`, `process.pid`) |
| 205 | +- `.version` - Version information (`service.version`) |
| 206 | +- `.type` - Classification (`messaging.operation.type`, `error.type`) |
| 207 | + |
| 208 | +#### Network properties |
| 209 | + |
| 210 | +- `.address` - Network addresses (`server.address`, `client.address`) |
| 211 | +- `.port` - Port numbers (`server.port`, `client.port`) |
| 212 | + |
| 213 | +#### Measurement properties |
| 214 | + |
| 215 | +- `.size` - Byte measurements (`http.request.body.size`) |
| 216 | +- `.count` - Quantities (`messaging.batch.message_count`) |
| 217 | +- `.duration` - Time measurements (`http.server.request.duration`) |
| 218 | + |
| 219 | +When creating custom domains, follow these same patterns. For inventory |
| 220 | +management, consider: |
| 221 | + |
| 222 | +- `inventory.item.name` |
| 223 | +- `inventory.item.id` |
| 224 | +- `inventory.location.address` |
| 225 | +- `inventory.batch.count` |
| 226 | + |
| 227 | +## Creating custom domains safely |
| 228 | + |
| 229 | +Sometimes your business logic requires attributes outside existing semantic |
| 230 | +conventions. This is normal—OpenTelemetry can't cover every possible business |
| 231 | +domain. |
| 232 | + |
| 233 | +### Guidelines for safe custom domains |
| 234 | + |
| 235 | +1. **Choose descriptive, generic names** that others could reuse. |
| 236 | +2. **Avoid company-specific terminology** in the domain name. |
| 237 | +3. **Follow hierarchical patterns** established by semantic conventions. |
| 238 | +4. **Consider if your domain could become a future semantic convention**. |
| 239 | + |
| 240 | +### Examples of well-designed custom attributes |
| 241 | + |
| 242 | +| Domain | Good attributes | Why they work | |
| 243 | +| :-------- | :--------------------------------------- | :-------------------------------- | |
| 244 | +| Business | `payment.method`, `order.status` | Clear, reusable business concepts | |
| 245 | +| Logistics | `inventory.location`, `shipment.carrier` | Domain-specific but transferable | |
| 246 | +| Process | `workflow.step.name`, `approval.status` | Generic process management | |
| 247 | +| Content | `document.format`, `media.codec` | Universal content concepts | |
| 248 | + |
| 249 | +## The rare exception: When prefixes make sense |
| 250 | + |
| 251 | +In rare cases, you might need company or application prefixes. This typically |
| 252 | +happens when your custom attribute might conflict with attributes from other |
| 253 | +sources in a distributed system. |
| 254 | + |
| 255 | +**Consider prefixes when:** |
| 256 | + |
| 257 | +- Your attribute might conflict with vendor attributes in a distributed system. |
| 258 | +- You're instrumenting proprietary technology that's truly company-specific. |
| 259 | +- You're capturing internal implementation details that shouldn't be |
| 260 | + generalized. |
| 261 | + |
| 262 | +For most business logic attributes, stick with domain-first naming. |
| 263 | + |
| 264 | +## Your action plan |
| 265 | + |
| 266 | +Naming span attributes well creates telemetry data that's maintainable, |
| 267 | +interoperable, and valuable across your organization. Here's your roadmap: |
| 268 | + |
| 269 | +1. **Always check semantic conventions first** - Use them when semantics match. |
| 270 | +2. **Lead with domain, never company** - Create vendor-neutral attributes. |
| 271 | +3. **Respect reserved namespaces** - Especially avoid `otel.*`. |
| 272 | +4. **Follow hierarchical patterns** - Use dots and underscores consistently. |
| 273 | +5. **Build for reusability** - Think beyond your current needs. |
| 274 | + |
| 275 | +By following these principles, you're not just solving today's instrumentation |
| 276 | +challenges—you're contributing to a more coherent, interoperable observability |
| 277 | +ecosystem that benefits everyone. |
| 278 | + |
| 279 | +In our next post in this series, we'll shift our focus from spans to |
| 280 | +metrics—exploring how to name the quantitative measurements that tell us how our |
| 281 | +systems are performing, and why the same principles of separation and |
| 282 | +domain-first thinking apply to the numbers that matter most. |
0 commit comments