-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathecdc.go
135 lines (118 loc) · 3.77 KB
/
ecdc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package main
import (
"errors"
"fmt"
"net/http"
"strings"
"time"
"unicode"
"github.com/PuerkitoBio/goquery"
)
type ecdcExporter struct {
Url string
Mp *metadataProvider
}
type ecdcStat struct {
CovidStat
continent string
}
func newEcdcExporter(lp *metadataProvider) *ecdcExporter {
return &ecdcExporter{Url: "https://www.ecdc.europa.eu/en/geographical-distribution-2019-ncov-cases", Mp: lp}
}
//GetMetrics parses the ECDC table
func (e *ecdcExporter) GetMetrics() (metrics, error) {
stats, err := getEcdcStat(e.Url)
if err != nil {
return nil, err
}
result := make([]metric, 0)
for i := range stats {
tags := e.getTags(stats, i)
deaths := stats[i].deaths
infected := stats[i].infected
population := e.Mp.getPopulation(stats[i].location)
if deaths > 0 {
result = append(result, metric{Name: "cov19_world_death", Value: float64(deaths), Tags: &tags})
if population > 0 {
result = append(result, metric{Name: "cov19_world_fatality_rate", Value: fatalityRate(infected, deaths), Tags: &tags})
}
}
result = append(result, metric{Name: "cov19_world_infected", Value: float64(infected), Tags: &tags})
if population > 0 {
result = append(result, metric{Name: "cov19_world_infection_rate", Value: infectionRate(infected, population), Tags: &tags})
result = append(result, metric{Name: "cov19_world_infected_per_100k", Value: infection100k(infected, population), Tags: &tags})
}
}
return result, nil
}
//Health checks the functionality of the exporter
func (e *ecdcExporter) Health() []error {
errors := make([]error, 0)
worldStats, _ := e.GetMetrics()
if len(worldStats) < 200 {
errors = append(errors, fmt.Errorf("World stats are failing"))
}
for _, m := range worldStats {
country := (*m.Tags)["country"]
if mp.getLocation(country) == nil {
errors = append(errors, fmt.Errorf("Could not find location for country: %s", country))
}
}
return errors
}
func normalizeCountryName(name string) string {
name = strings.TrimSpace(name)
parts := strings.FieldsFunc(name, func(r rune) bool { return r == ' ' || r == '_' })
for i, part := range parts {
if strings.ToUpper(part) == "AND" || strings.ToUpper(part) == "OF" {
parts[i] = strings.ToLower(part)
} else {
runes := []rune(part)
parts[i] = string(unicode.ToUpper(runes[0])) + strings.ToLower(string(runes[1:]))
}
}
return strings.Join(parts, " ")
}
func (e *ecdcExporter) getTags(stats []ecdcStat, i int) map[string]string {
var tags map[string]string
if e.Mp != nil && e.Mp.getLocation(stats[i].location) != nil {
location := e.Mp.getLocation(stats[i].location)
tags = map[string]string{"country": stats[i].location, "continent": stats[i].continent, "latitude": ftos(location.lat), "longitude": ftos(location.long)}
} else {
tags = map[string]string{"country": stats[i].location, "continent": stats[i].continent}
}
return tags
}
func getEcdcStat(url string) ([]ecdcStat, error) {
client := http.Client{Timeout: 3 * time.Second}
response, err := client.Get(url)
if err != nil {
return nil, err
}
defer response.Body.Close()
document, _ := goquery.NewDocumentFromReader(response.Body)
rows := document.Find("table").Find("tbody").Find("tr")
if rows.Size() == 0 {
return nil, errors.New("Could not find table")
}
result := make([]ecdcStat, 0)
rows.Each(func(i int, s *goquery.Selection) {
if i < rows.Size()-1 {
rowStart := s.Find("td").First()
location := normalizeCountryName(rowStart.Next().Text())
infections := atoi(rowStart.Next().Next().Text())
deaths := atoi(rowStart.Next().Next().Next().Text())
if (infections > 0 || deaths > 0) && location != "Other" {
result = append(result, ecdcStat{
CovidStat{
location: location,
infected: infections,
deaths: deaths,
},
rowStart.Text(),
})
}
}
})
return result, nil
}