Data is gorgeous. As a #CitizenScientist, I get pleasure from gathering information and attempting to make sense of the world round me. At work, we use Prometheus to assemble metric information from our clusters, and at residence, I exploit Prometheus to assemble information from my hobbies. This article explores take an software—a Python script that gathers temperature and humidity information from a sensor—and instrument it to supply information in a model that Prometheus can gather. I am going to additionally create a systemd service to start out and handle the appliance.
What is Prometheus?
Prometheus is an open supply monitoring and alerting system that gathers metrics and offers a strong question language for exploring information. I’ve written about setting up Prometheus locally at residence. Prometheus is incessantly used to assemble information from container orchestration clusters akin to Kubernetes and OpenShift.
In my job as a website reliability engineer operating OpenShift Dedicated clusters for Red Hat, Prometheus is the core of a strong monitoring and alerting system for all of our clusters, operators, and purposes. It is used at big scale by giant enterprise organizations, however it’s equally at residence, effectively, at residence, accumulating information for hobbyist tasks.
In my earlier article about using a Raspberry Pi Zero and DHT22 to collect temperature and humidity data, I confirmed write a Python script to assemble the info and print it to the display screen. That is sweet for checking the info manually for every second, however it will be much more helpful for me to assemble and retailer the info to look at it traditionally. This is the place Prometheus shines as a time-series database with its personal question language and graph capabilities.
Instrument the app for Prometheus
In a nutshell, instrumenting the appliance for Prometheus requires taking the info from the sensor, labeling it, and serving it as textual content over HTTP in order that Prometheus can discover and retailer the info. Prometheus will examine these textual content pages, or “targets,” at a specified interval, in search of updates to the info. So, the appliance might want to replace the goal metrics as new sensor information is obtained.
The format of the info uncovered for Prometheus to assemble consists of a key (a metric title—that which is being measured) and a price separated by an area:
dht22_temperature 84.01999931335449
Prometheus additionally helps elective labels to make it simpler to filter and mixture information. This software makes use of labels to distinguish between Celsius and Fahrenheit scales for the dht22_temperature
metric. The is the label within the instance above. Check out the Prometheus data model for extra particulars.
You can modify the script manually to arrange an online server and print the sensor information, however Prometheus offers a Prometheus Python client that makes the method significantly simpler. You can set up the shopper utilizing the pip Python package deal supervisor. If you do not have already got it, set up pip utilizing your distribution’s package deal supervisor, after which use it to put in prometheus-client
. I am operating Raspberry Pi OS on my sensor system, so I am going to use apt-get
, however substitute your package deal supervisor of alternative:
# Install pip
sudo apt-get set up pip3# Install prometheus-client
sudo pip3 set up prometheus-client
Next, it is advisable tweak the earlier article’s sensor script to retailer the sensor information as Prometheus gauges. A gauge is “a metric that represents a single numerical value that can arbitrarily go up and down,” versus, say, a counter, which solely goes up. Prometheus has many various metric sorts. A gauge is ideal to symbolize temperature and humidity information.
Gauges are offered by the prometheus_client.Gauge
module, so it is advisable import the module earlier than you should use gauges within the script. Because start_http_server
is used later to show the metrics by way of HTTP, import that now as effectively:
# Import Gauge and start_http_server from prometheus_client
from prometheus_client import Gauge, start_http_server
Next, create the gauges to retailer the humidity and temperature information. The ['scale']
bit provides the “scale” label for the temperature gauge. Then the gauge is initialized with each celsius
and fahrenheit
values for the label:
# Create Prometheus gauges for humidity and temperature in
# Celsius and Fahrenheit
gh = Gauge('dht22_humidity_percent',
'Humidity share measured by the DHT22 Sensor')
gt = Gauge('dht22_temperature',
'Temperature measured by the DHT22 Sensor', ['scale'])# Initialize the labels for the temperature scale
gt.labels('celsius')
gt.labels('fahrenheit')
You can set the gauges with the sensor information when checking the sensor:
strive:
# Get the sensor information
humidity, temperature = Adafruit_DHT.read_retry(SENSOR, SENSOR_PIN)
besides RuntimeError as e:
log.error("RuntimeError: ".format(e))if humidity is not None and temperature is not None:
# Update the gauge with the sensor information
gh.set(humidity)
gt.labels('celsius').set(temperature)
gt.labels('fahrenheit').set(celsius_to_fahrenheit(temperature))
This is finished inside a whereas True:
loop (not proven above; see the total script beneath) to repeatedly replace the gauges with information from the sensor.
Finally, Prometheus’ start_metrics_server
will serve the collected metrics by way of HTTP. This is named earlier than the whereas
loop in order that the server begins first:
# Start the Prometheus metrics server to show the metrics information
metrics_port = 8000
start_http_server(metrics_port)
With all this collectively, the script ought to look one thing like this:
#!/usr/bin/env python3import logging
import timeimport Adafruit_DHT
from prometheus_client import Gauge, start_http_server
from systemd.journal import JournalHandler# Setup logging to the Systemd Journal
log = logging.getLogger('dht22_sensor')
log.addHandler(JournalHandler())
log.setLevel(logging.INFO)# Initialize the DHT22 sensor
# Read information from GPIO4 pin on the Raspberry Pi
SENSOR = Adafruit_DHT.DHT22
SENSOR_PIN = four# The time in seconds between sensor reads
READ_INTERVAL = 30.zero# Create Prometheus gauges for humidity and temperature in
# Celsius and Fahrenheit
gh = Gauge('dht22_humidity_percent',
'Humidity share measured by the DHT22 Sensor')
gt = Gauge('dht22_temperature',
'Temperature measured by the DHT22 Sensor', ['scale'])# Initialize the labels for the temperature scale
gt.labels('celsius')
gt.labels('fahrenheit')def celsius_to_fahrenheit(degrees_celsius):
return (degrees_celsius * 9/5) + 32def read_sensor():
strive:
humidity, temperature = Adafruit_DHT.read_retry(SENSOR, SENSOR_PIN)
besides RuntimeError as e:
# GPIO entry could require sudo permissions
# Other RuntimeError exceptions could happen, however
# are frequent. Just strive once more.
log.error("RuntimeError: ".format(e))if humidity is not None and temperature is not None:
gh.set(humidity)
gt.labels('celsius').set(temperature)
gt.labels('fahrenheit').set(celsius_to_fahrenheit(temperature))log.information("Temp:*C, Humidity: %".format(temperature, humidity))
time.sleep(READ_INTERVAL)
if __name__ == "__main__":
# Expose metrics
metrics_port = 8000
start_http_server(metrics_port)
print("Serving sensor metrics on :".format(metrics_port))
log.information("Serving sensor metrics on :".format(metrics_port))whereas True:
read_sensor()
Set up the systemd unit and logging
The script is able to go and would work with Prometheus as it’s. But I am operating this on headless (i.e., no monitor, keyboard, and so on.) Raspberry Pi Zero Ws put in in challenge packing containers with DHT22 sensors, arrange in several rooms of the home. I am going to add a systemd service to mechanically begin the script at boot and ensure it retains operating. I am going to additionally benefit from the systemd journal and ship log information from the script (e.g., startup or error messages) to the journal.
The systemd service will probably be a separate file systemd makes use of, however it wants the python3-systemd
package deal to ship logs to the journal from the script. You can set up it with apt-get
(or your package deal supervisor):
# Install the python3-systemd package deal for Journal integration
sudo apt-get set up python3-systemd
You can configure the Python logger throughout the service monitor script to ship logs to the journal by utilizing the systemd.journal.JournalHandler
module. After importing it, you’ll be able to add the JournalHandler
as a handler for the logger:
from systemd.journal import JournalHandler# Setup logging to the Systemd Journal
log = logging.getLogger('dht22_sensor')
log.addHandler(JournalHandler())
log.setLevel(logging.INFO)
Now it could possibly log to the journal with log.information()
. For instance:
# This will ship the message to the Systemd Journal,
# and present up in `systemctl standing` and with `journalctl`
log.information("Serving sensor metrics on :".format(metrics_port))
With the script up to date to log to the systemd journal, create a systemd service for the sensor-metrics.py
script:
# /and so on/systemd/system/sensor-metrics.service
[Unit]
Description=DHT22 Sensor Metrics Service
After=community.goal
StartRestrictIntervalSec=zero[Service]
Type=easy
Restart=all the time
ExecStart=python3 /choose/sensor-metrics/sensor-metrics.py[Install]
WantedBy=multi-user.goal
This merely tells systemd to search for a script in /choose/sensor-metrics/sensor-metrics.py
, begin it, and hold it operating. This will develop into the sensor-metrics
service.
Link (or transfer, should you favor) the sensor-metrics.py
script to /choose/sensor-metrics/sensor-metrics.py
:
# Create /choose/sensor-metrics and hyperlink the sensor-metrics.py script from the present listing into it
sudo mkdir /choose/sensor-metrics
sudo ln -s $(pwd)/sensor-metrics.py /choose/sensor-metrics/
Link the sensor-metrics.service
file to /and so on/systemd/system
:
# Link the sensor-metrics.service file into the Systemd listing
sudo ln -s $(pwd)/sensor-metrics.service /and so on/systemd/system/
Now you’ll be able to allow the sensor-metrics service to start out on boot and examine the standing:
# Enable and begin the sensor-metrics.service
sudo systemctl allow sensor-metrics.service
sudo systemctl begin sensor-metrics.service
Now the service is operating and set to start out on boot.
To discover out if all the things is operating, examine the service standing with systemctl
:
sudo systemctl standing sensor-metrics.service
You ought to see one thing like this (if all the things is working):
● sensor-metrics.service - DHT22 Sensor Metrics Service
Loaded: loaded (/residence/chris/sensor-metrics.service; enabled; vendor preset: enabled)
Active: energetic (operating) since Wed 2021-06-30 03:33:02 BST; 8s in the past
Main PID: 4129 (python3)
Tasks: 2 (restrict: 877)
CGroup: /system.slice/sensor-metrics.service
└─4129 /usr/bin/python3 /choose/sensor-metrics/sensor-metrics.pyJun 30 03:33:02 cumulo systemd[1]: Started DHT22 Sensor Metrics Service.
Jun 30 03:33:05 cumulo /choose/sensor-metrics/sensor-metrics.py[4129]: Serving sensor metrics on :8000
Jun 30 03:33:05 cumulo /choose/sensor-metrics/sensor-metrics.py[4129]: Temp:30.6*C, Humidity: 47.1%
Success!
Check the metrics goal
With the service operating and the script modified to gather sensor information in gauges and show it for Prometheus, you’ll be able to view the info as Prometheus will.
In a browser, navigate to http://<IP OF YOUR HOST>:8000
, substituting the IP deal with of the machine operating the sensor-metrics service.
You ought to see a web page with a number of metrics in regards to the Python shopper (bonus!), in addition to the dht22_temperature and dht22_humidity metrics. It ought to look one thing like this:
Data actually IS stunning! Look at that! Humidity and temperature in two completely different scales!
The information will replace every time the service script checks the sensor information. Now for the final step: exhibiting Prometheus the place to search for all this information.
Create a Prometheus scrape config
Before shifting on, I like to recommend you learn my earlier article about running Prometheus at home and have an occasion already arrange. If you have not, go forward and try this now (and inform all your pals what an awesome expertise it was). The article exhibits arrange Prometheus to learn dynamic scrape configs from a file and reload mechanically. These scrape configs level Prometheus to the metric information targets it ought to ingest (i.e., “scrape”).
Add a scrape config for the sensor-metrics information to the array (if any) within the scrape config JSON setup within the earlier article. Note the array beneath has the one Prometheus sensor-metrics goal. Yours could already produce other targets. Just add to the record.
// This scrape config goal factors to the IP Address of the Raspberry Pi and the Port used within the sensor-metrics.py script
// Substitute your individual IP and the port you selected
[
"labels": , "targets": ["192.168.1.119:8000"]
]
After restarting Prometheus (or ready for it to search out and cargo the brand new scrape config), Prometheus will start in search of metrics information on the goal you specified above.
Bringing all of it collectively
Finally, all the things is operating, and you may have a look at the info you are accumulating! Open the Prometheus internet interface to your Prometheus server. Mine is http://localhost:9090/graph
, and yours would be the similar should you adopted together with the earlier article. Click on the “graph” tab, and seek for dht22_temperaturescale=~"fahrenheit"
to see the temperature information being collected.
Well. That’s disappointing.
OK, so, two issues:
- Time-series information is underwhelming at first as a result of you do not have a lot information but. It will get higher over time.
- Ambient temperature information takes a considerably longer interval to show something fascinating as a result of it does not change a lot.
So, give it time. Eventually, it’s going to look far more fascinating and get higher:
MUCH higher!
Do some #CitizenScience
Prometheus works very effectively for accumulating metric information, storing it as time-series information, and offering a strategy to discover it. I hope this text has impressed you to carry out some #CitizenScience at residence, create your individual information, and discover!