Last active
December 2, 2021 00:25
-
-
Save vilaca/9f4421292d06c5a7da35b44bc22039b8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "encoding/json" | |
| "fmt" | |
| "io" | |
| "io/ioutil" | |
| "log" | |
| "net/http" | |
| "strings" | |
| "time" | |
| "github.com/prometheus/client_golang/prometheus" | |
| "github.com/prometheus/client_golang/prometheus/promauto" | |
| "github.com/prometheus/client_golang/prometheus/promhttp" | |
| ) | |
| const CmlOpendataUrl = "http://opendata-cml.qart.pt:8080/lastmeasurements" | |
| const WrongMeasurementValue = -99 | |
| const PollingInterval = 5 * time.Minute | |
| type SensorReading struct { | |
| Id string | |
| Value float64 | |
| } | |
| var ( | |
| dict = map[string]map[string]string{ | |
| "CT0TMD": { | |
| "Category": "Transit", | |
| "Description": "Vehicles"}, | |
| "ME00HR": { | |
| "Unit": "%", | |
| "Category": "Weather", | |
| "Description": "Relative humidity"}, | |
| "ME00PA": { | |
| "Unit": "mbar", | |
| "Category": "Weather", | |
| "Description": "Atmospheric pressure"}, | |
| "ME00PP": { | |
| "Unit": "mm", | |
| "Category": "Weather", | |
| "Description": "Precipitation"}, | |
| "ME00UV": { | |
| "Category": "Weather", | |
| "Description": "Ultra violet"}, | |
| "ME00VD": { | |
| "Unit": "º", | |
| "Category": "Weather", | |
| "Description": "Wind direction"}, | |
| "ME00VI": { | |
| "Unit": "km/h", | |
| "Category": "Weather", | |
| "Description": "Wind intensity"}, | |
| "METEMP": { | |
| "Unit": "ºC", | |
| "Category": "Weather", | |
| "Description": "Temperature"}, | |
| "QA00CO": { | |
| "Unit": "mg/m3", | |
| "Unit": "mg/m3", | |
| "Category": "Air quality", | |
| "Description": "Carbon monoxide"}, | |
| "QA00NO": { | |
| "Unit": "µg/m3", | |
| "Category": "Air quality", | |
| "Description": "Nitrogen oxide"}, | |
| "QA00O3": { | |
| "Unit": "µg/m3", | |
| "Category": "Air quality", | |
| "Description": "Ozone"}, | |
| "QA0NO2": { | |
| "Unit": "µg/m3", | |
| "Category": "Air quality", | |
| "Description": "Nitrogen dioxide"}, | |
| "QA0SO2": { | |
| "Unit": "µg/m3", | |
| "Category": "Air quality", | |
| "Description": "Sulfur dioxide"}, | |
| "QAPM10": { | |
| "Unit": "µg/m3", | |
| "Category": "Air quality", | |
| "Description": "Particles < 10 µm"}, | |
| "QAPM25": { | |
| "Unit": "µg/m3", | |
| "Category": "Air quality", | |
| "Description": "Particles < 2.5 µm"}, | |
| "RULAEQ": { | |
| "Unit": "dB(A)", | |
| "Category": "Noise", | |
| "Description": "Noise level"}, | |
| } | |
| cache = map[string]prometheus.Gauge{} | |
| runs = promauto.NewCounter(prometheus.CounterOpts{ | |
| Name: "lx_sensor_runs", | |
| Help: "The total number of runs", | |
| }) | |
| badRead = promauto.NewCounter(prometheus.CounterOpts{ | |
| Name: "lx_sensor_bad_reads", | |
| Help: "The total number of bad reads", | |
| }) | |
| executionTime = promauto.NewGauge(prometheus.GaugeOpts{ | |
| Name: "lx_sensor_pooling_execution_time", | |
| Help: "Amount of time it took to pool and update metrics", | |
| }) | |
| ) | |
| func getMeasurements() ([]SensorReading, error) { | |
| resp, err := http.Get(CmlOpendataUrl) | |
| if err != nil { | |
| return nil, err | |
| } | |
| defer func(Body io.ReadCloser) { | |
| err := Body.Close() | |
| if err != nil { | |
| log.Print(err) | |
| } | |
| }(resp.Body) | |
| body, err := ioutil.ReadAll(resp.Body) | |
| if err != nil { | |
| return nil, err | |
| } | |
| return measurements, nil | |
| } | |
| func newGauge(key string) prometheus.Gauge { | |
| keyType := key[0:6] | |
| labels := dict[keyType] | |
| cached := prometheus.NewGauge(prometheus.GaugeOpts{ | |
| Name: "lx_sensor_measurement_" + strings.ToLower(key), | |
| ConstLabels: labels, | |
| Help: "Sensor measurement", | |
| }) | |
| cache[key] = cached | |
| //fmt.Println(key, "->", measurement[i].Value) | |
| prometheus.MustRegister(cached) | |
| return cached | |
| } | |
| func recordMetrics() { | |
| go func() { | |
| for { | |
| start := time.Now() | |
| measurements, err := getMeasurements() | |
| if err != nil { | |
| log.Println(err) | |
| continue | |
| } | |
| for i := 0; i < len(measurements); i++ { | |
| if measurements[i].Value == WrongMeasurementValue { | |
| badRead.Inc() | |
| continue | |
| } | |
| key := measurements[i].Id | |
| cached := cache[key] | |
| if cached == nil { | |
| cached = newGauge(key) | |
| } | |
| cached.Set(measurements[i].Value) | |
| } | |
| runs.Inc() | |
| elapsed := time.Since(start) | |
| executionTime.Set(float64(elapsed.Milliseconds())) | |
| time.Sleep(PollingInterval) | |
| } | |
| }() | |
| } | |
| func main() { | |
| recordMetrics() | |
| http.Handle("/metrics", promhttp.Handler()) | |
| err := http.ListenAndServe(":9090", nil) | |
| if err != nil { | |
| fmt.Println(err) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment