ELK Stack — Beats Exercises
Practice Exercises
These exercises reinforce the Beats concepts covered in this chapter. Each exercise increases in difficulty from basic setup to advanced processor configurations.
Exercise 1: Basic Filebeat Setup to Ship Application Logs
Scenario: You have a Java application that writes logs to /var/log/webapp/application.log. The logs follow a standard pattern with timestamps. You need to ship these logs to your Elasticsearch cluster at https://es-node-1:9200.
Requirements:
- Configure Filebeat to monitor
/var/log/webapp/application.log - Add custom fields:
app: webapp,environment: staging - Place custom fields at the root level of the event
- Tag events with
webappandstaging - Exclude lines starting with
TRACE - Configure output to Elasticsearch with basic authentication
- Enable JSON logging to
/var/log/filebeat/
Show Solution
# /etc/filebeat/filebeat.yml
filebeat.inputs:
- type: log
id: webapp-logs
enabled: true
paths:
- /var/log/webapp/application.log
fields:
app: webapp
environment: staging
fields_under_root: true
tags: ["webapp", "staging"]
exclude_lines: ['^TRACE']
output.elasticsearch:
hosts: ["https://es-node-1:9200"]
username: "filebeat_writer"
password: "changeme"
ssl:
enabled: true
certificate_authorities: ["/etc/filebeat/certs/ca.crt"]
logging.level: info
logging.to_files: true
logging.files:
path: /var/log/filebeat
name: filebeat
keepfiles: 7
permissions: 0644
Test and start:
# Test configuration
sudo filebeat test config -e
# Test output connectivity
sudo filebeat test output
# Start Filebeat
sudo systemctl start filebeat
sudo systemctl enable filebeat
# Verify data is flowing
curl -s -u elastic:changeme \
"https://es-node-1:9200/filebeat-*/_search?size=1" | python3 -m json.tool
Exercise 2: Enabling and Configuring Filebeat Modules
Scenario: You manage a web server stack running Nginx and MySQL. You want Filebeat to collect logs from both services and set up the pre-built Kibana dashboards.
Requirements:
- Enable the
system,nginx, andmysqlmodules - Configure the Nginx module to read access logs from
/opt/nginx/logs/access.logand error logs from/opt/nginx/logs/error.log - Configure the MySQL module to read error logs from
/var/log/mysql/error.logand slow query logs from/var/log/mysql/slow-query.log - Keep system module defaults
- Load dashboards into Kibana
- Verify data is indexed
Show Solution
Step 1: Enable the modules.
sudo filebeat modules enable system nginx mysql
Step 2: Configure the Nginx module.
# /etc/filebeat/modules.d/nginx.yml
- module: nginx
access:
enabled: true
var.paths: ["/opt/nginx/logs/access.log*"]
error:
enabled: true
var.paths: ["/opt/nginx/logs/error.log*"]
ingress_controller:
enabled: false
Step 3: Configure the MySQL module.
# /etc/filebeat/modules.d/mysql.yml
- module: mysql
error:
enabled: true
var.paths: ["/var/log/mysql/error.log*"]
slowlog:
enabled: true
var.paths: ["/var/log/mysql/slow-query.log*"]
Step 4: Keep system module at defaults.
# /etc/filebeat/modules.d/system.yml
- module: system
syslog:
enabled: true
auth:
enabled: true
Step 5: Load dashboards, index templates, and ingest pipelines.
# Full setup — loads dashboards, index templates, ILM policies, and ingest pipelines
sudo filebeat setup
# Or load only dashboards
sudo filebeat setup --dashboards
Step 6: Restart Filebeat and verify.
sudo systemctl restart filebeat
# Check Nginx index
curl -s -u elastic:changeme \
"https://es-node-1:9200/filebeat-*/_search" \
-H "Content-Type: application/json" \
-d '{
"size": 1,
"query": {
"match": {
"event.module": "nginx"
}
}
}' | python3 -m json.tool
# Check MySQL index
curl -s -u elastic:changeme \
"https://es-node-1:9200/filebeat-*/_search" \
-H "Content-Type: application/json" \
-d '{
"size": 1,
"query": {
"match": {
"event.module": "mysql"
}
}
}' | python3 -m json.tool
Open Kibana → Dashboard → search for [Filebeat Nginx] to see the pre-built visualizations.
Exercise 3: Metricbeat System Monitoring
Scenario: You need to monitor system health on a production database server. Collect CPU, memory, disk, network, filesystem, and process metrics. Track the top 5 processes by CPU and memory. Send metrics to Elasticsearch every 15 seconds.
Requirements:
- Configure Metricbeat with the system module
- Collect: cpu, memory, load, network, diskio, filesystem, process, process_summary
- Set collection period to 15 seconds
- Track top 5 processes by CPU and top 5 by memory
- Add host metadata and cloud metadata processors
- Add a custom field
role: database-server - Output to Elasticsearch with TLS
Show Solution
# /etc/metricbeat/metricbeat.yml
metricbeat.modules:
- module: system
metricsets:
- cpu
- memory
- load
- network
- diskio
- filesystem
- process
- process_summary
enabled: true
period: 15s
processes: ['.*']
process.include_top_n:
by_cpu: 5
by_memory: 5
cpu.metrics: ["percentages", "normalized_percentages"]
core.metrics: ["percentages"]
processors:
- add_host_metadata:
when.not.contains.tags: forwarded
- add_cloud_metadata: ~
- add_fields:
target: ""
fields:
role: database-server
output.elasticsearch:
hosts: ["https://es-node-1:9200"]
username: "metricbeat_writer"
password: "changeme"
ssl:
enabled: true
certificate_authorities: ["/etc/metricbeat/certs/ca.crt"]
certificate: "/etc/metricbeat/certs/metricbeat.crt"
key: "/etc/metricbeat/certs/metricbeat.key"
setup.kibana:
host: "https://kibana-host:5601"
ssl:
enabled: true
certificate_authorities: ["/etc/metricbeat/certs/ca.crt"]
setup.dashboards.enabled: true
logging.level: info
logging.to_files: true
logging.files:
path: /var/log/metricbeat
name: metricbeat
keepfiles: 7
Test and start:
# Test configuration
sudo metricbeat test config -e
# Test output
sudo metricbeat test output
# Load dashboards
sudo metricbeat setup --dashboards
# Start Metricbeat
sudo systemctl start metricbeat
sudo systemctl enable metricbeat
# Verify metrics are flowing (check CPU metricset)
curl -s -u elastic:changeme \
"https://es-node-1:9200/metricbeat-*/_search" \
-H "Content-Type: application/json" \
-d '{
"size": 1,
"query": {
"match": {
"metricset.name": "cpu"
}
},
"sort": [{"@timestamp": "desc"}]
}' | python3 -m json.tool
Open Kibana → Dashboard → [Metricbeat System] Host overview to see CPU, memory, and disk graphs.
Exercise 4: Adding Processors to Filebeat
Scenario: Your application writes JSON-formatted logs. You need to parse the JSON, add infrastructure metadata, remove sensitive fields, drop health check noise, and add custom tags for routing.
Sample log line:
{"timestamp":"2026-04-01T14:49:00Z","level":"info","service":"order-api","user_id":"u-12345","auth_token":"Bearer eyJhbGci...","message":"Order created","trace_id":"t-abc-123"}
Requirements:
- Parse the JSON
messagefield into top-level event fields - Add host metadata and Docker metadata
- Drop the
auth_tokenfield (sensitive data) - Drop events where
messagecontainsGET /healthz - Rename
leveltolog.levelandservicetoservice.name - Add custom fields:
environment: production,team: commerce - Drop events with empty messages
Show Solution
# /etc/filebeat/filebeat.yml
filebeat.inputs:
- type: log
id: order-api-logs
enabled: true
paths:
- /var/log/order-api/*.log
tags: ["order-api", "json"]
processors:
# 1. Parse JSON log lines into structured fields
- decode_json_fields:
fields: ["message"]
target: ""
overwrite_keys: true
expand_keys: true
add_error_key: true
# 2. Add infrastructure metadata
- add_host_metadata:
when.not.contains.tags: forwarded
- add_docker_metadata:
host: "unix:///var/run/docker.sock"
match_source: true
# 3. Drop sensitive fields
- drop_fields:
fields:
- "auth_token"
- "agent.ephemeral_id"
ignore_missing: true
# 4. Drop health check noise
- drop_event:
when:
contains:
message: "GET /healthz"
# 5. Drop events with empty messages
- drop_event:
when:
regexp:
message: "^\\s*$"
# 6. Rename fields for ECS compliance
- rename:
fields:
- from: "level"
to: "log.level"
- from: "service"
to: "service.name"
ignore_missing: true
fail_on_error: false
# 7. Add custom fields for routing
- add_fields:
target: ""
fields:
environment: production
team: commerce
output.elasticsearch:
hosts: ["https://es-node-1:9200"]
username: "filebeat_writer"
password: "changeme"
ssl:
enabled: true
certificate_authorities: ["/etc/filebeat/certs/ca.crt"]
logging.level: info
logging.to_files: true
logging.files:
path: /var/log/filebeat
name: filebeat
keepfiles: 7
Test and verify:
# Test config
sudo filebeat test config -e
# Start in debug mode to see processor output
sudo filebeat -e -d "processors"
# After starting, check that auth_token is NOT in indexed events
curl -s -u elastic:changeme \
"https://es-node-1:9200/filebeat-*/_search" \
-H "Content-Type: application/json" \
-d '{
"size": 1,
"query": {
"exists": {
"field": "auth_token"
}
}
}' | python3 -m json.tool
Expected: zero hits (auth_token was stripped by drop_fields).
The indexed event should look like:
{
"@timestamp": "2026-04-01T14:49:00.000Z",
"log.level": "info",
"service.name": "order-api",
"user_id": "u-12345",
"message": "Order created",
"trace_id": "t-abc-123",
"environment": "production",
"team": "commerce",
"host": {
"name": "web-01",
"hostname": "web-01",
"architecture": "x86_64",
"os": { "platform": "ubuntu", "version": "22.04" }
},
"tags": ["order-api", "json"]
}
Exercise 5: Heartbeat Uptime Monitoring
Scenario: You need to set up uptime monitoring for your production infrastructure. Monitor a web application (HTTPS), a REST API health endpoint, a PostgreSQL database (TCP), a Redis cache (TCP), and three internal servers (ICMP ping).
Requirements:
- HTTP monitor: check
https://app.example.comevery 30 seconds — verify status 200 and body contains “ok” - HTTP monitor: check
https://api.example.com/healthevery 60 seconds — verify JSON response contains"status": "healthy" - TCP monitor: check PostgreSQL on
db-primary:5432anddb-replica:5432every 30 seconds - TCP monitor: check Redis on
redis-01:6379andredis-02:6379every 15 seconds - ICMP monitor: ping
10.0.1.10,10.0.1.11,10.0.1.12every 60 seconds - Add appropriate tags to each monitor
- Load Heartbeat dashboards into Kibana
Show Solution
# /etc/heartbeat/heartbeat.yml
heartbeat.monitors:
# 1. Web application — HTTPS with body check
- type: http
id: web-app
name: "Production Web App"
enabled: true
urls:
- "https://app.example.com"
schedule: '@every 30s'
timeout: 10s
check.response:
status: [200]
body:
- "ok"
ssl:
verification_mode: full
tags: ["web", "production", "critical"]
# 2. API health endpoint — HTTPS with JSON check
- type: http
id: api-health
name: "REST API Health"
enabled: true
urls:
- "https://api.example.com/health"
schedule: '@every 60s'
timeout: 10s
check.response:
status: [200]
json:
- description: "API reports healthy"
condition:
contains:
status: "healthy"
ssl:
verification_mode: full
tags: ["api", "production", "critical"]
# 3. PostgreSQL — TCP port check
- type: tcp
id: postgres-check
name: "PostgreSQL"
enabled: true
hosts:
- "db-primary:5432"
- "db-replica:5432"
schedule: '@every 30s'
timeout: 5s
tags: ["database", "postgresql", "production"]
# 4. Redis — TCP port check
- type: tcp
id: redis-check
name: "Redis Cache"
enabled: true
hosts:
- "redis-01:6379"
- "redis-02:6379"
schedule: '@every 15s'
timeout: 3s
tags: ["cache", "redis", "production"]
# 5. Server ping — ICMP check
- type: icmp
id: server-ping
name: "Internal Servers"
enabled: true
hosts:
- "10.0.1.10"
- "10.0.1.11"
- "10.0.1.12"
schedule: '@every 60s'
timeout: 5s
wait: 1s
tags: ["infrastructure", "ping"]
# Processors
processors:
- add_host_metadata: ~
- add_cloud_metadata: ~
# Output
output.elasticsearch:
hosts: ["https://es-node-1:9200"]
username: "heartbeat_writer"
password: "changeme"
ssl:
enabled: true
certificate_authorities: ["/etc/heartbeat/certs/ca.crt"]
# Kibana
setup.kibana:
host: "https://kibana-host:5601"
ssl:
enabled: true
certificate_authorities: ["/etc/heartbeat/certs/ca.crt"]
setup.dashboards.enabled: true
# Logging
logging.level: info
logging.to_files: true
logging.files:
path: /var/log/heartbeat
name: heartbeat
keepfiles: 7
Test, load dashboards, and start:
# Test config
sudo heartbeat test config -e
# Test output
sudo heartbeat test output
# Load dashboards
sudo heartbeat setup --dashboards
# Start Heartbeat
sudo systemctl start heartbeat-elastic
sudo systemctl enable heartbeat-elastic
# Verify uptime data is flowing
curl -s -u elastic:changeme \
"https://es-node-1:9200/heartbeat-*/_search" \
-H "Content-Type: application/json" \
-d '{
"size": 5,
"sort": [{"@timestamp": "desc"}],
"_source": ["monitor.name", "monitor.status", "url.full", "monitor.type"]
}' | python3 -m json.tool
Expected output:
{
"hits": {
"hits": [
{
"_source": {
"monitor.name": "Production Web App",
"monitor.status": "up",
"url.full": "https://app.example.com",
"monitor.type": "http"
}
},
{
"_source": {
"monitor.name": "PostgreSQL",
"monitor.status": "up",
"url.full": "tcp://db-primary:5432",
"monitor.type": "tcp"
}
}
]
}
}
Open Kibana → Observability → Uptime to see all monitors, their status, response times, and availability percentages.
Summary
| Exercise | Skill Practiced |
|---|---|
| 1 | Basic Filebeat input, output, and logging configuration |
| 2 | Filebeat modules — enabling, configuring, and loading dashboards |
| 3 | Metricbeat system module — metrics collection and process monitoring |
| 4 | Processors — JSON parsing, field manipulation, conditional filtering |
| 5 | Heartbeat — HTTP, TCP, and ICMP uptime monitoring |
Return to Beats Hub to review chapter topics.