The PDU Exporter is a lightweight custom Prometheus exporter designed to collect metrics from Power Distribution Unit (PDU) devices that expose raw status data via the /status.cgi endpoint over HTTP, transforming this data into Prometheus-compatible metrics.
- Supports basic authentication
- Exposes metrics such as current, voltage, power, energy, temperature, humidity, and sensor existence
- Dockerized for easy deployment
| Metric Name | Description | Labels |
|---|---|---|
current |
Current in Amperes | address |
voltage |
Voltage in Volts | address |
power |
Power in Watts | address |
power_factor |
Power factor (0.0 to 1.0) | address |
energy |
Energy in kilowatt-hours | address |
temperature |
Temperature in Celsius | address, channel |
humidity |
Humidity in percent | address, channel |
sensor_exists |
Sensor existence (1.0 or 0.0) | type |
Method: POST, PUT
Description: Reloads the configuration without restarting the process.
POST /-/reload
PUT /-/reload
You can also reload configuration by sending the SIGHUP signal to the pdu_exporter process ID using the command below:
kill -s SIGHUP $(pidof pdu_exporter)Method: GET
Query Parameters:
target: IP address or hostname of the PDU.
GET /pdu?target=192.168.1.1
Method: GET
Description: Returns a list of rack names extracted from each PDU address block.
Query Parameters:
target: IP address or hostname of the PDU.
GET /api/rack-names?target=192.168.1.1
{
"rack_names": {
"rack_1": "# 1 Rack A",
"rack_2": "# 2 Rack B",
...
"rack_32": "# 32 Rack AF"
}
}
scrape_configs:
- job_name: 'pdu'
metrics_path: /pdu
static_configs:
- targets:
- 192.168.1.1
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 127.0.0.1:9117 # Address of the PDU Exporter container or host
basic_auth: # Sets the `Authorization` header on every request
username: user # Configured username
password: pass # Configured password# How long until a scrape request times out.
scrape_configs:
# Interval (in seconds) for sending TCP keepalive packets to the PDU.
tcp_keepalive_seconds: 10
# Maximum duration (in seconds) allowed for a single scrape request.
scrape_timeout_seconds: 5
# Maximum time (in seconds) to wait when establishing a TCP connection to the PDU.
connect_timeout_seconds: 2
# How long (in seconds) an idle connection is kept in the pool before being closed.
pool_idle_timeout_seconds: 30
# Maximum number of idle connections to keep per host in the connection pool.
pool_max_idle_per_host: 2
# Usernames and hashed passwords that have full access to the web server via basic authentication.
# If empty, no basic authentication is required. Passwords are hashed with bcrypt.
basic_auth_users:
user: $2a$12$eId/v3HxJFjZWCkeTV/.VeUg5Qie66aPumgGlzELcy2ndCxpo5fV6
rlggyp: $2a$12$fKG1d9B5d7JDa78s7XBHDu/YD.46VK.t3W8BnujOwErrNCvRB9vsSrefresh_rate: 30 seconds
appenders:
rolling_file:
kind: rolling_file
path: "/etc/pdu_exporter/logs/app.log"
policy:
kind: compound
trigger:
kind: size
limit: 1 mb
roller:
kind: fixed_window
pattern: "/etc/pdu_exporter/logs/app-{}.log"
base: 1
count: 7
encoder:
pattern: "{d(%Y-%m-%d %H:%M:%S)} [{l}] {t} - {m}{n}"
root:
level: info
appenders:
- rolling_fileBelow is a sample docker-compose.yaml:
services:
pdu_exporter:
image: rlggyp/pdu_exporter:latest
container_name: pdu_exporter
user: 1000:1000
pull_policy: always
environment:
- CONFIG_FILE=/etc/pdu_exporter/configs/pdu_exporter.yaml
- LOG_CONFIG_FILE=/etc/pdu_exporter/configs/log4rs.yaml
ports:
- 9117:9117
volumes:
- ./configs:/etc/pdu_exporter/configs
- ./logs:/etc/pdu_exporter/logs
restart: unless-stoppedDirectory structure example:
.
├── configs
│ ├── pdu_exporter.yaml
│ └── log4rs.yaml
├── logs
└── docker-compose.yaml
- Place your
pdu_exporter.yamlandlog4rs.yamlin theconfigsdirectory. - Logs will be written to the
logsdirectory.
You have two options to run the PDU Exporter:
-
Build the image:
docker build -t pdu_exporter:latest . -
Edit your
docker-compose.yamland change theimageline to use your local image:image: pdu_exporter:latest
-
Start the service:
docker compose up -d
No need to build anything. Just use the provided docker-compose.yaml (with image: rlggyp/pdu_exporter:latest) and run:
docker compose up -d- 400 Bad Request:
targetparameter is missing. - 401 Unauthorized: Authentication fails.
- 502 Bad Gateway: Device returned an error (non-200 response).
- 503 Service Unavailable: PDU is unreachable (network error).
- 500 Internal Server Error: I/O or parsing errors.
- Assumes the PDU
/status.cgiresponse contains exactly 2016 elements. - Metrics parsing is tightly coupled with this structure.
- Only supports plain HTTP (no TLS, no SNMP).
This project is licensed under the MIT License. See the LICENSE file for details.