What Is Instrumentation Scope in OpenTelemetry?
A friendly, step-by-step guide to the small piece of identity that tells you which part of your code produced a span, a metric, or a log, and why that tiny label makes big systems easier to run.
Imagine a large newspaper with many reporters. Every article that reaches the printing room carries a headline and a story, but it also carries a small line at the top: the name of the desk that wrote it, such as “Sports Desk”, “City Desk”, or “Business Desk”, and the edition of the style guide that desk followed. That small line does not change the story. Yet when an editor spots a mistake, or wants to know which desk is filing too many articles, or needs to apply a rule to all sports stories, that line is the first thing they use.
Software that is watched by OpenTelemetry has the same need. A program produces thousands of spans, metrics, and log records, and they come from many places: the web framework, the database driver, the message queue client, a payment module written by your own team, and a caching library you downloaded last year. When something looks wrong, one of the first questions anyone asks is, “Which part of the code produced this?” OpenTelemetry answers that question with a small, standard piece of information called the instrumentation scope.
In this guide you will learn what an instrumentation scope is, what it contains, how it differs from the other kinds of labels on telemetry, how it gets created, how to name one well, what happens to it on the way from your code to your dashboard, and what mistakes to avoid. We will move slowly, explain every new word when it first appears, and lean on everyday pictures so that no step feels like a jump.
1The Problem: Which Part of the Code Said That?
Before we meet the answer, let us feel the question.
A modern application is rarely one block of code. It is a stack of many pieces layered on top of each other. At the top sits the code your team wrote. Beneath it sit web frameworks, database drivers, HTTP clients, caching libraries, and message queue clients, most of them written by other people. Each of these pieces may be watched by OpenTelemetry. When one of them handles a request, it can report a span, which is a record of one unit of work with a start time and a duration. It can also report metrics, which are numbers measured over time, and logs, which are lines describing events.
Now imagine you are looking at a dashboard and you see a strange spike in a metric called “request duration”. Several different pieces of code might report a metric with that very name. The web framework reports how long it took to handle a request. The HTTP client reports how long it took to call another service. The database driver reports how long a query took. All three measure a “duration”, and all three may use similar names. Without a way to tell them apart, the numbers blur together into one confusing line.
It is like a kitchen where every cook writes “ready” on a slip and drops it into one big bowl. When a plate is late, nobody knows which cook, or which station, wrote the slip that was supposed to say it was ready. A name written on each slip would solve the confusion at once.
The same problem appears in other ways. A library you installed may be sending far too many spans, and you want to turn it off without touching anything else. A new version of an instrumentation library may have a bug in how it records durations, and you want to find every piece of data it produced. A team wants to see only the telemetry produced by its own module, not the telemetry from libraries. In all these cases, the key is a reliable, standard answer to the question, “Which piece of code was responsible for creating this telemetry?” That answer is the instrumentation scope.
Why Not Just Use the Span Name or the Metric Name?
A fair question is why a separate label is needed at all. Spans already have names, and metrics already have names. The reason is that those names describe what happened, while the scope describes who reported it. A span called “query” might come from a database plugin, from a search library, or from your own code. A metric called “duration” might come from anywhere. Names of events are chosen to be readable and general. Names of sources are chosen to be exact and stable. Keeping the two ideas apart means each can do its job, and it means a report can be sliced along either direction: show me all “query” spans, or show me everything from this one plugin.
A Small Idea With Large Effects
The instrumentation scope may look like a minor detail, a short string attached to data. But small identifying labels have large effects in big systems. A single postal code lets a whole country’s mail be sorted by machines. A single product barcode lets a shop track millions of items. In the same way, a single scope name lets a whole platform of hundreds of services sort, filter, and tune telemetry by source, without anyone reading the code. That is the real value, and it is why the next chapters spend time on getting the small details right.
2The Vocabulary You Need First
A short glossary keeps the rest of the article smooth.
OpenTelemetry
An open-source project that gives software one shared, vendor-neutral way to create and send traces, metrics, and logs.
Instrumentation
The code that observes a program and produces telemetry about it. It may be added by hand or by an automatic agent.
Telemetry
The general word for the data software sends about itself: traces, metrics, and logs.
Signal
One kind of telemetry. The three main signals are traces, metrics, and logs.
Resource
A description of the producer of telemetry as a whole, such as the service name, its version, and the machine it runs on.
Attribute
A key and value label attached to something, such as route equals checkout. Values can be text, numbers, or true and false.
Provider
A factory that hands out tracers, meters, or loggers. There is a tracer provider, a meter provider, and a logger provider.
Tracer, Meter, Logger
The objects your code uses to create spans, record metrics, and write logs. Each one belongs to exactly one scope.
A few more words will appear later. The API is the set of calls your code makes to report telemetry, and the SDK is the machinery behind those calls that does the real work of collecting and sending data. OTLP, short for the OpenTelemetry Protocol, is the standard format used to send telemetry from an application to a Collector or a monitoring product. The Collector is a separate program that receives, processes, and forwards telemetry. A backend is the monitoring product or storage system that finally keeps the data and draws the charts.
Two more words will help. Automatic instrumentation means that an agent or plugin adds telemetry to common libraries for you, without changes to your code. Manual instrumentation means that you write the calls to create spans and record metrics yourself. Most real systems use both. The scope is how you tell the two apart in your data: automatic plugins arrive with scope names chosen by their authors, while your manual code uses scope names that you choose.
One distinction is worth fixing in your mind right now, because it is the source of most confusion. The instrumented library is the code being watched, such as a database driver. The instrumentation library is the code doing the watching, such as the OpenTelemetry plugin written for that driver. The instrumentation scope identifies the watcher, not the thing being watched. We will return to this idea again, because getting it right is the key to naming scopes well.
3What Instrumentation Scope Is
A clear definition, a short history, and a list of what it holds.
An instrumentation scope is a logical unit of code, within an application, that produces telemetry. It gives that unit a name, and optionally a version, a link to a schema, and a few extra labels. Every tracer, meter, and logger in OpenTelemetry is created for exactly one scope, and every span, metric, and log record produced through it carries that scope along. So when telemetry arrives at a backend, the backend can tell not only what happened, but also which unit of code reported it.
The idea is a little older than its name. In the early days of OpenTelemetry, the same concept was called the instrumentation library, because the most common unit of code that reported telemetry was a library, such as an HTTP plugin. Over time, people realized that the unit might not be a library at all. It might be a module of your own application, a package, or even a single class. So the project renamed the concept instrumentation scope, a more general word. You may still meet the older name in old documents, old tool settings, and in labels such as “otel.library.name” on data from older exporters. They mean the same thing.
The Four Fields
An instrumentation scope can carry up to four pieces of information.
| Field | Required? | What it holds | Example idea |
|---|---|---|---|
| Name | Yes, in practice | A name that identifies the unit of code reporting telemetry | A package or plugin name |
| Version | Optional | The version of that unit of code | 1.4.2 |
| Schema URL | Optional | A web address naming the version of the telemetry naming rules that this code follows | A link ending in a version number |
| Attributes | Optional | Extra labels that describe the scope itself | A module group or team name |
Of these, the name is by far the most important. It is the field that backends show, that filters use, and that engineers type into search boxes. The other three fields add helpful detail, but a scope with only a name is already useful. If you remember only one rule, remember this: always give your tracers, meters, and loggers a clear, stable name.
Think of a library book’s catalog card. The title is the name. The edition number is the version. The classification scheme the library used, such as a particular edition of a shelving system, is the schema. A few extra notes in the margin, such as “donated by the school”, are the attributes. The title lets you find the book, and the other details help you understand exactly which copy you are holding.
How the Idea Grew Out of Real Problems
The scope was not invented in an office. It grew out of problems that people met while running real systems. Early users of tracing noticed that when they combined data from several plugins, they could not tell the plugins apart. Users of metrics noticed that two plugins could report a metric with the same name and different meanings. Users of logs wanted to keep the familiar logger names they had used for years. Each group needed the same thing: a standard, built-in way to say who was speaking. Rather than solve it three times, the project defined one concept and used it in all three signals, which is why the scope looks and behaves the same in traces, metrics, and logs.
What a Scope Is Not
It helps to say plainly what a scope is not. It is not a trace; a trace follows one request across many services, while a scope labels the code unit that produced a piece of data. It is not a span; a span is one unit of work. It is not a service; a service is the resource. It is not a team or an owner, although you can choose names that reflect ownership. And it is not a permission or a signature. It is simply an honest label, set by the author of the instrumentation, that says which part of the code is reporting.
Why It Is Called a “Scope”
The word “scope” suggests a boundary: a region of code within which all telemetry shares the same source label. A scope may cover a whole plugin, one package, one module, or one class, depending on how finely you want to tell sources apart. Choosing the size of the scope is a design choice, much like choosing how many desks a newspaper has. Too few, and the labels say little. Too many, and the labels become noise. We will discuss how to choose in the naming chapter.
4Three Layers of Labels: Resource, Scope, and Signal
The most common beginner confusion is mixing up where a fact belongs. A simple three-layer picture clears it up.
Telemetry in OpenTelemetry is organized in layers, like a set of nested boxes. The outermost box is the resource. It describes the entity producing the data: the service name, the version of the service, the cloud region, the host, the container. Everything a single service sends shares the same resource. Inside the resource are one or more scopes. Each scope describes one unit of code inside that service that reported telemetry. Inside each scope are the actual signal items: the spans, the metric data points, or the log records. Each of those items carries its own attributes, which describe that one event.
flowchart TD
R["Resource: service name, version, region, host"] --> S1["Scope: HTTP server plugin, version 1.2"]
R --> S2["Scope: database plugin, version 0.9"]
R --> S3["Scope: your checkout module, version 2.0"]
S1 --> T1["Spans from the HTTP plugin with their own attributes"]
S2 --> T2["Spans and metrics from the database plugin with their own attributes"]
S3 --> T3["Custom spans and logs from your module with their own attributes"]
Let us walk through the figure. At the top is one resource, for example “the checkout service, version 5, running in the eu-west region”. Under it are three scopes, each representing a different unit of code inside that service. Under each scope are the items that unit produced. The hierarchy is not just a drawing. It is the exact structure that OpenTelemetry uses when it sends data over the network, so the grouping you see in the picture is literally how the data is packed.
Why the Layers Exist at All
One might ask why OpenTelemetry bothers with three layers instead of letting every item carry every label. The answer is efficiency and clarity. A service might send a million spans in a minute. If every span repeated the service name, the version, the region, the host, and the plugin name, most of the message would be the same text over and over. By storing shared facts once at the right layer, and letting items carry only what is unique to them, the messages stay small. The layers also make meaning clearer: a reader knows at a glance that a fact on the resource describes the producer, while a fact on an item describes that item.
Where Does a Fact Belong?
Whenever you want to attach a piece of information to telemetry, ask which layer it describes. If it describes the whole service, it belongs on the resource. If it describes the code unit that reported the data, it belongs on the scope. If it describes one particular event, it belongs on that event’s own attributes.
flowchart TD
Q["I want to attach a fact to telemetry"] --> Q1{"Does it describe the whole service or machine?"}
Q1 -->|"Yes"| R["Put it on the resource"]
Q1 -->|"No"| Q2{"Does it describe the code unit that reported the data?"}
Q2 -->|"Yes"| S["Put it on the scope"]
Q2 -->|"No, it describes one event"| A["Put it on that event's attributes"]
| Layer | Describes | Shared by | Examples |
|---|---|---|---|
| Resource | The producer as a whole | Everything one service sends | Service name, service version, region, host |
| Scope | The code unit that reported | All items made through one tracer, meter, or logger | Plugin name, plugin version, module group |
| Signal item attributes | One single event | Only that span, data point, or log record | Route, status code, user tier |
Think of a parcel. The company name on the shipping label is the resource: it is the same for every parcel the company sends. The name of the packing station that prepared this batch is the scope: it is the same for every parcel from that station. The delivery address and weight are the item attributes: they differ for every single parcel.
A very common mistake is to put the application’s own version into the scope version. The application’s version belongs on the resource. The scope version is the version of the code unit that does the instrumenting, such as a plugin or a module that you version separately.
5The Fields in Detail
Each field has a job. Knowing the job makes it easier to fill in well.
The Name
The name should identify the unit of code that is doing the instrumenting. For an instrumentation plugin written for a library, the name is usually the name of the plugin package. For code in your own application, the name is usually the name of a package, a module, or a component. The name should be stable, meaning it does not change from run to run or from request to request, and unique enough that it will not be confused with another unit of code. A common convention is to use the full package name or a reverse domain style name, because those are already designed to be unique.
If you ask for a tracer, meter, or logger and give an empty or missing name, OpenTelemetry does not crash. It gives you a working one with a fallback name and writes a message to its own diagnostics. This kind of forgiving design keeps your application running, but your telemetry will carry a blank source label, which makes it much harder to use. Treat the name as required even though the system tolerates a missing one.
The Version
The version records which release of that unit of code produced the data. It is especially valuable for instrumentation plugins, because behavior can change between releases. If you discover that version 1.3 of a plugin recorded some durations incorrectly, the scope version lets you find exactly which data came from version 1.3, and which came from the fixed version. If your unit of code is not versioned separately, it is fine to omit the version.
The Schema URL
The schema URL is a web address that points to a published description of the naming rules used by the telemetry. OpenTelemetry has a set of semantic conventions, which are agreed names for common labels, such as the name of the HTTP method or the database system. These conventions change over time, and some labels have been renamed. The schema URL says, “This code produced its telemetry using the naming rules of this particular version.” A backend or a Collector can use that information to translate older names into newer ones. We give this idea its own chapter later.
The Attributes
Scope attributes are extra labels that describe the scope itself, not any individual event. They are a newer addition to the specification. They are useful for facts that are the same for all telemetry from one code unit but are more detailed than the name, such as a grouping label or a small flag. They are rarely needed, and most instrumentation libraries do not set them. Keep them small and stable, and never put changing or private data in them, because they are repeated in every batch of data from the scope.
Equality: When Are Two Scopes the Same?
Systems often need to decide whether two pieces of telemetry came from the same scope. By the standard’s rules, two scopes are the same when all of their fields match: the same name, the same version, the same schema URL, and the same attributes. If even one field differs, they are different scopes. This is why a plugin that is upgraded from version one to version two is seen as a different scope after the upgrade, even though its name is unchanged. It is also why asking a provider twice with identical details returns the same tool, while asking with a different version returns a different one.
This detail has practical meaning. When you look at a chart of a metric, and you see two lines with the same scope name but different versions, you are probably seeing a rolling upgrade, where some instances run the old plugin version and others run the new one. When the upgrade is complete, the old line fades away. Reading scope equality correctly helps you interpret such patterns without alarm.
Who is speaking
The one field you should always set clearly. It identifies the code unit that produced the data.
Which release
Helps you find data from a buggy or fixed release of a plugin or module.
Which naming rules
Lets tools translate older label names into newer ones automatically.
Extra scope facts
Small, stable details about the code unit itself. Rarely needed.
6How a Scope Is Created: Providers and Their Factories
You almost never create a scope directly. It comes into being when you ask a provider for a tracer, meter, or logger.
In OpenTelemetry there is no standalone “create a scope” button. Instead, the scope is born as a side effect of asking for the tool that reports telemetry. The application sets up three providers at startup: a tracer provider, a meter provider, and a logger provider. Each provider is a factory. When a piece of code wants to report telemetry, it asks the right provider for a tracer, meter, or logger, and in the same request it gives the scope’s name, and optionally the version, the schema URL, and attributes. The provider hands back a tool that is permanently tied to that scope.
flowchart LR
A["HTTP Server Plugin"] -->|"asks with its own name and version"| P1["Tracer Provider"]
B["Database Plugin"] -->|"asks with its own name and version"| P1
C["Your Checkout Module"] -->|"asks with its own name"| P1
C -->|"asks with its own name"| P2["Meter Provider"]
P1 --> T1["Tracer for HTTP scope"]
P1 --> T2["Tracer for database scope"]
P1 --> T3["Tracer for checkout scope"]
P2 --> M1["Meter for checkout scope"]
T1 --> X["SDK pipeline: processors and exporters"]
T2 --> X
T3 --> X
M1 --> X
Look at the figure carefully. Three different pieces of code each ask the tracer provider for a tracer, and each gets a separate tracer tied to its own scope. The checkout module also asks the meter provider for a meter, again with its own name. Both tools belong to the checkout scope, one for traces and one for metrics. At the end, all tools feed the same pipeline inside the SDK, which processes and exports the data together.
Where the Scope Is Chosen
The scope is chosen by whoever writes the code that requests the tool. If you use automatic instrumentation, meaning an agent that adds telemetry to common libraries without code changes, then the plugin authors have already chosen the scope names, and each plugin uses its own. If you write custom instrumentation in your own code, you choose the name. This means that a single running application often contains scopes chosen by many different people: the OpenTelemetry community for the plugins, and your own team for custom code.
Reuse and Caching
Asking a provider for a tracer with the same scope information twice gives you the same tool, or an equivalent one. Providers keep track of what they have already handed out. This means it is safe, and cheap, to ask again. Still, the usual good practice is to ask once, when a module starts up, and store the tool in a variable that the rest of the module can use. Asking on every single request wastes a little time and adds nothing.
It is like a staff office handing out name badges. When you join a team, you ask the office for a badge with your team name on it. The office remembers it has already made one for your team. You wear your badge all day. You do not return to the office before every meeting to ask for a new badge.
Define the tracer, meter, or logger once per module, near the top of the file or in a small helper, and give it the same name as the module. This keeps scope names consistent and makes the code easy to read.
Libraries and the API Without an SDK
A reusable library that wants to report telemetry depends only on the OpenTelemetry API, not on the SDK. It asks the global provider for a tracer, naming itself as the scope. If the application that uses the library has installed the SDK, real telemetry flows. If it has not, the provider hands back a tool that does nothing, and the library’s calls cost almost nothing. This arrangement lets library authors add telemetry without forcing any monitoring choice on their users. The scope name the library chooses becomes the label under which all its telemetry appears, so it is wise for a library author to choose a name that is clear, unique, and unlikely ever to change.
Configuration by Scope
Because scope is a stable identity, the specification has been growing ways to configure telemetry by scope. The general idea is that an operator can say “turn off all tracing from scopes whose names match this pattern”, or “use these settings for this one scope”. Parts of this are still under development in the specification, and tool support varies, so check what your SDK offers. Even where such features are young, the direction is clear: the scope is becoming the natural handle for controlling telemetry source by source.
No Global Scope Is Created for You
Some beginners expect OpenTelemetry to invent a scope for the whole application. It does not. If your application code reports telemetry, it must ask for a tracer, meter, or logger and give its own name. Many teams create one scope per major component, such as “orders”, “payments”, and “inventory”, so that data can be filtered and charted by component.
7Naming Scopes Well
A good name is the single biggest factor in how useful scopes will be.
The Golden Rule: Name the Watcher, Not the Watched
Remember the distinction from the vocabulary chapter. The instrumented library is the code being watched. The instrumentation library is the code doing the watching. The scope name belongs to the watcher. If you are writing a plugin that adds OpenTelemetry to a database driver, the scope name is the name of your plugin, not the name of the driver. This rule matters because the plugin has its own version and its own bugs. If the scope were named after the driver, you could not tell which plugin, or which version of a plugin, had produced the data.
If the telemetry is produced by your own application code, which uses the OpenTelemetry API directly and is not a separate plugin, then the code that watches and the code that is watched are the same. In that case, name the scope after the package, module, or component of your application doing the reporting.
Deciding How Fine-Grained to Be
One of the hardest naming choices is size. Should a large application have one scope, ten, or a hundred? A useful test is to ask, “Would anyone ever want to look at, filter, or switch off the telemetry from just this unit?” If the answer is yes, the unit deserves its own scope. If the answer is no, merge it into a larger one. A payments component that is owned by one team and has its own dashboards deserves its own scope. A tiny helper function used by three modules does not, because nobody will ever want to filter by it. Aim for the level at which people actually make decisions.
Another test is ownership. If a unit of code has a single clear owner, such as a team or a plugin author, a scope that matches that boundary makes it easy to route questions and alerts to the right people. Scopes that cut across ownership boundaries tend to create arguments about who should fix a problem.
Examples From Common Ecosystems
Instrumentation plugins follow naming habits that match the way each programming language names packages. The exact names vary by plugin and version, so the table below shows the style rather than a promise about any specific name.
| Language | Style of scope name | Idea of an example |
|---|---|---|
| Java | Reverse domain style or plugin name with a library and version | A name beginning with io.opentelemetry followed by the library name |
| Python | Dotted module path of the plugin package | A name beginning with opentelemetry.instrumentation followed by the library name |
| JavaScript | Scoped package name of the plugin | A name beginning with @opentelemetry/instrumentation- followed by the library name |
| .NET | Namespace or assembly name of the plugin | A name beginning with OpenTelemetry.Instrumentation followed by the library name |
| Go | Import path of the plugin package | A path beginning with go.opentelemetry.io/contrib/instrumentation |
Three Short Naming Stories
Story one: the helpful library. A team wrote a plugin that adds telemetry to a message queue client. They first named the scope after the queue client itself, thinking it was neat. Later, a second team wrote a competing plugin for the same client and used the same name. Data from the two plugins became indistinguishable, and a bug in one plugin was blamed on the other. After renaming each scope after its own plugin package, the confusion ended.
Story two: the all-in-one name. A small company gave every tracer in its application the same name, the company’s product name. For a while it worked. As the product grew to thirty components, engineers could no longer tell which component produced a slow span, and filters by scope were useless. A cleanup that gave each component its own name restored the usefulness of scope almost overnight.
Story three: the moving name. A developer built scope names from the current request path to get “more detail”. Within a day, the backend showed tens of thousands of different scopes, dashboards slowed down, and memory in the application crept up. Moving the path to an attribute on each span, and using a single fixed scope name, fixed everything.
Practical Naming Rules
- Use stable names. Never include a request ID, a user ID, a timestamp, or any value that changes. Every different name creates a new scope, and many backends treat each scope as a separate group.
- Use unique names. A dotted package path or reverse domain name rarely collides with others. Short generic names such as “app” or “utils” do.
- Choose the right size. One scope per library plugin is natural. For your own code, one scope per major component or package is usually enough. One scope for the whole application hides detail. One scope per class creates too many.
- Match the code structure. If your project has packages named “orders” and “payments”, use scope names that follow them, so engineers can map telemetry to code folders easily.
- Do not use the service name. The service name belongs on the resource. Repeating it as the scope name adds nothing and hides which part of the service spoke.
- Keep the name readable. People will see it on dashboards, so make it recognizable.
Good scope names are like clear street names. “Main Street” is stable and unique within a town. A street sign that said “the road where Tom’s car was parked at noon” would be useless the next day. Name your code by what it permanently is, never by what happened to be going on.
8Internal Working: From Your Code to the Wire
What actually happens to a scope between the moment you ask for a tracer and the moment data lands in a backend.
When your code asks a provider for a tracer, meter, or logger, the provider builds a small object that remembers the scope’s name, version, schema URL, and attributes. Whenever this tool creates a span, records a metric, or emits a log record, it attaches a reference to that scope information. The tool does not copy the scope’s details into every single item. It points to the same shared scope object, which is cheap in memory.
Spans, metrics, and logs then travel through the SDK’s pipeline. For traces, finished spans go through span processors, which may batch them, and then to an exporter. For metrics, data points are summarized and collected at intervals by a metric reader. For logs, records go through log processors and an exporter. At every step, each item still knows which scope it belongs to.
The Scope Is Shared, Not Copied
It is worth pausing on how little work the scope adds to each item. A span does not carry its own private copy of the scope’s name and version. It carries a reference to a scope object that was created once. If a plugin creates ten thousand spans, they all point to the same object. This is a common design in efficient systems: store a shared fact once, and let many items point to it. Memory use stays low, and updating or inspecting the fact is simple.
Scope and the Provider’s Registry
Behind the scenes, each provider keeps a registry of the tools it has handed out, keyed by scope. When you ask for a tracer, the provider checks the registry. If an equal scope is already there, you get the existing tool. If not, it creates a new one and adds it. This registry is also how the provider can later apply scope-based settings, such as turning off tracing for certain scopes, because it knows every scope that has asked for a tool.
Grouping at Export Time
When the exporter packs data to send it, it groups items by resource first, and then by scope inside each resource. This is the grouping you saw in the three-layer picture. Items from the same scope are placed together in one group, and the scope’s details are written once for the whole group, not once per item. This keeps messages small. If a hundred spans came from the same plugin, the plugin’s name and version appear only once, followed by the hundred spans.
A module asks for a tool
The module calls a provider with a scope name, and optionally a version, schema URL, and attributes. The provider builds or finds a tracer, meter, or logger tied to that scope.
The tool is used during real work
Each time the module starts a span, records a number, or writes a log line, the tool creates the item and attaches a reference to its scope.
Processors and readers handle the items
Batching, sampling, and summarizing happen. Sampling decisions are based on trace information, not on scope, but every kept item still carries its scope.
The exporter groups by resource and scope
Items are packed into groups. Each group writes the scope’s name, version, schema URL, and attributes once, followed by the items that belong to it.
The message travels as OTLP
The standard protocol has a place for the scope in its structure, sitting between the resource and the items. Collectors and backends read it from there.
The backend stores and shows it
The backend keeps the scope information with the data and offers it as something you can display, search, and filter by.
This path shows that the scope is not an afterthought. It is built into the structure of OTLP, between the resource and the items. A tool that reads OTLP knows exactly where to find it, which is why scope information survives across vendors and systems without special arrangements.
Because scope details are written once per group, a scope costs very little in network size. The cost grows with the number of different scopes, not with the number of items.
9Scope Across the Three Signals
The idea is the same everywhere, but each signal uses it a little differently.
Traces
For traces, the scope identifies the tracer that created each span. In a trace backend, you can often see the scope name next to a span, in a details panel, or use it as a filter. This is how you answer “which plugin made this span?” A single trace commonly contains spans from many scopes, because one request passes through a web framework plugin, an HTTP client plugin, a database plugin, and your own code, each with its own scope. Seeing the scope on each span makes the picture of a trace much easier to read.
Metrics
For metrics, the scope identifies the meter that created each instrument. It plays a more serious role here, because it takes part in the identity of a metric. If two different meters, in two different scopes, both create an instrument called “request duration”, OpenTelemetry treats them as two different metric streams, not one. Their data is kept separate. This protects you from accidental mixing, but it also means that if you expected two code units to share one metric, you must plan for that.
The scope also matters when you configure views, which are rules in the SDK that change how metrics are reported. A view can select instruments by many criteria, and one of them is the name of the meter, so a rule can apply only to instruments from a particular plugin. For example, you might change the histogram buckets for one plugin’s duration metric without touching anyone else’s. Views can also match on the meter’s version and schema URL.
When metrics are exported to systems that use labels, such as Prometheus-style systems, the scope’s name and version are commonly added as labels on every metric. This is how the scope identity travels into a world that has no native concept of scope. If you see labels with a scope name and scope version on your metrics in a Prometheus-style system, now you know where they came from.
A Closer Look at Metric Identity
Because scope takes part in a metric’s identity, it is worth spelling out what that means. A metric stream is identified by the scope that created it, the instrument’s name, and some other properties of the instrument, such as its type and unit. Two streams that differ in any of these are different. Suppose your own order code and a plugin both create a counter named “requests”. They are separate streams. If you look at the combined data in a system that merges by metric name alone, you might see them added together or in conflict. If you want one combined view, you can do it deliberately in your backend by summing across scopes, rather than hoping the two will merge themselves.
Think of it like two shops in different towns that both sell an item called “bread”. The sales figures are kept in each shop’s own ledger. A head office that wants the total must add the two ledgers on purpose. It would be wrong for the ledgers to merge on their own, because the shops might measure sales in different ways.
Logs
For logs, the scope identifies the logger that created each log record. In many setups, logs from a logging library are bridged into OpenTelemetry by a small piece of code, and that bridge sets the scope according to the original logger’s name. This means a log record in your backend can keep the name of the class or module that wrote it, such as the logger name you are used to seeing in text log files. This makes it easier to filter logs by component.
Where Scope Is Most Helpful
- Finding out which plugin or module produced a span, metric, or log.
- Turning off or filtering noisy sources.
- Tuning metric views for one source only.
- Spotting problems tied to one plugin release.
Where Scope Is Not the Tool
- Describing the whole service. Use the resource.
- Describing one event. Use that event’s attributes.
- Making sampling decisions. Sampling uses trace data.
- Proving who sent the data. Scope names can be set by anyone.
10Scope in the Collector and in Backends
Once telemetry leaves your application, the scope keeps working, because tools downstream understand it.
The OpenTelemetry Collector reads OTLP, so it sees scope information on every batch. Several of its processors can use it. The filter and transform processors can select data by scope name, which lets you drop everything from one noisy plugin, or edit data coming from one source only. The attributes processor can select the items it edits by the name and version of the instrumentation library, which is the older name for the scope. This lets a platform team say, “Apply this label cleanup only to data produced by this plugin.” In that way, scope becomes a handle for precise, central control.
Mapping to Other Systems
Not every backend understands scope as a first-class idea, so exporters translate it into whatever the target system offers. For trace systems that use tags, the scope’s name and version are commonly written as span tags with names that reflect the scope. For Prometheus-style systems, they become labels on metrics. Older exporters used names built on the word “library”, for example for the name and version of the instrumentation library. Newer ones use names built on the word “scope”. If you move between tools, expect to see both styles, and know that they mean the same thing.
| Destination | How scope usually appears |
|---|---|
| OTLP-aware backend | Shown natively as scope name, version, and attributes |
| Trace system that uses tags | Written as tags on each span, with names for scope name and scope version |
| Prometheus-style system | Added as labels for scope name and scope version on each metric |
| Older exporters | May still use the older “library” wording for the same fields |
Dropping a Source With a Rule
One of the most popular uses of scope in the Collector is to remove a whole source of telemetry. The idea is simple: write a rule that says “if the scope name equals this value, drop the item”. This does not change your applications at all. It is applied centrally, takes effect when the Collector configuration is reloaded, and can be reversed just as easily. Teams use this to quiet noisy plugins, to remove telemetry from internal helper libraries that nobody reads, and to cut costs. Before dropping a source, check that no dashboard or alert depends on it, because a dropped source cannot be recovered after the fact.
Editing One Source Only
The same selection power works for edits. A rule can say “for items from this scope, delete this label” or “for items from this scope, add this team label”. Because the rule is tied to scope, other sources are untouched. This precision is much safer than a broad rule that edits everything. It also fits the way responsibility is often divided: one team owns one plugin or component, and rules for that component are written against its scope.
Using Scope to Debug
In a backend, filtering by scope name is one of the fastest ways to understand a surprising result. If a dashboard shows a metric from an unexpected source, the scope shows which plugin is responsible. If traces are full of tiny spans, grouping spans by scope shows which plugin creates most of them, and you can decide whether to reduce or disable it. If a bug appears after an upgrade, comparing data from before and after, split by scope version, tells you whether a plugin update caused it.
It is like a sorting office that can sort letters by the post office they came from. If one branch sends damaged envelopes, the sorting office can set aside everything from that branch and tell its manager. Without the branch stamp, the office would see only a pile of letters with no clue where the problem began.
11The Schema URL: Keeping Names Consistent Over Time
The schema URL is the quiet hero that helps old and new data live together.
OpenTelemetry publishes semantic conventions: agreed names for common labels. For instance, there is an agreed name for the HTTP method of a request and an agreed name for its status code. These conventions are improved over time, and when a better name is found, the project may rename a label. A rename causes pain: dashboards built on the old name stop working for services that use the new name, and the two groups of data cannot be compared easily.
The schema idea is a solution. A schema is a published file that describes how names changed from one version of the conventions to the next. When a plugin sets a schema URL, it declares which version of the conventions it used. A tool that understands schemas can read the file and translate labels from the older naming to the newer one, or the other way around. In this way, data from an old plugin and data from a new plugin can be brought to one naming style.
flowchart LR
O["Old plugin with schema version one"] --> C["Collector or backend that understands schemas"]
N["New plugin with schema version two"] --> C
C --> U["Unified data using one naming style"]
Resource and Scope Schemas
Both the resource and the scope can carry a schema URL. The resource’s schema URL applies to the naming of the resource’s labels. The scope’s schema URL applies to the naming of the telemetry produced by that scope. The two may differ, because different code units may have been written at different times, following different versions of the conventions. Having the schema on each scope means that every code unit can state its own naming rules honestly.
A Small Example of a Rename
Imagine that, in an early version of the conventions, the label for the HTTP method had one name, and in a later version it was changed to a clearer name. A plugin written against the early version sets its schema URL to point at the early version. A plugin written against the later version points at the later one. A Collector that understands schemas reads the published file that records the rename, sees that the two plugins use different names for the same thing, and rewrites the older plugin’s label to the newer name. The result is that a single dashboard filter works for both plugins, even though the plugins were written years apart.
Without this mechanism, someone would have to write and maintain a custom rule for every rename, in every Collector, and remember to remove it later. With it, the knowledge of what changed is published once, in one place, for everyone.
Why It Is Often Left Empty
In practice, support for schema translation in tools is still growing, and many plugins and backends do not use it yet. As a result, you will often see an empty schema URL. This is fine. The field is there so that the problem can be solved cleanly when tools catch up. A good habit for authors of instrumentation plugins is to set it, because it costs almost nothing and helps in the future.
If you write a reusable instrumentation plugin, set both the scope version and the schema URL. They tell your users exactly what they are running and which naming rules it follows.
12A Worked Journey Through One Service
Let us follow a small imaginary service and see how scopes show up in practice.
Suppose a company runs an order service. It uses a web framework to receive requests, a database driver to store orders, an HTTP client to call a payment service, and its own code to apply business rules. Automatic instrumentation is installed, and the team has also added custom spans in their own code.
When the service starts, several things happen. The web framework plugin asks the tracer provider for a tracer, naming itself and its version. The database plugin does the same, with its own name and version. The HTTP client plugin does the same again. The team’s own code, in a package named for the order logic, asks for a tracer with that package’s name, and also asks the meter provider for a meter with the same name, because it records a custom metric for orders placed. That makes four scopes for traces and one for metrics, and the resource at the top says “order service, version seven, region west”.
A customer places an order. The web framework plugin creates a server span through its tracer, carrying its scope. The team’s order logic creates a custom span for “apply discount rules” through its own tracer, carrying the order package scope. The database plugin creates a span for the insert query, with the database scope. The HTTP client plugin creates a span for the payment call, with the HTTP client scope. All four spans belong to one trace, because they share a trace ID, but each was made by a different scope.
When the exporter sends the data, it groups the four spans under the single resource and under four different scope groups. Each group writes its scope’s name and version once. The backend receives this structure, stores it, and shows each span with its scope information.
Later, an engineer notices that the database plugin creates very many tiny spans for internal steps, making traces hard to read. Using the scope name, the engineer can filter the view to hide that scope, and a platform engineer can add a rule in the Collector to drop spans from that scope entirely. The rest of the telemetry is untouched. Without scopes, this would have required a code change or a risky guess about which spans to remove.
Weeks later, the team ships a new version of its own order package and bumps the package’s version number. The scope for the order package now shows the new version. During the next hour, a dashboard that splits order spans by scope version shows two groups: the old version on instances that have not yet restarted, and the new one on the updated instances. The engineers compare the two groups and see that the new version’s discount step is slightly slower. Because the scope version marks exactly which code produced each span, they can say with confidence that the slowdown came from the new release, and fix it before it spreads to every instance.
The scope did not change what any span said about the request. It only recorded who said it. This light touch is exactly why it is so safe and so useful.
13Advantages, Disadvantages, and Trade-offs
An honest look at what scope gives you and what it costs.
Advantages
- Clear source identity: you always know which code unit produced a piece of telemetry.
- Precise control: filter, drop, or tune data from one source without touching others.
- Easier debugging: pinpoint noisy or buggy plugins and releases quickly.
- Safer metrics: instruments from different sources do not collide by accident.
- Built into the protocol, so it survives across tools and vendors.
- Very cheap: scope details are stored once per group, not per item.
- Supports gradual change through versions and schema URLs.
Disadvantages
- Quality depends on good naming, and names are chosen by many different authors.
- Some backends show scope poorly or hide it, so the benefit is not always visible.
- Splitting metrics by scope can surprise people who expected one shared metric.
- Too many scopes create clutter and confusion.
- Mixing up scope, resource, and attributes leads to misplaced facts.
- Schema translation support is still uneven across tools.
- Names are not proof of origin and can be set by anyone.
Scope Compared With Other Ways of Grouping
People sometimes try to get the benefits of scope in other ways, and it is useful to see why scope is usually better. They may add a custom attribute called “component” to every span. This works for spans but needs discipline in every line of code, does nothing for plugins you do not control, and has to be repeated on every single item. They may use the span name’s prefix to guess the source, which is fragile and breaks when names change. They may rely on the service name alone, which is too coarse. The scope is built in, set once per tool, shared by every item, and understood by every OTLP-aware tool. For these reasons, it is the recommended way to say which code unit produced the data.
The Key Trade-offs
The first trade-off is detail versus clutter. Fine-grained scopes give precise control, but too many of them make dashboards and filters unwieldy. The second is separation versus sharing. Separate scopes keep metrics from different sources apart, which protects accuracy, but if you truly want two code units to contribute to one metric, you must arrange it deliberately. The third is standardization versus freedom. The name is a free-form string, which gives authors flexibility, but it also means conventions and discipline matter, because the system will not check your names for you.
Think of the signs on a large office building. If every single desk has a sign, nobody can read the signs because there are too many. If the whole building has one sign, nobody can find anything. Floors and departments are the natural level. Good scopes sit at the same sensible level.
14Performance and Scalability
Scopes are light, but a few habits keep them that way.
The cost of a scope has three parts: the time to create the tracer, meter, or logger, the memory to hold the scope’s details, and the bytes to send them. All three are tiny. Creating a tool happens once per module, at startup, or at most a few times. The scope object is small and shared by all items from that scope. And, as we learned, the details are written once per group in the exported message. A service with fifty scopes pays almost nothing extra for them.
What Can Go Wrong at Scale
- Creating tools on every request. Asking for a tracer or meter inside request-handling code means the provider does a lookup on every call. Providers are efficient, but doing this millions of times is wasted work. Create tools once and keep them.
- Dynamic names. If a name includes a changing value, the system creates a new scope for each distinct value. Memory grows and the data fragments into many tiny groups. In the worst case, some tools hold on to each scope forever.
- Very many scopes. A few dozen is normal. Thousands usually signal a naming mistake, such as one scope per object or per request.
- Metric multiplication. In systems that turn scope into labels, every extra scope that reports the same metric name adds a separate series. This is correct behavior, but it can raise costs, so keep the number of scopes reporting the same metric small.
Thinking About Volume
Scope does not change how many spans, metrics, or logs your application produces, but it does help you see where the volume comes from. A simple exercise is to rank scopes by the amount of data each one produces. In most systems, a small number of scopes produce most of the volume, often a few plugins that create many small spans or a few metrics with many label combinations. Knowing this lets you spend effort where it matters. Tuning the top three scopes usually saves far more than trimming a hundred small ones, and the scope label is what makes this ranking possible in the first place.
Memory and Lifetime of Scopes
A scope lives as long as its provider remembers it, which is usually as long as the application runs. This is fine for a handful of stable scopes. It becomes a problem only when scopes are created without limit, which is why dynamic names are dangerous. An application that creates a new scope for every request will slowly grow in memory, because the provider’s registry keeps every scope it has ever seen. In long-running services, this kind of leak can take days to show up, and then fail in the middle of the night. A stable, small set of scope names is the cure.
Scaling Out
Scope information is the same on every instance of a service, because every instance runs the same code. So when you run many copies of a service, the scopes line up automatically, and backends can combine data across instances by scope name without any extra effort. This is another reason to keep names stable and the same across all environments, from testing to production.
15Security and Privacy
Scope is mostly harmless, but a few points deserve care.
Scope information is metadata about your code, and it travels with every batch of telemetry. That makes three concerns worth knowing.
The first is information leakage through names. Scope names that follow your internal package structure can reveal how your code is organized, the names of internal projects, or even customer names if someone carelessly built a name from customer data. When telemetry goes to an outside vendor, those names go with it. Choose names that are meaningful to engineers but do not reveal secrets, and never build a name from private data.
The second is trust. A scope name is a free-form string set by whoever writes the instrumentation. It is not a signature, and it proves nothing about who sent the data. A malicious or careless sender can set any scope name it likes. So never use the scope name to decide who is allowed to do something, or to grant extra privileges. Use proper authentication at the receiving end for that. Treat scope as a helpful label, not as a proof of identity.
The third concerns scope attributes. Because they travel with every batch, they should hold only small, stable, non-sensitive facts. Do not put secrets, personal data, or anything that changes per request in them. If you need such information, it belongs on a protected, event-level attribute that you can control and remove with a processor if needed.
Choosing Names With Privacy in Mind
When you choose a scope name, picture it appearing on a dashboard that many people, including people outside your team, may see. A name like “payments.refunds” is helpful and harmless. A name that includes a customer’s company name, an internal codename that you want to keep secret, or an unreleased product name is riskier. The best names are descriptive of the code’s job rather than of its business context, and they are stable enough that you would be comfortable seeing them in a vendor’s support ticket.
If a Collector rule is based on scope name to decide what to drop or keep, remember that someone could rename a scope in a new release. Review such rules when you upgrade plugins.
16Monitoring, Logging, and Troubleshooting
When scope information looks wrong or missing, a calm, step-by-step approach finds the cause.
| Symptom | Likely cause | What to check |
|---|---|---|
| Scope name is blank or a default | Tool created with an empty name | Look at where the tracer, meter, or logger is requested |
| Hundreds of scopes appear | Names built from changing values, or tools created per object | Search for names built with variables or loops |
| Same metric appears twice, with different scopes | Two code units create an instrument with the same name | Decide whether to rename one or to merge them with a view |
| Scope version is the application version | Version mixed up with the resource | Set application version on the resource, scope version on the plugin |
| Backend does not show scope | The product hides it or maps it differently | Check how the exporter or backend maps scope fields |
| View rule does not apply to a plugin | Meter name in the rule does not match exactly | Copy the exact name from real data |
| Scope attributes missing downstream | An older exporter or backend ignores them | Check support for scope attributes in your tools |
A Methodical Order
Start at the source. Find where the tracer, meter, or logger in question is created, and check the name, version, and other fields passed. Next, check what the SDK actually sends, using a debug exporter or a local Collector that prints what it receives, which shows the scope exactly as it leaves the application. Then check the Collector: do any rules rename, drop, or rewrite data based on scope? Finally, check the backend: does it show scope fields, and where? Working from the source outward isolates the stage at which the information goes missing or changes.
A Worked Troubleshooting Story
A team noticed that a dashboard showing “database call duration” had suddenly split into two lines after a weekend release, even though they had changed nothing about the metric. Looking at the labels, they saw the lines were identical except for the scope version. The release had upgraded the database plugin, and during the rolling restart some instances ran the old version while others ran the new one. Once all instances had restarted, the old line faded and the new one carried on. The team added a short note to their runbook: when a metric splits by scope version after a release, wait for the rollout to finish before worrying. What could have been a long investigation took five minutes, because they knew to look at the scope.
Keeping an Inventory
A good habit for larger organizations is to keep a short inventory of the scope names in use across services. Many backends can list distinct scope names, and a periodic look at this list reveals surprises: a plugin you did not know was installed, a name that changed after an upgrade, or a suspicious flood of new names. It also helps new engineers learn what the system is made of.
Watching for Drift
When you upgrade an instrumentation plugin, its scope name or version may change, and so may the names of the spans and metrics it produces. After upgrades, compare the list of scopes and the volume of data per scope before and after. A drop to zero for a scope that used to be busy may mean the plugin changed its name, which could silently break dashboards and alerts that filter by the old name.
When you build dashboards or alerts that filter by scope name, record which scope names they depend on, so that an upgrade review can check them quickly.
17Design Patterns, Anti-Patterns, and Best Practices
Habits that keep scopes useful, and habits that quietly spoil them.
Patterns That Work
- One scope per component. Give each major module or package its own scope, named after the component.
- Create once, reuse. Request the tracer, meter, or logger at module startup and keep it in a variable.
- Name the watcher. For plugins, use the plugin’s name. For application code, use the package or module name.
- Version your plugins. If you publish reusable instrumentation, set the scope version and the schema URL.
- Keep names the same everywhere. Use identical names in testing, staging, and production so data lines up.
- Use scope for control. Use scope names in Collector rules and SDK views to tune or drop data from one source.
- Keep an inventory. Review the list of scope names periodically.
Anti-Patterns to Avoid
What it looks like
Using the same scope name, such as the application name, for every tracer, meter, and logger in the program.
Why it hurts
You lose the ability to tell components apart. Filters and views cannot target one source, and every span looks like it came from the same place.
Better approach
Give each module or component its own stable scope name.
What it looks like
Building scope names from changing data, such as user IDs, request paths, or timestamps.
Why it hurts
Each different value creates a new scope. Memory use grows, backends become cluttered, and grouping by scope becomes useless.
Better approach
Keep scope names fixed. Put changing data on the event’s own attributes.
What it looks like
Naming a plugin’s scope after the library it watches instead of after the plugin itself.
Why it hurts
You cannot tell which plugin or which plugin version produced the data. Two different plugins for the same library would look identical.
Better approach
Name the watcher: use the plugin’s own package name and version.
What it looks like
Putting the application’s version, region, or host into scope fields.
Why it hurts
These are facts about the whole producer, so they belong on the resource. Placing them on the scope scatters them and confuses tools that expect them in the resource.
Better approach
Use the resource for producer-level facts and keep scope for the code unit’s own identity.
What it looks like
Trusting the scope name as proof of where data came from, for example to grant access or skip checks.
Why it hurts
Anyone who can send telemetry can choose any scope name. It is a label, not a credential.
Better approach
Use real authentication between senders and receivers, and treat scope as helpful metadata only.
Reviewing Scope in Code Review
Scope choices are easy to review when a teammate adds new instrumentation. Reviewers can ask a handful of quick questions. Is the name stable, with no changing values? Does it follow the naming style of the rest of the project? Is the tracer, meter, or logger created once and reused? Does the name identify the component rather than the whole service? Is any private information being used in the name or in scope attributes? These questions take a minute to ask, and they prevent the kind of naming mistakes that are slow and annoying to repair after thousands of services depend on them.
It also helps to agree, as a team, on one place in each project where scope names are defined, such as a small constants file. Then every module can import the same name, spelling mistakes disappear, and a rename, when it is truly needed, is a single change that can be reviewed in one place.
Documenting Scopes for Your Team
A one-page note that lists your application’s own scopes, what each one covers, and who owns it, is one of the cheapest and most valuable pieces of documentation you can write. It lets a new engineer read a trace and understand where each span came from. It lets an on-call engineer know whom to ask. And it creates a gentle pressure to keep the list small and the names sensible, because nobody wants to explain fifty confusing names on one page.
A Short Checklist
- Does every tracer, meter, and logger have a clear, stable name?
- Is each one created once per module and reused?
- Does the name identify the watcher, not the watched library?
- Are application-level facts on the resource and event-level facts on the event?
- Do plugins you publish set a version and a schema URL?
- Are Collector rules and views that use scope names reviewed after upgrades?
- Is there an inventory of scope names in use?
18Real-World Scenarios
Common situations that show scope at work. These are illustrative patterns frequently seen in production systems.
An online marketplace silencing a noisy plugin
A marketplace notices that traces are crowded with hundreds of tiny spans created by one database plugin for internal steps. Engineers group spans by scope name and see that this single plugin makes most of them. The platform team adds a Collector rule to drop spans from that scope, and traces become short and readable again, while all other telemetry is unchanged.
A bank tracking down a bad plugin release
After an upgrade, a bank sees odd latency numbers for outgoing calls. Filtering metrics by scope version shows that only data from the newest release of the HTTP client plugin looks strange. The team rolls back that plugin, reports the bug, and confirms by scope version that the numbers return to normal.
A streaming company tuning histogram buckets
A video platform finds that the default buckets for one plugin’s duration metric are too coarse. Using a view that selects by meter name, the team changes the buckets for that plugin only. Metrics from every other plugin and from the team’s own code keep their defaults.
A large company organizing telemetry by component
A company with many teams asks each team to create one scope per component, named after the component’s package. Dashboards and alerts are then built around scope names, so each team can see only its own telemetry, and it is easy to see which component is responsible when something goes wrong.
A retailer measuring the cost of telemetry by source
A retailer wants to understand why its monitoring bill is growing. Grouping data volume by scope name shows that two plugins account for most of the spans, and one internal module produces a very high number of metric series. The team adjusts those three sources first, instead of making broad cuts across everything, and the bill falls without any loss of the telemetry they actually use.
A platform team onboarding new services
A platform team publishes a short guide telling every new service how to name its scopes: one per major package, named after the package, with no changing values. New services follow the guide, and from the first day their telemetry is easy to filter. The team also adds a weekly report listing new scope names, which catches mistakes such as names built from request data within days.
A library author publishing a plugin
An author writes an OpenTelemetry plugin for a popular library. The plugin names its scope after its own package, sets its version from the plugin’s release number, and sets the schema URL for the naming rules it follows. Users can now report bugs by saying exactly which plugin version they ran, and tools can translate names between versions.
A logging bridge keeping logger names
A team bridges its existing logging library into OpenTelemetry. The bridge sets the scope name from each logger’s original name. In the backend, engineers filter log records by scope and see only the logs from one class or module, just as they did with text log files before.
19Frequently Asked Questions
Short answers to questions that appear again and again.
20Summary and Key Takeaways
If you remember only a few things, remember these.
Instrumentation scope is the small piece of identity that says which unit of code produced a piece of telemetry. It sits between the resource, which describes the whole producer, and the individual spans, metrics, and log records, which describe single events. It is created whenever a tracer, meter, or logger is requested, it travels in every standard OTLP message, and it gives engineers a precise handle for finding, filtering, tuning, and debugging telemetry from one source at a time.
Key Takeaways
- Scope names the speaker. It identifies the code unit that produced telemetry, so you can always answer “which part of the code said this?”
- Four fields, one that matters most. Name, version, schema URL, and attributes. Always set a clear, stable name.
- Three layers. Resource describes the whole producer, scope describes the code unit, and attributes describe one event. Put each fact on the right layer.
- Name the watcher, not the watched. Use the plugin’s or module’s own name, never the name of the library being observed or the service as a whole.
- Created through providers. Ask a tracer, meter, or logger provider with a name, once per module, and reuse the result.
- Scope shapes metrics. It is part of a metric’s identity and can be used to select instruments in views, so same-named instruments from different scopes stay separate.
- It is a control handle downstream. Collector processors, exporters, and backends use scope for filtering, mapping, and display.
- Keep it stable and honest. Avoid changing values in names, avoid secrets, and never treat a scope name as proof of identity.