4
4
"context"
5
5
"encoding/json"
6
6
"fmt"
7
- operationalinsights "github.com/Azure/azure-sdk-for-go/services/operationalinsights/v1/operationalinsights"
8
- "github.com/Azure/go-autorest/autorest"
9
- "github.com/Azure/go-autorest/autorest/to"
10
7
"github.com/prometheus/client_golang/prometheus"
11
8
"github.com/prometheus/client_golang/prometheus/promhttp"
12
9
log "github.com/sirupsen/logrus"
@@ -15,11 +12,15 @@ import (
15
12
"time"
16
13
)
17
14
18
- const (
19
- OPINSIGHTS_URL_SUFFIX = "/v1"
20
- )
21
-
22
15
func handleProbeRequest (w http.ResponseWriter , r * http.Request ) {
16
+ defer func () {
17
+ if r := recover (); r != nil {
18
+ log .Errorf (fmt .Sprintf ("%v" , r ))
19
+ http .Error (w , fmt .Sprintf ("%v" , r ), http .StatusBadRequest )
20
+ return
21
+ }
22
+ }()
23
+
23
24
registry := prometheus .NewRegistry ()
24
25
25
26
requestTime := time .Now ()
@@ -42,11 +43,7 @@ func handleProbeRequest(w http.ResponseWriter, r *http.Request) {
42
43
}
43
44
44
45
ctx := context .Background ()
45
-
46
- // Create and authorize a operationalinsights client
47
- queryClient := operationalinsights .NewQueryClientWithBaseURI (AzureEnvironment .ResourceIdentifiers .OperationalInsights + OPINSIGHTS_URL_SUFFIX )
48
- queryClient .Authorizer = OpInsightsAuthorizer
49
- queryClient .ResponseInspector = respondDecorator ()
46
+ queryClient := NewLoganalyticsQueryClient ()
50
47
51
48
metricList := kusto.MetricList {}
52
49
metricList .Init ()
@@ -69,7 +66,9 @@ func handleProbeRequest(w http.ResponseWriter, r *http.Request) {
69
66
70
67
if executeQuery {
71
68
w .Header ().Add ("X-metrics-cached" , "false" )
72
- for _ , queryConfig := range Config .Queries {
69
+ for _ , queryRow := range Config .Queries {
70
+ queryConfig := queryRow
71
+
73
72
// check if query matches module name
74
73
if queryConfig .Module != moduleName {
75
74
continue
@@ -88,63 +87,46 @@ func handleProbeRequest(w http.ResponseWriter, r *http.Request) {
88
87
contextLogger .Debug ("starting query" )
89
88
90
89
resultTotalRecords := 0
91
- for _ , workspaceId := range opts .Loganalytics .Workspace {
92
- workspaceLogger := contextLogger .WithField ("workspaceId" , workspaceId )
93
-
94
- // Set options
95
- workspaces := []string {}
96
- queryBody := operationalinsights.QueryBody {
97
- Query : & queryConfig .Query ,
98
- Timespan : queryConfig .Timespan ,
99
- Workspaces : & workspaces ,
90
+
91
+ resultChannel := make (chan probeResult )
92
+ wgProbes := NewWaitGroupWithSize (r )
93
+ wgProcess := NewWaitGroup ()
94
+
95
+ // collect metrics
96
+ wgProcess .Add (1 )
97
+ go func () {
98
+ defer wgProcess .Done ()
99
+ for result := range resultChannel {
100
+ resultTotalRecords ++
101
+ metricList .Add (result .Name , result .Metrics ... )
100
102
}
103
+ }()
101
104
105
+ // query workspaces
106
+ for _ , row := range opts .Loganalytics .Workspace {
107
+ workspaceId := row
102
108
// Run the query and get the results
103
109
prometheusQueryRequests .With (prometheus.Labels {"workspace" : workspaceId , "module" : moduleName , "metric" : queryConfig .Metric }).Inc ()
104
110
105
- var results , queryErr = queryClient .Execute (ctx , workspaceId , queryBody )
106
- resultTotalRecords = 1
107
-
108
- if queryErr == nil {
109
- contextLogger .Debug ("parsing result" )
110
- resultTables := * results .Tables
111
-
112
- if len (resultTables ) >= 1 {
113
- for _ , table := range resultTables {
114
- if table .Rows == nil || table .Columns == nil {
115
- // no results found, skip table
116
- continue
117
- }
118
-
119
- for _ , v := range * table .Rows {
120
- resultTotalRecords ++
121
- resultRow := map [string ]interface {}{}
122
-
123
- for colNum , colName := range * resultTables [0 ].Columns {
124
- resultRow [to .String (colName .Name )] = v [colNum ]
125
- }
126
-
127
- for metricName , metric := range kusto .BuildPrometheusMetricList (queryConfig .Metric , queryConfig .MetricConfig , resultRow ) {
128
- // inject workspaceId
129
- for num := range metric {
130
- metric [num ].Labels ["workspaceTable" ] = to .String (table .Name )
131
- metric [num ].Labels ["workspaceID" ] = workspaceId
132
- }
133
-
134
- metricList .Add (metricName , metric ... )
135
- }
136
- }
137
- }
138
- }
139
-
140
- workspaceLogger .Debug ("metrics parsed" )
141
- } else {
142
- workspaceLogger .Errorln (queryErr .Error ())
143
- http .Error (w , queryErr .Error (), http .StatusBadRequest )
144
- return
145
- }
111
+ wgProbes .Add ()
112
+ go func () {
113
+ defer wgProbes .Done ()
114
+ SendQueryToLoganalyticsWorkspace (
115
+ ctx ,
116
+ contextLogger ,
117
+ workspaceId ,
118
+ queryClient ,
119
+ queryConfig ,
120
+ resultChannel ,
121
+ )
122
+ }()
146
123
}
147
124
125
+ // wait until queries are done for closing channel and waiting for result process
126
+ wgProbes .Wait ()
127
+ close (resultChannel )
128
+ wgProcess .Wait ()
129
+
148
130
elapsedTime := time .Since (startTime )
149
131
contextLogger .WithField ("results" , resultTotalRecords ).Debugf ("fetched %v results" , resultTotalRecords )
150
132
prometheusQueryTime .With (prometheus.Labels {"module" : moduleName , "metric" : queryConfig .Metric }).Observe (elapsedTime .Seconds ())
@@ -186,11 +168,3 @@ func handleProbeRequest(w http.ResponseWriter, r *http.Request) {
186
168
h := promhttp .HandlerFor (registry , promhttp.HandlerOpts {})
187
169
h .ServeHTTP (w , r )
188
170
}
189
-
190
- func respondDecorator () autorest.RespondDecorator {
191
- return func (p autorest.Responder ) autorest.Responder {
192
- return autorest .ResponderFunc (func (r * http.Response ) error {
193
- return nil
194
- })
195
- }
196
- }
0 commit comments