Snippets · Processors
Enforce required resource attributes (semantic conventions)
Telemetry nobody can attribute is noise you pay to store: dashboards group by service and environment, and a record without them lands in no team's view. This filter processor drops any log record, span or metric whose resource lacks one of the three attributes, so the gap shows up as missing data at the source instead of as unowned data in the backend.
- Category
- Compliance
- Source
- OTLP
- Components
- otlpbatchfiltermemory_limiterotlphttp
- 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
# Drops any record whose resource lacks one of the three attributes every
# dashboard and alert here groups by. A record is dropped when ANY condition
# is true.
filter/enforce-semconv:
error_mode: ignore
logs:
log_record:
- resource.attributes["service.name"] == nil
- resource.attributes["service.namespace"] == nil
- resource.attributes["deployment.environment.name"] == nil
traces:
span:
- resource.attributes["service.name"] == nil
- resource.attributes["service.namespace"] == nil
- resource.attributes["deployment.environment.name"] == nil
metrics:
metric:
- resource.attributes["service.name"] == nil
- resource.attributes["service.namespace"] == nil
- resource.attributes["deployment.environment.name"] == nil
batch:
timeout: 5s
exporters:
otlphttp:
endpoint: https://your-backend:4318
service:
pipelines:
logs:
receivers: [otlp]
processors: [memory_limiter, filter/enforce-semconv, batch]
exporters: [otlphttp]
traces:
receivers: [otlp]
processors: [memory_limiter, filter/enforce-semconv, batch]
exporters: [otlphttp]
metrics:
receivers: [otlp]
processors: [memory_limiter, filter/enforce-semconv, batch]
exporters: [otlphttp]
LinkMesh
LinkMesh has no built-in template for this job. Add it as a custom processor in raw mode, with filter as the component type and this body - the same lines as under filter/enforce-semconv in the collector config:
error_mode: ignore
logs:
log_record:
- resource.attributes["service.name"] == nil
- resource.attributes["service.namespace"] == nil
- resource.attributes["deployment.environment.name"] == nil
traces:
span:
- resource.attributes["service.name"] == nil
- resource.attributes["service.namespace"] == nil
- resource.attributes["deployment.environment.name"] == nil
metrics:
metric:
- resource.attributes["service.name"] == nil
- resource.attributes["service.namespace"] == nil
- resource.attributes["deployment.environment.name"] == nil
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.
4 log records in, 1 log record out
Before
- body
- complete
- resource.service.name
- shop
- resource.service.namespace
- web
- resource.deployment.environment.name
- prod
After
- body
- complete
- resource.service.name
- shop
- resource.service.namespace
- web
- resource.deployment.environment.name
- prod
Before
- body
- no namespace
- resource.service.name
- shop
- resource.deployment.environment.name
- prod
After
Dropped
Before
- body
- old environment key
- resource.service.name
- shop
- resource.service.namespace
- web
- resource.deployment.environment
- prod
After
Dropped
Before
- body
- nothing set
After
Dropped
The gotcha
The OpenTelemetry semantic conventions renamed deployment.environment to deployment.environment.name, and anything still sending the old key gets dropped by this filter: in our test a record carrying deployment.environment, but not the new key, was dropped along with the incomplete ones - 4 records in, 1 out - and the collector log said nothing about any of the three drops.
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: Filter records on a route
Related snippets
- Drop sensitive attributes before exportDelete named attributes, and every captured HTTP request header, from logs, spans and metrics before they are exported.
- 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.
- Redact everything except an attribute allowlistTurn masking around - name the attributes you keep, and the redaction processor removes everything else.