From 56ed94db42d37fe7b7381c9f1f35a83166f1a01c Mon Sep 17 00:00:00 2001 From: Michael Hanselmann Date: Sun, 11 Jul 2021 19:51:46 +0200 Subject: [PATCH 1/3] prometheus: Fix typos in comments Signed-off-by: Michael Hanselmann --- tasmota/xsns_75_prometheus.ino | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tasmota/xsns_75_prometheus.ino b/tasmota/xsns_75_prometheus.ino index 196cbbae91b0..2727119e413b 100644 --- a/tasmota/xsns_75_prometheus.ino +++ b/tasmota/xsns_75_prometheus.ino @@ -24,7 +24,8 @@ #define XSNS_75 75 -const char *UnitfromType(const char *type) // find unit for measurment type +// Find appropriate unit for measurement type. +const char *UnitfromType(const char *type) { if (strcmp(type, "time") == 0) { return "seconds"; @@ -56,7 +57,9 @@ const char *UnitfromType(const char *type) // find unit for measurment type return ""; } -String FormatMetricName(const char *metric) { // cleanup spaces and uppercases for Prmetheus metrics conventions +// Replace spaces and periods in metric name to match Prometheus metrics +// convention. +String FormatMetricName(const char *metric) { String formatted = metric; formatted.toLowerCase(); formatted.replace(" ", "_"); @@ -135,7 +138,7 @@ void HandleMetrics(void) { String jsonStr = TasmotaGlobal.mqtt_data; JsonParser parser((char *)jsonStr.c_str()); JsonParserObject root = parser.getRootObject(); - if (root) { // did JSON parsing went ok? + if (root) { // did JSON parsing succeed? for (auto key1 : root) { JsonParserToken value1 = key1.getValue(); if (value1.isObject()) { @@ -160,7 +163,7 @@ void HandleMetrics(void) { String sensor = FormatMetricName(key1.getStr()); String type = FormatMetricName(key2.getStr()); const char *unit = UnitfromType(type.c_str()); - if (strcmp(type.c_str(), "totalstarttime") != 0) { // this metric causes prometheus of fail + if (strcmp(type.c_str(), "totalstarttime") != 0) { // this metric causes Prometheus of fail if (strcmp(type.c_str(), "id") == 0) { // this metric is NaN, so convert it to a label, see Wi-Fi metrics above WSContentSend_P(PSTR("# TYPE tasmota_sensors_%s_%s gauge\ntasmota_sensors_%s_%s{sensor=\"%s\",id=\"%s\"} 1\n"), type.c_str(), unit, type.c_str(), unit, sensor.c_str(), value); From 9e441630f110d160737d75357621d5e1d6ad13c0 Mon Sep 17 00:00:00 2001 From: Michael Hanselmann Date: Sun, 11 Jul 2021 19:52:23 +0200 Subject: [PATCH 2/3] prometheus: Add comment with link to exposition format Signed-off-by: Michael Hanselmann --- tasmota/xsns_75_prometheus.ino | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tasmota/xsns_75_prometheus.ino b/tasmota/xsns_75_prometheus.ino index 2727119e413b..574bd75a8754 100644 --- a/tasmota/xsns_75_prometheus.ino +++ b/tasmota/xsns_75_prometheus.ino @@ -20,6 +20,13 @@ #ifdef USE_PROMETHEUS /*********************************************************************************************\ * Prometheus support + * + * The text format for metrics, labels and values is documented at [1]. Only + * the UTF-8 text encoding is supported. + * + * [1] + * https://github.com/prometheus/docs/blob/master/content/docs/instrumenting/exposition_formats.md + * \*********************************************************************************************/ #define XSNS_75 75 From 16b5f2fe92a1da8040670257a91c0fe0f9ea93c5 Mon Sep 17 00:00:00 2001 From: Michael Hanselmann Date: Sun, 11 Jul 2021 20:15:01 +0200 Subject: [PATCH 3/3] prometheus: Expose device name as part of device info The device name can be useful to identify a particular instance in Prometheus. Example: ``` tasmota_info{...,devicename="livingroom"} 1 ``` Signed-off-by: Michael Hanselmann --- tasmota/xsns_75_prometheus.ino | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tasmota/xsns_75_prometheus.ino b/tasmota/xsns_75_prometheus.ino index 574bd75a8754..d997016b5ae1 100644 --- a/tasmota/xsns_75_prometheus.ino +++ b/tasmota/xsns_75_prometheus.ino @@ -74,6 +74,16 @@ String FormatMetricName(const char *metric) { return formatted; } +// Labels can be any sequence of UTF-8 characters, but backslash, double-quote +// and line feed must be escaped. +String FormatLabelValue(const char *value) { + String formatted = value; + formatted.replace("\\", "\\\\"); + formatted.replace("\"", "\\\""); + formatted.replace("\n", "\\n"); + return formatted; +} + void HandleMetrics(void) { if (!HttpCheckPriviledgedAccess()) { return; } @@ -84,8 +94,8 @@ void HandleMetrics(void) { char parameter[FLOATSZ]; // Pseudo-metric providing metadata about the running firmware version. - WSContentSend_P(PSTR("# TYPE tasmota_info gauge\ntasmota_info{version=\"%s\",image=\"%s\",build_timestamp=\"%s\"} 1\n"), - TasmotaGlobal.version, TasmotaGlobal.image_name, GetBuildDateAndTime().c_str()); + WSContentSend_P(PSTR("# TYPE tasmota_info gauge\ntasmota_info{version=\"%s\",image=\"%s\",build_timestamp=\"%s\",devicename=\"%s\"} 1\n"), + TasmotaGlobal.version, TasmotaGlobal.image_name, GetBuildDateAndTime().c_str(), FormatLabelValue(SettingsText(SET_DEVICENAME)).c_str()); WSContentSend_P(PSTR("# TYPE tasmota_uptime_seconds gauge\ntasmota_uptime_seconds %d\n"), TasmotaGlobal.uptime); WSContentSend_P(PSTR("# TYPE tasmota_boot_count counter\ntasmota_boot_count %d\n"), Settings->bootcount); WSContentSend_P(PSTR("# TYPE tasmota_flash_writes_total counter\ntasmota_flash_writes_total %d\n"), Settings->save_flag);