package main import ( "fmt" "github.com/namsral/flag" "net/http" "time" "os" "github.com/prometheus/client_golang/prometheus/promhttp" log "github.com/sirupsen/logrus" ) var station string var debug bool var reportList = make(map[string]report) var metricpath string var mysql_host string var mysql_db string var mysql_user string var mysql_pass string var mysql_table string var port int //var promcalls bool var trace bool var useProm bool var useMysql bool func usage() { fmt.Printf("Usage of %s:\n", os.Args[0]) flag.PrintDefaults() } func init() { flag.StringVar(&station, "station", "", "callsign to monitor on pskreporter") flag.StringVar(&mysql_host, "host", "db", "name/ip of mysql host") flag.StringVar(&mysql_db, "db", "digimode_stats", "db name") flag.StringVar(&mysql_user, "user", "wsjtx", "mysql username") flag.StringVar(&mysql_pass, "pass", "secret", "mysql password") flag.StringVar(&mysql_table, "table", "pskreporter_stats", "mysql table name") flag.StringVar(&metricpath, "metricpath", "/metrics", "path for prometheus metric endpoint") flag.IntVar(&port, "port", 2113, "port for prometheus metric endpoint") flag.BoolVar(&useProm, "prometheus", false, "activate prometheus exporter") flag.BoolVar(&useMysql, "mysql", false, "activate mysql exporter") // flag.BoolVar(&promcalls, "promcalls", false, "activate prometheus callsign metrics") flag.BoolVar(&trace, "trace", false, "log almost everything") flag.BoolVar(&debug, "debug", false, "enable debug logging") flag.Parse() formatter := &log.TextFormatter{ FullTimestamp: true, } log.SetFormatter(formatter) if trace { log.SetLevel(log.TraceLevel) log.Info("trace logging enabled") } else { log.Info("normal logging enabled") } if !useProm && !useMysql { usage() log.Fatal("you have to enable at least one exporter. see -mysql and -prometheus flags") } if useProm { log.Info("prometheus exporter enabled..") } if useMysql { log.Info("mysql exporter enabled..") // wait for stupid mysql container to come up.. _, db_down := dbConn() for db_down { log.Info("waiting for db to come up..") time.Sleep(2 * time.Second) _, db_down = dbConn() } init_db() } } func handleResults(reports chan report) { for { select { case report := <- reports : _ , seen := reportList[report.CallSign] // check if receiver is known if seen { // check if fetched record is newer than existing one if report.lastReport > reportList[report.CallSign].lastReport { log.WithFields(log.Fields{ "Callsign":report.CallSign, "Report":report.Signal, "Grid":report.Grid, "Geohash":report.GeoHash, "Mode":report.Mode, "Continent":report.Continent, "LastReport":report.lastReport, "ITUZone":fmt.Sprintf("%d",report.ITUZone), "CQZone":fmt.Sprintf("%d",report.CQZone), "DXCC":report.Dxcc, }).Trace("known receiver with fresh report") if useProm { handlePrometheus(report) } if useMysql { handleMysql(report) } // put in cache reportList[report.CallSign] = report } else { // just hit an old entry, no need to store log.Trace("known receiver with known report") } } else { // FIXME is it safe that lastReport is the last Report from the other station or is it the last Report he reported us? // if it is the last, the check could be wrong :-/ // -> add debugging output to check! if report.lastReport > (time.Now().Unix() - 300) { log.WithFields(log.Fields{ "Callsign":report.CallSign, "Report":report.Signal, "Grid":report.Grid, "Geohash":report.GeoHash, "Mode":report.Mode, "Continent":report.Continent, "LastReport":report.lastReport, "ITUZone":fmt.Sprintf("%d",report.ITUZone), "CQZone":fmt.Sprintf("%d",report.CQZone), "DXCC":report.Dxcc, }).Trace("unknown receiver with fresh report") if useProm { handlePrometheus(report) } if useMysql { handleMysql(report) } } else { log.Trace("unknown receiver with old report") } // put in cache reportList[report.CallSign] = report } } } } func main(){ reports := make(chan report) go fetchReports(reports) go handleResults(reports) log.Infof("listening on :%d%s",port, metricpath) http.Handle(metricpath, promhttp.Handler()) http.ListenAndServe(fmt.Sprintf(":%d",port), nil) }