Sooner or later one team’s Collector fleet becomes everyone’s. A platform team stands up collection for its own services, it works, and then the next business unit wants in, and the one after that, and maybe eventually external customers whose data you ingest. Now you’re running shared collection infrastructure for many tenants — and the questions change from “does telemetry flow?” to “whose telemetry is this, where should it go, who’s allowed to change how it’s handled, and how do I stop one loud tenant from degrading everyone else?”
This guide is about designing that multi-tenant Collector architecture deliberately rather than letting it accrete. We’ll cover what multi-tenancy actually means here, the isolation choices (dedicated pipelines vs a shared pipeline with routing), how you identify which tenant a signal belongs to, routing telemetry per tenant, per-tenant processing and destinations, the noisy-neighbor problem, and the governance and RBAC that keep tenants from stepping on each other.
Platform engineers and architects running OpenTelemetry collection as a shared service for multiple teams, business units, or customers. If you’re the team that operates the pipeline everyone else sends to — and you’re feeling the tension between isolation and not maintaining a hundred near-identical configs — this is for you. Prerequisites: a Collector fleet and multiple distinct consumers of it.
What multi-tenancy means for a Collector fleet
“Tenant” is deliberately broad. Depending on your organization it might be:
- Teams or squads sharing one platform-run collection layer, each owning their own services and wanting their own destinations and retention.
- Business units with separate cost centers, compliance obligations, or backends, all ingesting through common infrastructure.
- External customers whose telemetry you collect and must keep strictly isolated from one another — the hardest case, where a leak between tenants is a serious incident.
The common thread is that a single collection fabric serves multiple parties who must not see each other’s data, may need different handling, and shouldn’t be able to affect each other’s service. Everything below follows from those three requirements: isolation, per-tenant handling, and fairness.
Two isolation models: dedicated vs shared pipelines
There are two ends of a spectrum, and most real deployments land somewhere between them.
Dedicated pipelines per tenant give each tenant its own receiver, processors, and exporters — often its own Collector instance or its own OTLP endpoint. Isolation is strong and simple to reason about: a misconfiguration in tenant A’s pipeline cannot touch tenant B’s data because they never share a path. The cost is multiplication — more pipelines, more configs, more infrastructure to run and keep consistent — and it scales poorly to hundreds of tenants.
A shared pipeline with attribute-based routing runs one set of receivers and splits telemetry by a tenant identifier partway through, applying per-tenant processing and destinations on separate branches. It’s far more efficient and far easier to operate at scale, but isolation now depends entirely on the routing being correct — a wrong rule sends tenant A’s data down tenant B’s branch, which for external customers is a breach.
Most teams start dedicated for a few high-stakes tenants and move to shared-with-routing as the tenant count grows and per-tenant infrastructure becomes untenable — reserving full isolation for the tenants where the blast radius of a mistake justifies it.
Identifying the tenant
Routing is only as good as your ability to say which tenant a given signal belongs to. Three common mechanisms, often combined:
- Resource attributes. The cleanest: emitters tag telemetry with a
tenant.id(orservice.namespace,deployment.environment.name) resource attribute, and the pipeline routes on it. Requires that producers set it reliably — which you can enforce at the edge if they don’t. - Per-tenant OTLP endpoints. Each tenant sends to a distinct endpoint or port, and the receiving Collector stamps a tenant attribute based on which listener caught it. Simple and hard to spoof, at the cost of managing many endpoints.
- Headers. Tenants include an identifying header (e.g. an
X-Tenant-IDor an auth token that maps to a tenant); the Collector extracts it into an attribute. Handy for HTTP/OTLP ingest, but only as trustworthy as your ability to validate it.
For external customers, prefer a mechanism the tenant cannot forge — a dedicated authenticated endpoint beats a self-asserted attribute. Whatever you pick, normalize it early into a single resource attribute so the rest of the pipeline has one consistent thing to route on.
Routing telemetry per tenant
With a tenant attribute in place, the OpenTelemetry Collector’s routing connector (and
the older routing processor) splits the stream into per-tenant pipelines. You define
a table that maps attribute values to downstream pipelines:
connectors:
routing:
default_pipelines: [logs/unrouted]
table:
- context: resource
condition: attributes["tenant.id"] == "acme"
pipelines: [logs/acme]
- context: resource
condition: attributes["tenant.id"] == "globex"
pipelines: [logs/globex]
service:
pipelines:
logs/in:
receivers: [otlp]
exporters: [routing]
logs/acme:
receivers: [routing]
processors: [redaction/acme, probabilistic_sampler/acme]
exporters: [otlphttp/acme]
logs/globex:
receivers: [routing]
processors: [transform/globex]
exporters: [loki/globex]
Each tenant’s branch is a full pipeline with its own processors and exporters. Note the
default_pipelines catch-all — telemetry that matches no tenant has to go somewhere,
and sending it to a quarantine/unrouted pipeline (rather than silently dropping or,
worse, misrouting it) is the safe default. A signal with no recognized tenant is a bug
to investigate, not data to guess about.
Tenant identity is just one attribute to route on. The same priority-ordered, first-match-wins mechanic works for any content-based split — severity, namespace, status code — which we cover in more depth, including how LinkMesh turns the condition into a field/operator/value builder instead of hand-written OTTL, in Route Telemetry by Attribute.
Per-tenant processing, destinations, and quotas
The payoff of per-tenant branches is that each tenant gets its own handling:
- Different processing. Tenant A demands aggressive PII redaction for compliance; tenant B wants raw fidelity; tenant C samples heavily to control cost. Each branch carries the redaction and sampling chain that tenant needs, not a lowest-common-denominator compromise.
- Different destinations. Tenant A ships to their own Grafana Cloud stack, tenant B to your shared Loki, tenant C to a Datadog account they own. Per-tenant exporters make “your data goes to your backend” literally true.
- Per-tenant quotas. This is where the noisy-neighbor problem gets solved. Without limits, one tenant emitting a runaway volume of logs consumes the shared Collector’s memory, CPU, and export bandwidth — degrading everyone. Per-tenant sampling and volume caps on each branch contain the blast radius so a loud tenant hits their cap, not the fleet’s ceiling.
Noisy neighbors are the defining risk of the shared model. A tenant that 10בs its volume overnight can starve the pipeline for everyone unless each branch is bounded. Design quotas in from the start; retrofitting them after an incident is painful.
Governance and RBAC: who can change whose pipeline
Multi-tenancy is as much an authority problem as a data-flow one. On shared infrastructure, the questions “who can change tenant A’s redaction rules?” and “can tenant B accidentally reroute tenant A’s data?” need real answers, not conventions. Without governance you get the worst of both worlds: a shared pipeline where any operator can alter any tenant’s handling, and no record of who changed what.
The controls that matter:
- Scoped change rights. A tenant’s owner can edit their branch; they cannot touch another tenant’s processing or destinations. The platform team governs the shared intake and routing table.
- A versioned, audited config. Every change to any branch is recorded — who, what, when — so a misroute or a redaction weakening is traceable and reversible.
- Preview before apply. A routing or processing change previewed on a sample before it ships is how you catch “this rule sends A’s data to B’s backend” before it becomes a cross-tenant leak.
This is the same governance and enforcement discipline that applies to any fleet, with the stakes raised because a mistake crosses a tenant boundary instead of just breaking your own dashboards.
How a control plane makes it manageable
Hand-maintaining routing tables and per-tenant pipelines across a fleet is exactly where multi-tenant configs sprawl and drift. LinkMesh is built to hold this shape: its visual builder composes per-route processing chains and routes telemetry by label, environment, or tenant, so each tenant’s branch — its redaction, its sampling, its destination — is a first-class thing you compose once and push over OpAMP to the fleet.

