Snippets · Processors
Drop sensitive attributes before export
Some attributes should never leave the host - captured cookies and Authorization headers, a user's e-mail, a session ID - and some are simply too expensive to store. delete_key removes one key by name; delete_matching_keys removes every key matching a pattern, which is how this config catches all http.request.header.* attributes at once.
- Category
- ReductionCompliance
- Source
- OTLP
- Components
- otlpbatchmemory_limitertransformotlphttp
- Destination
- OTLP/HTTP endpoint
OpenTelemetry Collector
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
processors:
memory_limiter:
check_interval: 1s
limit_percentage: 80
spike_limit_percentage: 25
# Removes named attributes, and every captured HTTP request header, from
# log records, spans and metric data points.
transform/drop-attributes:
error_mode: ignore
log_statements:
- context: log
statements:
- delete_key(attributes, "user.email")
- delete_key(attributes, "session.id")
- delete_matching_keys(attributes, "^http\\.request\\.header\\..*")
trace_statements:
- context: span
statements:
- delete_key(attributes, "user.email")
- delete_key(attributes, "session.id")
- delete_matching_keys(attributes, "^http\\.request\\.header\\..*")
metric_statements:
- context: datapoint
statements:
- delete_key(attributes, "user.email")
- delete_key(attributes, "session.id")
batch:
timeout: 5s
exporters:
otlphttp:
endpoint: https://your-backend:4318
service:
pipelines:
logs:
receivers: [otlp]
processors: [memory_limiter, transform/drop-attributes, batch]
exporters: [otlphttp]
traces:
receivers: [otlp]
processors: [memory_limiter, transform/drop-attributes, batch]
exporters: [otlphttp]
metrics:
receivers: [otlp]
processors: [memory_limiter, transform/drop-attributes, batch]
exporters: [otlphttp]
LinkMesh
LinkMesh has no built-in template for this job. Add it as a custom processor in raw mode, with transform as the component type and this body - the same lines as under transform/drop-attributes in the collector config:
error_mode: ignore
log_statements:
- context: log
statements:
- delete_key(attributes, "user.email")
- delete_key(attributes, "session.id")
- delete_matching_keys(attributes, "^http\\.request\\.header\\..*")
trace_statements:
- context: span
statements:
- delete_key(attributes, "user.email")
- delete_key(attributes, "session.id")
- delete_matching_keys(attributes, "^http\\.request\\.header\\..*")
metric_statements:
- context: datapoint
statements:
- delete_key(attributes, "user.email")
- delete_key(attributes, "session.id")
How custom components are validated and rolled out: create a custom processor.
Download config.yamlValidated with otelcol-contrib v0.161.0 on 2026-10-26
Complete config files, each checked with the collector's own validate command (otelcol-contrib v0.161.0). Replace https://your-backend:4318 with your own OTLP endpoint before you run it.
Before and after
Example telemetry in, and what this exact config sent out when we ran it in otelcol-contrib v0.161.0. CI re-runs it on every change and fails if the output differs. Changed values are highlighted.
1 log record in, 1 log record out
Before
- body
- GET /cart 200
- attributes.http.request.method
- GET
- attributes.http.request.header.cookie
- sid=abc
- attributes.http.request.header.authorization
- Bearer x
- attributes.user.email
- anna.meier@example.ch
- attributes.session.id
- s-81723
- attributes.url.path
- /cart
- resource.service.name
- shop
- resource.user.email
- ops@example.ch
After
- body
- GET /cart 200
- attributes.http.request.method
- GET
- attributes.url.path
- /cart
- resource.service.name
- shop
- resource.user.email
- ops@example.ch
The gotcha
These statements run on the record: a log record, a span, a data point. The same key set on the resource is untouched. In our test user.email was deleted from the log record and arrived intact on the resource. To remove it there too, add a resource context with delete_key(attributes, "user.email").
Manage this across a fleet
LinkMesh manages collector configuration across a fleet from one self-hosted control plane, so a change like this is made once rather than host by host. The first 25 Collectors are free after a no-card registration in the OpenSight Customer Portal (5 without one).
Doing this in LinkMesh: Mask PII
Related snippets
- Pseudonymise user IDs with a salted hashReplace user.id with a salted SHA-256 on logs and spans - same user, same value, so per-user queries still join.
- Mask PII in logs (e-mail, card numbers, IBAN, tokens, IPs)Rewrite e-mail addresses, card numbers, IBANs, bearer tokens and IPs to placeholders on the collector, before the data leaves your network.
- Reduce metric cardinality (aggregate away per-request attributes)Strip user and request IDs from metric attributes and sum the points that collapse together, so one series per route remains.
- Deduplicate repeated log recordsCollapse a burst of identical errors into one record with a count, instead of storing it a thousand times.