例えば以下のようなメトリクスがあったとします。みての通り、名前は一緒でラベルだけが異なるメトリクスです。

  • mqtt_topic{instance="127.0.0.1:9981",job="mqtt",topic="/home/sensor/temp"}
  • mqtt_topic{instance="127.0.0.1:9981",job="mqtt",topic="/home/sensor/humidity"}

これらを演算しようとして以下のようにしても no data になります。

 mqtt_topic{topic="/home/sensor/temp"} *  mqtt_topic{topic="/home/sensor/humidity"}

Vector Matching に書いてある通りですが、デフォルトではこのようなベクター同士の演算の場合、左右でラベルが全て一致するメトリクス同士のみが結果に出力されます。

SQL の INNER JOIN でラベル全ての一致が ON 条件に入ってるのをイメージするとわかりやすそうです。

この条件を変更するには、ignoring() または on() を使います。今回のケースでは以下の2つの結果は同じです。

 mqtt_topic{topic="/home/sensor/temp"} *  ignoring(topic) mqtt_topic{topic="/home/sensor/humidity"}
 mqtt_topic{topic="/home/sensor/temp"} *  on(instance,job) mqtt_topic{topic="/home/sensor/humidity"}

ignoring() は JOIN の条件から指定したラベルを除くように働き、on() は JOIN の条件を明示的にすべて指定するように働きます。

リテラル演算との組合せ

数値リテラル(スカラ)とベクターを演算すると、結果はベクターになります。スカラ値との演算時には上記のように ignoring() や on() は指定できません (syntax error になります)。複雑な計算をする場合、適切な場所に on() または ignoring() を書く必要があります。つまりベクター同士の演算になる場所に書きます。

例えば、topic="/home/sensor/temp" を温度、topic="/home/sensor/humidity" を湿度として不快指数を計算したいと思う場合、以下のようになります。

(0.81 * mqtt_topic{topic="/home/sensor/temp"})
  + ignoring(topic) (0.01 *  mqtt_topic{topic="/home/sensor/humidity"})
  * ignoring(topic) (0.99 *  mqtt_topic{topic="/home/sensor/temp"} - 14.3)
  + 46.3
  1. トップ
  2. tech
  3. PromQL でラベル違いのメトリクス同士を演算して no data

最近はこう

ssh-keygen -t ecdsa -b 521

最近の raspi イメージはデフォルトで弱い暗号方式を無効化してあるのでさっさと ecdsa 鍵に乗り換えましょう……

  1. トップ
  2. tech
  3. ssh-keygen

クランプ式電流計は回路を切断せずに電流計測ができるので便利なのだけど、ホット側かコールド側いずれか一方だけをクランプする必要があるため、ほとんどの場合では実際には切断せずに計測というのは難しい。

ということで、写真のように短い延長ケーブルをつくった。線が分離しており、片方だけを挟める。前もって接続しておくことでいつでも計測できるようになる。100均で割けるタイプの延長コードがあればそれでいいけど、最近は二重絶縁のものが主流なのがかえって作りにくくなってしまった。

詳しい施行方法はパナソニックのサイトの「仕様」を見るとわかる。(備考:この延長ケーブルを作るのにあたっては特段なんの資格もいりません)


しかしまだ使えてない。特に冷蔵庫に使いたいんだけど、冷蔵庫の電源を落とすには若干の手順が必要なので面倒 (内容物の確認 → 電源オフ→ 7分間は再度電源入れないこと)

  1. トップ
  2. tech
  3. クランプ式電流計用にホットコールド分離ケーブルをつくる

MQTT のトピックを subscribe して一時的に保持し、prometheus 向けに exporter として働くデーモンを書いた。要は pushgateway の MQTT 版のようなもの。

うちではセンサーデータの一部を MQTT サーバに送りつけるようにしてあるので、それを面倒なことなしに prometheus に登録していきたい。

使いかたと挙動

mqtt_topic_exporter --mqtt.server=mqtts://user:pass@mqttserver:8883 --mqtt.topic="/home/sensor/+"

みたいに引数を指定する。mqtt.topic はそのまま subscribe に渡される。ワイルドカードも使える。

mqtt_topic_exporter は MQTT サーバに接続して値を待つ。値がきたらメッセージ内容を数値として扱い gauge のメトリクスとして登録する。

/metrics にアクセスすると以下のようにメトリクスが登録される。

mqtt_topic{topic="/home/sensor/temp"} 30.0

また、topic がしばらく受信できないと、該当メトリクスは一定時間で削除される。

./mqtt_topic_exporter --help
usage: mqtt_topic_exporter --mqtt.server=MQTT.SERVER --mqtt.topic=MQTT.TOPIC [<flags>]

Flags:
  -h, --help                     Show context-sensitive help (also try --help-long and --help-man).
      --web.listen-address=":9981"  
                                 Address on which to expose metrics and web interface.
      --web.telemetry-path="/metrics"  
                                 Path under which to expose metrics.
      --mqtt.retain-time="1m"    Retain duration for a topic
      --mqtt.server=MQTT.SERVER  MQTT Server address URI mqtts://user:pass@host:port
      --mqtt.topic=MQTT.TOPIC ...  
                                 Watch MQTT topic
      --log.level="info"         Only log messages with the given severity or above. Valid levels: [debug, info, warn, error, fatal]
      --log.format="logger:stderr"  
                                 Set the log target and format. Example: "logger:syslog?appname=bob&local=7" or "logger:stdout?json=true"
      --version                  Show application version.
  1. トップ
  2. tech
  3. MQTT のトピックを prometheus に登録する