package main import ( "encoding/json" "flag" "fmt" "io/ioutil" "log" "net/http" "github.com/cabify/gotoprom" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/robfig/cron/v3" ) var addr = flag.String("listen-address", "127.0.0.1:8080", "The address to listen on for HTTP requests.") type OntCovidData struct { Help string `json:"help"` Success bool `json:"success"` Result struct { Sort string `json:"sort"` IncludeTotal bool `json:"include_total"` ResourceID string `json:"resource_id"` Fields []struct { Type string `json:"type"` ID string `json:"id"` Info struct { Notes string `json:"notes"` TypeOverride string `json:"type_override"` Label string `json:"label"` } `json:"info,omitempty"` } `json:"fields"` RecordsFormat string `json:"records_format"` Records []struct { ID int `json:"_id"` ReportDate string `json:"report_date"` PreviousDayDosesAdministered json.Number `json:"previous_day_total_doses_administered"` PreviousDayAtLeastOne json.Number `json:"previous_day_at_least_one"` PreviousDayFullyVaccinated json.Number `json:"previous_day_fully_vaccinated"` TotalDosesAdministered json.Number `json:"total_doses_administered"` TotalDosesAtLeastOne json.Number `json:"total_individuals_at_least_one"` TotalDosesInFullyVaccinatedIndividuals json.Number `json:"total_doses_in_fully_vaccinated_individuals"` TotalIndividualsFullyVaccinated json.Number `json:"total_individuals_fully_vaccinated"` } `json:"records"` Limit int `json:"limit"` Links struct { Start string `json:"start"` Next string `json:"next"` } `json:"_links"` Total int `json:"total"` } `json:"result"` } type OntCovidDataByAge struct { Help string `json:"help"` Success bool `json:"success"` Result struct { IncludeTotal bool `json:"include_total"` ResourceID string `json:"resource_id"` Fields []struct { Type string `json:"type"` ID string `json:"id"` Info struct { Notes string `json:"notes"` TypeOverride string `json:"type_override"` Label string `json:"label"` } `json:"info,omitempty"` } `json:"fields"` RecordsFormat string `json:"records_format"` Records []struct { ID int `json:"_id"` Date string `json:"Date"` Agegroup string `json:"Agegroup"` AtLeastOneDoseCumulative json.Number `json:"At least one dose_cumulative"` SecondDoseCumulative json.Number `json:"Second_dose_cumulative"` TotalPopulation json.Number `json:"Total population"` PercentAtLeastOneDose json.Number `json:"Percent_at_least_one_dose"` PercentFullyVaccinated json.Number `json:"Percent_fully_vaccinated"` } `json:"records"` Limit int `json:"limit"` Links struct { Start string `json:"start"` Next string `json:"next"` } `json:"_links"` Total int `json:"total"` } `json:"result"` } type AgeRecord struct { AtLeastOneDoseCumulative func() prometheus.Gauge `name:"at_least_one_dose_cumaltive" help:""` SecondDoseCumulative func() prometheus.Gauge `name:"second_dose_cumulative" help:""` TotalPopulation func() prometheus.Gauge `name:"total_population" help:""` PercentAtLeastOneDose func() prometheus.Gauge `name:"percent_at_least_one_dose" help:""` PercentFullyVaccinated func() prometheus.Gauge `name:"percent_fully_vaccinated" help:""` } type DataRecord struct { PreviousDayDosesAdministered func() prometheus.Gauge `name:"previous_day_doses_administered" help:"Previous day doses administered"` PreviousDayAtLeastOne func() prometheus.Gauge `name:"previous_day_at_least_one" help:"Previous day doses administered at least one shot"` PreviousDayFullyVaccinated func() prometheus.Gauge `name:"previous_day_fully_vaccinated" help:"Previous day doses administered fully vaccinated"` TotalDosesAdministered func() prometheus.Gauge `name:"total_doses_administered" help:"Total doses administered"` TotalDosesAtLeastOne func() prometheus.Gauge `name:"total_individuals_at_least_one" help:"Total at least one dose in individuals"` TotalDosesInFullyVaccinatedIndividuals func() prometheus.Gauge `name:"total_doses_in_fully_vaccinated_individuals" help:"Total does in fully vaccinated individuals"` TotalIndividualsFullyVaccinated func() prometheus.Gauge `name:"total_individuals_fully_vaccinated" help:"Total individuals fully vaccinated"` EligiblePopulation func() prometheus.Gauge `name:"eligible_population" help:"Total population eligible for the vaccination"` Age12To17yrs AgeRecord `namespace:"age_12_17yrs"` Age18To29yrs AgeRecord `namespace:"age_18_29yrs"` Age30To39yrs AgeRecord `namespace:"age_30_39yrs"` Age40To49yrs AgeRecord `namespace:"age_40_49yrs"` Age50To59yrs AgeRecord `namespace:"age_50_59yrs"` Age60To69yrs AgeRecord `namespace:"age_60_69yrs"` Age70To79yrs AgeRecord `namespace:"age_70_79yrs"` Age80Plus AgeRecord `namespace:"age_80_plus"` AgeAdults18Plus AgeRecord `namespace:"age_adult_18_plus"` AgeUndisclosedOrMissing AgeRecord `namespace:"age_undisclosed_or_missing"` } var dataRecord DataRecord func init() { gotoprom.MustInit(&dataRecord, "ontvacstat") } func fetchUrl(dataUrl string) []byte { resp, getErr := http.Get(dataUrl) if getErr != nil { log.Println(getErr) } body, readErr := ioutil.ReadAll(resp.Body) if readErr != nil { log.Println(readErr) } return body } func updateMetrics() { dataUrl := "https://data.ontario.ca/api/3/action/datastore_search?sort=report_date+desc&limit=1&resource_id=8a89caa9-511c-4568-af89-7f2174b4378c" dataAgeUrl := "https://data.ontario.ca/api/3/action/datastore_search?resource_id=775ca815-5028-4e9b-9dd4-6975ff1be021&sort=Date%20desc&limit=9" eligiblePopulation := 0.0 dataUrlOut := fetchUrl(dataUrl) data := OntCovidData{} dataErr := json.Unmarshal(dataUrlOut, &data) if dataErr != nil { log.Println(dataUrl, dataErr) return } dataAgeUrlOut := fetchUrl(dataAgeUrl) dataAge := OntCovidDataByAge{} dataAgeErr := json.Unmarshal(dataAgeUrlOut, &dataAge) if dataAgeErr != nil { log.Println(dataAgeUrl, dataAgeErr) return } previousDayDosesAdministered, err := data.Result.Records[0].PreviousDayDosesAdministered.Float64() if err != nil { log.Println(err) } previousDayAtLeastOne, err := data.Result.Records[0].PreviousDayAtLeastOne.Float64() if err != nil { log.Println(err) } previousDayFullyVaccinated, err := data.Result.Records[0].PreviousDayFullyVaccinated.Float64() if err != nil { log.Println(err) } totalDosesAdministered, err := data.Result.Records[0].TotalDosesAdministered.Float64() if err != nil { log.Println(err) } totalDosesAtLeastOne, err := data.Result.Records[0].TotalDosesAtLeastOne.Float64() if err != nil { log.Println(err) } totalDosesInFullyVaccinatedIndividuals, err := data.Result.Records[0].TotalDosesInFullyVaccinatedIndividuals.Float64() if err != nil { log.Println(err) } totalIndividualsFullyVaccinated, err := data.Result.Records[0].TotalIndividualsFullyVaccinated.Float64() if err != nil { log.Println(err) } for _, record := range dataAge.Result.Records { atLeastOneDoseCumulative, err := record.AtLeastOneDoseCumulative.Float64() if err != nil { log.Println(err) } secondDoseCumulative, err := record.SecondDoseCumulative.Float64() if err != nil { log.Println(err) } totalPopulation, err := record.TotalPopulation.Float64() if err != nil { log.Println(err) } percentAtLeastOneDose, err := record.PercentAtLeastOneDose.Float64() if err != nil { log.Println(err) } percentFullyVaccinated, err := record.PercentFullyVaccinated.Float64() if err != nil { log.Println(err) } switch record.Agegroup { case "12-17yrs": { dataRecord.Age12To17yrs.AtLeastOneDoseCumulative().Set(atLeastOneDoseCumulative) dataRecord.Age12To17yrs.SecondDoseCumulative().Set(secondDoseCumulative) dataRecord.Age12To17yrs.TotalPopulation().Set(totalPopulation) dataRecord.Age12To17yrs.PercentAtLeastOneDose().Set(percentAtLeastOneDose) dataRecord.Age12To17yrs.PercentFullyVaccinated().Set(percentFullyVaccinated) eligiblePopulation += totalPopulation } case "18-29yrs": { dataRecord.Age18To29yrs.AtLeastOneDoseCumulative().Set(atLeastOneDoseCumulative) dataRecord.Age18To29yrs.SecondDoseCumulative().Set(secondDoseCumulative) dataRecord.Age18To29yrs.TotalPopulation().Set(totalPopulation) dataRecord.Age18To29yrs.PercentAtLeastOneDose().Set(percentAtLeastOneDose) dataRecord.Age18To29yrs.PercentFullyVaccinated().Set(percentFullyVaccinated) eligiblePopulation += totalPopulation } case "30-39yrs": { dataRecord.Age30To39yrs.AtLeastOneDoseCumulative().Set(atLeastOneDoseCumulative) dataRecord.Age30To39yrs.SecondDoseCumulative().Set(secondDoseCumulative) dataRecord.Age30To39yrs.TotalPopulation().Set(totalPopulation) dataRecord.Age30To39yrs.PercentAtLeastOneDose().Set(percentAtLeastOneDose) dataRecord.Age30To39yrs.PercentFullyVaccinated().Set(percentFullyVaccinated) eligiblePopulation += totalPopulation } case "40-49yrs": { dataRecord.Age40To49yrs.AtLeastOneDoseCumulative().Set(atLeastOneDoseCumulative) dataRecord.Age40To49yrs.SecondDoseCumulative().Set(secondDoseCumulative) dataRecord.Age40To49yrs.TotalPopulation().Set(totalPopulation) dataRecord.Age40To49yrs.PercentAtLeastOneDose().Set(percentAtLeastOneDose) dataRecord.Age40To49yrs.PercentFullyVaccinated().Set(percentFullyVaccinated) eligiblePopulation += totalPopulation } case "50-59yrs": { dataRecord.Age50To59yrs.AtLeastOneDoseCumulative().Set(atLeastOneDoseCumulative) dataRecord.Age50To59yrs.SecondDoseCumulative().Set(secondDoseCumulative) dataRecord.Age50To59yrs.TotalPopulation().Set(totalPopulation) dataRecord.Age50To59yrs.PercentAtLeastOneDose().Set(percentAtLeastOneDose) dataRecord.Age50To59yrs.PercentFullyVaccinated().Set(percentFullyVaccinated) eligiblePopulation += totalPopulation } case "60-69yrs": { dataRecord.Age60To69yrs.AtLeastOneDoseCumulative().Set(atLeastOneDoseCumulative) dataRecord.Age60To69yrs.SecondDoseCumulative().Set(secondDoseCumulative) dataRecord.Age60To69yrs.TotalPopulation().Set(totalPopulation) dataRecord.Age60To69yrs.PercentAtLeastOneDose().Set(percentAtLeastOneDose) dataRecord.Age60To69yrs.PercentFullyVaccinated().Set(percentFullyVaccinated) eligiblePopulation += totalPopulation } case "70-79yrs": { dataRecord.Age70To79yrs.AtLeastOneDoseCumulative().Set(atLeastOneDoseCumulative) dataRecord.Age70To79yrs.SecondDoseCumulative().Set(secondDoseCumulative) dataRecord.Age70To79yrs.TotalPopulation().Set(totalPopulation) dataRecord.Age70To79yrs.PercentAtLeastOneDose().Set(percentAtLeastOneDose) dataRecord.Age70To79yrs.PercentFullyVaccinated().Set(percentFullyVaccinated) eligiblePopulation += totalPopulation } case "80+": { dataRecord.Age80Plus.AtLeastOneDoseCumulative().Set(atLeastOneDoseCumulative) dataRecord.Age80Plus.SecondDoseCumulative().Set(secondDoseCumulative) dataRecord.Age80Plus.TotalPopulation().Set(totalPopulation) dataRecord.Age80Plus.PercentAtLeastOneDose().Set(percentAtLeastOneDose) dataRecord.Age80Plus.PercentFullyVaccinated().Set(percentFullyVaccinated) eligiblePopulation += totalPopulation } case "Adults_18plus": { dataRecord.AgeAdults18Plus.AtLeastOneDoseCumulative().Set(atLeastOneDoseCumulative) dataRecord.AgeAdults18Plus.SecondDoseCumulative().Set(secondDoseCumulative) dataRecord.AgeAdults18Plus.TotalPopulation().Set(totalPopulation) dataRecord.AgeAdults18Plus.PercentAtLeastOneDose().Set(percentAtLeastOneDose) dataRecord.AgeAdults18Plus.PercentFullyVaccinated().Set(percentFullyVaccinated) } case "Undisclosed_or_missing": { dataRecord.AgeUndisclosedOrMissing.AtLeastOneDoseCumulative().Set(atLeastOneDoseCumulative) dataRecord.AgeUndisclosedOrMissing.SecondDoseCumulative().Set(secondDoseCumulative) dataRecord.AgeUndisclosedOrMissing.TotalPopulation().Set(totalPopulation) dataRecord.AgeUndisclosedOrMissing.PercentAtLeastOneDose().Set(percentAtLeastOneDose) dataRecord.AgeUndisclosedOrMissing.PercentFullyVaccinated().Set(percentFullyVaccinated) eligiblePopulation += totalPopulation } default: { log.Println("Unknown Age Group: ", record.Agegroup) } } } dataRecord.PreviousDayDosesAdministered().Set(previousDayDosesAdministered) dataRecord.PreviousDayAtLeastOne().Set(previousDayAtLeastOne) dataRecord.PreviousDayFullyVaccinated().Set(previousDayFullyVaccinated) dataRecord.TotalDosesAdministered().Set(totalDosesAdministered) dataRecord.TotalDosesAtLeastOne().Set(totalDosesAtLeastOne) dataRecord.TotalDosesInFullyVaccinatedIndividuals().Set(totalDosesInFullyVaccinatedIndividuals) dataRecord.TotalIndividualsFullyVaccinated().Set(totalIndividualsFullyVaccinated) dataRecord.EligiblePopulation().Set(float64(eligiblePopulation)) } func main() { c := cron.New() c.AddFunc("@hourly", func() { updateMetrics() }) c.Start() updateMetrics() flag.Parse() http.Handle("/metrics", promhttp.Handler()) fmt.Println("Listening on port 8080") log.Fatal(http.ListenAndServe(*addr, nil)) }