ELK Stack — Processors
What Are Processors?
Processors are lightweight transformation plugins built into every Beat. They allow you to filter, enrich, transform, and drop events before they are sent to the output. Processors run on the Beat itself (at the edge), reducing the load on Logstash or Elasticsearch ingest pipelines.
Processors are defined in the processors section of the Beat configuration file and are executed in the order they are listed.
Why Use Processors?
| Benefit | Description |
|---|---|
| Reduce data volume | Drop noisy or irrelevant events before shipping |
| Enrich at the edge | Add host, cloud, container, or Kubernetes metadata without Logstash |
| Improve security | Remove sensitive fields (passwords, tokens) before data leaves the server |
| Simplify pipelines | Handle common transformations without needing Logstash |
| Lower costs | Less data shipped = lower storage and network costs |
Processor Ordering
Processors execute sequentially in the order they are defined. The output of one processor becomes the input of the next.
processors:
# Step 1: Add hostname and OS info
- add_host_metadata: ~
# Step 2: Add cloud provider metadata (AWS, GCP, Azure)
- add_cloud_metadata: ~
# Step 3: Remove sensitive fields
- drop_fields:
fields: ["agent.ephemeral_id", "host.mac"]
# Step 4: Drop empty or noisy events
- drop_event:
when:
regexp:
message: "^\\s*$"
add_fields
Add custom static fields to every event:
processors:
- add_fields:
target: ""
fields:
environment: production
team: platform-engineering
datacenter: us-east-1
# Nested target — adds fields under a specific key
- add_fields:
target: project
fields:
name: web-api
version: "2.5.0"
owner: backend-team
Result: each event will contain environment: production, team: platform-engineering, and a nested project.name: web-api.
drop_event
Drop events entirely based on conditions:
processors:
# Drop DEBUG-level log lines
- drop_event:
when:
regexp:
message: "^DEBUG"
# Drop events from a specific container
- drop_event:
when:
equals:
container.name: "logspam-sidecar"
# Drop health check requests from Nginx logs
- drop_event:
when:
contains:
message: "GET /healthz"
# Drop events where HTTP status is 2xx (keep only errors)
- drop_event:
when:
range:
http.response.status_code:
gte: 200
lt: 300
drop_fields
Remove specific fields from events:
processors:
- drop_fields:
fields:
- host.mac
- host.ip
- agent.ephemeral_id
- ecs.version
# ignore_missing: don't error if a field doesn't exist
ignore_missing: true
rename
Rename fields in the event:
processors:
- rename:
fields:
- from: "log.file.path"
to: "source_file"
- from: "host.hostname"
to: "server_name"
ignore_missing: true
fail_on_error: false
include_fields
Keep only the specified fields and remove everything else. Useful for reducing event size:
processors:
- include_fields:
fields:
- "@timestamp"
- message
- host.name
- log.level
- service.name
- trace.id
add_host_metadata
Enrich every event with information about the host where the Beat is running:
processors:
- add_host_metadata:
when.not.contains.tags: forwarded
# Optionally specify which network interface to report
# netinfo.enabled: true
# cache.ttl: 5m
# geo:
# name: us-east-dc
# location: "40.7128, -74.0060"
Adds fields like host.name, host.hostname, host.architecture, host.os.platform, host.os.version, host.ip, host.mac.
add_cloud_metadata
Automatically detect and add cloud provider metadata (works on AWS, GCP, Azure, and more):
processors:
- add_cloud_metadata: ~
When running on AWS EC2, this adds:
cloud.provider: awscloud.instance.id: i-0abcd1234cloud.region: us-east-1cloud.availability_zone: us-east-1acloud.machine.type: m5.xlargecloud.account.id: 123456789012
add_docker_metadata
Add Docker container metadata to events:
processors:
- add_docker_metadata:
host: "unix:///var/run/docker.sock"
# Match container by log file path (for Filebeat)
match_source: true
match_source_index: 4
# Only add specific fields
# match_fields: ["system.process.cgroup.id"]
# match_pids: ["process.pid", "process.ppid"]
Adds fields like container.id, container.name, container.image.name, container.labels.*.
add_kubernetes_metadata
Add Kubernetes pod and container metadata:
processors:
- add_kubernetes_metadata:
host: ${NODE_NAME}
# Scope: node or cluster
scope: node
matchers:
- logs_path:
logs_path: "/var/log/containers/"
default_indexers.enabled: true
default_matchers.enabled: true
Adds fields like kubernetes.pod.name, kubernetes.namespace, kubernetes.node.name, kubernetes.labels.*, kubernetes.container.name.
decode_json_fields
Parse JSON strings embedded inside a field:
processors:
- decode_json_fields:
fields: ["message"]
# Merge decoded JSON into the root of the event
target: ""
# Overwrite existing keys if they conflict
overwrite_keys: true
# Expand dots in JSON keys into nested objects
expand_keys: true
# Add error if JSON parsing fails
add_error_key: true
# Max depth for nested JSON
max_depth: 5
This is extremely useful when your application writes structured JSON logs. For example, if the message field contains:
{"level":"error","service":"payment-api","trace_id":"abc123","msg":"timeout"}
After processing, the event will have top-level fields: level, service, trace_id, msg.
dissect
Tokenize a string field using a dissect pattern (faster than regex):
processors:
- dissect:
tokenizer: '%{client_ip} %{ident} %{user} [%{timestamp}] "%{method} %{uri} %{protocol}" %{status} %{bytes}'
field: "message"
target_prefix: "apache"
Input: 192.168.1.50 - admin [01/Apr/2026:14:47:00 +0530] "GET /api/users HTTP/1.1" 200 1234
Result: apache.client_ip: 192.168.1.50, apache.method: GET, apache.uri: /api/users, apache.status: 200, etc.
Conditional Processing (when)
Most processors support a when condition to run only on matching events:
processors:
# Only add Kubernetes metadata if running in K8s
- add_kubernetes_metadata:
when:
has_fields: ["kubernetes"]
# Drop events only if log level is DEBUG
- drop_event:
when:
equals:
log.level: "debug"
# Add a field only for specific hosts
- add_fields:
when:
regexp:
host.name: "^prod-web-.*"
target: ""
fields:
tier: frontend
# Complex conditions with AND/OR/NOT
- drop_event:
when:
and:
- equals:
http.response.status_code: 200
- contains:
url.path: "/healthz"
- not:
has_fields: ["error"]
Condition Types
| Condition | Description | Example |
|---|---|---|
equals |
Exact match | equals: { log.level: "debug" } |
contains |
Substring match | contains: { message: "timeout" } |
regexp |
Regex match | regexp: { host.name: "^prod-.*" } |
range |
Numeric range | range: { http.response.status_code: { gte: 400 } } |
has_fields |
Field exists | has_fields: ["error.message"] |
or |
Logical OR | Combine multiple conditions |
and |
Logical AND | Combine multiple conditions |
not |
Logical NOT | Negate a condition |
Complete Processor Chain Example
A real-world processor chain for a production Filebeat deployment:
processors:
# 1. Parse JSON log lines
- decode_json_fields:
fields: ["message"]
target: ""
overwrite_keys: true
add_error_key: true
# 2. Add infrastructure metadata
- add_host_metadata:
when.not.contains.tags: forwarded
- add_cloud_metadata: ~
- add_docker_metadata: ~
# 3. Add custom fields
- add_fields:
target: ""
fields:
environment: production
cluster: us-east-primary
# 4. Remove sensitive fields
- drop_fields:
fields:
- "password"
- "authorization"
- "cookie"
- "agent.ephemeral_id"
ignore_missing: true
# 5. Rename fields for consistency
- rename:
fields:
- from: "level"
to: "log.level"
- from: "svc"
to: "service.name"
ignore_missing: true
# 6. Drop noisy events
- drop_event:
when:
or:
- contains:
message: "GET /healthz"
- regexp:
message: "^\\s*$"
- and:
- equals:
log.level: "debug"
- not:
regexp:
service.name: "^payment-.*"
Quick Reference
| Processor | Purpose |
|---|---|
add_fields |
Add static fields to events |
drop_event |
Discard events matching a condition |
drop_fields |
Remove specific fields from events |
include_fields |
Keep only listed fields, drop everything else |
rename |
Rename fields |
add_host_metadata |
Add hostname, OS, IP information |
add_cloud_metadata |
Add AWS/GCP/Azure cloud metadata |
add_docker_metadata |
Add Docker container info |
add_kubernetes_metadata |
Add K8s pod, namespace, labels |
decode_json_fields |
Parse JSON strings into structured fields |
dissect |
Tokenize strings using dissect patterns |
| Conditions: | equals, contains, regexp, range, has_fields, and, or, not |
Next: Elastic Agent and Fleet — the modern unified approach to data collection.