-
Notifications
You must be signed in to change notification settings - Fork 2
/
scrapper.go
133 lines (118 loc) · 4.83 KB
/
scrapper.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
package scrapper
import (
"errors"
"strings"
"github.com/prometheus/client_golang/prometheus"
"github.com/simelo/rextporter/src/client"
"github.com/simelo/rextporter/src/config"
"github.com/simelo/rextporter/src/util"
log "github.com/sirupsen/logrus"
)
// Scrapper get metrics from raw data
type Scrapper interface {
// GetMetric recive the metrics collector channel and should return the metric val
GetMetric(metricsCollector chan<- prometheus.Metric) (val interface{}, err error)
GetJobName() string
GetInstanceName() string
GetDataSource() string
}
// FordwaderScrapper get metrics from an already metrics endpoint
type FordwaderScrapper interface {
// GetMetric should return the metrics vals as raw string
GetMetric() (val interface{}, err error)
GetJobName() string
GetInstanceName() string
}
type baseScrapper struct {
jobName string
instanceName string
}
type baseAPIScrapper struct {
baseScrapper
dataSource string
clientFactory client.Factory
parser BodyParser
jsonPath string
}
type baseFordwaderScrapper struct {
baseScrapper
clientFactory client.FordwaderFactory
}
func (s baseScrapper) GetJobName() string {
return s.jobName
}
func (s baseScrapper) GetInstanceName() string {
return s.instanceName
}
func (s baseAPIScrapper) GetDataSource() string {
return s.dataSource
}
// BodyParser decode body from different formats, an get some data node
type BodyParser interface {
decodeBody(body []byte) (val interface{}, err error)
pathLookup(path string, val interface{}) (node interface{}, err error)
}
// NewScrapper will put all the required info to scrap metrics from the body returned by the client.
func NewScrapper(cf client.Factory, parser BodyParser, resConf config.RextResourceDef, srvConf config.RextServiceDef, mtrConf config.RextMetricDef, nSolver config.RextNodeSolver) (scrapper Scrapper, err error) {
dataSource := strings.TrimPrefix(resConf.GetResourcePATH(srvConf.GetBasePath()), srvConf.GetBasePath())
srvOpts := srvConf.GetOptions()
jobName, err := srvOpts.GetString(config.OptKeyRextServiceDefJobName)
if err != nil {
log.WithError(err).Errorln("Can not find jobName")
return scrapper, err
}
instanceName, err := srvOpts.GetString(config.OptKeyRextServiceDefInstanceName)
if err != nil {
log.WithError(err).Errorln("Can not find instanceName")
return scrapper, err
}
if len(mtrConf.GetLabels()) > 0 {
return createVecScrapper(cf, parser, jobName, instanceName, dataSource, nSolver, mtrConf)
}
return createAtomicScrapper(cf, parser, jobName, instanceName, dataSource, mtrConf, nSolver)
}
func createVecScrapper(cf client.Factory, parser BodyParser, jobName, instanceName, dataSource string, nSolver config.RextNodeSolver, mtrConf config.RextMetricDef) (scrapper Scrapper, err error) {
if mtrConf.GetMetricType() == config.KeyMetricTypeCounter || mtrConf.GetMetricType() == config.KeyMetricTypeGauge {
return newNumericVec(cf, parser, jobName, instanceName, dataSource, nSolver, mtrConf), nil
}
log.WithError(errors.New("histogram vec and summary vec are not supported yet")).Errorln("invalid operation")
return NumericVec{}, config.ErrKeyNotSupported
}
func createAtomicScrapper(cf client.Factory, parser BodyParser, jobName, instanceName, dataSource string, mtrConf config.RextMetricDef, nSolver config.RextNodeSolver) (scrapper Scrapper, err error) {
if mtrConf.GetMetricType() == config.KeyMetricTypeSummary {
log.WithError(errors.New("summary scrapper is not supported yet")).Errorln("invalid operation")
return Histogram{}, config.ErrKeyNotSupported
}
if mtrConf.GetMetricType() == config.KeyMetricTypeHistogram {
bObj, err := mtrConf.GetOptions().GetObject(config.OptKeyRextMetricDefHMetricBuckets)
if err != nil {
log.WithError(err).Errorln("no buckets definitions found")
return scrapper, err
}
buckets, okBuckets := bObj.([]float64)
if !okBuckets {
log.WithField("val", bObj).Errorln("value is not a float64 array(buckets)")
return scrapper, config.ErrKeyInvalidType
}
return newHistogram(cf, parser, jobName, instanceName, dataSource, nSolver.GetNodePath(), buckets), nil
}
return newNumeric(cf, parser, nSolver.GetNodePath(), jobName, instanceName, dataSource), nil
}
func getData(cf client.Factory, p BodyParser, metricsCollector chan<- prometheus.Metric) (data interface{}, err error) {
const generalScopeErr = "error getting data"
var cl client.Client
if cl, err = cf.CreateClient(); err != nil {
errCause := "can ot create client"
return data, util.ErrorFromThisScope(errCause, generalScopeErr)
}
var body []byte
if body, err = cl.GetData(metricsCollector); err != nil {
errCause := "client can not get data"
return data, util.ErrorFromThisScope(errCause, generalScopeErr)
}
if data, err = p.decodeBody(body); err != nil {
errCause := "scrapper can not decode the body"
return data, util.ErrorFromThisScope(errCause, generalScopeErr)
}
return data, err
}