Prometheus
https://github.com/narethim/tools/blob/master/setup-prometheus-node-exporter-arm64.md
https://grafana.com/docs/grafana-cloud/quickstart/noagent_linuxnode/
docker run -d --restart=always --net mqtt \ --name=prometheus \ -p 9099:9090 \ --add-host=host.docker.internal:host-gateway \ -v ~/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml \ prom/prometheus
Linux Exporter
https://linuxhit.com/prometheus-node-exporter-on-raspberry-pi-how-to-install/
https://stackoverflow.com/questions/31324981/how-to-access-host-port-from-docker-container
wget https://github.com/prometheus/node_exporter/releases/download/v0.18.1/node_exporter-0.18.1.linux-arm64.tar.gz tar -xvzf node_exporter-0.18.1.linux-arm64.tar.gz sudo cp node_exporter-0.18.1.linux-arm64/node_exporter /usr/local/bin sudo chmod +x /usr/local/bin/node_exporter sudo useradd -m -s /bin/bash node_exporter sudo mkdir /var/lib/node_exporter sudo chown -R node_exporter:node_exporter /var/lib/node_exporter sudo nano /etc/systemd/system/node_exporter.service
[Unit] Description=Node Exporter [Service] # Provide a text file location for https://github.com/fahlke/raspberrypi_exporter data with the # --collector.textfile.directory parameter. ExecStart=/usr/local/bin/node_exporter --collector.textfile.directory /var/lib/node_exporter/textfile_collector [Install] WantedBy=multi-user.target
sudo systemctl daemon-reload sudo systemctl enable node_exporter.service sudo systemctl start node_exporter.service
Prometheus configuration
- job_name: linux honor_timestamps: true scrape_interval: 60s scrape_timeout: 5s metrics_path: /metrics scheme: http follow_redirects: true enable_http2: true static_configs: - targets: - host.docker.internal:9100
Grafana Dashboard
In Grafana, click Dashboards in the left side menu (looks like four boxes) and from the menu that appears select Manage.
Click Import. Enter the ID number 10180 for the Linux dashboard, and click Load.
Node-RED
[{"id":"d1f3d002.63ee48","type":"subflow","name":"rbe 5m","info":"","category":"","in":[{"x":60,"y":120,"wires":[{"id":"dd19c0de.9bebd"}]}],"out":[{"x":420,"y":160,"wires":[{"id":"29eae4ad.d68f2c","port":0}]}],"env":[],"meta":{},"color":"#DDAA99"},{"id":"dd19c0de.9bebd","type":"rbe","z":"d1f3d002.63ee48","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":190,"y":120,"wires":[["29eae4ad.d68f2c"]]},{"id":"8b22fc2a.83d07","type":"inject","z":"d1f3d002.63ee48","name":"","props":[{"p":"reset","v":"1","vt":"str"}],"repeat":"300","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":200,"y":80,"wires":[["dd19c0de.9bebd"]]},{"id":"29eae4ad.d68f2c","type":"switch","z":"d1f3d002.63ee48","name":"","property":"reset","propertyType":"msg","rules":[{"t":"null"}],"checkall":"true","repair":false,"outputs":1,"x":280,"y":160,"wires":[[]]},{"id":"82572bd7fa2754e2","type":"link out","z":"f6f2187d.f17ca8","name":"link out 9","mode":"link","links":["058f796bc37b7250","56f925dd66127bbb"],"x":265,"y":140,"wires":[]},{"id":"7fddbf716a47caa3","type":"mqtt in","z":"f6f2187d.f17ca8","name":"","topic":"#","qos":"0","datatype":"auto","broker":"61c70212c61507f5","nl":false,"rap":false,"inputs":0,"x":130,"y":140,"wires":[["82572bd7fa2754e2","f04495f04028c894"]]},{"id":"873f73b8bd187f78","type":"subflow:d1f3d002.63ee48","z":"f6f2187d.f17ca8","name":"","x":360,"y":260,"wires":[["5b24a3ea71452cd8","a2a978223a03ad4b","f656e5b024503c03"]]},{"id":"058f796bc37b7250","type":"link in","z":"f6f2187d.f17ca8","name":"link in 1","links":["190658415505c339","82572bd7fa2754e2"],"x":215,"y":260,"wires":[["873f73b8bd187f78"]]},{"id":"f04495f04028c894","type":"debug","z":"f6f2187d.f17ca8","name":"debug 8","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":290,"y":80,"wires":[]},{"id":"f656e5b024503c03","type":"function","z":"f6f2187d.f17ca8","name":"Metrics List","func":"\n\n\nvar metrics = {};\n\nmetrics.timestamp = new Date().getTime();\nmetrics.topic = msg.topic;\nmetrics.payload = msg.payload;\n\nvar mname = msg.topic.replace(/\\//g,\"_\")\n\n\nflow.set(\"metrics.\" + mname, metrics);\n\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":410,"y":340,"wires":[[]]},{"id":"1fdeb63853f6378a","type":"http in","z":"f6f2187d.f17ca8","name":"","url":"/metrics","method":"get","upload":false,"swaggerDoc":"","x":190,"y":580,"wires":[["0df212d8de0af553"]]},{"id":"78bcb731b3070bde","type":"http in","z":"f6f2187d.f17ca8","name":"","url":"/metrics/:vargroup","method":"get","upload":false,"swaggerDoc":"","x":220,"y":660,"wires":[["a9bfbf0b470f5412"]]},{"id":"a9bfbf0b470f5412","type":"function","z":"f6f2187d.f17ca8","name":"Metrics","func":"\nvar metrics = flow.get(\"metrics\")||{};\n\n\nvar net = global.get(\"config.networkId\") || \"local\";\n\nvar oot = \"\";\n//oot = 'stat_state {network=\"local\", node=\"mynodered1\", device=\"prometheus\", vargroup=\"stat\", varkey=\"state\"} 1\\n';\n\nfor (var m in metrics) {\n\n var tops = metrics[m].topic.split(\"/\");\n \n if (isNaN(metrics[m].payload)) { continue; }\n if (tops[3] != msg.req.params.vargroup) { continue; } \n\n \n oot += tops[3] + '_' + tops[4] + '{network=\"' + net + '\",node=\"' + tops[1] + '\",device=\"' + tops[2] + '\",vargroup=\"' + tops[3] + '\",varkey=\"' + tops[4] + '\"} ' + metrics[m].payload + \"\\n\";\n\n}\n\n\nmsg.payload = oot;\n\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":520,"y":660,"wires":[["2bf9db2387e3c2c3","011f1ef5757fc34b"]]},{"id":"0df212d8de0af553","type":"function","z":"f6f2187d.f17ca8","name":"Metrics","func":"\n//temperature{ node = \"mynode\", topic = \"zigbee2mqtt_0x00157d00032b1234\" } { { payload } }\n\nvar metrics = flow.get(\"metrics\")||{};\n//flow.set(\"metrics\",{});\n\nvar net = global.get(\"config.networkId\") || \"local\";\n\nvar oot = \"\";\n//oot = 'stat_state {network=\"local\", node=\"mynodered1\", device=\"prometheus\", vargroup=\"stat\", varkey=\"state\"} 1\\n';\n\nfor (var m in metrics) {\n\n if (isNaN(metrics[m].payload)) { continue; }\n \n var tops = metrics[m].topic.split(\"/\");\n\n //if (tops[3] != \"dat\") { continue; } \n\n oot += tops[3] + '_' + tops[4] + '{network=\"' + net + '\",node=\"' + tops[1] + '\",device=\"' + tops[2] + '\",vargroup=\"' + tops[3] + '\",varkey=\"' + tops[4] + '\"} ' + metrics[m].payload + \"\\n\";\n\n}\n\n\nmsg.payload = oot;\n\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":520,"y":580,"wires":[["2bf9db2387e3c2c3","011f1ef5757fc34b"]]},{"id":"011f1ef5757fc34b","type":"debug","z":"f6f2187d.f17ca8","name":"debug 16","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":740,"y":580,"wires":[]},{"id":"2bf9db2387e3c2c3","type":"http response","z":"f6f2187d.f17ca8","name":"","statusCode":"","headers":{},"x":730,"y":620,"wires":[]},{"id":"61c70212c61507f5","type":"mqtt-broker","name":"","broker":"mqtt","port":"1883","clientid":"","autoConnect":true,"usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"userProps":"","sessionExpiry":""}]