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