func main() { flag.Parse() // Initialize Intel Edison edisonAdaptor := edison.NewEdisonAdaptor("edison") edisonAdaptor.Connect() lightSensor := gpio.NewGroveLightSensorDriver(edisonAdaptor, "light", *sensorLightPin, *sensorPollingInterval) lightSensor.Start() gobot.On(lightSensor.Event("data"), func(data interface{}) { raw := float64(data.(int)) // convert to lux resistance := (1023.0 - raw) * 10.0 / raw * 15.0 light = 10000.0 / math.Pow(resistance, 4.0/3.0) lightUpdated = time.Now() log.Debugln("illuminance: ", light) }) soundSensor := gpio.NewGroveSoundSensorDriver(edisonAdaptor, "sound", *sensorSoundPin, *sensorPollingInterval) soundSensor.Start() gobot.On(soundSensor.Event("data"), func(data interface{}) { sound = float64(data.(int)) soundUpdated = time.Now() log.Debugln("sound level: ", sound) }) tempSensor := gpio.NewGroveTemperatureSensorDriver(edisonAdaptor, "temp", *sensorTempPin, *sensorPollingInterval) tempSensor.Start() gobot.On(tempSensor.Event("data"), func(data interface{}) { celsius = data.(float64) fahrenheit = celsius*1.8 + 32 tempUpdated = time.Now() log.Debugln("temperature: ", celsius) }) // Initialize prometheus exporter exporter := NewExporter() prometheus.MustRegister(exporter) log.Infof("Listening on: %s", *listenAddress) http.Handle(*metricPath, prometheus.Handler()) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(` <html> <head> <title>IoT Edison exporter</title> </head> <body> <h1>Prometheus exporter for sensor metrics from Intel Edison</h1> <p><a href='` + *metricPath + `'>Metrics</a></p> </body> </html> `)) }) log.Fatal(http.ListenAndServe(*listenAddress, nil)) }
// Send a list of notifications to the configured alert manager. func (n *NotificationHandler) sendNotifications(reqs NotificationReqs) error { n.mtx.RLock() defer n.mtx.RUnlock() alerts := make([]map[string]interface{}, 0, len(reqs)) for _, req := range reqs { for ln, lv := range n.externalLabels { if _, ok := req.Labels[ln]; !ok { req.Labels[ln] = lv } } alerts = append(alerts, map[string]interface{}{ "summary": req.Summary, "description": req.Description, "runbook": req.Runbook, "labels": req.Labels, "payload": map[string]interface{}{ "value": req.Value, "activeSince": req.ActiveSince, "generatorURL": req.GeneratorURL, "alertingRule": req.RuleString, }, }) } buf, err := json.Marshal(alerts) if err != nil { return err } log.Debugln("Sending notifications to alertmanager:", string(buf)) resp, err := n.httpClient.Post( n.alertmanagerURL+alertmanagerAPIEventsPath, contentTypeJSON, bytes.NewBuffer(buf), ) if err != nil { return err } defer resp.Body.Close() _, err = ioutil.ReadAll(resp.Body) if err != nil { return err } // BUG: Do we need to check the response code? return nil }
func (e *Exporter) scrape(ch chan<- prometheus.Metric) { defer func(begun time.Time) { e.duration.Set(time.Since(begun).Seconds()) }(time.Now()) e.error.Set(0) e.totalScrapes.Inc() db, err := sql.Open("postgres", e.dsn) if err != nil { log.Println("Error opening connection to database:", err) e.error.Set(1) return } defer db.Close() for namespaceAndQuery, mapping := range e.metricMap { namespace := namespaceAndQuery.namespace log.Debugln("Querying namespace: ", namespace, " query: ", namespaceAndQuery.query) func() { // Don't fail on a bad scrape of one metric rows, err := db.Query(namespaceAndQuery.query) if err != nil { log.Println("Error running query on database: ", namespace, err) e.error.Set(1) return } defer rows.Close() var columnNames []string columnNames, err = rows.Columns() if err != nil { log.Println("Error retrieving column list for: ", namespace, err) e.error.Set(1) return } // Make a lookup map for the column indices var columnIdx = make(map[string]int, len(columnNames)) for i, n := range columnNames { columnIdx[n] = i } var columnData = make([]interface{}, len(columnNames)) var scanArgs = make([]interface{}, len(columnNames)) for i := range columnData { scanArgs[i] = &columnData[i] } for rows.Next() { err = rows.Scan(scanArgs...) if err != nil { log.Println("Error retrieving rows:", namespace, err) e.error.Set(1) return } // Get the label values for this row var labels = make([]string, len(mapping.labels)) for idx, columnName := range mapping.labels { labels[idx], _ = dbToString(columnData[columnIdx[columnName]]) } // Loop over column names, and match to scan data. Unknown columns // will be filled with an untyped metric number *if* they can be // converted to float64s. NULLs are allowed and treated as NaN. for idx, columnName := range columnNames { if metricMapping, ok := mapping.columnMappings[columnName]; ok { // Is this a metricy metric? if metricMapping.discard { continue } value, ok := dbToFloat64(columnData[idx]) if !ok { e.error.Set(1) log.Errorln("Unexpected error parsing column: ", namespace, columnName, columnData[idx]) continue } // Generate the metric ch <- prometheus.MustNewConstMetric(metricMapping.desc, metricMapping.vtype, value, labels...) } else { // Unknown metric. Report as untyped if scan to float64 works, else note an error too. desc := prometheus.NewDesc(fmt.Sprintf("%s_%s", namespace, columnName), fmt.Sprintf("Unknown metric from %s", namespace), nil, nil) // Its not an error to fail here, since the values are // unexpected anyway. value, ok := dbToFloat64(columnData[idx]) if !ok { log.Warnln("Unparseable column type - discarding: ", namespace, columnName, err) continue } ch <- prometheus.MustNewConstMetric(desc, prometheus.UntypedValue, value, labels...) } } } }() } }