-
Notifications
You must be signed in to change notification settings - Fork 4.9k
/
timeseries_metadata_collector.go
136 lines (110 loc) · 4.07 KB
/
timeseries_metadata_collector.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
136
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License;
// you may not use this file except in compliance with the Elastic License.
package gcp
import (
"context"
"fmt"
"strings"
"cloud.google.com/go/monitoring/apiv3/v2/monitoringpb"
"github.com/elastic/elastic-agent-libs/mapstr"
)
// NewStackdriverCollectorInputData returns a ready to use MetadataCollectorInputData to be sent to Metadata collectors
func NewStackdriverCollectorInputData(ts *monitoringpb.TimeSeries, projectID, zone string, region string, regions []string) *MetadataCollectorInputData {
return &MetadataCollectorInputData{
TimeSeries: ts,
ProjectID: projectID,
Zone: zone,
Region: region,
Regions: regions,
}
}
// NewStackdriverMetadataServiceForTimeSeries apart from having a long name takes a time series object to return the
// Stackdriver canonical Metadata extractor
func NewStackdriverMetadataServiceForTimeSeries(ts *monitoringpb.TimeSeries) MetadataService {
return &StackdriverTimeSeriesMetadataCollector{
timeSeries: ts,
}
}
// StackdriverTimeSeriesMetadataCollector is the implementation of MetadataCollector to collect metrics from Stackdriver
// common TimeSeries objects
type StackdriverTimeSeriesMetadataCollector struct {
timeSeries *monitoringpb.TimeSeries
}
// Metadata parses a Timeseries object to return its metadata divided into "unknown" (first object) and ECS (second
// object https://www.elastic.co/guide/en/ecs/master/index.html)
func (s *StackdriverTimeSeriesMetadataCollector) Metadata(ctx context.Context, in *monitoringpb.TimeSeries) (MetadataCollectorData, error) {
m := mapstr.M{}
var availabilityZone, accountID string
if in.Resource != nil && in.Resource.Labels != nil {
availabilityZone = in.Resource.Labels[TimeSeriesResponsePathForECSAvailabilityZone]
accountID = in.Resource.Labels[TimeSeriesResponsePathForECSAccountID]
}
ecs := mapstr.M{
ECSCloud: mapstr.M{
ECSCloudAccount: mapstr.M{
ECSCloudAccountID: accountID,
ECSCloudAccountName: accountID,
},
ECSCloudProvider: "gcp",
},
}
if availabilityZone != "" {
_, _ = ecs.Put(ECSCloud+"."+ECSCloudAvailabilityZone, availabilityZone)
// Get region name from availability zone name
region := getRegionName(availabilityZone)
if region != "" {
_, _ = ecs.Put(ECSCloud+"."+ECSCloudRegion, region)
}
}
//Remove keys from resource that refers to ECS fields
if s.timeSeries == nil {
return MetadataCollectorData{}, fmt.Errorf("no time series data found in google found response")
}
if s.timeSeries.Metric != nil {
metrics := make(map[string]interface{})
// common.Mapstr seems to not work as expected when deleting keys so I have to iterate over all results to add
// the ones I want
for k, v := range s.timeSeries.Metric.Labels {
if k == TimeSeriesResponsePathForECSInstanceName {
continue
}
metrics[k] = v
}
//Do not write metrics labels if it's content is empty
for k, v := range metrics {
_, _ = m.Put(LabelMetrics+"."+k, v)
}
}
if s.timeSeries.Resource != nil {
resources := make(map[string]interface{})
// common.Mapstr seems to not work as expected when deleting keys so I have to iterate over all results to add
// the ones I want
for k, v := range s.timeSeries.Resource.Labels {
if k == TimeSeriesResponsePathForECSAvailabilityZone || k == TimeSeriesResponsePathForECSInstanceID || k == TimeSeriesResponsePathForECSAccountID {
continue
}
resources[k] = v
}
//Do not write resources labels if it's content is empty
for k, v := range resources {
_, _ = m.Put(LabelResource+"."+k, v)
}
}
if s.timeSeries.Metadata != nil {
_, _ = m.Put(LabelSystem, s.timeSeries.Metadata.SystemLabels)
_, _ = m.Put(LabelUserMetadata, s.timeSeries.Metadata.UserLabels)
}
return MetadataCollectorData{
Labels: m,
ECS: ecs,
}, nil
}
func getRegionName(availabilityZone string) string {
azSplit := strings.Split(availabilityZone, "-")
if len(azSplit) != 3 {
return ""
}
region := azSplit[0] + "-" + azSplit[1]
return region
}