How do the instruments and block_instruments arguments of Traceloop.init() control OpenLLMetry?
answer
- default is: everything installed is on
- allowlist versus subtract-from-default
- two spans for one call
- version drift can break one instrumentor
- blocking is silent, so comment it
basics
~20 sThey narrow auto-instrumentation. Passing instruments={...} turns the default all-on behaviour into an allowlist of only those libraries; block_instruments={...} keeps the default and subtracts specific ones. Both take members of the SDK's Instruments enum and are used to cut span noise, avoid duplicate patching, and quarantine a misbehaving instrumentor.
solid answer
~40 sBy default `Traceloop.init()` activates every instrumentation package it finds installed. Two arguments override that: `instruments`, a set that becomes an exclusive allowlist, and `block_instruments`, a set subtracted from the defaults. Values come from `traceloop.sdk.instruments.Instruments` — `Instruments.OPENAI`, `Instruments.ANTHROPIC`, `Instruments.LANGCHAIN` and so on. Three real reasons to reach for them: span volume, when a chatty framework or vector-store client triples your ingest for little insight; **duplicate instrumentation**, when you already run the standalone OpenTelemetry instrumentation for that library or your framework emits its own spans, so every call appears twice; and containment, when a library upgrade makes one instrumentor error or produce wrong spans and you need the rest of your tracing to keep working while you pin a version. Prefer `block_instruments` for surgical removals — an allowlist silently drops coverage for libraries added later.
code
python · 8 linesfrom traceloop.sdk import Traceloop
from traceloop.sdk.instruments import Instruments
# Exclusive allowlist: only these instrumentors run.
Traceloop.init(
app_name="rag-api",
instruments={Instruments.OPENAI, Instruments.LANGCHAIN},
)go deeper
Know that Traceloop.init() instruments every supported library it finds by default, and that instruments and block_instruments exist to narrow that using the SDK's Instruments enum.
Explain the difference precisely: instruments is an exclusive allowlist, block_instruments subtracts from the defaults, and they differ in what happens to libraries added later.
Lead with duplicate instrumentation as the real production case — double spans, doubled cost figures, skewed latency — and cover containment during version drift. Note that blocking is silent and needs a comment and an owner.
Decide who may block what. Set a default of tracing everything with volume shaped in the collector, require a documented reason and expiry for each block, and keep the set identical across environments so staging and production produce comparable traces.
## Default: everything installed is instrumented `Traceloop.init()` with no instrumentation arguments enables every instrumentor whose package is present. That is the right default for a one-line integration, and for most applications it never needs touching. The two arguments exist for the cases where "everything" is the wrong answer. ## Allowlist versus blocklist ``` from traceloop.sdk.instruments import Instruments Traceloop.init(app_name="rag-api", instruments={Instruments.OPENAI, Instruments.LANGCHAIN}) Traceloop.init(app_name="rag-api", block_instruments={Instruments.ANTHROPIC}) ``` `instruments` is exclusive: pass it and *only* those instrumentors run, no matter what else is installed. `block_instruments` is subtractive: everything runs except the named ones. They express opposite defaults for future libraries — with an allowlist, a library someone adds next quarter is silently untraced; with a blocklist, it is traced automatically. That asymmetry is the whole basis of choosing between them, and it is what a senior answer should lead with: use the blocklist unless you have a positive reason to freeze coverage. ## Reason one: span volume and cost An agent loop with a chatty framework can emit dozens of spans per request, many of them internal framework bookkeeping with no diagnostic value. Ingest is usually billed by volume, and a trace nobody can read is not observability. Blocking one noisy instrumentor is a blunt but effective control at the source. The more precise alternative is filtering or sampling downstream in a collector, which keeps the option of turning detail back on without a redeploy — the tradeoff is that you pay to ship the data before you drop it. ## Reason two: duplicate instrumentation This is the failure that actually shows up in production and the one interviewers like. If the same library is patched twice — because you already run the standalone `opentelemetry-instrumentation-*` package for it, or because your framework emits its own spans for the same call, or because another vendor's agent auto-instruments on startup — you get two spans for one call. The visible symptoms are duplicated cost and token figures, nested spans that look like retries that never happened, and latency percentiles computed over double the events. Blocking one side is the fix; deciding *which* side to keep is a judgment call based on which produces the richer attributes and which your dashboards already key on. ## Reason three: containment during upgrades Instrumentation is version-coupled: an instrumentor patches specific methods of a specific client, and a major client release can move or rename them. The result is a package that errors on patching, produces spans missing key attributes, or, in the worst case, interferes with the library. Blocking that one instrumentor keeps the rest of your LLM tracing alive while you pin versions or wait for a fix — far better than ripping out the SDK because one dependency moved. ## Operational consequences to state out loud - **Blocking is silent.** A blocked library produces no spans and no warning. Six months later someone debugs "why has our vector store no latency data" and the answer is a line in `init` nobody remembers. Comment the reason next to the argument and give it an expiry. - **Blocking is not a privacy control.** Turning off an instrumentor removes the whole span, including latency and error signal, which is a heavy price to avoid recording content. Content capture has its own switch; use that instead when the concern is what is *inside* the span. - **Environment-varying sets are a debugging trap.** If staging traces a library that production blocks, your "it works in staging" investigations start from different data. Keep the set identical unless you have a specific reason. - **Not installed is not the same as blocked.** If the instrumentation package for a library is absent, it is untraced regardless of these arguments. When spans are missing, check installation before you go looking for a blocklist. ## How to answer the question well A weak answer stops at "it turns instrumentation on and off". A strong one names the allowlist/blocklist asymmetry, gives duplicate instrumentation as the concrete production case, notes that blocking is silent and needs a comment and an expiry, and separates volume control (which may belong in a collector) from privacy control (which belongs in the content-capture setting, not here).
- How would you notice duplicate instrumentation in the first place?Cost and token totals roughly double against the provider's own usage figures, and a trace shows two spans with near-identical durations wrapping one call, often nested so it resembles a retry. Comparing span counts per request before and after adding a dependency is the fastest confirmation. The fix is to block one of the two instrumentations, keeping whichever produces the richer attributes.
- Is block_instruments a reasonable way to keep prompt text out of your traces?No — it is a sledgehammer. Blocking removes the entire span, so you also lose latency, errors and token usage for that library, which is most of the value. Content capture has a dedicated toggle, and a collector can strip specific attributes centrally. Reach for blocking when you do not want the library traced at all, not when you object to one field.
- Why prefer block_instruments over an explicit instruments allowlist in a growing codebase?Because they behave differently for libraries added later. An allowlist freezes coverage: any new client someone introduces is silently untraced until the list is edited, and nobody gets an error to prompt that. A blocklist keeps the default of tracing everything and removes only what you deliberately excluded, so new dependencies arrive observable by default.
- An instrumentor breaks after a provider client upgrade. What do you do first?Block that instrumentor so the rest of your tracing keeps working, and pin the client version if you can roll back. Then verify whether the instrumentation package has a release supporting the new client, since the coupling is to specific patched methods. Treat the block as temporary with a ticket attached rather than leaving a permanent hole in coverage.
saying these in an interview costs you the question
- Assuming instruments and block_instruments are just two spellings of the same thing
- Using an allowlist and being surprised that new libraries stop being traced
- Blocking an instrumentor to hide prompt content and losing all its spans
- Forgetting that an uninstalled instrumentation package looks identical to a blocked one
- Leaving a temporary block in place permanently with no comment