How to Name Your Spans


One of the most fundamental yet often overlooked aspects of good instrumentation is naming. This post is the first in a series dedicated to the art and science of naming things in OpenTelemetry. We'll start with spans, the building blocks of a distributed trace, and give you the most important takeaway right at the beginning: how to name the spans that describe your unique business logic.
Naming your business spans
While OpenTelemetry's automatic instrumentation is fantastic for covering standard operations (like incoming HTTP requests or database calls), the most valuable insights often come from the custom spans you add to your own business logic. These are the operations unique to your application's domain.
For these custom spans, we recommend a pattern that borrows from basic grammar. Simple, clear sentences often follow a subject -> verb -> direct object structure. The "subject" (the service performing the work) is already part of the trace's context. We can use the rest of that structure for our span name:
{verb} {object}
This pattern is descriptive, easy to understand, and helps maintain low cardinality—a crucial concept we'll touch on later.
- {verb}: A verb describing the work being done (for example: process, send, calculate, render).
- {object}: A noun describing what is being acted upon (for example: payment, invoice, shopping_cart, ad).
Let's look at some examples:
Bad Name | Good Span Name | Why It's Better |
process_payment_for_user_jane_doe | process payment | The verb and object are clear. The user ID belongs in an attribute. |
sendinvoice#98765 | send invoice | Aggregable. You can easily find the P95 latency for sending all invoices. |
render_ad_for_campaign_summer_sale | render ad | The specific campaign is a detail, not the core operation. Put it in an attribute. |
calculate_shipping_for_zip_90210 | calculate shipping | The operation is consistent. The zip code is a parameter, not part of the name. |
validation_failed | validate user_input | Focus on the operation, not the outcome. The result belongs in the span's status. |
By adhering to the {verb} {object}
format, you create a clear, consistent
vocabulary for your business operations. This makes your traces incredibly
powerful. A product manager could ask, "How long does it take to process
payments?" and an engineer can immediately filter for those spans and get an
answer.
Why this pattern works
So why is process payment
good and process*invoice*#98765
bad? The reason is
cardinality.
Cardinality refers to the number of unique values a piece of data can have. A span name should have low cardinality. If you include unique identifiers like a user ID or an invoice number in the span name, you will create a unique name for every single operation. This floods your observability backend, makes it impossible to group and analyze similar operations, and can significantly increase costs.
The {verb} {object}
pattern naturally produces low-cardinality names. The
unique, high-cardinality details (invoice\_#98765, user_jane_doe
) belong in
span attributes, which we will cover in a future blog post.
Learning from Semantic Conventions
This {verb} {object}
approach isn't arbitrary. It's a best practice that
reflects the principles behind the official OpenTelemetry Semantic Conventions
(SemConv). SemConv provides a standardized set of names for common operations,
ensuring that a span for an HTTP request is named consistently, regardless of
the language or framework.
When you look closely, you'll see this same pattern of describing an operation on a resource echoed throughout the conventions. By following it for your custom spans, you are aligning with the established philosophy of the entire OpenTelemetry ecosystem.
Let's look at a few examples from SemConv.
HTTP spans
For server-side HTTP spans, the convention is {method} {route}
.
- Example:
GET /api/users/:ID
- Analysis: This is a verb (
GET
) acting on an object (/api/users/:id
). The use of a route template instead of the actual path (/api/users/123
) is a perfect example of maintaining low cardinality.
Database spans
Database spans are often named {db.operation} {db.name}.{db.sql.table}
.
- Example:
INSERT my_database.users
- Analysis: This is a verb (
INSERT
) acting on an object (my_database
.users). The specific values being inserted are high-cardinality and are rightly excluded from the name.
RPC spans
For Remote Procedure Calls, the convention is {rpc.service}/{rpc.method}
.
- Example:
com.example.UserService/GetUser
- Analysis: While the format is different, the principle is the same. It
describes a method (
GetUser
), which is a verb, within a service (com.example.UserService
), which is the object or resource.
The key takeaway is that by using {verb} {object}
, you are speaking the same
language as the rest of your instrumentation.
Cultivating a healthy system
Naming spans is not a trivial task. It's a foundational practice for building a
robust and effective observability strategy. By adopting a clear, consistent
pattern like {verb} {object}
for your business-specific spans, you can
transform your telemetry data from a tangled mess into a well-tended garden.
A well-named span is a gift to your future self and your team. It provides clarity during stressful outages, enables powerful performance analysis, and ultimately helps you build better, more reliable software.
In our next post in this series, we will dig into the next layer of detail: span attributes. We'll explore how to add the rich, high-cardinality context to your spans that is necessary for deep debugging, without compromising the aggregability of your span names.
Subscribe to my newsletter
Read articles from Juraci Paixão Kröhling directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Juraci Paixão Kröhling
Juraci Paixão Kröhling
🚀 Building Solutions in Observability | Co-Founder of OllyGarden As the co-founder of OllyGarden, I focus on creating tools and frameworks that enhance observability and address challenges in telemetry and distributed systems. My work leverages expertise in OpenTelemetry and insights from industry collaborations to develop practical, scalable solutions. 💡 A Career Rooted in Technology and Innovation With experience spanning startups, enterprise environments, and global collaborations, I bring a well-rounded approach to building software systems. My focus areas include observability practices, data pipelines, and message queue processing, ensuring reliability and efficiency in modern systems. 🤝 Collaborating Across the Ecosystem I value working with and learning from others in the technology ecosystem. Through discussions with experts and partnerships, I continuously seek to address industry challenges and uncover new opportunities for growth and innovation. 🌱 Continuous Development I am dedicated to refining my skills in software engineering and advancing observability practices. By staying engaged with emerging technologies and trends, I aim to develop solutions that address real-world challenges and drive progress in the field. 🎯 How I Can Contribute Addressing observability challenges Implementing OpenTelemetry solutions Exploring partnerships to bring ideas to life