Refactor documentation

Fixes #46
This commit is contained in:
Christoph Petrausch
2022-01-04 10:09:54 +01:00
parent c6c8f27cc9
commit 4b660055f0
4 changed files with 191 additions and 101 deletions

136
Readme.md
View File

@@ -3,31 +3,74 @@
This exporter translates from MQTT topics to prometheus metrics. The core design is that clients send arbitrary JSON messages This exporter translates from MQTT topics to prometheus metrics. The core design is that clients send arbitrary JSON messages
on the topics. The translation is programmed into the mqtt2prometheus since we often can not change the IoT devices sending on the topics. The translation between the MQTT representation and prometheus metrics is configured in the mqtt2prometheus exporter since we often can not change the IoT devices sending
the messages. Clients can push the messages. Clients can push metrics via MQTT to an MQTT Broker. This exporter subscribes to the broker and
metrics via MQTT to an MQTT Broker. This exporter subscribes to the broker and publish the received messages as prometheus metrics. Currently, the exporter supports only MQTT 3.1.
publish the received messages as prometheus metrics. I wrote this exporter to publish
metrics from small embedded sensors based on the NodeMCU to prometheus. The used arduino scetch can be found in the [dht22tomqtt](https://github.com/hikhvar/dht22tomqtt) repository. A local hacking environment with mqtt2prometheus, a MQTT broker and a prometheus server is in the [hack](https://github.com/hikhvar/mqtt2prometheus/tree/master/hack) directory. ![Overview Diagram](docs/overview.drawio.svg)
I wrote this exporter to publish metrics from small embedded sensors based on the NodeMCU to prometheus.
The used arduino scetch can be found in the [dht22tomqtt](https://github.com/hikhvar/dht22tomqtt) repository.
A local hacking environment with mqtt2prometheus, a MQTT broker and a prometheus server is in the [hack](https://github.com/hikhvar/mqtt2prometheus/tree/master/hack) directory.
## Assumptions about Messages and Topics ## Assumptions about Messages and Topics
This exporter makes some assumptions about the MQTT topics. This exporter assumes that each This exporter makes some assumptions about the MQTT topics. This exporter assumes that each
client publish the metrics into a dedicated topic. The regular expression ìn the configuration field `mqtt.device_id_regex` client publish the metrics into a dedicated topic. The regular expression in the configuration field `mqtt.device_id_regex`
defines how to extract the device ID from the MQTT topic. This allow an arbitrary place of the device ID in the mqtt topic. defines how to extract the device ID from the MQTT topic. This allows an arbitrary place of the device ID in the mqtt topic.
For example the [tasmota](https://github.com/arendst/Tasmota) firmware pushes the telemetry data to the topics `tele/<deviceid>/SENSOR`. For example the [tasmota](https://github.com/arendst/Tasmota) firmware pushes the telemetry data to the topics `tele/<deviceid>/SENSOR`.
Let us assume the default configuration from [#ConfigFile]. A sensor publishes the following message Let us assume the default configuration from [configuration file](#config-file). A sensor publishes the following message
```json ```json
{"temperature":23.20,"humidity":51.60, "computed": {"heat_index":22.92} } {"temperature":23.20,"humidity":51.60, "computed": {"heat_index":22.92} }
``` ```
to the MQTT topic `devices/me/livingroom`. This message becomes the following prometheus metrics: to the MQTT topic `devices/home/livingroom`. This message becomes the following prometheus metrics:
```text ```text
temperature{sensor="livingroom",topic="devices/me/livingroom"} 23.2 temperature{sensor="livingroom",topic="devices/home/livingroom"} 23.2
heat_index{sensor="livingroom",topic="devices/me/livingroom"} 22.92 heat_index{sensor="livingroom",topic="devices/home/livingroom"} 22.92
humidity{sensor="livingroom",topic="devices/me/livingroom"} 51.6 humidity{sensor="livingroom",topic="devices/home/livingroom"} 51.6
``` ```
The label `sensor` is extracted with the default `device_id_regex` `(.*/)?(?P<deviceid>.*)` from the MQTT topic `devices/home/livingroom`.
The `device_id_regex` is able to extract exactly one label from the topic path. It extracts only the `deviceid` regex capture group into the `sensor` prometheus label.
To extract more labels from the topic path, have a look at [this FAQ answer](#extract-more-labels-from-the-topic-path).
The topic path can contain multiple wildcards. MQTT has two wildcards:
* `+`: Single level of hierarchy in the topic path
* `#`: Many levels of hierarchy in the topic path
This [page](https://mosquitto.org/man/mqtt-7.html) explains the wildcard in depth.
For example the `topic_path: devices/+/sensors/#` will match:
* `devices/home/sensors/foo/bar`
* `devices/workshop/sensors/temperature`
### JSON Seperator
The exporter interprets `mqtt_name` as [gojsonq](https://github.com/thedevsaddam/gojsonq) paths. Those paths will be used
to find the value in the JSON message.
For example `mqtt_name: computed.heat_index`
addresses
```json
{
"computed": {
"heat_index":22.92
}
}
```
Some sensors might use a `.` in the JSON keys. Therefore, there the configuration option `json_parsing.seperator` in
the exporter config. This allows us to use any other string to separate hierarchies in the gojsonq path.
E.g let's assume the following MQTT JSON message:
```json
{
"computed": {
"heat.index":22.92
}
}
```
We can now set `json_parsing.seperator` to `/`. This allows us to specify `mqtt_name` as `computed/heat.index`. Keep in mind,
`json_parsing.seperator` is a global setting. This affects all `mqtt_name` fields in your configuration.
### Tasmota ### Tasmota
An example configuration for the tasmota based Gosund SP111 device is given in [examples/gosund_sp111.yaml](examples/gosund_sp111.yaml). An example configuration for the tasmota based Gosund SP111 device is given in [examples/gosund_sp111.yaml](examples/gosund_sp111.yaml).
@@ -71,7 +114,7 @@ The exporter can be configured via command line and config file.
Available command line flags: Available command line flags:
```text ```text
Usage of ./mqtt2prometheus.linux_amd64: Usage of ./mqtt2prometheus:
-config string -config string
config file (default "config.yaml") config file (default "config.yaml")
-listen-address string -listen-address string
@@ -84,6 +127,8 @@ Usage of ./mqtt2prometheus.linux_amd64:
sets the default loglevel (default: "info") sets the default loglevel (default: "info")
-version -version
show the builds version, date and commit show the builds version, date and commit
-web-config-file string
[EXPERIMENTAL] Path to configuration file that can enable TLS or authentication for metric scraping.
``` ```
The logging is implemented via [zap](https://github.com/uber-go/zap). The logs are printed to `stderr` and valid log levels are The logging is implemented via [zap](https://github.com/uber-go/zap). The logs are printed to `stderr` and valid log levels are
those supported by zap. those supported by zap.
@@ -93,26 +138,25 @@ those supported by zap.
The config file can look like this: The config file can look like this:
```yaml ```yaml
# Settings for the MQTT Client. Currently only these three are supported
mqtt: mqtt:
# The MQTT broker to connect to # The MQTT broker to connect to
server: tcp://127.0.0.1:1883 server: tcp://127.0.0.1:1883
# Optional: Username and Password for authenticating with the MQTT Server # Optional: Username and Password for authenticating with the MQTT Server
# user: bob user: bob
# password: happylittleclouds password: happylittleclouds
# Optional: for TLS client certificates # Optional: for TLS client certificates
# ca_cert: certs/AmazonRootCA1.pem ca_cert: certs/AmazonRootCA1.pem
# client_cert: certs/xxxxx-certificate.pem.crt client_cert: certs/xxxxx-certificate.pem.crt
# client_key: certs/xxxxx-private.pem.key client_key: certs/xxxxx-private.pem.key
# Optional: Used to specify ClientID. The default is <hostname>-<pid> # Optional: Used to specify ClientID. The default is <hostname>-<pid>
# client_id: somedevice client_id: somedevice
# The Topic path to subscribe to. Be aware that you have to specify the wildcard. # The Topic path to subscribe to. Be aware that you have to specify the wildcard, if you want to follow topics for multiple sensors.
topic_path: v1/devices/me/+ topic_path: v1/devices/me/+
# Optional: Regular expression to extract the device ID from the topic path. The default regular expression, assumes # Optional: Regular expression to extract the device ID from the topic path. The default regular expression, assumes
# that the last "element" of the topic_path is the device id. # that the last "element" of the topic_path is the device id.
# The regular expression must contain a named capture group with the name deviceid # The regular expression must contain a named capture group with the name deviceid
# For example the expression for tasamota based sensors is "tele/(?P<deviceid>.*)/.*" # For example the expression for tasamota based sensors is "tele/(?P<deviceid>.*)/.*"
# device_id_regex: "(.*/)?(?P<deviceid>.*)" device_id_regex: "(.*/)?(?P<deviceid>.*)"
# The MQTT QoS level # The MQTT QoS level
qos: 0 qos: 0
cache: cache:
@@ -120,6 +164,11 @@ cache:
# Set the timeout to -1 to disable the deletion of metrics from the cache. The exporter presents the ingest timestamp # Set the timeout to -1 to disable the deletion of metrics from the cache. The exporter presents the ingest timestamp
# to prometheus. # to prometheus.
timeout: 24h timeout: 24h
json_parsing:
# Separator. Used to split path to elements when accessing json fields.
# You can access json fields with dots in it. F.E. {"key.name": {"nested": "value"}}
# Just set separator to -> and use key.name->nested as mqtt_name
separator: .
# This is a list of valid metrics. Only metrics listed here will be exported # This is a list of valid metrics. Only metrics listed here will be exported
metrics: metrics:
# The name of the metric in prometheus # The name of the metric in prometheus
@@ -146,8 +195,8 @@ metrics:
sensor_type: dht22 sensor_type: dht22
# The name of the metric in prometheus # The name of the metric in prometheus
- prom_name: heat_index - prom_name: heat_index
# The name of the metric in a MQTT JSON message # The path of the metric in a MQTT JSON message
mqtt_name: heat_index mqtt_name: computed.heat_index
# The prometheus help text for this metric # The prometheus help text for this metric
help: DHT22 heatIndex calculation help: DHT22 heatIndex calculation
# The prometheus type for this metric. Valid values are: "gauge" and "counter" # The prometheus type for this metric. Valid values are: "gauge" and "counter"
@@ -177,6 +226,7 @@ metrics:
# Metric value to use if a match cannot be found in the map above. # Metric value to use if a match cannot be found in the map above.
# If not specified, parsing error will occur. # If not specified, parsing error will occur.
error_value: 1 error_value: 1
``` ```
### Environment Variables ### Environment Variables
@@ -204,7 +254,43 @@ Then load that file into the environment before starting the container:
``` ```
## Best Practices ## Frequently Asked Questions
### Listen to multiple Topic Pathes
The exporter can only listen to one topic_path per instance. If you have to listen to two different topic_paths it is The exporter can only listen to one topic_path per instance. If you have to listen to two different topic_paths it is
recommended to run two instances of the mqtt2prometheus exporter. You can run both on the same host or if you run in Kubernetes, recommended to run two instances of the mqtt2prometheus exporter. You can run both on the same host or if you run in Kubernetes,
even in the same pod. even in the same pod.
### Extract more Labels from the Topic Path
A regular use case is, that user want to extract more labels from the topic path. E.g. they have sensors not only in their `home` but also
in their `workshop` and they encode the location in the topic path. E.g. a sensor pushes the message
```json
{"temperature":3.0,"humidity":34.60, "computed": {"heat_index":15.92} }
```
to the topic `devices/workshop/storage`, this will produce the prometheus metrics with the default configuration.
```text
temperature{sensor="storage",topic="devices/workshop/storage"} 3.0
heat_index{sensor="storage",topic="devices/workshop/storage"} 15.92
humidity{sensor="storage",topic="devices/workshop/storage"} 34.60
```
The following prometheus [relabel_config](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config) will extract the location from the topic path as well and attaches the `location` label.
```yaml
relabel_config:
- source_labels: [ "topic" ]
target_label: location
regex: '/devices/(.*)/.*'
action: replace
replacement: "$1"
```
With this config added to your prometheus scrape config you will get the following metrics in prometheus storage:
```text
temperature{sensor="storage", location="workshop", topic="devices/workshop/storage"} 3.0
heat_index{sensor="storage", location="workshop", topic="devices/workshop/storage"} 15.92
humidity{sensor="storage", location="workshop", topic="devices/workshop/storage"} 34.60
```

View File

@@ -1,4 +1,3 @@
# Settings for the MQTT Client. Currently only these three are supported
mqtt: mqtt:
# The MQTT broker to connect to # The MQTT broker to connect to
server: tcp://127.0.0.1:1883 server: tcp://127.0.0.1:1883

1
docs/overview Normal file
View File

@@ -0,0 +1 @@
<mxfile host="Electron" modified="2022-01-04T09:03:04.859Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/16.0.2 Chrome/96.0.4664.55 Electron/16.0.5 Safari/537.36" etag="YEpctki0tbog8IQj9Ey3" version="16.0.2" type="device"><diagram name="Page-1" id="822b0af5-4adb-64df-f703-e8dfc1f81529">3ZjLcpswFIafhqUzXIxNlrXjpNNJpmmdSdtVR8AJKAFEhYjtPn2lIsCKwJc2duNuPOiXkMT3H+lINpxpuryiKI9vSAiJYZvh0nAuDNs+dz3+K4RVJYzdcSVEFIeVZLXCHP8EKZpSLXEIhdKQEZIwnKtiQLIMAqZoiFKyUJs9kEQdNUcRaMI8QImufsEhi6VqmWZb8R5wFMuhPVdW+Ch4iigpMzleRjKoalJUdyObFjEKyWJNcmaGM6WEsOopXU4hEVRrYtV7lz21zZQpZGyXF54/LL59vrK/e/fTQV7ef51fPl4M7KqXZ5SUEsXNp7s7rkwoeQIqZ85WNSj+Ebl4DFYJzkKgjuFMFjFmMM9RICoWPD64FrM04SWLP/qCDoTXfiM0zD6WjHcDUi+qsLBc/hxiyn3GJONCQUqBciKnCpTBspeB1ZDlsQokBUZXvIl8YVgbKuPU8mR5seZ6bVi8ZvhYakgGWtR03RLnDxL6HgaMNQM05oJV3vvxckkgv25u7gulgVBDGbs6FLMDyuhQUBwNyhyygujhSKvY4gVzeyDuFD/9Jun81vh4HXiGh8IzPA08dS8voktfcUeF5/bAK94mPVulZ/9jeucaJQh5JpVFQllMIpKhZNaqE5Vj2+aakFzSewTGVvJYgEpGutiKgTZv+3xepKQBbHefIRrBJlPsblMoJIjhZ3Uerw65XiJrMXpb+gku4k7618jnpzGFGEpwJFJnwAHxLO5MRGBift55JytSHIaVOcDTrkwewp6c4Iz9/iB3YrgXmyJ7l8zTH0S9ET8wz3gGspSwH8jizvxl77fia9aakIeHgvv+0qBmEn/hmZ63T2tlWPW5+20vjY6jQekXAcU+6Dv4Sa4Oqwew7N48sz1r/Kqro574UE3U6vsHXDqW5mn6gzE7p6LrGMpjpObNR+SR/fLe0HFE7ro3HOyIbLmnvt8Md9xvrB5rjrThjLTgvJqJC7LojY+Ag/9l23G3ZWX7fKRm5beflPWb0m3/pnKs/zZeYz8a/tG1wNt/N+LF9i+qypf2H0Bn9gs=</diagram></mxfile>

4
docs/overview.drawio.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 35 KiB