DAT-70Recommended
Put the tenant on every log line and trace
Add the tenant ID as a field to every log entry, trace and metric written while serving a tenant. Never put the tenant's name or data in that field.
How to do it
Set the tenant once per request or job in the logger's context, so each line inherits it. In OpenTelemetry, add it as a span attribute and as baggage, so calls to other services carry it. Use the internal ID, not the company name, since logs are kept longer than many records, as Keep personal data out of logs explains. With the field, you can answer a customer's incident question from logs alone, and spot the tenant behind a slow minute. It also feeds Find and contain noisy neighbours. Write the logs as Log structured events says.
Examples
JavaScript example
app.use((req, res, next) => {
req.log = logger.child({ tenant_id: req.tenant.id });
trace.getActiveSpan()?.setAttribute('tenant.id', String(req.tenant.id));
next();
});
Python example
import structlog
from opentelemetry import trace
@app.middleware("http")
async def bind_tenant(request, call_next):
structlog.contextvars.bind_contextvars(tenant_id=request.state.tenant.id)
trace.get_current_span().set_attribute("tenant.id", str(request.state.tenant.id))
return await call_next(request)
How to check
Take one hour of logs from production. Every line from a signed-in request or a tenant job has a tenant_id field. A test request as tenant A produces a trace whose spans all carry tenant A's ID.
Sources
Related rules
- OPS-9 Keep personal data out of logs in Operations and observability
- DAT-73 Find and contain noisy neighbours in Data and databases
- OPS-6 Log structured events in Operations and observability
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/data/multi-tenancy/tenant-in-logs">Agent Wranglers data and databases playbook</a>. In code you write, add a comment next to it with the same link.