Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nixos/prometheus: add mqtt-exporter #289395

Merged
merged 3 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions nixos/doc/manual/release-notes/rl-2505.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

- [agorakit](https://github.com/agorakit/agorakit), an organization tool for citizens' collectives. Available with [services.agorakit](options.html#opt-services.agorakit.enable).

- [mqtt-exporter](https://github.com/kpetremann/mqtt-exporter/), a Prometheus exporter for exposing messages from MQTT. Available as [services.prometheus.exporters.mqtt](#opt-services.prometheus.exporters.mqtt.enable).

<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->

## Backward Incompatibilities {#sec-release-25.05-incompatibilities}
Expand Down
1 change: 1 addition & 0 deletions nixos/modules/services/monitoring/prometheus/exporters.nix
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ let
"mikrotik"
"modemmanager"
"mongodb"
"mqtt"
"mysqld"
"nats"
"nextcloud"
Expand Down
140 changes: 140 additions & 0 deletions nixos/modules/services/monitoring/prometheus/exporters/mqtt.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
{
config,
lib,
pkgs,
options,
utils,
}:

let
inherit (lib)
mkIf
mkEnableOption
mkOption
types
;
cfg = config.services.prometheus.exporters.mqtt;
toConfigBoolean = x: if x then "True" else "False";
toConfigList = builtins.concatStringsSep ",";
in
{
# https://github.com/kpetremann/mqtt-exporter/tree/master?tab=readme-ov-file#configuration
port = 9000;
extraOpts = {
keepFullTopic = mkEnableOption "Keep entire topic instead of the first two elements only. Usecase: Shelly 3EM";
logLevel = mkOption {
type = types.enum [
"CRITICAL"
"ERROR"
"WARNING"
"INFO"
"DEBUG"
];
default = "INFO";
example = "DEBUG";
description = "Logging level";
};
logMqttMessage = mkEnableOption "Log MQTT original message, only if `LOG_LEVEL` is set to DEBUG.";
mqttIgnoredTopics = mkOption {
type = types.listOf types.str;
default = [ ];
description = "Lists of topics to ignore. Accepts wildcards.";
};
mqttAddress = mkOption {
type = types.str;
default = "127.0.0.1";
description = "IP or hostname of MQTT broker.";
};
mqttPort = mkOption {
type = types.port;
default = 1883;
description = "TCP port of MQTT broker.";
};
mqttTopic = mkOption {
type = types.str;
default = "#";
description = "Topic path to subscribe to.";
};
mqttKeepAlive = mkOption {
type = types.int;
default = 60;
example = 30;
description = "Keep alive interval to maintain connection with MQTT broker.";
};
mqttUsername = mkOption {
type = types.nullOr types.str;
default = null;
example = "mqttexporter";
description = "Username which should be used to authenticate against the MQTT broker.";
};
mqttV5Protocol = mkEnableOption "Force to use MQTT protocol v5 instead of 3.1.1.";
mqttClientId = mkOption {
type = types.nullOr types.str;
default = null;
description = "Set client ID manually for MQTT connection";
};
mqttExposeClientId = mkEnableOption "Expose the client ID as a label in Prometheus metrics.";
prometheusPrefix = mkOption {
type = types.str;
default = "mqtt_";
description = "Prefix added to the metric name.";
};
topicLabel = mkOption {
type = types.str;
default = "topic";
description = "Define the Prometheus label for the topic.";
};
zigbee2MqttAvailability = mkEnableOption "Normalize sensor name for device availability metric added by Zigbee2MQTT.";
zwaveTopicPrefix = mkOption {
type = types.str;
default = "zwave/";
description = "MQTT topic used for Zwavejs2Mqtt messages.";
};
esphomeTopicPrefixes = mkOption {
type = types.listOf types.str;
default = [ ];
description = "MQTT topic used for ESPHome messages.";
};
hubitatTopicPrefixes = mkOption {
type = types.listOf types.str;
default = [ "hubitat/" ];
description = "MQTT topic used for Hubitat messages.";
};
environmentFile = mkOption {
type = types.nullOr types.path;
default = null;
example = [ "/run/secrets/mqtt-exporter" ];
description = ''
File to load as environment file. Useful for e.g. setting `MQTT_PASSWORD`
without putting any secrets into the Nix store.
'';
};
};
serviceOpts = {
environment = {
KEEP_FULL_TOPIC = toConfigBoolean cfg.keepFullTopic;
LOG_LEVEL = cfg.logLevel;
LOG_MQTT_MESSAGE = toConfigBoolean cfg.logMqttMessage;
MQTT_IGNORED_TOPIC = toConfigList cfg.mqttIgnoredTopics;
MQTT_ADDRESS = cfg.mqttAddress;
MQTT_PORT = toString cfg.mqttPort;
MQTT_TOPIC = cfg.mqttTopic;
MQTT_KEEPALIVE = toString cfg.mqttKeepAlive;
MQTT_USERNAME = cfg.mqttUsername;
MQTT_V5_PROTOCOL = toConfigBoolean cfg.mqttV5Protocol;
MQTT_CLIENT_ID = mkIf (cfg.mqttClientId != null) cfg.mqttClientId;
PROMETHEUS_ADDRESS = cfg.listenAddress;
PROMETHEUS_PORT = toString cfg.port;
PROMETHEUS_PREFIX = cfg.prometheusPrefix;
TOPIC_LABEL = cfg.topicLabel;
ZIGBEE2MQTT_AVAILABILITY = toConfigBoolean cfg.zigbee2MqttAvailability;
ZWAVE_TOPIC_PREFIX = cfg.zwaveTopicPrefix;
ESPHOME_TOPIC_PREFIXES = toConfigList cfg.esphomeTopicPrefixes;
HUBITAT_TOPIC_PREFIXES = toConfigList cfg.hubitatTopicPrefixes;
};
serviceConfig = {
EnvironmentFile = mkIf (cfg.environmentFile != null) cfg.environmentFile;
ExecStart = lib.getExe pkgs.mqtt-exporter;
};
};
}
32 changes: 32 additions & 0 deletions nixos/tests/prometheus-exporters.nix
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,38 @@ let
'';
};

mqtt = {
exporterConfig = {
enable = true;
environmentFile = pkgs.writeText "mqtt-exporter-envfile" ''
MQTT_PASSWORD=testpassword
'';
};
metricProvider = {
services.mosquitto = {
enable = true;
listeners = [{
users.exporter = {
acl = [ "read #" ];
passwordFile = pkgs.writeText "mosquitto-password" "testpassword";
};
}];
};
systemd.services.prometheus-mqtt-exporter ={
wants = [ "mosquitto.service" ];
after = [ "mosquitto.service" ];
};
};
exporterTest = ''
wait_for_unit("mosquitto.service")
wait_for_unit("prometheus-mqtt-exporter.service")
wait_for_open_port(9000)
succeed(
"curl -sSf http://localhost:9000/metrics | grep '^python_info'"
)
'';
};

mysqld = {
exporterConfig = {
enable = true;
Expand Down
Loading