Semantic Conventions in OpenTelemetry
The shared dictionary that lets every service, every library and every monitoring tool describe the same thing in the same words. Learn what it is, how it works inside, and how to use it without breaking your dashboards.
Picture ten teams in one company, each measuring how long a web request takes. One team calls the measurement latency. Another calls it response_time_ms. A third calls it duration. One counts in seconds, one in milliseconds, one in microseconds. Then a bad night arrives, the checkout page is slow, and you need a single chart that covers all ten teams. You cannot build it, because the same idea wears ten different names and three different units.
This is the exact headache that OpenTelemetry Semantic Conventions were created to cure. They are an agreed list of names, meanings, units and rules for the data that software sends out about itself. When every tool follows the list, a chart built for one service works for all services, and a dashboard bought from one vendor still works when you switch to another.
In this guide we start from zero. We explain what telemetry is, why naming matters so much, and what a convention actually looks like. Then we walk through the conventions for traces, metrics and logs, see how they travel through a real system, learn how they change over time without breaking things, and finish with mistakes to avoid. Every new word is explained the first time it appears, and each big idea comes with an everyday comparison.
1What Are Semantic Conventions?
A convention is simply an agreement. Semantic conventions are the agreement about what to call things and what those names mean.
OpenTelemetry, often shortened to OTel, is an open-source project that gives software a standard way to produce telemetry. Telemetry is the stream of information a running program sends out about itself: what it is doing, how long things take, what went wrong. Developers and operations teams read this stream to understand and fix their systems.
Semantic conventions are a set of written rules inside the OpenTelemetry project. They say which names to use for pieces of telemetry, what each name means, what kind of value it holds, and what unit a number is measured in. The word semantic just means “about meaning”. The rules are not about how data is moved from place to place. They are about what the data says.
The three things a convention fixes
First, the name. If a web request has an HTTP method such as GET or POST, the convention says the field is called http.request.method. Not method, not verb, not HttpMethod. Second, the meaning and allowed values. The convention explains that this field holds the method of the request, written in capital letters, and lists the well-known values. Third, the shape and unit. If a measurement is a duration, the convention says it is a number of seconds, and tells you which kind of metric holds it.
Think of the standard shipping container. Before containers, every port packed goods in its own sizes of crates and barrels, and loading a ship was slow and messy. After everyone agreed on a few standard box sizes, cranes, trucks, trains and ships all worked together. Semantic conventions are the standard box sizes for monitoring data. Your app packs data into the standard box, and any tool downstream already knows how to lift it.
Where the conventions live
The conventions are maintained by the OpenTelemetry community in a dedicated project called Semantic Conventions. They are written in a machine-readable form, and from that source the project produces the human-friendly documentation pages and the code constants that libraries use. You can read them in the Semantic Conventions section of the OpenTelemetry website. Each page covers one area, such as HTTP, databases, messaging or Kubernetes, and lists every name with its type, its description and an example.
What they are not
It helps to be clear about what semantic conventions are not. They are not a programming interface: you do not call them like a function. They are not a wire format: that job belongs to a separate piece called OTLP, the OpenTelemetry Protocol. And they are not enforced by the software. The tools will happily accept a field named banana. The conventions work only because people and libraries choose to follow them, much like spelling rules work because writers choose to follow the dictionary.
You can use OpenTelemetry without ever reading the conventions, because the instrumentation libraries you install already follow them for you. You only need to study them when you write your own instrumentation, build dashboards and alerts, or move data between tools.
2The Problem They Solve
Every monitoring tool once spoke its own language. That made your data hard to combine, hard to move and hard to trust.
A short history of naming chaos
Before OpenTelemetry, there were many competing ways to collect traces and metrics. Two open-source projects, OpenTracing and OpenCensus, tried to standardize how code is instrumented. In 2019 they merged into OpenTelemetry, which is now a Cloud Native Computing Foundation project. The merge fixed the question of how to collect data. It did not automatically fix the question of what to call things.
Each vendor and each library author had their own habits. One Java library might label the HTTP method as http.method. A Go library might call it request_verb. A home-grown tool might send method. The backend, which is the system that stores and displays the data, sees three unrelated fields. A person who wants one graph of “all POST requests” must remember all three names and write three queries.
flowchart LR subgraph Before["Before: every team invents names"] A1["Service A sends http.method"] --> D1["Backend sees 3 unrelated fields"] A2["Service B sends request_verb"] --> D1 A3["Service C sends method"] --> D1 end subgraph After["After: shared conventions"] B1["Service A sends http.request.method"] --> D2["Backend sees 1 field"] B2["Service B sends http.request.method"] --> D2 B3["Service C sends http.request.method"] --> D2 end
Four kinds of pain
Broken dashboards
A chart written for one team’s field names shows nothing for another team. Each service needs a custom copy of every chart.
Wrong math
One service reports milliseconds and another reports seconds under the same name. Averages across them are silently wrong.
Vendor lock-in
Dashboards and alerts are built on one vendor’s field names. Switching tools means rewriting everything.
Slow onboarding
Every new engineer must learn a private vocabulary before they can read any graph, and the vocabulary is rarely written down.
Electrical plugs are a good picture. A traveler carries a bag of adapters because each country chose a different plug. Phone chargers moved to a common connector so people stopped carrying the bag. Without semantic conventions, your observability setup is the bag of adapters. With them, one plug fits everywhere.
Big names agreeing on one dictionary
The agreement is not only theoretical. In 2023, Elastic donated its Elastic Common Schema, a long-used set of field names for logs and events, to the OpenTelemetry project, and the two efforts were merged into one body of conventions. Observability products from companies such as Datadog, Grafana Labs, Honeycomb, New Relic, Splunk, Dynatrace and Elastic can receive OpenTelemetry data, and many of them build screens that rely on the standard names. Jaeger, a tracing tool that began at Uber and is now a CNCF project, also works with OpenTelemetry data. When these tools share a vocabulary, your data becomes portable.
Conventions do not fix bad data. If a service reports the wrong number under the right name, the dashboard will faithfully show the wrong number. The conventions give everyone the same words; they cannot make everyone tell the truth.
3A Quick Telemetry Refresher
Before we read the conventions, we need five words: signal, trace, span, attribute and resource.
Signals: the kinds of data
A signal is one category of telemetry. OpenTelemetry has three main ones that are stable and widely used: traces, metrics and logs. A fourth, profiles, which describe where a program spends its processor time, is newer and still maturing. Each signal answers a different question, and the conventions cover all of them.
Traces
The story of one request as it travels through many services. Answers: where did the time go for this request?
Metrics
Numbers measured over time, such as requests per second or memory in use. Answers: how is the system doing overall?
Logs
Time-stamped text or structured records of things that happened. Answers: what exactly happened at this moment?
Profiles
Samples of what code is running and using resources. Answers: which function burns the most processor time?
Traces and spans
A trace follows a single request, such as one click on the Buy button. The trace is made of spans. A span is one timed piece of work, like “handle the web request”, “ask the database a question” or “call the payment service”. Spans are arranged like a family tree: a parent span can have child spans. The span has a start time, an end time, a name, and a status that says whether it worked.
Every span also has a kind, which tells you its role in a conversation between two programs. There are five kinds. SERVER means the span is the receiving side of a call. CLIENT means it is the calling side. PRODUCER means it sent a message to a queue. CONSUMER means it received a message from a queue. INTERNAL means the work happened inside one program and did not cross a boundary. The conventions use the kind to decide which fields a span should carry.
Attributes: the labels
An attribute is a label stuck onto a piece of telemetry. It is a pair made of a key and a value, for example the key http.response.status_code with the value 200. Values can be text, true or false, whole numbers, decimal numbers, or lists of these. Attributes can be attached to spans, to metric data points, to log records and to resources. Almost everything in semantic conventions is, at its heart, a list of agreed attribute keys.
Resources: who is talking
A resource is a special bundle of attributes that describes the thing producing the telemetry, such as the service name, the server, the cloud region or the Kubernetes pod. Resource attributes are attached once and then apply to every signal that thing sends. The difference is simple. Span attributes describe what happened; resource attributes describe who it happened to.
A patient chart in a hospital has a header and a body. The header holds the patient’s name, age and room number, written once. The body holds a list of timed notes: “9:05 temperature taken”, “9:40 medicine given”. The header is the resource. The timed notes are the spans, metrics and logs. Each note carries small labels like “left arm” or “morning dose”, and those are attributes.
flowchart LR App["Your application code"] --> Lib["Instrumentation library"] Lib --> SDK["OpenTelemetry SDK"] SDK --> Exp["Exporter using OTLP"] Exp --> Col["OpenTelemetry Collector"] Col --> Back["Backend and dashboards"] Conv["Semantic conventions: the shared dictionary"] -.-> Lib Conv -.-> Col Conv -.-> Back
4Anatomy of a Convention
Each entry in the conventions is like a small recipe card. Once you can read one card, you can read them all.
What one attribute entry says
Take the attribute http.response.status_code. Its entry tells you the key (the exact spelling), the type (a whole number), a plain-language description (the numeric status code the server sent back), one or more examples (200, 404, 503), and a requirement level that says how strongly the convention wants you to include it. Some entries also list a fixed set of allowed values, called an enumeration, such as the well-known HTTP methods.
Requirement levels
Not every attribute is equally important, so the conventions use four requirement levels. They work like the words on a form: required fields, fields required only in some cases, suggested fields and optional extras.
| Level | Meaning | Everyday comparison |
|---|---|---|
| Required | Always include it. | The name on a passport application |
| Conditionally Required | Include it when a stated condition is true. | “Spouse name” only if you are married |
| Recommended | Include it unless you have a good reason not to. | A phone number on a contact form |
| Opt-In | Leave it off unless the user turns it on, often because it is costly or sensitive. | Sharing your live location |
Opt-In is a quiet but important idea. Some details, such as the full text of a database query or the contents of HTTP headers, can reveal private data or add a lot of volume. The conventions describe them but keep them off by default, so you must choose to switch them on.
What a span entry says
A span convention goes beyond attributes. It also says how to name the span, which kind it should have, and how to set its status. For web servers, for instance, the convention says the span name is built from the HTTP method and the route, giving names like GET /users/{id}. Good span names are short and have a small number of possible values, so that you can group thousands of spans under the same name.
What a metric entry says
A metric convention lists the metric name, the instrument type (the kind of measuring device: a counter, an up-down counter, a histogram or a gauge), the unit, a description, and the attributes that may be attached to each data point. We look at these in detail in the metrics chapter.
Stability
Finally, each convention has a stability label that tells you how likely it is to change. The three working stages are Development, Release Candidate and Stable. We cover what they promise in a later chapter, because stability is what lets you build on the conventions with confidence.
When you open any convention page, look first at the requirement level and stability columns. They tell you in seconds whether an attribute is safe to build an alert on or still likely to be renamed.
Reading a convention page, line by line
The first visit to a convention page can feel crowded, so here is a calm way to read it. Start at the top, where a short paragraph says what the page covers and which signal it describes. Next, look for the stability note, because it tells you how much trust to place in everything below. Then scan the tables from left to right: key, type, description, examples and requirement level. Read the description column slowly, because it often hides the rule that matters, such as “this must be the route template, not the real path”.
Many pages also contain a column or note about cardinality or about sanitization. These notes are easy to skip and costly to ignore. A note that says “SHOULD have low cardinality” is a direct warning not to put raw identifiers in that field. A note about sanitization tells you that the library should replace sensitive parts of a value before it leaves your program.
Pay attention to attribute groups. A page for HTTP spans often says that it also includes the attributes of a network group or a URL group. This is the reuse we described earlier. You do not need to hunt through the other pages by hand, because the page lists the borrowed attributes in place. Finally, look at the deprecation notes. If a name is marked as replaced, the note names its successor, which saves you from guessing.
A convention page works like the label on packaged food. The label lists ingredients, amounts and warnings in a fixed order, so once you know where to look you can compare any two products in seconds. You would not buy food with the label torn off, and you should not ship telemetry without checking the label of the convention you follow.
5Resource Conventions: Who Is Sending This Data?
The first thing any tool needs to know about telemetry is where it came from. Resource conventions answer that.
Why resources come first
Imagine a pile of ten thousand spans arriving at your backend. Without knowing which service made each one, the pile is useless. Resource attributes are the return address. They let a backend group data by service, filter by environment, and tell the difference between the production checkout service and the test version running on someone’s laptop.
A resource is the ID badge a worker wears. The badge says the person’s name, department, building and employee number. Every piece of work they hand in is understood in that light. You do not rewrite the badge on every report; you wear it once and everyone knows who you are.
The most important resource attributes
service.name
The logical name of your service, such as “checkout”. This is the single most important attribute. Backends use it to group everything. Companion fields include service.version, service.namespace and service.instance.id.
deployment.environment.name
Tells production from staging from development. Older versions of the conventions used the shorter key deployment.environment.
cloud.provider and cloud.region
Which cloud (for example aws, gcp or azure), which region and which availability zone the work ran in. Useful for spotting a problem that affects only one region.
host.name and host.id
The machine, virtual machine or server that ran the program, along with operating system details under the os namespace.
k8s.* attributes
Cluster, namespace, pod and deployment names, such as k8s.pod.name and k8s.namespace.name. They connect telemetry to the orchestrator that runs your containers.
container.* attributes
The container name, id and image name, so you can tell which version of a packaged app produced the data.
process.* attributes
The process id, the program name and the language runtime it uses, which helps when several programs share one machine.
telemetry.sdk.*
Which OpenTelemetry SDK made the data: its name, language and version. Handy when you debug odd behavior in one language.
How resource values get filled in
You rarely type these by hand. The SDK includes resource detectors, small helpers that look around the environment and fill in what they can find: the cloud metadata service gives the region, the operating system gives the host name, and the container runtime gives the container id. For the rest, two environment variables are the standard route. OTEL_SERVICE_NAME sets the service name, and OTEL_RESOURCE_ATTRIBUTES sets any other resource attributes as a list of key and value pairs.
In Kubernetes, the OpenTelemetry Collector has a helper called the k8s attributes processor. It looks up each pod that sends data and adds the pod, namespace and deployment names. This way application developers do not have to code any of it.
If you forget to set service.name, the SDK falls back to a name that starts with “unknown_service”. Many teams discover this only when a dashboard shows a mysterious service with that name. Always set the name on purpose, and keep it the same across versions, because renaming a service splits its history in two.
Everyday example: one name, many pods
A shopping site runs forty copies of its checkout service across three regions. All forty carry service.name set to “checkout”, but each has its own service.instance.id and pod name. A single chart can show total checkout traffic, or be split by region, or zoom into the one pod that is misbehaving, all because the resource attributes follow the convention.
6Trace and Span Conventions: The HTTP Example
HTTP is the best-known convention, so it is the perfect way to see how names, kinds, statuses and attributes fit together.
Naming a span
A span name should answer “what kind of work is this?” in a few words, and it should have a small number of possible values. For a web server, the convention builds the name from the HTTP method and the route template: GET /users/{id}. Notice that the name holds the template, not the real path. If it held /users/48213, you would get a different name for every user, and no tool could group them. When the route is not known, the name falls back to just the method.
A span name is like the title on a library shelf label. The label says “Cooking: Italian”, not the title of every book on the shelf. Good labels are few and general, so you can find the shelf fast. The exact details, such as the real path of the page, go in the attributes, like the catalog card for each book.
Choosing the span kind
For an HTTP call, the program that receives the request records a span of kind SERVER, and the program that sends it records a span of kind CLIENT. The two spans are linked in the same trace, and together they show how long the request took on the wire versus how long the server worked. Without the kind, a tool could not draw this picture correctly.
flowchart TD S1["SERVER span: GET /checkout"] --> S2["INTERNAL span: validate cart"] S1 --> S3["CLIENT span: POST to payment service"] S3 --> S4["SERVER span in payment service: POST /charge"] S4 --> S5["CLIENT span: query on payments database"] S1 --> S6["PRODUCER span: publish order created message"]
The key HTTP attributes
| Attribute | What it holds | Example |
|---|---|---|
| http.request.method | The HTTP method. Unknown methods are recorded as the special value _OTHER. | GET |
| http.response.status_code | The number the server sent back. | 503 |
| http.route | The route template that matched on the server. | /users/{id} |
| url.path and url.scheme | The path part and the protocol part of the address. | /users/48213 and https |
| url.full | The complete address, mostly used on client spans. | https://shop.example/cart |
| server.address and server.port | The host and port of the server being talked to. | shop.example and 443 |
| network.protocol.version | The version of the protocol used. | 1.1 or 2 |
| user_agent.original | The value of the User-Agent header. | a browser identification string |
| error.type | A low-cardinality description of what went wrong, when something did. | timeout or 500 |
Whether each attribute is Required, Conditionally Required or Recommended differs between client spans and server spans, so check the convention page for the side you are instrumenting.
Setting the status the right way
A span status is Unset, Ok or Error. The HTTP convention has a careful rule that surprises many people. On the server side, only status codes in the 500 range make the span an Error, because a 404 means the server did its job correctly by saying “not found”. On the client side, both 400-range and 500-range codes make the span an Error, because from the caller’s view the request did not get what it wanted. In both cases you should also set error.type to explain why.
How a server span is filled in, step by step
The request arrives
The instrumentation library starts a SERVER span and records what it already knows: method, scheme, path and client address.
The router picks a route
Only now is the route template known, so the span name and http.route are updated.
The handler does the work
Child spans appear for database calls and outgoing requests, each following its own convention.
The response goes out
The status code is stored in http.response.status_code, and the span status is set by the server-side rule.
The span ends
The span is handed to the SDK for batching and export. If an exception happened, its details are recorded too.
The same HTTP attributes feed the HTTP metrics. A server that follows the convention for spans almost always follows it for metrics too, so one set of names lets you jump from a slow graph to the traces behind it.
Database and messaging spans in practice
HTTP is only the beginning. A database call is recorded as a span of kind CLIENT, because your program is the caller and the database is the receiver. The convention builds the span name from the operation and the target, giving names such as SELECT orders. As with web routes, the name uses the general shape, not the specific values, so thousands of different order lookups all share one name. The attributes then say which database system is in use, which collection or table was touched, and, only if you allow it, the query text with its values removed.
Messaging brings two extra span kinds into play. When a program puts a message on a queue, it records a PRODUCER span. When another program picks that message up, it records a CONSUMER span. The span name follows the pattern of the operation followed by the queue or topic name, for example publish orders. The attributes name the messaging system, the destination and the operation type, such as publish, receive or process.
A subtle point is that the producer and the consumer rarely run at the same moment. The message may sit in a queue for seconds or hours. For this reason, the producer and consumer spans are often connected with a link rather than a strict parent and child relationship. A link is a pointer that says “this work is related to that other span” without claiming that one ran inside the other. The conventions explain when to use links and when to use a parent, so check the messaging page before you design a queue-based flow.
Example: following one order across a queue
A checkout service publishes an “order created” message. The span name is publish orders, the kind is PRODUCER, and the messaging system attribute names the broker. Ten minutes later, a shipping service processes the message. Its span is named process orders, has kind CONSUMER, and is linked back to the producer span. A person reading the trace sees the full story, including the ten-minute wait, without anyone needing to guess how the two halves connect.
If a convention page offers more than one way to model something, such as a link versus a parent, the page usually says which is the default and why. Follow the default unless you have a strong reason, so that your traces look familiar to every tool and every teammate.
7Metric Conventions
A metric is a number tracked over time. The conventions make sure that a number with the same name always means the same thing and uses the same unit.
The four measuring devices
OpenTelemetry metrics are recorded through instruments, and the convention for each metric tells you which one to use. A counter only goes up, like the number of requests served. An up-down counter goes up and down, like the number of requests being handled right now. A histogram records many measurements and sorts them into buckets, which lets you later work out averages and percentiles such as the 95th percentile. A gauge records a value at a moment, like the current temperature.
A car dashboard has several devices. The odometer only counts up, like a counter. The fuel gauge reads the current level, like a gauge. A trip log that notes how long each journey took, then lets you ask “how long did most trips take?”, is like a histogram. The conventions are the manufacturer’s rule that every dashboard labels the speedometer in the same way.
Common metrics
| Metric name | Instrument | Unit | Meaning |
|---|---|---|---|
| http.server.request.duration | Histogram | s (seconds) | How long the server took to handle each request |
| http.client.request.duration | Histogram | s (seconds) | How long outgoing requests took |
| http.server.active_requests | Up-down counter | {request} | Requests being handled right now |
| db.client.operation.duration | Histogram | s (seconds) | How long database calls took |
| process.cpu.time | Counter | s (seconds) | Processor time used by a program |
| system.memory.usage | Up-down counter | By (bytes) | Memory currently in use on a machine |
Stability varies across this list. The HTTP metrics are among the first to reach Stable, while others are still maturing, so confirm the current stage on the convention page before you rely on a name in an alert.
Rules for metric names and units
The conventions set several habits worth copying. Names use dots to separate namespaces, such as http.server.request.duration. The unit is not put in the name; it is stored separately in a field, so you never see a name like latency_ms. Units follow the Unified Code for Units of Measure, called UCUM. Seconds are written s, bytes By, and a plain ratio is written 1. For things you simply count, the unit is a word in curly brackets such as {request} or {connection}, which names what is being counted.
There is also a helpful split between usage and utilization. Usage is an absolute amount, like bytes of memory used. Utilization is a fraction between zero and one, like the share of memory used. Mixing them up is a classic way to build a chart that looks fine and means nothing.
Why low cardinality matters
Cardinality means the number of different values something can take. Every unique mix of attribute values on a metric becomes its own time series that the backend must store. Suppose a web service has 50 routes, 5 methods and 10 status codes. That is at most 50 times 5 times 10, or 2,500 series for one metric, which is manageable. Now add a user id attribute with one million different users. The count explodes to billions, and the monitoring bill and query speed suffer terribly.
That is why the metric conventions only allow attributes with a small, bounded set of values. The route template is allowed; the raw path is not. The status code is allowed; the user id is not. Detailed, high-cardinality facts belong on spans and logs, where each item is stored once.
The histogram for HTTP durations suggests bucket boundaries running from a few milliseconds up to about ten seconds, written in seconds. If you create your own duration metric in milliseconds with different buckets, you can no longer combine it with the standard one.
8Log and Event Conventions
Logs are the oldest form of telemetry. Conventions turn them from loose sentences into records that tools can sort, search and connect to traces.
The shape of a log record
A log record in OpenTelemetry has a fixed set of fields. It has a timestamp for when the event happened, a severity that says how serious it is, a body that holds the message, a set of attributes for extra labels, and the resource that says who wrote it. Most importantly, it can carry a trace id and a span id. When these two are filled in, you can click from a log line straight to the exact trace and span that produced it.
A ship’s logbook becomes much more useful when every entry carries the exact time, the officer on duty and the leg of the voyage. A plain diary line like “rough seas today” helps nobody later. A logbook entry with those details can be matched against the weather report, the route and the crew rota. Trace id and span id are the voyage leg that lets logs line up with traces.
Severity levels
Different logging libraries use different words: “warning”, “warn”, “critical”, “fatal”. To make them comparable, OpenTelemetry defines a severity number from 1 to 24, split into six bands.
| Band | Severity numbers | Typical use |
|---|---|---|
| TRACE | 1 to 4 | Very fine detail for deep debugging |
| DEBUG | 5 to 8 | Developer-facing diagnostics |
| INFO | 9 to 12 | Normal events worth recording |
| WARN | 13 to 16 | Something odd that may need attention |
| ERROR | 17 to 20 | An operation failed |
| FATAL | 21 to 24 | The program cannot continue |
Exceptions
When code throws an error, the convention gives three standard attributes. exception.type holds the kind of error, exception.message holds its message, and exception.stacktrace holds the trail of function calls that led to it. Because these names are shared, a backend can group every “connection refused” error across all your languages into one view, even though a Java service and a Python service describe it in different native formats.
Events
An event is a named occurrence, such as “order placed” or “user logged in”. Events carry a name and attributes, and the conventions define well-known event names for some areas. Recording an event as a log record keeps it independent from any one span, while older guidance often attached events directly to spans. The project has been moving some event-style data toward log records, so check the current guidance for the area you use before you decide.
Structured beats free text
The biggest practical lesson is to put facts into attributes rather than burying them in sentences. A line such as “payment of 42 dollars failed for order 9912” is easy for a person but hard for a machine. A record with a short message and separate attributes for the order and the failure reason can be counted, filtered and graphed, and it respects the naming rules in the next chapters.
You do not have to rewrite your logging code. OpenTelemetry offers bridges for popular logging libraries, which take the logs you already write, add the resource, the trace id and the span id, and send them in the standard form.
9The Domains Covered by the Conventions
The conventions are not one big list. They are split into areas, called domains, one for each kind of technology your system touches.
Each domain groups the names for one technology: spans, metrics, logs and resources together. When you instrument a database, you open the database page and find everything you need in one place. Here is a tour of the domains you are most likely to meet.
Databases
Names for the system in use, the operation, the target collection or table, and the query text. Older versions used db.system and db.statement; newer ones use names such as db.system.name and db.query.text.
Messaging
Covers brokers and queues such as Kafka, RabbitMQ and Amazon SQS. Attributes include messaging.system, messaging.destination.name and the type of operation, with PRODUCER and CONSUMER span kinds.
RPC
Remote procedure calls such as gRPC, where one program calls a function in another. Attributes name the system, the service and the method being called.
Functions as a service
Describes functions like AWS Lambda: the function name, the trigger that started it, and whether it was a cold start.
Cloud and Kubernetes
Provider, region, account, cluster, namespace and pod. These mostly arrive as resource attributes.
Network, client and server
Shared building blocks such as client.address, server.address, network.transport and network.protocol.name, reused by HTTP, RPC and others.
System and process
Metrics about processor, memory, disk and network on a host, plus the same for a single process, under the system and process namespaces.
Generative AI
A newer domain with names for the model requested, the operation performed and token counts, such as gen_ai.request.model and gen_ai.usage.input_tokens. It is still evolving, so expect changes.
Shared building blocks
Notice how the domains reuse each other. The HTTP convention does not invent its own way to name a server address; it borrows server.address and server.port from the shared network group. A database call over the network borrows the same pair. This reuse is deliberate. It means one query such as “show me everything talking to host X” works across HTTP, databases and messaging at once.
A postal system has one standard way to write an address: name, street, city, postal code. Letters, parcels and couriers all use it. If every kind of mail had its own address format, sorting would be a nightmare. The shared network attributes are the standard address format for telemetry.
Domains also differ in maturity
Some domains, such as HTTP, have reached Stable. Others, such as databases, messaging and generative AI, have been moving through the stages and may include names that are still Development. The sensible habit is to check the stability label of each name you use, as we discuss in chapter 11.
Example: one problem, three domains
A support engineer investigates slow orders. The HTTP span shows the API was slow. Its child database span, following the database convention, shows a slow query on the orders table. A neighbouring messaging span shows the order-created message waited in the queue. Because all three share the same server and network attribute names, the engineer filters by one host and sees the whole story on one screen.
Choosing which domain page to read
New users often ask which page to open first. A simple method works well. Start with the resource pages, because every service needs them. Next, open the page for the protocol that carries your traffic, such as HTTP or gRPC. Then open the page for each technology you call, such as your database or message broker. Finally, open the page for the platform you run on, such as a cloud provider, a serverless service or Kubernetes. Four groups, read in that order, cover almost every service.
Real systems usually mix several domains inside one request. A serverless function behind a web gateway uses the HTTP page, the function page and the cloud page together. A chat feature built on a language model uses the HTTP page for the call, and the generative AI page for the model name and the token counts. You do not have to pick only one. The shared building blocks make it natural to combine them, because the same attribute never appears with two different meanings.
Think of packing for a trip. You consult one list for documents, one for clothes and one for electronics. Each list is short and easy to check, and together they cover the whole bag. Domain pages are the packing lists of instrumentation: small, focused, and meant to be used together.
Do not copy attributes from a page you did not need. Adding every optional attribute from every page makes spans heavy, increases cost and may expose data you did not mean to share. Start with the Required and Conditionally Required names, add Recommended names that you will actually query, and leave Opt-In names off until you have a reason.
10Naming Rules and Your Own Attributes
The standard names cover a lot, but your business has facts nobody else has. The naming rules show how to add your own without causing a clash.
The grammar of a name
Attribute names follow a simple grammar. They are written in lowercase. Dots separate namespaces, which are groups that go from general to specific, like http then response then status_code. Inside one segment, if you need more than one word, you join them with an underscore, as in status_code. The name should describe what the value is, not how it is stored or how it might be used.
| Do this | Not this | Why |
|---|---|---|
| http.request.method | HTTP-Method | Lowercase, dots for namespaces |
| http.response.status_code | httpResponseStatusCode | No camelCase; underscores join words in a segment |
| checkout.order.duration with unit s | checkout_duration_ms | Unit goes in the unit field, not in the name |
| db.collection.name | table_name_for_query | Describes what it is, not how it is used |
| com.shopfast.cart.size | cart_size | Custom names carry your own prefix |
Adding your own attributes safely
When the standard list has no name for your fact, you create a custom attribute. The rule is to put it in a namespace you own. A company usually uses its reversed web address or its company name as the first segment, for example com.shopfast. or shopfast.. This guarantees no future standard name will collide with yours.
Two things are off limits. First, do not add new names inside a standard namespace, such as inventing http.cache_hit. If the OpenTelemetry project adds a similarly named attribute later with a different meaning, your data and the standard data will be mixed. Second, the otel. namespace is reserved for OpenTelemetry’s own use.
Think of a phone book. Everyone may choose a name for their own pet, but nobody should change the official spelling of a street. Your own namespace is your private yard. The standard namespaces are the public streets that everybody shares and nobody may repaint.
A short process for extending
Search the registry first
Look for an existing name that already means what you need. Reusing one is always better than inventing one.
Check the unit and type
Make sure your value matches the expected type and unit, such as seconds for durations.
Create it in your own namespace
If nothing fits, add the new name under your company prefix, in lowercase with the usual grammar.
Write it down
Record the name, type, meaning and an example in a shared team document, so others do not invent a twin.
Consider proposing it upstream
If many companies could use it, open a proposal to the OpenTelemetry project so it can become a standard name.
Rules for values
Values have rules too. Fixed lists, such as the names of cloud providers, are written in lowercase and use the exact words from the convention. When an instrumentation meets a value outside a known list, it records a catch-all value, like _OTHER for an unknown HTTP method, instead of copying the raw text. This keeps the number of distinct values small, which protects you from the cardinality problem we met in chapter 7.
Once a custom name is in dashboards and alerts, renaming it is painful. Choose carefully the first time, and have one person or a small group review new names before they spread across the codebase.
Lists and template keys
Attribute values are not always a single item. An attribute can hold a list, such as a list of text values. HTTP headers are a good example. Because a header may appear several times in one request, the convention stores its values as a list of text. The key itself follows a template, where one part is a placeholder that you fill in with the header name in lowercase. In this way one rule covers every possible header, and since headers are Opt-In, you list only the ones you choose to capture.
When you design your own attributes, borrow the same habits. Use a list when the thing really is a list, and avoid packing several values into one text with commas, because tools cannot search inside such a text reliably. Use a number when the value is a number, so that you can sum, average and compare it. Use true or false for a yes or no fact. Choosing the right type from the start saves a great deal of cleanup later.
Example: describing a shopping cart
ShopFast wants to record the items in a cart. A weak design would store the text “shoes,hat,socks” in one attribute. A better design stores a whole number for the number of items under a ShopFast-prefixed key, and a list of text values for the product categories. Now an analyst can ask for carts with more than five items, or carts that include the shoes category, without writing special text-parsing rules.
11Stability, Versioning and Schema URLs
A dictionary that changes without warning is a dangerous dictionary. This chapter explains how conventions evolve while keeping your dashboards alive.
The stability stages
| Stage | What it promises | Should you build alerts on it? |
|---|---|---|
| Development | Names and meanings may still change, even in breaking ways. | Carefully, and be ready to update |
| Release Candidate | Close to final; only small fixes are expected. | Usually yes, with attention to release notes |
| Stable | Existing names will not be changed in breaking ways. New optional attributes may still be added. | Yes |
Development used to be called Experimental, and you may still see the older word in documents. Names that are no longer recommended are marked Deprecated and point to their replacement.
A real migration: the HTTP renames
The HTTP convention is the best example of a name change. While it was maturing, its names were cleaned up and made consistent with the rest of the conventions. Before it became Stable in late 2023, many libraries were already emitting the old names.
| Older name | Newer name |
|---|---|
| http.method | http.request.method |
| http.status_code | http.response.status_code |
| http.url | url.full |
| http.target | url.path and url.query |
| net.peer.name | server.address (on client spans) |
| http.server.duration in milliseconds | http.server.request.duration in seconds |
If a library simply switched to the new names overnight, every dashboard and alert built on the old ones would go blank. To avoid this, instrumentation libraries offer an opt-in switch through the environment variable OTEL_SEMCONV_STABILITY_OPT_IN. Setting it to http makes the library emit only the new names. Setting it to http/dup makes it emit both old and new at the same time. Similar values exist for other areas, such as databases. If you set nothing, libraries that have not fully moved keep emitting the old names.
flowchart LR P1["Phase 1: old names only"] --> P2["Phase 2: emit old and new together with http/dup"] P2 --> P3["Phase 3: move dashboards and alerts to new names"] P3 --> P4["Phase 4: emit new names only with http"]
Versions and schema URLs
The conventions are released in numbered versions, so that you can say “we follow version 1.x”. Each version is a snapshot of every name. Telemetry can announce which snapshot it follows through a schema URL, a web address stored on the resource or on the instrumentation scope. The address points to a schema file that lists the changes between versions, such as “attribute A was renamed to B”.
A tool that understands schemas can read the schema URL and translate data from one version to another. A backend or Collector can then turn older names into newer ones automatically, so the dashboards only need to understand one version. The Collector community has components aimed at schema translation, though how much you can rely on them depends on the feature and version, so test before you promise it to your team.
Think of editions of a textbook. The second edition may rename a chapter or fix a formula. If the publisher also prints a “what changed” sheet, a teacher can move from the first to the second edition without confusion. The schema URL is the label on the cover saying which edition you hold, and the schema file is the “what changed” sheet.
A migration plan you can follow
Inventory
List the dashboards, alerts and queries that use old names, and which libraries emit them.
Enable duplicates
Turn on the dual mode so both names arrive. Watch your storage cost during this period.
Rewrite and compare
Update each chart and alert to the new names, then compare results with the old ones to check they agree. Remember that units may have changed from milliseconds to seconds.
Switch to new only
Once nothing reads the old names, move to the new-only mode and remove the duplicates.
Pin the version of the conventions that your instrumentation packages use, and read the release notes before upgrading. Treat a convention upgrade the way you treat a database schema change: plan it, test it, and roll it out in steps.
12How It Works Inside: From Source File to Dashboard
The conventions are just a document, so how do they end up shaping real data? Follow one name on its whole journey.
Step 1: the source of truth
The conventions begin as structured, machine-readable files kept in the project repository. Each file describes groups of attributes, spans and metrics with their types, requirement levels and stability. From these files, the project builds two things automatically: the documentation pages that people read, and ready-made code constants that libraries import. Because the same source feeds both, the docs and the code cannot drift apart.
OpenTelemetry also provides a tool called Weaver. It reads a collection of conventions, called a registry, and can check it, generate documentation and generate code from it. Companies can use it with their own custom registry layered on top of the standard one, so that internal names get the same documentation and checking as official ones.
Step 2: instrumentation sets the names
An instrumentation library is a package that watches a framework, such as a web server or a database driver, and creates telemetry for it automatically. Using the generated constants, the library writes the correct attribute names every time. This is why you rarely mistype a convention: you never type it, the library does.
Step 3: the SDK processes the data
The OpenTelemetry SDK is the engine inside your program that collects the telemetry. It does not check names against the conventions; it treats them as plain keys. But it does influence convention-related behavior. A sampler, which decides whether a trace is kept or thrown away, only sees the attributes that were present when the span began, so important sampling facts must be set at the start. The SDK also enforces limits, such as a default maximum of 128 attributes per span, set through variables like OTEL_ATTRIBUTE_COUNT_LIMIT.
Step 4: the Collector shapes the stream
The OpenTelemetry Collector is a separate program that receives data, processes it and forwards it. It is the best place to fix naming problems in one place. It can run next to each application as an agent, or as a central gateway that many services send to. Its processors can add missing resource attributes, rename old names to new ones, drop sensitive attributes and batch data for efficient delivery.
flowchart TD Reg["Convention source files in YAML"] --> Docs["Documentation pages"] Reg --> Const["Generated code constants"] Const --> Inst["Instrumentation library"] Inst --> Data["Spans, metrics and logs with standard names"] Data --> SDK["SDK: samplers, processors, limits"] SDK --> OTLP["OTLP export"] OTLP --> Coll["Collector: detect resources, rename, filter, batch"] Coll --> Store["Backend storage and dashboards"]
Step 5: the backend reads the names
At the end of the line, the backend stores the data and builds screens from it. Because it expects service.name, it can draw a map of services. Because it expects http.response.status_code, it can compute error rates. Features like automatic service maps and ready-made dashboards depend on the names being where they are supposed to be.
The journey resembles a recipe published by a cookery school. The school keeps one master recipe, from which the printed book and the cooking-app instructions are both produced. Cooks in many kitchens follow it. A head chef at the pass checks plates before they leave, which is the Collector. Finally the diners, the backend, enjoy a dish they already recognize. If any cook invents their own recipe, the diners notice the difference.
Because nothing in the SDK enforces the conventions, a typo goes through silently. A field named http.reponse.status_code will be accepted, stored and ignored by every dashboard. Use the generated constants, review changes, and consider automated conformance checks.
Context propagation: how services stay in one story
Conventions name the data, but something else carries a trace from one service to the next. That something is context propagation. When a service calls another service, it adds a small piece of information to the outgoing request. For HTTP, the widely used standard is the W3C Trace Context, which places the trace id and the parent span id in a header named traceparent. The receiving service reads the header and continues the same trace, so the spans from both services join into a single tree.
Propagation and conventions work as a pair. Propagation makes sure that the spans belong to the same trace. Conventions make sure that each span describes itself in the agreed words. If propagation breaks, you see separate, disconnected traces. If conventions are ignored, you see a connected trace in which each part uses a different language. You need both for the full picture, and when you debug a broken trace it helps to check which of the two has failed.
A related idea is baggage, a set of key and value pairs that travels along with the request through every service. Baggage is useful for carrying a few business facts, like a customer tier, to every hop. It is not stored automatically on spans, and everything in it travels over the network, so keep it small and never place secrets in it.
Imagine a relay race in which each runner carries a baton with a number on it. The baton number is the propagated trace id, and it shows that all runners belong to the same team. The conventions are the uniform rules: every runner wears the team colors in the same way, so a spectator can read the race at a glance. A numbered baton in mismatched clothing, or matching uniforms without a baton, would each leave the spectator confused.
13Security, Monitoring and Cost
Standard names make data easy to use. They also make it easy to leak or overspend. Here is how to stay safe and affordable.
Protecting private data
Telemetry often travels to third-party systems and sits in storage for weeks, so it must not carry secrets. The conventions already warn about the risky spots. A full web address, url.full, can contain a username and password, or a secret token in the query string. Instrumentation is expected to remove credentials from addresses and to hide the values of well-known sensitive query parameters. Database query text can contain customer data, so conventions call for parameter values to be replaced with placeholders by default. HTTP headers are Opt-In for the same reason.
Credentials in addresses
Passwords and tokens hiding inside url.full or url.query. Strip or mask them before export.
Personal data in queries
Names and emails inside raw SQL text. Keep parameters as placeholders and treat query text as sensitive.
User identifiers
Attributes that identify a person may fall under privacy law. Collect only what you need and mask or hash where possible.
Headers and bodies
Cookies and authorization headers carry secrets. Leave header capture off unless a specific header is clearly safe.
The Collector is a good last line of defense. Its attribute and transform processors can delete or rewrite attributes for every service in one place, so a single rule protects the entire company even if one team forgets.
Watching the quality of your telemetry
Treat telemetry as a product with its own health checks. Useful checks include: how many services have a real service.name rather than an “unknown_service” value, how many spans lack a status code on HTTP calls, and which attribute keys appear that are not in your registry. Tools such as Weaver can compare live telemetry against a registry and report differences, and the Collector reports its own metrics about data it receives, drops and fails to send. Review these on a dashboard just like application health.
Controlling cost
Most observability bills grow with volume and cardinality. The conventions help in four ways. Opt-In attributes are off by default, so you choose what to pay for. The low-cardinality rules for span names and metric attributes keep time series counts predictable. Standard names let you write one drop or filter rule that applies to all services. And the catch-all values like _OTHER prevent odd inputs from creating endless new values.
A quick cost test: for any attribute you plan to put on a metric, ask “can I list every value it could ever take?” If the answer is no, it belongs on a span or log instead.
A governance checklist for teams
As the number of services grows, a little governance keeps the data healthy. It does not need to be heavy. A short checklist, reviewed every quarter, is often enough.
- Ownership: name one team that owns the company registry of custom attributes and answers questions about naming.
- Review: require a quick review for any new custom attribute, covering the name, type, unit and cardinality.
- Privacy: keep a list of attributes that may hold personal or secret data, with the rule for each: drop, hash or mask.
- Versions: record the convention version used by each service and plan upgrades together.
- Cost: review the top attributes by number of unique values every month, and fix the ones that grow without bound.
- Training: give each new engineer a one-page guide to the naming grammar and the standard dashboards.
It also helps to keep a small set of golden dashboards, such as request rate, error rate and duration by service, built only from standard names. If a service does not appear correctly on the golden dashboards, that is an immediate sign that its telemetry does not follow the conventions, and the owning team can fix it before an incident exposes the gap.
Governance works best when it is a helpful service, not a gate. Provide templates, shared libraries and clear examples so that following the conventions is the easiest path for every developer.
14Advantages, Disadvantages and Trade-offs
Standardization is powerful, but it is not free. An honest look at both sides helps you decide how strictly to follow the rules.
Advantages
- One dashboard or alert works across every service and language.
- Switching or adding a monitoring tool does not mean renaming all your data.
- New engineers learn one vocabulary that is public and documented.
- Vendors can build smart features, such as service maps, because they can rely on standard fields.
- Traces, metrics and logs share names, so you can move between them quickly.
- Community review improves quality, and units are consistent.
Disadvantages
- Names sometimes change while an area is maturing, which creates migration work.
- Not every domain is Stable yet, so some names carry risk.
- Nothing enforces the rules, so mistakes pass silently.
- The standard cannot cover every business fact; custom names are still needed.
- Some conventions are detailed, which makes custom instrumentation take more care.
- Following the standard does not guarantee that a vendor’s screens support every attribute.
Trade-offs you will face
| Choice | Benefit | Cost |
|---|---|---|
| Use the newest names immediately | Aligned with the future and with new tooling | Old dashboards break without a migration plan |
| Wait for Stable before adopting | Low risk of rename work | You may miss useful features for months |
| Emit old and new names together | Smooth, safe migration | Higher storage and ingestion cost during the overlap |
| Normalize names in the Collector | One central fix for all services | The Collector becomes a critical component to operate |
| Add rich custom attributes | Powerful business insight | Possible cardinality, privacy and naming problems |
| Follow conventions strictly | Maximum portability | Less freedom to name things your own way |
Traffic rules are a good comparison. Driving on the agreed side of the road and obeying the same signs removes freedom to improvise, yet it is exactly what lets millions of strangers share the same roads safely. Occasionally the rules are updated, a new sign appears, and drivers must learn it. Few people would choose a road with no rules to avoid the occasional update.
Follow the conventions strictly for anything that touches shared infrastructure, such as HTTP, databases and resources. Be creative only in your own namespace, for the facts that make your business unique.
15Patterns, Anti-patterns and Best Practices
Teams that succeed with conventions tend to repeat a few good habits, and teams that struggle tend to repeat a few mistakes.
Patterns that work
Convention first
Before adding any attribute, search the conventions. Treat a missing name as a rare event, not a daily habit.
One shared helper library
A small internal package sets the service name, environment and your custom attributes. Teams call it instead of writing resource code themselves.
Gateway normalization
A central Collector adds missing resource attributes, fixes renamed fields and strips secrets for every service.
Own registry
Keep a written registry of your custom attributes, with types, meanings and owners, based on the same format as the standard one.
Conformance in CI
Automated tests run a sample of telemetry against the registry and fail the build when unknown or misspelled names appear.
Pinned versions
Record which convention version each service follows, and upgrade in planned steps with release notes in hand.
Anti-patterns to avoid
What it looks like
Every team invents its own spelling for something the conventions already name, such as statusCode, resp_code and http_status side by side.
Why it hurts
Dashboards fragment again, and the company returns to the chaos that conventions were meant to end.
Do this instead
Search first, use the standard name, and review new attributes in code review.
What it looks like
High-cardinality values such as user ids, order ids or raw URLs are attached to metrics and used as span names.
Why it hurts
The number of time series and span names explodes. Bills jump, queries slow down and the backend may start dropping data.
Do this instead
Use route templates and bounded categories on metrics and span names. Put unique identifiers on span or log attributes only.
What it looks like
Units are hidden in names, such as latency_ms, and different services use different units for the same measure.
Why it hurts
Averages and sums across services are wrong, and nobody notices until an incident.
Do this instead
Use the standard metric names with units in the unit field, and record durations in seconds.
Best practices at a glance
Set service.name deliberately
Keep it stable across releases, and set the environment and version as well.
Prefer automatic instrumentation
Libraries follow the conventions for you. Add manual spans only where you need business meaning.
Keep names low in cardinality
Span names and metric attributes should come from small sets.
Use your own namespace
Custom attributes get your company prefix and never live inside standard namespaces.
Plan migrations
Use the opt-in switch, run old and new together, then retire the old names.
Redact at the edge
Use the Collector to remove secrets before data leaves your network.
Common mistakes
Treating the conventions as optional decoration and fixing names only after dashboards are built. Renaming later means rewriting every query. Decide names early.
Marking every 404 on the server side as an error. By the convention, that makes healthy services look broken and floods your alerts.
Upgrading the instrumentation packages without reading the convention release notes. A renamed attribute can silently empty a chart.
16Real-World Walkthrough and Industry Usage
Let us put everything together with a made-up shop, then look at how real organizations lean on the same ideas.
ShopFast: an illustrative story
ShopFast is an imaginary online store. Its shopper opens the site, the request enters an API gateway, and the checkout service handles it. Checkout calls a payment service, writes to an orders database and drops a message on a queue, from which a shipping service picks it up. Every service sends telemetry to a Collector, which forwards it to an observability backend.
flowchart LR User["Shopper browser"] --> GW["API gateway"] GW --> Chk["Checkout service"] Chk --> Pay["Payment service"] Chk --> DB["Orders database"] Chk --> Q["Message queue"] Q --> Ship["Shipping service"] Chk -. telemetry .-> OC["OpenTelemetry Collector"] Pay -. telemetry .-> OC Ship -. telemetry .-> OC OC --> BE["Observability backend"]
At peak, imagine ShopFast handles 12,000 requests per second across 40 services. One evening, the error alert for checkout fires. Because every service follows the conventions, the on-call engineer can follow a short, predictable path.
Open the standard dashboard
The chart of http.server.request.duration, split by service.name, shows checkout slowing down. The same chart works for every service, so nobody had to build it for tonight.
Narrow by route and status
Splitting by http.route and http.response.status_code shows that only the payment route returns 500-range errors.
Jump to a trace
A failing trace shows a CLIENT span from checkout to payment with an error, and a SERVER span in payment that spent most of its time in a database child span.
Read the database span
Database attributes show the system, the operation and the collection involved, with parameters hidden, so the engineer sees a slow operation without seeing customer data.
Confirm with logs
The log records carry the same trace id, so one click shows connection timeouts at the database. The resource attributes show they all come from a single pod and zone.
The whole investigation took minutes because the names lined up. Without conventions, each step would have needed someone to remember a team-specific spelling.
How real organizations use the same ideas
Elastic and the Common Schema
Elastic maintained the Elastic Common Schema for years to standardize logs and events. In 2023 it donated the schema to OpenTelemetry, and the two sets of names were brought together. This helps users who had built many dashboards on the older names to move toward a single shared vocabulary.
Observability vendors
Companies such as Datadog, Grafana Labs, Honeycomb, New Relic, Splunk and Dynatrace accept OpenTelemetry data. Standard attributes such as service.name let them draw service maps and compute error rates automatically from data they did not instrument themselves. This is what makes switching vendors realistic.
Open-source tracing tools
Jaeger, which started at Uber and is now a CNCF project, works with OpenTelemetry data. Because spans follow shared conventions, a trace produced by one language library can be viewed in tools built by completely different groups.
Cloud providers and the Kubernetes world
Cloud providers publish OpenTelemetry distributions and integrations, such as the AWS Distro for OpenTelemetry. Parts of the Kubernetes project have been adding OpenTelemetry-based tracing, and Kubernetes attributes in the conventions give a common language for clusters, namespaces and pods across clouds.
A second illustrative story: tidying up a growing company
Consider another imaginary firm, BookNest, with about 150 services written in four languages by a dozen teams. Over five years, each team chose its own names. The company runs two monitoring tools after an acquisition, and nobody can build a company-wide view of errors. Leadership decides to adopt OpenTelemetry and its semantic conventions.
Agree on the minimum
A small group defines the minimum every service must send: a stable service name, an environment, a version and the standard HTTP attributes.
Normalize at the gateway
A central Collector maps the most common old names to the standard ones, so the new golden dashboards work before every team has changed its code.
Adopt automatic instrumentation
Teams replace hand-written telemetry with libraries that follow the conventions, one service at a time, starting with the busiest.
Retire the translation rules
As services move over, the Collector rules are removed, and a conformance check in the build pipeline prevents new drift.
The result is not magic, but it is measurable. The company builds one error dashboard instead of dozens, can compare the two monitoring tools on the same data, and cuts the time to find the owner of a failing service, because every span now carries a real service name and a version. This shape of plan, with a minimum standard, a central fix and a gradual move, is the one most large organizations follow.
17Frequently Asked Questions
Short answers to the questions people ask most often.
18Summary and Key Takeaways
If you remember only a handful of ideas from this guide, make it these.
Key Takeaways
- Semantic conventions are a shared dictionary. They fix the names, meanings, types and units of telemetry so the same idea has the same name everywhere.
- They cover every signal. Resources, traces, metrics and logs all have conventions, grouped into domains such as HTTP, databases, messaging, cloud and Kubernetes.
- Resource attributes say who, span attributes say what. Always set
service.namedeliberately, along with environment and version. - Keep cardinality low. Use route templates and bounded values for span names and metric attributes, and put unique identifiers on spans and logs instead.
- Stability labels guide your choices. Build alerts on Stable names, plan migrations with the opt-in switch and a period of duplicate names, and use schema URLs to translate between versions.
- Extend safely. Reuse existing names first, put custom attributes in your own namespace, and never invent names inside standard ones or the reserved otel namespace.
- Nothing enforces the rules for you. Use generated constants, a shared helper library, Collector normalization, redaction and automated conformance checks to keep your data clean and safe.