Wednesday, February 15, 2017

Air Pollution!

Since it has recently become a huge problem in my city and I'm currently working with prometheus I though it might be fun to get the pollution data and then plot it with grafana :)

Here's the task list:
- find the required data
- gather the data somehow
- scrub with prometheus
- display with grafana
- admire with satisfaction ;)

First we need to find some source of air pollution data, ideally it should provide an API we can use easily. One such case is World Air Quality Index. They gather data for more than 9k stations in 800 cities from 70 countries thanks to worlds Environmental Protection Agencies. API is easy, available and exports as JSON, all you really need is a token. A searchable cities list is also available: http://aqicn.org/city/all/.

Now let's gather the data by creating our own exporter for prometheus. We can use the code created by robustperception and documented by the prometheus team:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
from prometheus_client import start_http_server, Metric, REGISTRY
import json
import requests
import sys
import time

class JsonCollector(object):
  def __init__(self):
    pass

  def collect(self):
    # Fetch the JSON
    token = 'demo-token-won\'t-work' #apply for a token here: http://aqicn.org/data-platform/token/
    url = 'http://api.waqi.info/feed/'
    city = 'Wrocław' # Cities: http://aqicn.org/city/all/
    response = json.loads(requests.get(url+city+"/?token="+token).content.decode('Utf-8'))

    metric = Metric('aqi_airquality', 'Air Quality Index', 'gauge')
    metric.add_sample('aqi_airquality', value=response['data']['aqi'], labels={})
    yield metric

    metric = Metric('aqi_co', 'CO gases', 'gauge')
    metric.add_sample('aqi_co', value=response['data']['iaqi']['co']['v'], labels={})
    yield metric

    metric = Metric('aqi_humidity', 'Air Humidity', 'gauge')
    metric.add_sample('aqi_humidity', value=response['data']['iaqi']['h']['v'], labels={})
    yield metric

    metric = Metric('aqi_no2', 'NO2 gases', 'gauge')
    metric.add_sample('aqi_no2', value=response['data']['iaqi']['no2']['v'], labels={})
    yield metric

    metric = Metric('aqi_pressure', 'Air Pressure', 'gauge')
    metric.add_sample('aqi_pressure', value=response['data']['iaqi']['p']['v'], labels={})
    yield metric

    metric = Metric('aqi_pm25', 'pm2.5 particles', 'gauge')
    metric.add_sample('aqi_pm25', value=response['data']['iaqi']['pm25']['v'], labels={})
    yield metric

    metric = Metric('aqi_temp', 'Air temperature', 'gauge')
    metric.add_sample('aqi_temp', value=response['data']['iaqi']['t']['v'], labels={})
    yield metric
if __name__ == '__main__':
  # Usage: airq_exporter.py port
  start_http_server(int(sys.argv[1]))
  REGISTRY.register(JsonCollector())

  while True: time.sleep(1)

Ok so now to run our exporter on localhost and port 9999:

./airq_exporter.py 9999

Opening http://localhost:9999 should give a similar result:

telnet localhost 9999
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET /metrics HTTP/1.0

HTTP/1.0 200 OK
Server: BaseHTTP/0.3 Python/2.7.12
Date: Wed, 15 Feb 2017 12:06:22 GMT
Content-Type: text/plain; version=0.0.4; charset=utf-8

# HELP aqi_airquality Air Quality Index
# TYPE aqi_airquality gauge
aqi_airquality 219.0
# HELP aqi_co CO gases
# TYPE aqi_co gauge
aqi_co 12.7
# HELP aqi_humidity Air Humidity
# TYPE aqi_humidity gauge
aqi_humidity 80.0
# HELP aqi_no2 NO2 gases
# TYPE aqi_no2 gauge
aqi_no2 42.6
# HELP aqi_pressure Air Pressure
# TYPE aqi_pressure gauge
aqi_pressure 1037.0
# HELP aqi_pm25 pm25
# TYPE aqi_pm25 gauge
aqi_pm25 219.0
# HELP aqi_temp Air temperature
# TYPE aqi_temp gauge
aqi_temp 4.77
# HELP process_virtual_memory_bytes Virtual memory size in bytes.
# TYPE process_virtual_memory_bytes gauge
process_virtual_memory_bytes 132415488.0
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes 19132416.0
# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1487149538.19
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 6.08
# HELP process_open_fds Number of open file descriptors.
# TYPE process_open_fds gauge
process_open_fds 7.0
# HELP process_max_fds Maximum number of open file descriptors.
# TYPE process_max_fds gauge
process_max_fds 1024.0
Connection closed by foreign host.

So as you can see we gathered all the important data and there are also some typical prometheus client metrics.

Scrubbing the data is really simple, just edit your prometheus.conf and add:

  - job_name: 'airq'
    static_configs:
          - targets: ['IP:9999']

Remember to reload prometheus;)

Next step -> grafana. This is fairly easy now, since we have the data and need to present it. Choose anything that suits your needs. End result could look like this:
Grafana Dashboard
Grafana Dashboard for AirQuality
Looks like all the TODOs have been checked by now... so the last thing to do is 'admire with satisfaction;)'
All the code is available on github.

5 comments:

  1. Much thanks to you for peopling get the data they require. Extraordinary stuff not surprisingly. new delhi air quality

    ReplyDelete
  2. Harrah's Philadelphia Casino & Racetrack - Mapyro
    Harrah's Philadelphia Casino & Racetrack in 강원도 출장샵 Philadelphia offers a casino 창원 출장샵 and racetrack 군포 출장샵 in Philadelphia, PA. Get directions, reviews and information 순천 출장샵 for Harrah's 제주 출장안마

    ReplyDelete
  3. There are many video games right here — the part for reside 카지노사이트 video games alone includes 59︎ completely different titles. This works very properly, however there could possibly be} some video games within the on line casino that are not optimized for the smaller screen. Again, this deal is cut up equally between the site’s on line casino and poker part.

    ReplyDelete
  4. Some, Chen stated, get pleasure from people-watching as much because the actual slot play. What she discovered was that slot machine players fell naturally into four groups, which she calls utilitarian, pleasure, multipurpose and rest playing seekers. The explicit addictiveness of recent slots has to do with 카지노 사이트 the solitary, steady, rapid wagering they enable.

    ReplyDelete
  5. The winner is decided by the card combination that's closest to 21. The twist within the recreation is that if your card combination exceeds 21, you lose the sport. Strategically built in Incheon, Paradise City is minutes from Seoul’s worldwide airport, making for an easy journey for vacationers – it especially targets those from Japan and China. The on line casino is just meant for 다파벳 abroad guests; gambling in opposition to the law|is unlawful} for South Korean citizens, each at residence and abroad. Facilities separate from the on line casino advanced, together with the Cimer Spa, an unlimited Korean-style sauna, are geared toward home vacationers. Genting Jeju Casino contains 29 gaming tables and 16 slot machines.

    ReplyDelete