Map each tenant to its own collector group and the boundary becomes concrete: every member of the group shares one set of group-scoped sources, destinations and routes, and a scoped role gives that tenant’s owner edit rights over their group — and nothing else.

Because the config is versioned and audited, “who changed whose pipeline” always has an answer. Change rights are scoped to collectors and collector groups, so mapping each tenant to its own collector group gives that tenant’s owner edit rights over their part of the fleet and nobody else’s. And previewing a processing change on sampled records before it ships catches a bad redaction or drop rule before it reaches a tenant’s data. Pipeline telemetry never flows through LinkMesh — it stays on your infrastructure, routed straight to each tenant’s destination — so the control plane governs the split without ever becoming a place tenant data mingles. (For where multi-tenancy sits in a larger design, see OpenTelemetry architecture for enterprises.)
Where to start
- Pick your isolation model per tenant. Dedicated pipelines for the few high-stakes tenants, shared-with-routing for the many.
- Nail tenant identification. Normalize to one resource attribute early, and use an unforgeable mechanism for external tenants.
- Route with a catch-all. Split by tenant attribute and quarantine anything unrecognized rather than guessing.
- Bound every branch. Per-tenant quotas and sampling so no noisy neighbor can degrade the fleet.
- Govern the authority. Scoped change rights, a versioned audit trail, and preview before apply, so tenants can’t step on each other.
One fleet serving many tenants is efficient and, done carelessly, a leak waiting to happen. The architecture that holds is deliberate isolation, trustworthy tenant identification, bounded per-tenant branches, and governance over who can change what — so shared infrastructure stays shared without ever becoming shared data.
LinkMesh composes per-tenant routes — each with its own redaction, sampling caps, and destination — routes by label, environment, or tenant, and keeps a versioned, audited record of who changed whose pipeline, all while telemetry stays on your infra. Stand one up in minutes, or see what it does.