master
go 1,494 lines 53.8 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package weblog
4
5 import (
6 "bytes"
7 "context"
8 "fmt"
9 "os"
10 "reflect"
11 "strconv"
12 "strings"
13 "testing"
14
15 "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/collecttest"
16 "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/logs"
17 "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/oldmetrix"
18
19 "github.com/stretchr/testify/assert"
20 "github.com/stretchr/testify/require"
21 )
22
23 var (
24 dataConfigJSON, _ = os.ReadFile("testdata/config.json")
25 dataConfigYAML, _ = os.ReadFile("testdata/config.yaml")
26
27 dataCommonLog, _ = os.ReadFile("testdata/common.log")
28 dataFullLog, _ = os.ReadFile("testdata/full.log")
29 dataCustomLog, _ = os.ReadFile("testdata/custom.log")
30 dataCustomTimeFieldLog, _ = os.ReadFile("testdata/custom_time_fields.log")
31 dataIISLog, _ = os.ReadFile("testdata/u_ex221107.log")
32 )
33
34 func Test_testDataIsValid(t *testing.T) {
35 for name, data := range map[string][]byte{
36 "dataConfigJSON": dataConfigJSON,
37 "dataConfigYAML": dataConfigYAML,
38 "dataCommonLog": dataCommonLog,
39 "dataFullLog": dataFullLog,
40 "dataCustomLog": dataCustomLog,
41 "dataCustomTimeFieldLog": dataCustomTimeFieldLog,
42 "dataIISLog": dataIISLog,
43 } {
44 require.NotNil(t, data, name)
45 }
46 }
47
48 func TestCollector_ConfigurationSerialize(t *testing.T) {
49 collecttest.TestConfigurationSerialize(t, &Collector{}, dataConfigJSON, dataConfigYAML)
50 }
51
52 func TestCollector_Init(t *testing.T) {
53 collr := New()
54
55 assert.NoError(t, collr.Init(context.Background()))
56 }
57
58 func TestCollector_Init_ErrorOnCreatingURLPatterns(t *testing.T) {
59 collr := New()
60 collr.URLPatterns = []userPattern{{Match: "* !*"}}
61
62 assert.Error(t, collr.Init(context.Background()))
63 }
64
65 func TestCollector_Init_ErrorOnCreatingCustomFields(t *testing.T) {
66 collr := New()
67 collr.CustomFields = []customField{{Patterns: []userPattern{{Name: "p1", Match: "* !*"}}}}
68
69 assert.Error(t, collr.Init(context.Background()))
70 }
71
72 func TestCollector_Check(t *testing.T) {
73 collr := New()
74 defer collr.Cleanup(context.Background())
75 collr.Path = "testdata/common.log"
76 require.NoError(t, collr.Init(context.Background()))
77
78 assert.NoError(t, collr.Check(context.Background()))
79 }
80
81 func TestCollector_Check_ErrorOnCreatingLogReaderNoLogFile(t *testing.T) {
82 collr := New()
83 defer collr.Cleanup(context.Background())
84 collr.Path = "testdata/not_exists.log"
85 require.NoError(t, collr.Init(context.Background()))
86
87 assert.Error(t, collr.Check(context.Background()))
88 }
89
90 func TestCollector_Check_ErrorOnCreatingParserUnknownFormat(t *testing.T) {
91 collr := New()
92 defer collr.Cleanup(context.Background())
93 collr.Path = "testdata/custom.log"
94 require.NoError(t, collr.Init(context.Background()))
95
96 assert.Error(t, collr.Check(context.Background()))
97 }
98
99 func TestCollector_Check_ErrorOnCreatingParserEmptyLine(t *testing.T) {
100 collr := New()
101 defer collr.Cleanup(context.Background())
102 collr.Path = "testdata/custom.log"
103 collr.ParserConfig.LogType = logs.TypeCSV
104 collr.ParserConfig.CSV.Format = "$one $two"
105 require.NoError(t, collr.Init(context.Background()))
106
107 assert.Error(t, collr.Check(context.Background()))
108 }
109
110 func TestCollector_Charts(t *testing.T) {
111 collr := New()
112 defer collr.Cleanup(context.Background())
113 collr.Path = "testdata/common.log"
114 require.NoError(t, collr.Init(context.Background()))
115 require.NoError(t, collr.Check(context.Background()))
116
117 assert.NotNil(t, collr.Charts())
118 }
119
120 func TestCollector_Cleanup(t *testing.T) {
121 New().Cleanup(context.Background())
122 }
123
124 func TestCollector_Collect(t *testing.T) {
125 collr := prepareWebLogCollectFull(t)
126
127 //mx := collr.Collect()
128 //l := make([]string, 0)
129 //for k := range mx {
130 // l = append(l, k)
131 //}
132 //sort.Strings(l)
133 //for _, value := range l {
134 // fmt.Println(fmt.Sprintf("\"%s\": %d,", value, mx[value]))
135 //}
136
137 expected := map[string]int64{
138 "bytes_received": 1374096,
139 "bytes_sent": 1373185,
140 "custom_field_drink_beer": 221,
141 "custom_field_drink_wine": 231,
142 "custom_field_side_dark": 231,
143 "custom_field_side_light": 221,
144 "custom_time_field_random_time_field_time_avg": 230,
145 "custom_time_field_random_time_field_time_count": 452,
146 "custom_time_field_random_time_field_time_hist_bucket_1": 452,
147 "custom_time_field_random_time_field_time_hist_bucket_10": 452,
148 "custom_time_field_random_time_field_time_hist_bucket_11": 452,
149 "custom_time_field_random_time_field_time_hist_bucket_2": 452,
150 "custom_time_field_random_time_field_time_hist_bucket_3": 452,
151 "custom_time_field_random_time_field_time_hist_bucket_4": 452,
152 "custom_time_field_random_time_field_time_hist_bucket_5": 452,
153 "custom_time_field_random_time_field_time_hist_bucket_6": 452,
154 "custom_time_field_random_time_field_time_hist_bucket_7": 452,
155 "custom_time_field_random_time_field_time_hist_bucket_8": 452,
156 "custom_time_field_random_time_field_time_hist_bucket_9": 452,
157 "custom_time_field_random_time_field_time_hist_count": 452,
158 "custom_time_field_random_time_field_time_hist_sum": 103960,
159 "custom_time_field_random_time_field_time_max": 230,
160 "custom_time_field_random_time_field_time_min": 230,
161 "custom_time_field_random_time_field_time_sum": 103960,
162 "req_http_scheme": 218,
163 "req_https_scheme": 234,
164 "req_ipv4": 275,
165 "req_ipv6": 177,
166 "req_method_GET": 156,
167 "req_method_HEAD": 150,
168 "req_method_POST": 146,
169 "req_port_80": 96,
170 "req_port_81": 100,
171 "req_port_82": 84,
172 "req_port_83": 85,
173 "req_port_84": 87,
174 "req_proc_time_avg": 244,
175 "req_proc_time_count": 402,
176 "req_proc_time_hist_bucket_1": 402,
177 "req_proc_time_hist_bucket_10": 402,
178 "req_proc_time_hist_bucket_11": 402,
179 "req_proc_time_hist_bucket_2": 402,
180 "req_proc_time_hist_bucket_3": 402,
181 "req_proc_time_hist_bucket_4": 402,
182 "req_proc_time_hist_bucket_5": 402,
183 "req_proc_time_hist_bucket_6": 402,
184 "req_proc_time_hist_bucket_7": 402,
185 "req_proc_time_hist_bucket_8": 402,
186 "req_proc_time_hist_bucket_9": 402,
187 "req_proc_time_hist_count": 402,
188 "req_proc_time_hist_sum": 98312,
189 "req_proc_time_max": 497,
190 "req_proc_time_min": 2,
191 "req_proc_time_sum": 98312,
192 "req_ssl_cipher_suite_AES256-SHA": 101,
193 "req_ssl_cipher_suite_DHE-RSA-AES256-SHA": 111,
194 "req_ssl_cipher_suite_ECDHE-RSA-AES256-SHA": 127,
195 "req_ssl_cipher_suite_PSK-RC4-SHA": 113,
196 "req_ssl_proto_SSLv2": 74,
197 "req_ssl_proto_SSLv3": 57,
198 "req_ssl_proto_TLSv1": 76,
199 "req_ssl_proto_TLSv1.1": 87,
200 "req_ssl_proto_TLSv1.2": 73,
201 "req_ssl_proto_TLSv1.3": 85,
202 "req_type_bad": 49,
203 "req_type_error": 0,
204 "req_type_redirect": 119,
205 "req_type_success": 284,
206 "req_unmatched": 48,
207 "req_url_ptn_com": 120,
208 "req_url_ptn_net": 116,
209 "req_url_ptn_not_match": 0,
210 "req_url_ptn_org": 113,
211 "req_version_1.1": 168,
212 "req_version_2": 143,
213 "req_version_2.0": 141,
214 "req_vhost_198.51.100.1": 81,
215 "req_vhost_2001:db8:1ce::1": 100,
216 "req_vhost_localhost": 102,
217 "req_vhost_test.example.com": 87,
218 "req_vhost_test.example.org": 82,
219 "requests": 500,
220 "resp_1xx": 110,
221 "resp_2xx": 128,
222 "resp_3xx": 119,
223 "resp_4xx": 95,
224 "resp_5xx": 0,
225 "resp_code_100": 60,
226 "resp_code_101": 50,
227 "resp_code_200": 58,
228 "resp_code_201": 70,
229 "resp_code_300": 58,
230 "resp_code_301": 61,
231 "resp_code_400": 49,
232 "resp_code_401": 46,
233 "uniq_ipv4": 3,
234 "uniq_ipv6": 2,
235 "upstream_resp_time_avg": 255,
236 "upstream_resp_time_count": 452,
237 "upstream_resp_time_hist_bucket_1": 452,
238 "upstream_resp_time_hist_bucket_10": 452,
239 "upstream_resp_time_hist_bucket_11": 452,
240 "upstream_resp_time_hist_bucket_2": 452,
241 "upstream_resp_time_hist_bucket_3": 452,
242 "upstream_resp_time_hist_bucket_4": 452,
243 "upstream_resp_time_hist_bucket_5": 452,
244 "upstream_resp_time_hist_bucket_6": 452,
245 "upstream_resp_time_hist_bucket_7": 452,
246 "upstream_resp_time_hist_bucket_8": 452,
247 "upstream_resp_time_hist_bucket_9": 452,
248 "upstream_resp_time_hist_count": 452,
249 "upstream_resp_time_hist_sum": 115615,
250 "upstream_resp_time_max": 497,
251 "upstream_resp_time_min": 7,
252 "upstream_resp_time_sum": 115615,
253 "url_ptn_com_bytes_received": 379864,
254 "url_ptn_com_bytes_sent": 372669,
255 "url_ptn_com_req_method_GET": 38,
256 "url_ptn_com_req_method_HEAD": 39,
257 "url_ptn_com_req_method_POST": 43,
258 "url_ptn_com_req_proc_time_avg": 209,
259 "url_ptn_com_req_proc_time_count": 105,
260 "url_ptn_com_req_proc_time_max": 495,
261 "url_ptn_com_req_proc_time_min": 5,
262 "url_ptn_com_req_proc_time_sum": 22010,
263 "url_ptn_com_resp_code_100": 12,
264 "url_ptn_com_resp_code_101": 15,
265 "url_ptn_com_resp_code_200": 13,
266 "url_ptn_com_resp_code_201": 26,
267 "url_ptn_com_resp_code_300": 16,
268 "url_ptn_com_resp_code_301": 12,
269 "url_ptn_com_resp_code_400": 13,
270 "url_ptn_com_resp_code_401": 13,
271 "url_ptn_net_bytes_received": 349988,
272 "url_ptn_net_bytes_sent": 339867,
273 "url_ptn_net_req_method_GET": 51,
274 "url_ptn_net_req_method_HEAD": 33,
275 "url_ptn_net_req_method_POST": 32,
276 "url_ptn_net_req_proc_time_avg": 254,
277 "url_ptn_net_req_proc_time_count": 104,
278 "url_ptn_net_req_proc_time_max": 497,
279 "url_ptn_net_req_proc_time_min": 10,
280 "url_ptn_net_req_proc_time_sum": 26510,
281 "url_ptn_net_resp_code_100": 16,
282 "url_ptn_net_resp_code_101": 12,
283 "url_ptn_net_resp_code_200": 16,
284 "url_ptn_net_resp_code_201": 14,
285 "url_ptn_net_resp_code_300": 14,
286 "url_ptn_net_resp_code_301": 17,
287 "url_ptn_net_resp_code_400": 14,
288 "url_ptn_net_resp_code_401": 13,
289 "url_ptn_not_match_bytes_received": 0,
290 "url_ptn_not_match_bytes_sent": 0,
291 "url_ptn_not_match_req_proc_time_avg": 0,
292 "url_ptn_not_match_req_proc_time_count": 0,
293 "url_ptn_not_match_req_proc_time_max": 0,
294 "url_ptn_not_match_req_proc_time_min": 0,
295 "url_ptn_not_match_req_proc_time_sum": 0,
296 "url_ptn_org_bytes_received": 331836,
297 "url_ptn_org_bytes_sent": 340095,
298 "url_ptn_org_req_method_GET": 29,
299 "url_ptn_org_req_method_HEAD": 46,
300 "url_ptn_org_req_method_POST": 38,
301 "url_ptn_org_req_proc_time_avg": 260,
302 "url_ptn_org_req_proc_time_count": 102,
303 "url_ptn_org_req_proc_time_max": 497,
304 "url_ptn_org_req_proc_time_min": 2,
305 "url_ptn_org_req_proc_time_sum": 26599,
306 "url_ptn_org_resp_code_100": 15,
307 "url_ptn_org_resp_code_101": 11,
308 "url_ptn_org_resp_code_200": 20,
309 "url_ptn_org_resp_code_201": 16,
310 "url_ptn_org_resp_code_300": 10,
311 "url_ptn_org_resp_code_301": 19,
312 "url_ptn_org_resp_code_400": 13,
313 "url_ptn_org_resp_code_401": 9,
314 }
315
316 mx := collr.Collect(context.Background())
317 assert.Equal(t, expected, mx)
318 testCharts(t, collr, mx)
319 }
320
321 func TestCollector_Collect_CommonLogFormat(t *testing.T) {
322 collr := prepareWebLogCollectCommon(t)
323
324 expected := map[string]int64{
325 "bytes_received": 0,
326 "bytes_sent": 1388056,
327 "req_http_scheme": 0,
328 "req_https_scheme": 0,
329 "req_ipv4": 283,
330 "req_ipv6": 173,
331 "req_method_GET": 159,
332 "req_method_HEAD": 143,
333 "req_method_POST": 154,
334 "req_proc_time_avg": 0,
335 "req_proc_time_count": 0,
336 "req_proc_time_hist_bucket_1": 0,
337 "req_proc_time_hist_bucket_10": 0,
338 "req_proc_time_hist_bucket_11": 0,
339 "req_proc_time_hist_bucket_2": 0,
340 "req_proc_time_hist_bucket_3": 0,
341 "req_proc_time_hist_bucket_4": 0,
342 "req_proc_time_hist_bucket_5": 0,
343 "req_proc_time_hist_bucket_6": 0,
344 "req_proc_time_hist_bucket_7": 0,
345 "req_proc_time_hist_bucket_8": 0,
346 "req_proc_time_hist_bucket_9": 0,
347 "req_proc_time_hist_count": 0,
348 "req_proc_time_hist_sum": 0,
349 "req_proc_time_max": 0,
350 "req_proc_time_min": 0,
351 "req_proc_time_sum": 0,
352 "req_type_bad": 54,
353 "req_type_error": 0,
354 "req_type_redirect": 122,
355 "req_type_success": 280,
356 "req_unmatched": 44,
357 "req_version_1.1": 155,
358 "req_version_2": 147,
359 "req_version_2.0": 154,
360 "requests": 500,
361 "resp_1xx": 130,
362 "resp_2xx": 100,
363 "resp_3xx": 122,
364 "resp_4xx": 104,
365 "resp_5xx": 0,
366 "resp_code_100": 80,
367 "resp_code_101": 50,
368 "resp_code_200": 43,
369 "resp_code_201": 57,
370 "resp_code_300": 70,
371 "resp_code_301": 52,
372 "resp_code_400": 54,
373 "resp_code_401": 50,
374 "uniq_ipv4": 3,
375 "uniq_ipv6": 2,
376 "upstream_resp_time_avg": 0,
377 "upstream_resp_time_count": 0,
378 "upstream_resp_time_hist_bucket_1": 0,
379 "upstream_resp_time_hist_bucket_10": 0,
380 "upstream_resp_time_hist_bucket_11": 0,
381 "upstream_resp_time_hist_bucket_2": 0,
382 "upstream_resp_time_hist_bucket_3": 0,
383 "upstream_resp_time_hist_bucket_4": 0,
384 "upstream_resp_time_hist_bucket_5": 0,
385 "upstream_resp_time_hist_bucket_6": 0,
386 "upstream_resp_time_hist_bucket_7": 0,
387 "upstream_resp_time_hist_bucket_8": 0,
388 "upstream_resp_time_hist_bucket_9": 0,
389 "upstream_resp_time_hist_count": 0,
390 "upstream_resp_time_hist_sum": 0,
391 "upstream_resp_time_max": 0,
392 "upstream_resp_time_min": 0,
393 "upstream_resp_time_sum": 0,
394 }
395
396 mx := collr.Collect(context.Background())
397 assert.Equal(t, expected, mx)
398 testCharts(t, collr, mx)
399 }
400
401 func TestCollector_Collect_CustomLogs(t *testing.T) {
402 collr := prepareWebLogCollectCustom(t)
403
404 expected := map[string]int64{
405 "bytes_received": 0,
406 "bytes_sent": 0,
407 "custom_field_drink_beer": 52,
408 "custom_field_drink_wine": 40,
409 "custom_field_side_dark": 46,
410 "custom_field_side_light": 46,
411 "req_http_scheme": 0,
412 "req_https_scheme": 0,
413 "req_ipv4": 0,
414 "req_ipv6": 0,
415 "req_proc_time_avg": 0,
416 "req_proc_time_count": 0,
417 "req_proc_time_hist_bucket_1": 0,
418 "req_proc_time_hist_bucket_10": 0,
419 "req_proc_time_hist_bucket_11": 0,
420 "req_proc_time_hist_bucket_2": 0,
421 "req_proc_time_hist_bucket_3": 0,
422 "req_proc_time_hist_bucket_4": 0,
423 "req_proc_time_hist_bucket_5": 0,
424 "req_proc_time_hist_bucket_6": 0,
425 "req_proc_time_hist_bucket_7": 0,
426 "req_proc_time_hist_bucket_8": 0,
427 "req_proc_time_hist_bucket_9": 0,
428 "req_proc_time_hist_count": 0,
429 "req_proc_time_hist_sum": 0,
430 "req_proc_time_max": 0,
431 "req_proc_time_min": 0,
432 "req_proc_time_sum": 0,
433 "req_type_bad": 0,
434 "req_type_error": 0,
435 "req_type_redirect": 0,
436 "req_type_success": 0,
437 "req_unmatched": 8,
438 "requests": 100,
439 "resp_1xx": 0,
440 "resp_2xx": 0,
441 "resp_3xx": 0,
442 "resp_4xx": 0,
443 "resp_5xx": 0,
444 "uniq_ipv4": 0,
445 "uniq_ipv6": 0,
446 "upstream_resp_time_avg": 0,
447 "upstream_resp_time_count": 0,
448 "upstream_resp_time_hist_bucket_1": 0,
449 "upstream_resp_time_hist_bucket_10": 0,
450 "upstream_resp_time_hist_bucket_11": 0,
451 "upstream_resp_time_hist_bucket_2": 0,
452 "upstream_resp_time_hist_bucket_3": 0,
453 "upstream_resp_time_hist_bucket_4": 0,
454 "upstream_resp_time_hist_bucket_5": 0,
455 "upstream_resp_time_hist_bucket_6": 0,
456 "upstream_resp_time_hist_bucket_7": 0,
457 "upstream_resp_time_hist_bucket_8": 0,
458 "upstream_resp_time_hist_bucket_9": 0,
459 "upstream_resp_time_hist_count": 0,
460 "upstream_resp_time_hist_sum": 0,
461 "upstream_resp_time_max": 0,
462 "upstream_resp_time_min": 0,
463 "upstream_resp_time_sum": 0,
464 }
465
466 mx := collr.Collect(context.Background())
467 assert.Equal(t, expected, mx)
468 testCharts(t, collr, mx)
469 }
470
471 func TestCollector_Collect_CustomTimeFieldsLogs(t *testing.T) {
472 collr := prepareWebLogCollectCustomTimeFields(t)
473
474 expected := map[string]int64{
475 "bytes_received": 0,
476 "bytes_sent": 0,
477 "custom_time_field_time1_time_avg": 224,
478 "custom_time_field_time1_time_count": 72,
479 "custom_time_field_time1_time_hist_bucket_1": 72,
480 "custom_time_field_time1_time_hist_bucket_10": 72,
481 "custom_time_field_time1_time_hist_bucket_11": 72,
482 "custom_time_field_time1_time_hist_bucket_2": 72,
483 "custom_time_field_time1_time_hist_bucket_3": 72,
484 "custom_time_field_time1_time_hist_bucket_4": 72,
485 "custom_time_field_time1_time_hist_bucket_5": 72,
486 "custom_time_field_time1_time_hist_bucket_6": 72,
487 "custom_time_field_time1_time_hist_bucket_7": 72,
488 "custom_time_field_time1_time_hist_bucket_8": 72,
489 "custom_time_field_time1_time_hist_bucket_9": 72,
490 "custom_time_field_time1_time_hist_count": 72,
491 "custom_time_field_time1_time_hist_sum": 16152,
492 "custom_time_field_time1_time_max": 431,
493 "custom_time_field_time1_time_min": 121,
494 "custom_time_field_time1_time_sum": 16152,
495 "custom_time_field_time2_time_avg": 255,
496 "custom_time_field_time2_time_count": 72,
497 "custom_time_field_time2_time_hist_bucket_1": 72,
498 "custom_time_field_time2_time_hist_bucket_10": 72,
499 "custom_time_field_time2_time_hist_bucket_11": 72,
500 "custom_time_field_time2_time_hist_bucket_2": 72,
501 "custom_time_field_time2_time_hist_bucket_3": 72,
502 "custom_time_field_time2_time_hist_bucket_4": 72,
503 "custom_time_field_time2_time_hist_bucket_5": 72,
504 "custom_time_field_time2_time_hist_bucket_6": 72,
505 "custom_time_field_time2_time_hist_bucket_7": 72,
506 "custom_time_field_time2_time_hist_bucket_8": 72,
507 "custom_time_field_time2_time_hist_bucket_9": 72,
508 "custom_time_field_time2_time_hist_count": 72,
509 "custom_time_field_time2_time_hist_sum": 18360,
510 "custom_time_field_time2_time_max": 321,
511 "custom_time_field_time2_time_min": 123,
512 "custom_time_field_time2_time_sum": 18360,
513 "req_http_scheme": 0,
514 "req_https_scheme": 0,
515 "req_ipv4": 0,
516 "req_ipv6": 0,
517 "req_proc_time_avg": 0,
518 "req_proc_time_count": 0,
519 "req_proc_time_hist_bucket_1": 0,
520 "req_proc_time_hist_bucket_10": 0,
521 "req_proc_time_hist_bucket_11": 0,
522 "req_proc_time_hist_bucket_2": 0,
523 "req_proc_time_hist_bucket_3": 0,
524 "req_proc_time_hist_bucket_4": 0,
525 "req_proc_time_hist_bucket_5": 0,
526 "req_proc_time_hist_bucket_6": 0,
527 "req_proc_time_hist_bucket_7": 0,
528 "req_proc_time_hist_bucket_8": 0,
529 "req_proc_time_hist_bucket_9": 0,
530 "req_proc_time_hist_count": 0,
531 "req_proc_time_hist_sum": 0,
532 "req_proc_time_max": 0,
533 "req_proc_time_min": 0,
534 "req_proc_time_sum": 0,
535 "req_type_bad": 0,
536 "req_type_error": 0,
537 "req_type_redirect": 0,
538 "req_type_success": 0,
539 "req_unmatched": 0,
540 "requests": 72,
541 "resp_1xx": 0,
542 "resp_2xx": 0,
543 "resp_3xx": 0,
544 "resp_4xx": 0,
545 "resp_5xx": 0,
546 "uniq_ipv4": 0,
547 "uniq_ipv6": 0,
548 "upstream_resp_time_avg": 0,
549 "upstream_resp_time_count": 0,
550 "upstream_resp_time_hist_bucket_1": 0,
551 "upstream_resp_time_hist_bucket_10": 0,
552 "upstream_resp_time_hist_bucket_11": 0,
553 "upstream_resp_time_hist_bucket_2": 0,
554 "upstream_resp_time_hist_bucket_3": 0,
555 "upstream_resp_time_hist_bucket_4": 0,
556 "upstream_resp_time_hist_bucket_5": 0,
557 "upstream_resp_time_hist_bucket_6": 0,
558 "upstream_resp_time_hist_bucket_7": 0,
559 "upstream_resp_time_hist_bucket_8": 0,
560 "upstream_resp_time_hist_bucket_9": 0,
561 "upstream_resp_time_hist_count": 0,
562 "upstream_resp_time_hist_sum": 0,
563 "upstream_resp_time_max": 0,
564 "upstream_resp_time_min": 0,
565 "upstream_resp_time_sum": 0,
566 }
567
568 mx := collr.Collect(context.Background())
569 assert.Equal(t, expected, mx)
570 testCharts(t, collr, mx)
571 }
572
573 func TestCollector_Collect_CustomNumericFieldsLogs(t *testing.T) {
574 collr := prepareWebLogCollectCustomNumericFields(t)
575
576 expected := map[string]int64{
577 "bytes_received": 0,
578 "bytes_sent": 0,
579 "custom_numeric_field_numeric1_summary_avg": 224,
580 "custom_numeric_field_numeric1_summary_count": 72,
581 "custom_numeric_field_numeric1_summary_max": 431,
582 "custom_numeric_field_numeric1_summary_min": 121,
583 "custom_numeric_field_numeric1_summary_sum": 16152,
584 "custom_numeric_field_numeric2_summary_avg": 255,
585 "custom_numeric_field_numeric2_summary_count": 72,
586 "custom_numeric_field_numeric2_summary_max": 321,
587 "custom_numeric_field_numeric2_summary_min": 123,
588 "custom_numeric_field_numeric2_summary_sum": 18360,
589 "req_http_scheme": 0,
590 "req_https_scheme": 0,
591 "req_ipv4": 0,
592 "req_ipv6": 0,
593 "req_proc_time_avg": 0,
594 "req_proc_time_count": 0,
595 "req_proc_time_hist_bucket_1": 0,
596 "req_proc_time_hist_bucket_10": 0,
597 "req_proc_time_hist_bucket_11": 0,
598 "req_proc_time_hist_bucket_2": 0,
599 "req_proc_time_hist_bucket_3": 0,
600 "req_proc_time_hist_bucket_4": 0,
601 "req_proc_time_hist_bucket_5": 0,
602 "req_proc_time_hist_bucket_6": 0,
603 "req_proc_time_hist_bucket_7": 0,
604 "req_proc_time_hist_bucket_8": 0,
605 "req_proc_time_hist_bucket_9": 0,
606 "req_proc_time_hist_count": 0,
607 "req_proc_time_hist_sum": 0,
608 "req_proc_time_max": 0,
609 "req_proc_time_min": 0,
610 "req_proc_time_sum": 0,
611 "req_type_bad": 0,
612 "req_type_error": 0,
613 "req_type_redirect": 0,
614 "req_type_success": 0,
615 "req_unmatched": 0,
616 "requests": 72,
617 "resp_1xx": 0,
618 "resp_2xx": 0,
619 "resp_3xx": 0,
620 "resp_4xx": 0,
621 "resp_5xx": 0,
622 "uniq_ipv4": 0,
623 "uniq_ipv6": 0,
624 "upstream_resp_time_avg": 0,
625 "upstream_resp_time_count": 0,
626 "upstream_resp_time_hist_bucket_1": 0,
627 "upstream_resp_time_hist_bucket_10": 0,
628 "upstream_resp_time_hist_bucket_11": 0,
629 "upstream_resp_time_hist_bucket_2": 0,
630 "upstream_resp_time_hist_bucket_3": 0,
631 "upstream_resp_time_hist_bucket_4": 0,
632 "upstream_resp_time_hist_bucket_5": 0,
633 "upstream_resp_time_hist_bucket_6": 0,
634 "upstream_resp_time_hist_bucket_7": 0,
635 "upstream_resp_time_hist_bucket_8": 0,
636 "upstream_resp_time_hist_bucket_9": 0,
637 "upstream_resp_time_hist_count": 0,
638 "upstream_resp_time_hist_sum": 0,
639 "upstream_resp_time_max": 0,
640 "upstream_resp_time_min": 0,
641 "upstream_resp_time_sum": 0,
642 }
643
644 mx := collr.Collect(context.Background())
645
646 assert.Equal(t, expected, mx)
647 testCharts(t, collr, mx)
648 }
649
650 func TestCollector_IISLogs(t *testing.T) {
651 collr := prepareWebLogCollectIISFields(t)
652
653 expected := map[string]int64{
654 "bytes_received": 0,
655 "bytes_sent": 0,
656 "req_http_scheme": 0,
657 "req_https_scheme": 0,
658 "req_ipv4": 38,
659 "req_ipv6": 114,
660 "req_method_GET": 152,
661 "req_port_80": 152,
662 "req_proc_time_avg": 5,
663 "req_proc_time_count": 152,
664 "req_proc_time_hist_bucket_1": 133,
665 "req_proc_time_hist_bucket_10": 145,
666 "req_proc_time_hist_bucket_11": 146,
667 "req_proc_time_hist_bucket_2": 133,
668 "req_proc_time_hist_bucket_3": 133,
669 "req_proc_time_hist_bucket_4": 133,
670 "req_proc_time_hist_bucket_5": 133,
671 "req_proc_time_hist_bucket_6": 133,
672 "req_proc_time_hist_bucket_7": 133,
673 "req_proc_time_hist_bucket_8": 138,
674 "req_proc_time_hist_bucket_9": 143,
675 "req_proc_time_hist_count": 152,
676 "req_proc_time_hist_sum": 799,
677 "req_proc_time_max": 256,
678 "req_proc_time_min": 0,
679 "req_proc_time_sum": 799,
680 "req_type_bad": 42,
681 "req_type_error": 0,
682 "req_type_redirect": 0,
683 "req_type_success": 110,
684 "req_unmatched": 16,
685 "req_vhost_127.0.0.1": 38,
686 "req_vhost_::1": 114,
687 "requests": 168,
688 "resp_1xx": 0,
689 "resp_2xx": 99,
690 "resp_3xx": 11,
691 "resp_4xx": 42,
692 "resp_5xx": 0,
693 "resp_code_200": 99,
694 "resp_code_304": 11,
695 "resp_code_404": 42,
696 "uniq_ipv4": 1,
697 "uniq_ipv6": 1,
698 "upstream_resp_time_avg": 0,
699 "upstream_resp_time_count": 0,
700 "upstream_resp_time_hist_bucket_1": 0,
701 "upstream_resp_time_hist_bucket_10": 0,
702 "upstream_resp_time_hist_bucket_11": 0,
703 "upstream_resp_time_hist_bucket_2": 0,
704 "upstream_resp_time_hist_bucket_3": 0,
705 "upstream_resp_time_hist_bucket_4": 0,
706 "upstream_resp_time_hist_bucket_5": 0,
707 "upstream_resp_time_hist_bucket_6": 0,
708 "upstream_resp_time_hist_bucket_7": 0,
709 "upstream_resp_time_hist_bucket_8": 0,
710 "upstream_resp_time_hist_bucket_9": 0,
711 "upstream_resp_time_hist_count": 0,
712 "upstream_resp_time_hist_sum": 0,
713 "upstream_resp_time_max": 0,
714 "upstream_resp_time_min": 0,
715 "upstream_resp_time_sum": 0,
716 }
717
718 mx := collr.Collect(context.Background())
719 assert.Equal(t, expected, mx)
720 }
721
722 func testCharts(t *testing.T, c *Collector, mx map[string]int64) {
723 testVhostChart(t, c)
724 testPortChart(t, c)
725 testSchemeChart(t, c)
726 testClientCharts(t, c)
727 testHTTPMethodChart(t, c)
728 testURLPatternChart(t, c)
729 testHTTPVersionChart(t, c)
730 testRespCodeCharts(t, c)
731 testBandwidthChart(t, c)
732 testReqProcTimeCharts(t, c)
733 testUpsRespTimeCharts(t, c)
734 testSSLProtoChart(t, c)
735 testSSLCipherSuiteChart(t, c)
736 testURLPatternStatsCharts(t, c)
737 testCustomFieldCharts(t, c)
738 testCustomTimeFieldCharts(t, c)
739 testCustomNumericFieldCharts(t, c)
740
741 collecttest.TestMetricsHasAllChartsDims(t, c.Charts(), mx)
742 }
743
744 func testVhostChart(t *testing.T, c *Collector) {
745 if len(c.mx.ReqVhost) == 0 {
746 assert.Falsef(t, c.Charts().Has(reqByVhost.ID), "chart '%s' is created", reqByVhost.ID)
747 return
748 }
749
750 chart := c.Charts().Get(reqByVhost.ID)
751 assert.NotNilf(t, chart, "chart '%s' is not created", reqByVhost.ID)
752 if chart == nil {
753 return
754 }
755 for v := range c.mx.ReqVhost {
756 id := "req_vhost_" + v
757 assert.Truef(t, chart.HasDim(id), "chart '%s' has no dim for '%s' vhost, expected '%s'", chart.ID, v, id)
758 }
759 }
760
761 func testPortChart(t *testing.T, c *Collector) {
762 if len(c.mx.ReqPort) == 0 {
763 assert.Falsef(t, c.Charts().Has(reqByPort.ID), "chart '%s' is created", reqByPort.ID)
764 return
765 }
766
767 chart := c.Charts().Get(reqByPort.ID)
768 assert.NotNilf(t, chart, "chart '%s' is not created", reqByPort.ID)
769 if chart == nil {
770 return
771 }
772 for v := range c.mx.ReqPort {
773 id := "req_port_" + v
774 assert.Truef(t, chart.HasDim(id), "chart '%s' has no dim for '%s' port, expected '%s'", chart.ID, v, id)
775 }
776 }
777
778 func testSchemeChart(t *testing.T, c *Collector) {
779 if c.mx.ReqHTTPScheme.Value() == 0 && c.mx.ReqHTTPSScheme.Value() == 0 {
780 assert.Falsef(t, c.Charts().Has(reqByScheme.ID), "chart '%s' is created", reqByScheme.ID)
781 } else {
782 assert.Truef(t, c.Charts().Has(reqByScheme.ID), "chart '%s' is not created", reqByScheme.ID)
783 }
784 }
785
786 func testClientCharts(t *testing.T, c *Collector) {
787 if c.mx.ReqIPv4.Value() == 0 && c.mx.ReqIPv6.Value() == 0 {
788 assert.Falsef(t, c.Charts().Has(reqByIPProto.ID), "chart '%s' is created", reqByIPProto.ID)
789 } else {
790 assert.Truef(t, c.Charts().Has(reqByIPProto.ID), "chart '%s' is not created", reqByIPProto.ID)
791 }
792
793 if c.mx.UniqueIPv4.Value() == 0 && c.mx.UniqueIPv6.Value() == 0 {
794 assert.Falsef(t, c.Charts().Has(uniqIPsCurPoll.ID), "chart '%s' is created", uniqIPsCurPoll.ID)
795 } else {
796 assert.Truef(t, c.Charts().Has(uniqIPsCurPoll.ID), "chart '%s' is not created", uniqIPsCurPoll.ID)
797 }
798 }
799
800 func testHTTPMethodChart(t *testing.T, c *Collector) {
801 if len(c.mx.ReqMethod) == 0 {
802 assert.Falsef(t, c.Charts().Has(reqByMethod.ID), "chart '%s' is created", reqByMethod.ID)
803 return
804 }
805
806 chart := c.Charts().Get(reqByMethod.ID)
807 assert.NotNilf(t, chart, "chart '%s' is not created", reqByMethod.ID)
808 if chart == nil {
809 return
810 }
811 for v := range c.mx.ReqMethod {
812 id := "req_method_" + v
813 assert.Truef(t, chart.HasDim(id), "chart '%s' has no dim for '%s' method, expected '%s'", chart.ID, v, id)
814 }
815 }
816
817 func testURLPatternChart(t *testing.T, c *Collector) {
818 if isEmptyCounterVec(c.mx.ReqURLPattern) {
819 assert.Falsef(t, c.Charts().Has(reqByURLPattern.ID), "chart '%s' is created", reqByURLPattern.ID)
820 return
821 }
822
823 chart := c.Charts().Get(reqByURLPattern.ID)
824 assert.NotNilf(t, chart, "chart '%s' is not created", reqByURLPattern.ID)
825 if chart == nil {
826 return
827 }
828 for v := range c.mx.ReqURLPattern {
829 id := "req_url_ptn_" + v
830 assert.True(t, chart.HasDim(id), "chart '%s' has no dim for '%s' pattern, expected '%s'", chart.ID, v, id)
831 }
832 }
833
834 func testHTTPVersionChart(t *testing.T, c *Collector) {
835 if len(c.mx.ReqVersion) == 0 {
836 assert.Falsef(t, c.Charts().Has(reqByVersion.ID), "chart '%s' is created", reqByVersion.ID)
837 return
838 }
839
840 chart := c.Charts().Get(reqByVersion.ID)
841 assert.NotNilf(t, chart, "chart '%s' is not created", reqByVersion.ID)
842 if chart == nil {
843 return
844 }
845 for v := range c.mx.ReqVersion {
846 id := "req_version_" + v
847 assert.Truef(t, chart.HasDim(id), "chart '%s' has no dim for '%s' version, expected '%s'", chart.ID, v, id)
848 }
849 }
850
851 func testRespCodeCharts(t *testing.T, c *Collector) {
852 if isEmptyCounterVec(c.mx.RespCode) {
853 for _, id := range []string{
854 respCodes.ID,
855 respCodes1xx.ID,
856 respCodes2xx.ID,
857 respCodes3xx.ID,
858 respCodes4xx.ID,
859 respCodes5xx.ID,
860 } {
861 assert.Falsef(t, c.Charts().Has(id), "chart '%s' is created", id)
862 }
863 return
864 }
865
866 if !c.GroupRespCodes {
867 chart := c.Charts().Get(respCodes.ID)
868 assert.NotNilf(t, chart, "chart '%s' is not created", respCodes.ID)
869 if chart == nil {
870 return
871 }
872 for v := range c.mx.RespCode {
873 id := "resp_code_" + v
874 assert.Truef(t, chart.HasDim(id), "chart '%s' has no dim for '%s' code, expected '%s'", chart.ID, v, id)
875 }
876 return
877 }
878
879 findCodes := func(class string) (codes []string) {
880 for v := range c.mx.RespCode {
881 if v[:1] == class {
882 codes = append(codes, v)
883 }
884 }
885 return codes
886 }
887
888 var n int
889 ids := []string{
890 respCodes1xx.ID,
891 respCodes2xx.ID,
892 respCodes3xx.ID,
893 respCodes4xx.ID,
894 respCodes5xx.ID,
895 }
896 for i, chartID := range ids {
897 class := strconv.Itoa(i + 1)
898 codes := findCodes(class)
899 n += len(codes)
900 chart := c.Charts().Get(chartID)
901 assert.NotNilf(t, chart, "chart '%s' is not created", chartID)
902 if chart == nil {
903 return
904 }
905 for _, v := range codes {
906 id := "resp_code_" + v
907 assert.Truef(t, chart.HasDim(id), "chart '%s' has no dim for '%s' code, expected '%s'", chartID, v, id)
908 }
909 }
910 assert.Equal(t, len(c.mx.RespCode), n)
911 }
912
913 func testBandwidthChart(t *testing.T, c *Collector) {
914 if c.mx.BytesSent.Value() == 0 && c.mx.BytesReceived.Value() == 0 {
915 assert.Falsef(t, c.Charts().Has(bandwidth.ID), "chart '%s' is created", bandwidth.ID)
916 } else {
917 assert.Truef(t, c.Charts().Has(bandwidth.ID), "chart '%s' is not created", bandwidth.ID)
918 }
919 }
920
921 func testReqProcTimeCharts(t *testing.T, c *Collector) {
922 if isEmptySummary(c.mx.ReqProcTime) {
923 assert.Falsef(t, c.Charts().Has(reqProcTime.ID), "chart '%s' is created", reqProcTime.ID)
924 } else {
925 assert.Truef(t, c.Charts().Has(reqProcTime.ID), "chart '%s' is not created", reqProcTime.ID)
926 }
927
928 if isEmptyHistogram(c.mx.ReqProcTimeHist) {
929 assert.Falsef(t, c.Charts().Has(reqProcTimeHist.ID), "chart '%s' is created", reqProcTimeHist.ID)
930 } else {
931 assert.Truef(t, c.Charts().Has(reqProcTimeHist.ID), "chart '%s' is not created", reqProcTimeHist.ID)
932 }
933 }
934
935 func testUpsRespTimeCharts(t *testing.T, c *Collector) {
936 if isEmptySummary(c.mx.UpsRespTime) {
937 assert.Falsef(t, c.Charts().Has(upsRespTime.ID), "chart '%s' is created", upsRespTime.ID)
938 } else {
939 assert.Truef(t, c.Charts().Has(upsRespTime.ID), "chart '%s' is not created", upsRespTime.ID)
940 }
941
942 if isEmptyHistogram(c.mx.UpsRespTimeHist) {
943 assert.Falsef(t, c.Charts().Has(upsRespTimeHist.ID), "chart '%s' is created", upsRespTimeHist.ID)
944 } else {
945 assert.Truef(t, c.Charts().Has(upsRespTimeHist.ID), "chart '%s' is not created", upsRespTimeHist.ID)
946 }
947 }
948
949 func testSSLProtoChart(t *testing.T, c *Collector) {
950 if len(c.mx.ReqSSLProto) == 0 {
951 assert.Falsef(t, c.Charts().Has(reqBySSLProto.ID), "chart '%s' is created", reqBySSLProto.ID)
952 return
953 }
954
955 chart := c.Charts().Get(reqBySSLProto.ID)
956 assert.NotNilf(t, chart, "chart '%s' is not created", reqBySSLProto.ID)
957 if chart == nil {
958 return
959 }
960 for v := range c.mx.ReqSSLProto {
961 id := "req_ssl_proto_" + v
962 assert.Truef(t, chart.HasDim(id), "chart '%s' has no dim for '%s' ssl proto, expected '%s'", chart.ID, v, id)
963 }
964 }
965
966 func testSSLCipherSuiteChart(t *testing.T, c *Collector) {
967 if len(c.mx.ReqSSLCipherSuite) == 0 {
968 assert.Falsef(t, c.Charts().Has(reqBySSLCipherSuite.ID), "chart '%s' is created", reqBySSLCipherSuite.ID)
969 return
970 }
971
972 chart := c.Charts().Get(reqBySSLCipherSuite.ID)
973 assert.NotNilf(t, chart, "chart '%s' is not created", reqBySSLCipherSuite.ID)
974 if chart == nil {
975 return
976 }
977 for v := range c.mx.ReqSSLCipherSuite {
978 id := "req_ssl_cipher_suite_" + v
979 assert.Truef(t, chart.HasDim(id), "chart '%s' has no dim for '%s' ssl cipher suite, expected '%s'", chart.ID, v, id)
980 }
981 }
982
983 func testURLPatternStatsCharts(t *testing.T, collr *Collector) {
984 for _, p := range collr.URLPatterns {
985 chartID := fmt.Sprintf(urlPatternRespCodes.ID, p.Name)
986
987 if isEmptyCounterVec(collr.mx.RespCode) {
988 assert.Falsef(t, collr.Charts().Has(chartID), "chart '%s' is created", chartID)
989 continue
990 }
991
992 chart := collr.Charts().Get(chartID)
993 assert.NotNilf(t, chart, "chart '%s' is not created", chartID)
994 if chart == nil {
995 continue
996 }
997
998 stats, ok := collr.mx.URLPatternStats[p.Name]
999 assert.Truef(t, ok, "url pattern '%s' has no metric in w.mx.URLPatternStats", p.Name)
1000 if !ok {
1001 continue
1002 }
1003 for v := range stats.RespCode {
1004 id := fmt.Sprintf("url_ptn_%s_resp_code_%s", p.Name, v)
1005 assert.Truef(t, chart.HasDim(id), "chart '%s' has no dim for '%s' code, expected '%s'", chartID, v, id)
1006 }
1007 }
1008
1009 for _, p := range collr.URLPatterns {
1010 id := fmt.Sprintf(urlPatternReqMethods.ID, p.Name)
1011 if isEmptyCounterVec(collr.mx.ReqMethod) {
1012 assert.Falsef(t, collr.Charts().Has(id), "chart '%s' is created", id)
1013 continue
1014 }
1015
1016 chart := collr.Charts().Get(id)
1017 assert.NotNilf(t, chart, "chart '%s' is not created", id)
1018 if chart == nil {
1019 continue
1020 }
1021
1022 stats, ok := collr.mx.URLPatternStats[p.Name]
1023 assert.Truef(t, ok, "url pattern '%s' has no metric in w.mx.URLPatternStats", p.Name)
1024 if !ok {
1025 continue
1026 }
1027 for v := range stats.ReqMethod {
1028 dimID := fmt.Sprintf("url_ptn_%s_req_method_%s", p.Name, v)
1029 assert.Truef(t, chart.HasDim(dimID), "chart '%s' has no dim for '%s' method, expected '%s'", id, v, dimID)
1030 }
1031 }
1032
1033 for _, p := range collr.URLPatterns {
1034 id := fmt.Sprintf(urlPatternBandwidth.ID, p.Name)
1035 if collr.mx.BytesSent.Value() == 0 && collr.mx.BytesReceived.Value() == 0 {
1036 assert.Falsef(t, collr.Charts().Has(id), "chart '%s' is created", id)
1037 } else {
1038 assert.Truef(t, collr.Charts().Has(id), "chart '%s' is not created", id)
1039 }
1040 }
1041
1042 for _, p := range collr.URLPatterns {
1043 id := fmt.Sprintf(urlPatternReqProcTime.ID, p.Name)
1044 if isEmptySummary(collr.mx.ReqProcTime) {
1045 assert.Falsef(t, collr.Charts().Has(id), "chart '%s' is created", id)
1046 } else {
1047 assert.Truef(t, collr.Charts().Has(id), "chart '%s' is not created", id)
1048 }
1049 }
1050 }
1051
1052 func testCustomFieldCharts(t *testing.T, c *Collector) {
1053 for _, cf := range c.CustomFields {
1054 id := fmt.Sprintf(reqByCustomFieldPattern.ID, cf.Name)
1055 chart := c.Charts().Get(id)
1056 assert.NotNilf(t, chart, "chart '%s' is not created", id)
1057 if chart == nil {
1058 continue
1059 }
1060
1061 for _, p := range cf.Patterns {
1062 id := fmt.Sprintf("custom_field_%s_%s", cf.Name, p.Name)
1063 assert.True(t, chart.HasDim(id), "chart '%s' has no dim for '%s' pattern, expected '%s'", chart.ID, p, id)
1064 }
1065 }
1066 }
1067
1068 func testCustomTimeFieldCharts(t *testing.T, c *Collector) {
1069 for _, cf := range c.CustomTimeFields {
1070 id := fmt.Sprintf(reqByCustomTimeField.ID, cf.Name)
1071 chart := c.Charts().Get(id)
1072 assert.NotNilf(t, chart, "chart '%s' is not created", id)
1073 if chart == nil {
1074 continue
1075 }
1076 dimMinID := fmt.Sprintf("custom_time_field_%s_time_min", cf.Name)
1077 assert.True(t, chart.HasDim(dimMinID), "chart '%s' has no dim for '%s' name, expected '%s'", chart.ID, cf.Name, dimMinID)
1078
1079 dimMaxID := fmt.Sprintf("custom_time_field_%s_time_min", cf.Name)
1080 assert.True(t, chart.HasDim(dimMaxID), "chart '%s' has no dim for '%s' name, expected '%s'", chart.ID, cf.Name, dimMaxID)
1081
1082 dimAveID := fmt.Sprintf("custom_time_field_%s_time_min", cf.Name)
1083 assert.True(t, chart.HasDim(dimAveID), "chart '%s' has no dim for '%s' name, expected '%s'", chart.ID, cf.Name, dimAveID)
1084 }
1085 }
1086
1087 func testCustomNumericFieldCharts(t *testing.T, c *Collector) {
1088 for _, cf := range c.CustomNumericFields {
1089 id := fmt.Sprintf(customNumericFieldSummaryChartTmpl.ID, cf.Name)
1090 chart := c.Charts().Get(id)
1091 assert.NotNilf(t, chart, "chart '%s' is not created", id)
1092 if chart == nil {
1093 continue
1094 }
1095 dimMinID := fmt.Sprintf("custom_numeric_field_%s_summary_min", cf.Name)
1096 assert.True(t, chart.HasDim(dimMinID), "chart '%s' has no dim for '%s' name, expected '%s'", chart.ID, cf.Name, dimMinID)
1097
1098 dimMaxID := fmt.Sprintf("custom_numeric_field_%s_summary_min", cf.Name)
1099 assert.True(t, chart.HasDim(dimMaxID), "chart '%s' has no dim for '%s' name, expected '%s'", chart.ID, cf.Name, dimMaxID)
1100
1101 dimAveID := fmt.Sprintf("custom_numeric_field_%s_summary_min", cf.Name)
1102 assert.True(t, chart.HasDim(dimAveID), "chart '%s' has no dim for '%s' name, expected '%s'", chart.ID, cf.Name, dimAveID)
1103 }
1104 }
1105
1106 var (
1107 emptySummary = newWebLogSummary()
1108 emptyHistogram = oldmetrix.NewHistogram(oldmetrix.DefBuckets)
1109 )
1110
1111 func isEmptySummary(s oldmetrix.Summary) bool { return reflect.DeepEqual(s, emptySummary) }
1112 func isEmptyHistogram(h oldmetrix.Histogram) bool { return reflect.DeepEqual(h, emptyHistogram) }
1113
1114 func isEmptyCounterVec(cv oldmetrix.CounterVec) bool {
1115 for _, c := range cv {
1116 if c.Value() > 0 {
1117 return false
1118 }
1119 }
1120 return true
1121 }
1122
1123 func prepareWebLogCollectFull(t *testing.T) *Collector {
1124 t.Helper()
1125 format := strings.Join([]string{
1126 "$host:$server_port",
1127 "$remote_addr",
1128 "-",
1129 "-",
1130 "$time_local",
1131 `"$request"`,
1132 "$status",
1133 "$body_bytes_sent",
1134 "$request_length",
1135 "$request_time",
1136 "$upstream_response_time",
1137 "$scheme",
1138 "$ssl_protocol",
1139 "$ssl_cipher",
1140 "$side",
1141 "$drink",
1142 "$random_time_field",
1143 }, " ")
1144
1145 cfg := Config{
1146 ParserConfig: logs.ParserConfig{
1147 LogType: logs.TypeCSV,
1148 CSV: logs.CSVConfig{
1149 FieldsPerRecord: -1,
1150 Delimiter: " ",
1151 TrimLeadingSpace: false,
1152 Format: format,
1153 CheckField: checkCSVFormatField,
1154 },
1155 },
1156 Path: "testdata/full.log",
1157 ExcludePath: "",
1158 URLPatterns: []userPattern{
1159 {Name: "com", Match: "~ com$"},
1160 {Name: "org", Match: "~ org$"},
1161 {Name: "net", Match: "~ net$"},
1162 {Name: "not_match", Match: "* !*"},
1163 },
1164 CustomFields: []customField{
1165 {
1166 Name: "side",
1167 Patterns: []userPattern{
1168 {Name: "dark", Match: "= dark"},
1169 {Name: "light", Match: "= light"},
1170 },
1171 },
1172 {
1173 Name: "drink",
1174 Patterns: []userPattern{
1175 {Name: "beer", Match: "= beer"},
1176 {Name: "wine", Match: "= wine"},
1177 },
1178 },
1179 },
1180 CustomTimeFields: []customTimeField{
1181 {
1182 Name: "random_time_field",
1183 Histogram: oldmetrix.DefBuckets,
1184 },
1185 },
1186 Histogram: oldmetrix.DefBuckets,
1187 GroupRespCodes: true,
1188 }
1189 collr := New()
1190 collr.Config = cfg
1191 require.NoError(t, collr.Init(context.Background()))
1192 require.NoError(t, collr.Check(context.Background()))
1193 defer collr.Cleanup(context.Background())
1194
1195 p, err := logs.NewCSVParser(collr.ParserConfig.CSV, bytes.NewReader(dataFullLog))
1196 require.NoError(t, err)
1197 collr.parser = p
1198 return collr
1199 }
1200
1201 func prepareWebLogCollectCommon(t *testing.T) *Collector {
1202 t.Helper()
1203 format := strings.Join([]string{
1204 "$remote_addr",
1205 "-",
1206 "-",
1207 "$time_local",
1208 `"$request"`,
1209 "$status",
1210 "$body_bytes_sent",
1211 }, " ")
1212
1213 cfg := Config{
1214 ParserConfig: logs.ParserConfig{
1215 LogType: logs.TypeCSV,
1216 CSV: logs.CSVConfig{
1217 FieldsPerRecord: -1,
1218 Delimiter: " ",
1219 TrimLeadingSpace: false,
1220 Format: format,
1221 CheckField: checkCSVFormatField,
1222 },
1223 },
1224 Path: "testdata/common.log",
1225 ExcludePath: "",
1226 URLPatterns: nil,
1227 CustomFields: nil,
1228 Histogram: nil,
1229 GroupRespCodes: false,
1230 }
1231
1232 collr := New()
1233 collr.Config = cfg
1234 require.NoError(t, collr.Init(context.Background()))
1235 require.NoError(t, collr.Check(context.Background()))
1236 defer collr.Cleanup(context.Background())
1237
1238 p, err := logs.NewCSVParser(collr.ParserConfig.CSV, bytes.NewReader(dataCommonLog))
1239 require.NoError(t, err)
1240 collr.parser = p
1241 return collr
1242 }
1243
1244 func prepareWebLogCollectCustom(t *testing.T) *Collector {
1245 t.Helper()
1246 format := strings.Join([]string{
1247 "$side",
1248 "$drink",
1249 }, " ")
1250
1251 cfg := Config{
1252 ParserConfig: logs.ParserConfig{
1253 LogType: logs.TypeCSV,
1254 CSV: logs.CSVConfig{
1255 FieldsPerRecord: 2,
1256 Delimiter: " ",
1257 TrimLeadingSpace: false,
1258 Format: format,
1259 CheckField: checkCSVFormatField,
1260 },
1261 },
1262 CustomFields: []customField{
1263 {
1264 Name: "side",
1265 Patterns: []userPattern{
1266 {Name: "dark", Match: "= dark"},
1267 {Name: "light", Match: "= light"},
1268 },
1269 },
1270 {
1271 Name: "drink",
1272 Patterns: []userPattern{
1273 {Name: "beer", Match: "= beer"},
1274 {Name: "wine", Match: "= wine"},
1275 },
1276 },
1277 },
1278 Path: "testdata/custom.log",
1279 ExcludePath: "",
1280 URLPatterns: nil,
1281 Histogram: nil,
1282 GroupRespCodes: false,
1283 }
1284 collr := New()
1285 collr.Config = cfg
1286 require.NoError(t, collr.Init(context.Background()))
1287 require.NoError(t, collr.Check(context.Background()))
1288 defer collr.Cleanup(context.Background())
1289
1290 p, err := logs.NewCSVParser(collr.ParserConfig.CSV, bytes.NewReader(dataCustomLog))
1291 require.NoError(t, err)
1292 collr.parser = p
1293 return collr
1294 }
1295
1296 func prepareWebLogCollectCustomTimeFields(t *testing.T) *Collector {
1297 t.Helper()
1298 format := strings.Join([]string{
1299 "$time1",
1300 "$time2",
1301 }, " ")
1302
1303 cfg := Config{
1304 ParserConfig: logs.ParserConfig{
1305 LogType: logs.TypeCSV,
1306 CSV: logs.CSVConfig{
1307 FieldsPerRecord: 2,
1308 Delimiter: " ",
1309 TrimLeadingSpace: false,
1310 Format: format,
1311 CheckField: checkCSVFormatField,
1312 },
1313 },
1314 CustomTimeFields: []customTimeField{
1315 {
1316 Name: "time1",
1317 Histogram: oldmetrix.DefBuckets,
1318 },
1319 {
1320 Name: "time2",
1321 Histogram: oldmetrix.DefBuckets,
1322 },
1323 },
1324 Path: "testdata/custom_time_fields.log",
1325 ExcludePath: "",
1326 URLPatterns: nil,
1327 Histogram: nil,
1328 GroupRespCodes: false,
1329 }
1330 collr := New()
1331 collr.Config = cfg
1332 require.NoError(t, collr.Init(context.Background()))
1333 require.NoError(t, collr.Check(context.Background()))
1334 defer collr.Cleanup(context.Background())
1335
1336 p, err := logs.NewCSVParser(collr.ParserConfig.CSV, bytes.NewReader(dataCustomTimeFieldLog))
1337 require.NoError(t, err)
1338 collr.parser = p
1339 return collr
1340 }
1341
1342 func prepareWebLogCollectCustomNumericFields(t *testing.T) *Collector {
1343 t.Helper()
1344 format := strings.Join([]string{
1345 "$numeric1",
1346 "$numeric2",
1347 }, " ")
1348
1349 cfg := Config{
1350 ParserConfig: logs.ParserConfig{
1351 LogType: logs.TypeCSV,
1352 CSV: logs.CSVConfig{
1353 FieldsPerRecord: 2,
1354 Delimiter: " ",
1355 TrimLeadingSpace: false,
1356 Format: format,
1357 CheckField: checkCSVFormatField,
1358 },
1359 },
1360 CustomNumericFields: []customNumericField{
1361 {
1362 Name: "numeric1",
1363 Units: "bytes",
1364 },
1365 {
1366 Name: "numeric2",
1367 Units: "requests",
1368 },
1369 },
1370 Path: "testdata/custom_time_fields.log",
1371 ExcludePath: "",
1372 URLPatterns: nil,
1373 Histogram: nil,
1374 GroupRespCodes: false,
1375 }
1376 collr := New()
1377 collr.Config = cfg
1378 require.NoError(t, collr.Init(context.Background()))
1379 require.NoError(t, collr.Check(context.Background()))
1380 defer collr.Cleanup(context.Background())
1381
1382 p, err := logs.NewCSVParser(collr.ParserConfig.CSV, bytes.NewReader(dataCustomTimeFieldLog))
1383 require.NoError(t, err)
1384 collr.parser = p
1385 return collr
1386 }
1387
1388 func prepareWebLogCollectIISFields(t *testing.T) *Collector {
1389 t.Helper()
1390 format := strings.Join([]string{
1391 "-", // date
1392 "-", // time
1393 "$host", // s-ip
1394 "$request_method", // cs-method
1395 "$request_uri", // cs-uri-stem
1396 "-", // cs-uri-query
1397 "$server_port", // s-port
1398 "-", // cs-username
1399 "$remote_addr", // c-ip
1400 "-", // cs(User-Agent)
1401 "-", // cs(Referer)
1402 "$status", // sc-status
1403 "-", // sc-substatus
1404 "-", // sc-win32-status
1405 "$request_time", // time-taken
1406 }, " ")
1407 cfg := Config{
1408 ParserConfig: logs.ParserConfig{
1409 LogType: logs.TypeCSV,
1410 CSV: logs.CSVConfig{
1411 // Users can define number of fields
1412 FieldsPerRecord: -1,
1413 Delimiter: " ",
1414 TrimLeadingSpace: false,
1415 Format: format,
1416 CheckField: checkCSVFormatField,
1417 },
1418 },
1419 Path: "testdata/u_ex221107.log",
1420 ExcludePath: "",
1421 URLPatterns: nil,
1422 Histogram: nil,
1423 GroupRespCodes: false,
1424 }
1425
1426 collr := New()
1427 collr.Config = cfg
1428 require.NoError(t, collr.Init(context.Background()))
1429 require.NoError(t, collr.Check(context.Background()))
1430 defer collr.Cleanup(context.Background())
1431
1432 p, err := logs.NewCSVParser(collr.ParserConfig.CSV, bytes.NewReader(dataIISLog))
1433 require.NoError(t, err)
1434 collr.parser = p
1435 return collr
1436 }
1437
1438 // generateLogs is used to populate 'testdata/full.log'
1439 //func generateLogs(w io.Writer, num int) error {
1440 // var (
1441 // vhost = []string{"localhost", "test.example.com", "test.example.org", "198.51.100.1", "2001:db8:1ce::1"}
1442 // scheme = []string{"http", "https"}
1443 // client = []string{"localhost", "203.0.113.1", "203.0.113.2", "2001:db8:2ce:1", "2001:db8:2ce:2"}
1444 // method = []string{"GET", "HEAD", "POST"}
1445 // url = []string{"example.other", "example.com", "example.org", "example.net"}
1446 // version = []string{"1.1", "2", "2.0"}
1447 // status = []int{100, 101, 200, 201, 300, 301, 400, 401} // no 5xx on purpose
1448 // sslProto = []string{"TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3", "SSLv2", "SSLv3"}
1449 // sslCipher = []string{"ECDHE-RSA-AES256-SHA", "DHE-RSA-AES256-SHA", "AES256-SHA", "PSK-RC4-SHA"}
1450 //
1451 // customField1 = []string{"dark", "light"}
1452 // customField2 = []string{"beer", "wine"}
1453 // )
1454 //
1455 // var line string
1456 // for i := 0; i < num; i++ {
1457 // unmatched := randInt(1, 100) > 90
1458 // if unmatched {
1459 // line = "Unmatched! The rat the cat the dog chased killed ate the malt!\n"
1460 // } else {
1461 // // test.example.com:80 203.0.113.1 - - "GET / HTTP/1.1" 200 1674 2674 3674 4674 http TLSv1 AES256-SHA dark beer
1462 // line = fmt.Sprintf(
1463 // "%s:%d %s - - [22/Mar/2009:09:30:31 +0100] \"%s /%s HTTP/%s\" %d %d %d %d %d %s %s %s %s %s\n",
1464 // randFromString(vhost),
1465 // randInt(80, 85),
1466 // randFromString(client),
1467 // randFromString(method),
1468 // randFromString(url),
1469 // randFromString(version),
1470 // randFromInt(status),
1471 // randInt(1000, 5000),
1472 // randInt(1000, 5000),
1473 // randInt(1, 500),
1474 // randInt(1, 500),
1475 // randFromString(scheme),
1476 // randFromString(sslProto),
1477 // randFromString(sslCipher),
1478 // randFromString(customField1),
1479 // randFromString(customField2),
1480 // )
1481 // }
1482 // _, err := fmt.Fprint(w, line)
1483 // if err != nil {
1484 // return err
1485 // }
1486 // }
1487 // return nil
1488 //}
1489 //
1490 //var r = rand.New(rand.NewSource(time.Now().UnixNano()))
1491 //
1492 //func randFromString(s []string) string { return s[r.Intn(len(s))] }
1493 //func randFromInt(s []int) int { return s[r.Intn(len(s))] }
1494 //func randInt(min, max int) int { return r.Intn(max-min) + min }