---
# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
# or more contributor license agreements. Licensed under the Elastic License 2.0;
# you may not use this file except in compliance with the Elastic License 2.0.
# See ../../licenses/ELASTIC-LICENSE-2.0.txt for the full license text.
#
# Dashboard for Apache HTTP Server metrics collected via OpenTelemetry apachereceiver.
# Uses ES|QL with TS command for time-series optimization.
# Source: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/apachereceiver
#
# Apache OTel Receiver Metrics Reference:
# - apache.uptime (counter): Server uptime in seconds
# - apache.requests (counter): Total requests serviced
# - apache.traffic (counter): Total traffic in bytes
# - apache.cpu.time (counter): CPU time in jiffies
# - apache.request.time (counter): Request processing time in ms
# - apache.cpu.load (gauge): Current CPU load percentage
# - apache.load.1, apache.load.5, apache.load.15 (gauge): Load averages
# - apache.current_connections (gauge): Current connections
# - apache.connections.async (gauge): Async connections by state
# - apache.workers (gauge): Worker counts by state (busy/idle)
# - apache.scoreboard (gauge): Detailed worker status
#
# Attributes:
# - attributes.state: Used by apache.workers (busy/idle) and apache.scoreboard (various states)
# - attributes.connection_state: Used by apache.connections.async (writing/keepalive/closing)
#
# Resource Attributes:
# - resource.attributes.apache.server.name
# - resource.attributes.apache.server.port
dashboards:
- id: otel-apache-overview
name: '[OTel] Apache HTTP Server - Overview'
description: Overview of Apache HTTP Server metrics from OpenTelemetry apachereceiver
controls:
- type: options
label: Server Name
data_view: metrics-*
field: resource.attributes.apache.server.name
- type: options
label: Server Port
data_view: metrics-*
field: resource.attributes.apache.server.port
filters:
- field: data_stream.dataset
equals: apachereceiver.otel
panels:
# Overview Metrics Row
- title: Request Rate
hide_title: true
size: {w: 12, h: 4}
esql:
type: metric
query:
- TS metrics-*
- WHERE data_stream.dataset == "apachereceiver.otel"
- WHERE apache.requests IS NOT NULL
- STATS requests_rate = SUM(RATE(apache.requests))
primary:
field: requests_rate
label: Requests/sec
format:
type: number
- title: Traffic Rate
hide_title: true
size: {w: 12, h: 4}
esql:
type: metric
query:
- TS metrics-*
- WHERE data_stream.dataset == "apachereceiver.otel"
- WHERE apache.traffic IS NOT NULL
- STATS traffic_rate = SUM(RATE(apache.traffic))
primary:
field: traffic_rate
label: Traffic/sec
format:
type: bytes
- title: Active Connections
hide_title: true
size: {w: 12, h: 4}
esql:
type: metric
query:
- TS metrics-*
- WHERE data_stream.dataset == "apachereceiver.otel"
- WHERE apache.current_connections IS NOT NULL
- STATS connections = MAX(LAST_OVER_TIME(apache.current_connections))
primary:
field: connections
label: Connections
format:
type: number
pattern: 0,0
decimals: 0
- title: CPU Load
hide_title: true
size: {w: 12, h: 4}
esql:
type: metric
query:
- TS metrics-*
- WHERE data_stream.dataset == "apachereceiver.otel"
- WHERE apache.cpu.load IS NOT NULL
- STATS cpu_load = AVG(AVG_OVER_TIME(apache.cpu.load))
primary:
field: cpu_load
label: CPU Load
format:
type: percent
# Time Series Charts
- title: Request Rate Over Time
size: {w: 24, h: 10}
esql:
type: line
query:
- TS metrics-*
- WHERE data_stream.dataset == "apachereceiver.otel"
- WHERE apache.requests IS NOT NULL
- STATS requests_rate = SUM(RATE(apache.requests)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), resource.attributes.apache.server.name
- SORT time_bucket ASC
legend:
visible: show
position: right
dimension:
field: time_bucket
label: Time
data_type: date
metrics:
- field: requests_rate
label: Requests/sec
format:
type: number
breakdown:
field: resource.attributes.apache.server.name
- title: Traffic Rate Over Time
size: {w: 24, h: 10}
esql:
type: line
query:
- TS metrics-*
- WHERE data_stream.dataset == "apachereceiver.otel"
- WHERE apache.traffic IS NOT NULL
- STATS traffic_rate = SUM(RATE(apache.traffic)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), resource.attributes.apache.server.name
- SORT time_bucket ASC
legend:
visible: show
position: right
dimension:
field: time_bucket
label: Time
data_type: date
metrics:
- field: traffic_rate
label: Traffic/sec
format:
type: bytes
breakdown:
field: resource.attributes.apache.server.name
- title: CPU Time Rate
size: {w: 24, h: 10}
esql:
type: area
mode: stacked
query:
- TS metrics-*
- WHERE data_stream.dataset == "apachereceiver.otel"
- WHERE apache.cpu.time IS NOT NULL
- STATS cpu_time_rate = SUM(RATE(apache.cpu.time)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), resource.attributes.apache.server.name
- SORT time_bucket ASC
legend:
visible: show
position: right
dimension:
field: time_bucket
label: Time
data_type: date
metrics:
- field: cpu_time_rate
label: CPU Time/sec
format:
type: number
breakdown:
field: resource.attributes.apache.server.name
- title: Request Processing Time Rate
size: {w: 24, h: 10}
esql:
type: area
mode: stacked
query:
- TS metrics-*
- WHERE data_stream.dataset == "apachereceiver.otel"
- WHERE apache.request.time IS NOT NULL
- STATS request_time_rate = SUM(RATE(apache.request.time)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), resource.attributes.apache.server.name
- SORT time_bucket ASC
legend:
visible: show
position: right
dimension:
field: time_bucket
label: Time
data_type: date
metrics:
- field: request_time_rate
label: Request Time/sec
format:
type: number
suffix: ms
breakdown:
field: resource.attributes.apache.server.name
# Server Load and Connection Metrics
- title: Server Load Average
size: {w: 16, h: 10}
esql:
type: line
query:
- TS metrics-*
- WHERE data_stream.dataset == "apachereceiver.otel"
- WHERE `apache.load.1` IS NOT NULL
- STATS load_1m = AVG(AVG_OVER_TIME(`apache.load.1`)), load_5m = AVG(AVG_OVER_TIME(`apache.load.5`)), load_15m = AVG(AVG_OVER_TIME(`apache.load.15`))
BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), resource.attributes.apache.server.name
- SORT time_bucket ASC
legend:
visible: show
position: bottom
dimension:
field: time_bucket
label: Time
data_type: date
metrics:
- field: load_1m
label: 1-min Load
format:
type: percent
- field: load_5m
label: 5-min Load
format:
type: percent
- field: load_15m
label: 15-min Load
format:
type: percent
breakdown:
field: resource.attributes.apache.server.name
- title: Connection Metrics
size: {w: 16, h: 10}
esql:
type: line
query:
- TS metrics-*
- WHERE data_stream.dataset == "apachereceiver.otel"
- WHERE apache.current_connections IS NOT NULL
- STATS connections = AVG(AVG_OVER_TIME(apache.current_connections)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), resource.attributes.apache.server.name
- SORT time_bucket ASC
legend:
visible: show
position: bottom
dimension:
field: time_bucket
label: Time
data_type: date
metrics:
- field: connections
label: Current Connections
format:
type: number
pattern: 0,0
breakdown:
field: resource.attributes.apache.server.name
- title: CPU Load Over Time
size: {w: 16, h: 10}
esql:
type: line
query:
- TS metrics-*
- WHERE data_stream.dataset == "apachereceiver.otel"
- WHERE apache.cpu.load IS NOT NULL
- STATS cpu_load = AVG(AVG_OVER_TIME(apache.cpu.load)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), resource.attributes.apache.server.name
- SORT time_bucket ASC
legend:
visible: show
position: bottom
dimension:
field: time_bucket
label: Time
data_type: date
metrics:
- field: cpu_load
label: CPU Load
format:
type: percent
breakdown:
field: resource.attributes.apache.server.name
# Async Connections and Workers
- title: Async Connections by State
size: {w: 24, h: 12}
esql:
type: area
mode: stacked
query:
- TS metrics-*
- WHERE data_stream.dataset == "apachereceiver.otel"
- WHERE apache.connections.async IS NOT NULL
- STATS connections = AVG(AVG_OVER_TIME(apache.connections.async)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), attributes.connection_state
- SORT time_bucket ASC
legend:
visible: show
position: right
dimension:
field: time_bucket
label: Time
data_type: date
metrics:
- field: connections
label: Async Connections
format:
type: number
pattern: 0,0
breakdown:
field: attributes.connection_state
- title: Worker Distribution
size: {w: 24, h: 12}
esql:
type: pie
query:
- TS metrics-*
- WHERE data_stream.dataset == "apachereceiver.otel"
- WHERE apache.workers IS NOT NULL
- STATS workers = AVG(AVG_OVER_TIME(apache.workers)) BY state = attributes.state
- SORT workers DESC
- LIMIT 10
metrics:
- field: workers
label: Workers
format:
type: number
pattern: 0,0
breakdowns:
- field: state
label: Worker State
appearance:
donut: medium
# Scoreboard and Workers Over Time
- title: Scoreboard Status
size: {w: 48, h: 12}
esql:
type: bar
mode: stacked
query:
- TS metrics-*
- WHERE data_stream.dataset == "apachereceiver.otel"
- WHERE apache.scoreboard IS NOT NULL
- STATS scoreboard = AVG(AVG_OVER_TIME(apache.scoreboard)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), attributes.state
- SORT time_bucket ASC
legend:
visible: show
position: right
dimension:
field: time_bucket
label: Time
data_type: date
metrics:
- field: scoreboard
label: Scoreboard
format:
type: number
pattern: 0,0
breakdown:
field: attributes.state
- title: Workers by State Over Time
size: {w: 48, h: 12}
esql:
type: area
mode: stacked
query:
- TS metrics-*
- WHERE data_stream.dataset == "apachereceiver.otel"
- WHERE apache.workers IS NOT NULL
- STATS workers = AVG(AVG_OVER_TIME(apache.workers)) BY time_bucket = BUCKET(@timestamp, 20, ?_tstart, ?_tend), attributes.state
- SORT time_bucket ASC
legend:
visible: show
position: right
dimension:
field: time_bucket
label: Time
data_type: date
metrics:
- field: workers
label: Workers
format:
type: number
pattern: 0,0
breakdown:
field: attributes.state
# Server Performance Summary
- title: Server Performance Summary
size: {w: 48, h: 20}
description: Shows current state metrics per server. For request and traffic rates, see the time-series charts above.
esql:
type: datatable
query:
- FROM metrics-*
- WHERE data_stream.dataset == "apachereceiver.otel"
- WHERE resource.attributes.apache.server.name IS NOT NULL
- STATS connections = ROUND(MAX(apache.current_connections), 0), cpu_load_pct = ROUND(AVG(apache.cpu.load) * 100, 1), load_1m = ROUND(AVG(`apache.load.1`),
2), busy_workers = ROUND(MAX(apache.workers), 0) BY server_name = resource.attributes.apache.server.name, server_port = resource.attributes.apache.server.port
- KEEP server_name, server_port, connections, cpu_load_pct, load_1m, busy_workers
- SORT server_name ASC
- LIMIT 100
breakdowns:
- field: server_name
label: Server Name
- field: server_port
label: Port
- field: connections
label: Connections
- field: cpu_load_pct
label: CPU Load %
- field: load_1m
label: 1-min Load
- field: busy_workers
label: Busy Workers