Prometheus exporter for Klipper to capture operational metrics. This is a very rough first implementation and subject to potentially significant changes.
Implementation is based on the Multi-Target Exporter Pattern
to enabled a single exporter to collect metrics from multiple Klipper instances.
Metrics for the exporter itself are served from the /metrics endpoint and Klipper
metrics are serviced from the /probe endpoint with a specified target.
To start the Prometheus Klipper Exporter from the command line
$ prometheus-klipper-exporter
INFO[0000] Beginning to serve on port :9101 Then add a Klipper job to the Prometheus configuration file /etc/prometheus/prometheus.yml
scrape_configs:
- job_name: "klipper"
scrape_interval: 5s
metrics_path: /probe
static_configs:
- targets: [ 'klipper-host:7125' ]
params:
modules: [
"process_stats",
"job_queue",
"system_info",
"network_stats",
"directory_info",
"printer_objects",
"history",
"mmu",
]
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: klipper-exporter:9101
# optional exporter metrics
- job_name: "klipper-exporter"
scrape_interval: 5s
metrics_path: /metrics
static_configs:
- targets: [ 'klipper-exporter:9101' ]The exporter can be run on the host running Klipper, or on a separate machine.
Replace klipper-host with the hostname or IP address of the Klipper host,
and replace klipper-exporter with the hostname or IP address of the host
runnging prometheus-klipper-exporter.
To monitor multiple Klipper instances add multiple entries to the
static_config.targets for the klipper job. e.g.
...
static_configs:
- targets: [ 'klipper-host-1:7125', 'klipper-host-2:7125 ]
...$ make buildYou will typically want to install the exporter binary on a host that will be constantly running, either the Klipper host iteself, or a separate server, and ensure that the process restarts on system restart.
Example installation on Raspberry Pi, using systemd to run the exporter.
$ ssh pi@klipper-host
[klipper]$ mkdir /home/pi/klipper-exporter
[klipper]$ exit
$ scp prometheus-klipper-exporter pi@klipper-host:/home/pi/klipper-exporter
$ scp klipper-exporter.service pi@klipper-host:/home/pi/
$ ssh pi@klipper-host
[klipper]$ sudo mv klipper-exporter.service /etc/systemd/system/
[klipper]$ sudo systemctl daemon-reload
[klipper]$ sudo systemctl enable klipper-exporter.service
[klipper]$ sudo systemctl start klipper-exporter.service
[klipper]$ sudo systemctl status klipper-exporter.service
[klipper]$ exitTo run the exporter as a docker container.
$ docker run -d -p 9101:9101 ghcr.io/scross01/prometheus-klipper-exporter:latestSee the example/README.md for a complete example running Prometheus, Grafana, and the klipper-exporter in Docker using docker compose.
You can configure different sets of metrics to be collected by including the
modules parameter in the prometheus.yml configuration file.
...
params:
modules: [ "process_stats", "job_queue", "system_info" ]
...If the modules params are omitted then only the default metrics are collected. Each group of metrics is queried from a different Moonraker API endpoint.
| module | object | default | metrics |
|---|---|---|---|
process_stats |
x | klipper_moonraker_cpu_usageklipper_moonraker_memory_kbklipper_moonraker_websocket_connectionsklipper_system_cpuklipper_system_cpu_tempklipper_system_memory_availableklipper_system_memory_totalklipper_system_memory_usedklipper_system_uptime |
|
job_queue |
x | klipper_job_queue_length |
|
system_info |
x | klipper_system_cpu_count |
|
printer_objects |
controller_fan |
klipper_controller_fan_rpm{fan="fan"}klipper_controller_fan_speed={fan="fan"} |
|
printer_objects |
display_status |
klipper_print_gcode_progress |
|
printer_objects |
extruder |
klipper_extruder_powerklipper_extruder_pressure_advanceklipper_extruder_smooth_timeklipper_extruder_targetklipper_extruder_temperature |
|
printer_objects |
fan |
klipper_fan_rpmklipper_fan_speed |
|
printer_objects |
filament_sensor |
klipper_filament_sensor_detected{probe="probe"}klipper_filament_sensor_enabled{probe="probe"} |
|
printer_objects |
gcode |
klipper_gcode_extrude_factorklipper_gcode_position_eklipper_gcode_position_xklipper_gcode_position_yklipper_gcode_position_zklipper_gcode_speed_factorklipper_gcode_speed |
|
printer_objects |
generic_fan |
klipper_generic_fan_rpm{fan="fan"}klipper_generic_fan_speed{fan="fan"} |
|
printer_objects |
heater_bed |
klipper_heater_bed_powerklipper_heater_bed_targetklipper_heater_bed_temperature |
|
printer_objects |
heater_generic |
klipper_generic_heater_powerklipper_generic_heater_targetklipper_generic_heater_temperature |
|
printer_objects |
idle_timeout |
klipper_printing_time |
|
printer_objects |
mcu |
klipper_mcu_awake{mcu="mcu"}klipper_mcu_task_avg{mcu="mcu"}klipper_mcu_task_stddev{mcu="mcu"}klipper_mcu_clock_frequency{mcu="mcu"}klipper_mcu_invalid_bytes{mcu="mcu"}klipper_mcu_read_bytes{mcu="mcu"}klipper_mcu_ready_bytes{mcu="mcu"}klipper_mcu_receive_seq{mcu="mcu"}klipper_mcu_retransmit_bytes{mcu="mcu"}klipper_mcu_retransmit_seq{mcu="mcu"}klipper_mcu_rtoklipper_mcu_rttvar{mcu="mcu"}klipper_mcu_send_seq{mcu="mcu"}klipper_mcu_stalled_bytes{mcu="mcu"}klipper_mcu_srtt{mcu="mcu"}klipper_mcu_write_bytes{mcu="mcu"} |
|
printer_objects |
output_pin |
klipper_output_pin_value{pin="pin"} |
|
printer_objects |
print_stats |
klipper_print_filament_usedklipper_print_total_duration |
|
printer_objects |
temperature_fan |
klipper_temperature_fan_speed{fan="fan"}klipper_temperature_fan_temperature{fan="fan"}klipper_temperature_fan_target{fan="fan"} |
|
printer_objects |
temperature_probe |
klipper_temperature_probe_temperature{probe="probe"}klipper_temperature_probe_measured_max_temp{probe="probe"}klipper_temperature_probe_measured_min_temp{probe="probe"}klipper_temperature_probe_estimated_expansion{probe="probe"} |
|
printer_objects |
temperature_sensor |
klipper_temperature_sensor_temperature{sensor="sensor"}klipper_temperature_sensor_measured_max_temp{sensor="sensor"}klipper_temperature_sensor_measured_min_temp{sensor="sensor"}klipper_temperature_sensor_estimated_expansion{sensor="sensor"} |
|
printer_objects |
tmc_sensor |
klipper_tmc_sensor_enabled{sensor="sensor"}klipper_tmc_sensor_run_current{sensor="sensor"}klipper_tmc_sensor_temperature{sensor="sensor"} |
|
printer_objects |
toolhead |
klipper_toolhead_estimated_print_timeklipper_toolhead_max_accel_to_decelklipper_toolhead_max_accelklipper_toolhead_max_velocityklipper_toolhead_print_timeklipper_toolhead_square_corner_velocity |
|
printer_objects |
virtual_sdcard |
klipper_print_file_positionklipper_print_file_progress |
|
directory_info |
klipper_disk_usage_availableklipper_disk_usage_totalklipper_disk_usage_used |
||
network_stats |
klipper_network_tx_bandwidth{interface="interface"}klipper_network_rx_bytes{interface="interface"}klipper_network_tx_bytes{interface="interface"}klipper_network_rx_drop{interface="interface"}klipper_network_tx_drop{interface="interface"}klipper_network_rx_errs{interface="interface"}klipper_network_tx_errs{interface="interface"}klipper_network_rx_packets{interface="interface"}klipper_network_tx_packets{interface="interface"} |
||
history |
klipper_current_print_first_layer_heightklipper_current_print_layer_heightklipper_current_print_object_heightklipper_current_print_total_durationklipper_longest_jobklipper_longest_printklipper_total_filament_usedklipper_total_jobsklipper_total_print_timeklipper_total_time |
||
mmu |
klipper_mmu_enabled - MMU enabled stateklipper_mmu_homed - MMU homed stateklipper_mmu_num_gates - Number of MMU gatesklipper_mmu_has_bypass - MMU has bypass gateklipper_mmu_current_unit - Current MMU unitklipper_mmu_current_tool - Current tool (-1=unknown, -2=bypass)klipper_mmu_current_gate - Current gateklipper_mmu_print_state_info{state="..."} - MMU print stateklipper_mmu_action_info{action="..."} - MMU current actionklipper_mmu_operation_info{operation="..."} - MMU current operationklipper_mmu_filament_loaded - Filament loaded stateklipper_mmu_filament_position_mm - Filament position in mmklipper_mmu_filament_pos_state - Filament position state machine valueklipper_mmu_filament_direction - Filament direction (1=load, -1=unload)klipper_mmu_toolchanges_total - Total toolchanges in current printklipper_mmu_last_tool - Last tool usedklipper_mmu_next_tool - Next tool during toolchangeklipper_mmu_toolchange_purge_volume_mm3 - Suggested purge volumeklipper_mmu_runout - Runout detectedklipper_mmu_clog_detection_mode - Clog detection mode (0=off, 1=manual, 2=auto)klipper_mmu_endless_spool_enabled - Endless spool mode (0=off, 1=enabled, 2=pre-gate)klipper_mmu_sync_drive_enabled - Gear stepper synced to extruderklipper_mmu_sync_feedback_state_info{state="..."} - Sync feedback stateklipper_mmu_servo_position_info{position="..."} - Servo positionklipper_mmu_bowden_progress_percent - Bowden move progressklipper_mmu_encoder_position_mm - Encoder positionklipper_mmu_encoder_detection_length_mm - Clog detection lengthklipper_mmu_encoder_headroom_mm - Current clog detection headroomklipper_mmu_encoder_min_headroom_mm - Minimum headroom recordedklipper_mmu_encoder_desired_headroom_mm - Desired headroomklipper_mmu_encoder_flow_rate_percent - Encoder flow rateklipper_mmu_encoder_enabled - Encoder enabled for clog detectionklipper_mmu_gate_status{gate="..."} - Gate status (-1=unknown, 0=empty, 1=available, 2=buffered)klipper_mmu_gate_temperature{gate="..."} - Gate filament temperatureklipper_mmu_gate_speed_override_percent{gate="..."} - Gate speed overrideklipper_mmu_gate_ttg_map{gate="..."} - Tool-to-gate mappingklipper_mmu_gate_endless_spool_group{gate="..."} - Endless spool groupklipper_mmu_gate_spool_id{gate="..."} - Spoolman spool IDklipper_mmu_gate_info{gate="...",material="...",color="...",filament_name="..."} - Gate informationklipper_mmu_tool_extrusion_multiplier{tool="..."} - Tool extrusion multiplier (M221)klipper_mmu_tool_speed_multiplier{tool="..."} - Tool speed multiplier (M220)klipper_mmu_pre_gate_sensor_detected{gate="..."} - Pre-gate sensor filament detectedklipper_mmu_pre_gate_sensor_enabled{gate="..."} - Pre-gate sensor enabledklipper_mmu_slicer_total_toolchanges - Total toolchanges expected from slicerklipper_mmu_slicer_initial_tool - Initial tool from slicerklipper_mmu_machine_info{name="...",vendor="...",version="...",selector_type="..."} - MMU machine infoklipper_mmu_num_units - Number of MMU unitsklipper_mmu_active_filament_info{name="...",material="...",color="..."} - Active filament infoklipper_mmu_active_filament_temperature - Active filament temperatureklipper_mmu_active_filament_spool_id - Active filament Spoolman spool ID |
The simplest deployment option is to run the Klipper Exporter on a host that is in
the Moonraker trusted clients configuration. This is typically configured by default
to include all hosts in the local network. If you have a more restrictive configuration
then add the host to the moonraker.conf [authorization]
configuration section.
# moonraker.conf
[authorization]
trusted_clients:
klipper-exporter
...Untrusted clients must use an API key to access Moonraker's HTTP APIs. To fetch the current API key run the following on the Klipper host:
$ cd ~/moonraker/scripts
$ ./fetch-apikey.sh
abcdef01234567890123456789012345The API key can be set in one of three ways, from the scrape job configuraion in
prometheus.yml, using the -moonraker-apikey command line argument, or
setting the MOONRAKER_APIKEY environment variable.
Set in the MOONRAKER_APIKEY environment variable.
$ export MOONRAKER_APIKEY='abcdef01234567890123456789012345'
$ prometheus-klipper-exporterSet on the klipper exporter command line using -moonraker.apikey option.
$ prometheus-klipper-exporter -moonraker.apikey='abcdef01234567890123456789012345'Add the API key to the prometheus.yml scrape config, Add authorization
configuration with the type set to APIKEY. The key can either to set directly
in the config or referenced from file.
- job_name: "klipper"
...
authorization:
type: APIKEY
credentials: 'abcdef01234567890123456789012345'
# credentials_file: /path/to/private/apikey.txt
...Only one API key can be set for each job. If you have multiple klipper hosts with different API keys, create a separate job for each host.
-help
Display the command line help.
-logging.level <level>
Set the logging output verbosity to one of Trace, Debug, Info,
Warning, Error, Fatal and Panic. Default level is Info which will
log anything that is info level or above (warning, error, fatal, panic).
Logging level can also be set using the LOGGING_LEVEL environment variable. The
command line option takes precedence over the environment setting.
-moonraker.apikey <string>
Set the API Key to authenticate with the Klipper APIs. See API Key Authentication
-web.listen-address [<ip_address>]:<port>
Address on which to expose metrics and web interface. Default is :9101
which will listen on port 9101 on all interfaces, which is the equiviment
of 0.0.0.0:9101. Include the IP address to limit to listening on a specific
interface, e.g. 192.168.1.99:7070.
v0.14.0 removes the deprecated tempurature module option which contained a
subset of the metrics reported by the printer_objects. If you where using the
tempurature module then switch the configuration to use printer_objects instead.
v0.11.0 removes the deprecated -debug and -verbose command line options.
Use the -logging.level option or LOGGING_LEVEL environment setting instead.
v0.8.0 deprecates the tempurature module option which contains a subset of
the metrics reported by the printer_objects. If you where using the
tempurature module then switch the configuration to use printer_objects instead.
The v0.7.0 release introduces several metric changes that will break any
grafana charts that have previously been defined using the old metric names from
v0.6.x or earlier.
v0.7.0 now uses labels for network interfaces, temperature sensors,
temperature fans, and output pins, rather than defining separate metrics
for each unique entity.
These changes affect the following metrics groups
klipper_network_*klipper_temperature_sensor_*klipper_temperature_fan_*klipper_output_pin_*
For example:
klipper_network_wlan0_rx_bytesbecomesklipper_network_rx_bytes{interface="wlan0"}klipper_temperature_sensor_mtu_temperaturebecomesklipper_temperature_sensor_temperature{probe="mtu"}