github.com/netdata/go.d.plugin@v0.58.1/modules/weblog/charts.go (about) 1 // SPDX-License-Identifier: GPL-3.0-or-later 2 3 package weblog 4 5 import ( 6 "errors" 7 "fmt" 8 9 "github.com/netdata/go.d.plugin/agent/module" 10 ) 11 12 type ( 13 Charts = module.Charts 14 Chart = module.Chart 15 Dims = module.Dims 16 Dim = module.Dim 17 ) 18 19 const ( 20 prioReqTotal = module.Priority + iota 21 prioReqExcluded 22 prioReqType 23 24 prioRespCodesClass 25 prioRespCodes 26 prioRespCodes1xx 27 prioRespCodes2xx 28 prioRespCodes3xx 29 prioRespCodes4xx 30 prioRespCodes5xx 31 32 prioBandwidth 33 34 prioReqProcTime 35 prioRespTimeHist 36 prioUpsRespTime 37 prioUpsRespTimeHist 38 39 prioUniqIP 40 41 prioReqVhost 42 prioReqPort 43 prioReqScheme 44 prioReqMethod 45 prioReqVersion 46 prioReqIPProto 47 prioReqSSLProto 48 prioReqSSLCipherSuite 49 50 prioReqCustomFieldPattern // chart per custom field, alphabetical order 51 prioReqCustomTimeField // chart per custom time field, alphabetical order 52 prioReqCustomTimeFieldHist // histogram chart per custom time field 53 prioReqURLPattern 54 prioURLPatternStats 55 56 prioReqCustomNumericFieldSummary // 3 charts per url pattern, alphabetical order 57 ) 58 59 // NOTE: inconsistency with python web_log 60 // TODO: current histogram charts are misleading in netdata 61 62 // Requests 63 var ( 64 reqTotal = Chart{ 65 ID: "requests", 66 Title: "Total Requests", 67 Units: "requests/s", 68 Fam: "requests", 69 Ctx: "web_log.requests", 70 Priority: prioReqTotal, 71 Dims: Dims{ 72 {ID: "requests", Algo: module.Incremental}, 73 }, 74 } 75 reqExcluded = Chart{ 76 ID: "excluded_requests", 77 Title: "Excluded Requests", 78 Units: "requests/s", 79 Fam: "requests", 80 Ctx: "web_log.excluded_requests", 81 Type: module.Stacked, 82 Priority: prioReqExcluded, 83 Dims: Dims{ 84 {ID: "req_unmatched", Name: "unmatched", Algo: module.Incremental}, 85 }, 86 } 87 // netdata specific grouping 88 reqTypes = Chart{ 89 ID: "requests_by_type", 90 Title: "Requests By Type", 91 Units: "requests/s", 92 Fam: "requests", 93 Ctx: "web_log.type_requests", 94 Type: module.Stacked, 95 Priority: prioReqType, 96 Dims: Dims{ 97 {ID: "req_type_success", Name: "success", Algo: module.Incremental}, 98 {ID: "req_type_bad", Name: "bad", Algo: module.Incremental}, 99 {ID: "req_type_redirect", Name: "redirect", Algo: module.Incremental}, 100 {ID: "req_type_error", Name: "error", Algo: module.Incremental}, 101 }, 102 } 103 ) 104 105 // Responses 106 var ( 107 respCodeClass = Chart{ 108 ID: "responses_by_status_code_class", 109 Title: "Responses By Status Code Class", 110 Units: "responses/s", 111 Fam: "responses", 112 Ctx: "web_log.status_code_class_responses", 113 Type: module.Stacked, 114 Priority: prioRespCodesClass, 115 Dims: Dims{ 116 {ID: "resp_2xx", Name: "2xx", Algo: module.Incremental}, 117 {ID: "resp_5xx", Name: "5xx", Algo: module.Incremental}, 118 {ID: "resp_3xx", Name: "3xx", Algo: module.Incremental}, 119 {ID: "resp_4xx", Name: "4xx", Algo: module.Incremental}, 120 {ID: "resp_1xx", Name: "1xx", Algo: module.Incremental}, 121 }, 122 } 123 respCodes = Chart{ 124 ID: "responses_by_status_code", 125 Title: "Responses By Status Code", 126 Units: "responses/s", 127 Fam: "responses", 128 Ctx: "web_log.status_code_responses", 129 Type: module.Stacked, 130 Priority: prioRespCodes, 131 } 132 respCodes1xx = Chart{ 133 ID: "status_code_class_1xx_responses", 134 Title: "Informational Responses By Status Code", 135 Units: "responses/s", 136 Fam: "responses", 137 Ctx: "web_log.status_code_class_1xx_responses", 138 Type: module.Stacked, 139 Priority: prioRespCodes1xx, 140 } 141 respCodes2xx = Chart{ 142 ID: "status_code_class_2xx_responses", 143 Title: "Successful Responses By Status Code", 144 Units: "responses/s", 145 Fam: "responses", 146 Ctx: "web_log.status_code_class_2xx_responses", 147 Type: module.Stacked, 148 Priority: prioRespCodes2xx, 149 } 150 respCodes3xx = Chart{ 151 ID: "status_code_class_3xx_responses", 152 Title: "Redirects Responses By Status Code", 153 Units: "responses/s", 154 Fam: "responses", 155 Ctx: "web_log.status_code_class_3xx_responses", 156 Type: module.Stacked, 157 Priority: prioRespCodes3xx, 158 } 159 respCodes4xx = Chart{ 160 ID: "status_code_class_4xx_responses", 161 Title: "Client Errors Responses By Status Code", 162 Units: "responses/s", 163 Fam: "responses", 164 Ctx: "web_log.status_code_class_4xx_responses", 165 Type: module.Stacked, 166 Priority: prioRespCodes4xx, 167 } 168 respCodes5xx = Chart{ 169 ID: "status_code_class_5xx_responses", 170 Title: "Server Errors Responses By Status Code", 171 Units: "responses/s", 172 Fam: "responses", 173 Ctx: "web_log.status_code_class_5xx_responses", 174 Type: module.Stacked, 175 Priority: prioRespCodes5xx, 176 } 177 ) 178 179 // Bandwidth 180 var ( 181 bandwidth = Chart{ 182 ID: "bandwidth", 183 Title: "Bandwidth", 184 Units: "kilobits/s", 185 Fam: "bandwidth", 186 Ctx: "web_log.bandwidth", 187 Type: module.Area, 188 Priority: prioBandwidth, 189 Dims: Dims{ 190 {ID: "bytes_received", Name: "received", Algo: module.Incremental, Mul: 8, Div: 1000}, 191 {ID: "bytes_sent", Name: "sent", Algo: module.Incremental, Mul: -8, Div: 1000}, 192 }, 193 } 194 ) 195 196 // Timings 197 var ( 198 reqProcTime = Chart{ 199 ID: "request_processing_time", 200 Title: "Request Processing Time", 201 Units: "milliseconds", 202 Fam: "timings", 203 Ctx: "web_log.request_processing_time", 204 Priority: prioReqProcTime, 205 Dims: Dims{ 206 {ID: "req_proc_time_min", Name: "min", Div: 1000}, 207 {ID: "req_proc_time_max", Name: "max", Div: 1000}, 208 {ID: "req_proc_time_avg", Name: "avg", Div: 1000}, 209 }, 210 } 211 reqProcTimeHist = Chart{ 212 ID: "requests_processing_time_histogram", 213 Title: "Requests Processing Time Histogram", 214 Units: "requests/s", 215 Fam: "timings", 216 Ctx: "web_log.requests_processing_time_histogram", 217 Priority: prioRespTimeHist, 218 } 219 ) 220 221 // Upstream 222 var ( 223 upsRespTime = Chart{ 224 ID: "upstream_response_time", 225 Title: "Upstream Response Time", 226 Units: "milliseconds", 227 Fam: "timings", 228 Ctx: "web_log.upstream_response_time", 229 Priority: prioUpsRespTime, 230 Dims: Dims{ 231 {ID: "upstream_resp_time_min", Name: "min", Div: 1000}, 232 {ID: "upstream_resp_time_max", Name: "max", Div: 1000}, 233 {ID: "upstream_resp_time_avg", Name: "avg", Div: 1000}, 234 }, 235 } 236 upsRespTimeHist = Chart{ 237 ID: "upstream_responses_time_histogram", 238 Title: "Upstream Responses Time Histogram", 239 Units: "responses/s", 240 Fam: "timings", 241 Ctx: "web_log.upstream_responses_time_histogram", 242 Priority: prioUpsRespTimeHist, 243 } 244 ) 245 246 // Clients 247 var ( 248 uniqIPsCurPoll = Chart{ 249 ID: "current_poll_uniq_clients", 250 Title: "Current Poll Unique Clients", 251 Units: "clients", 252 Fam: "client", 253 Ctx: "web_log.current_poll_uniq_clients", 254 Type: module.Stacked, 255 Priority: prioUniqIP, 256 Dims: Dims{ 257 {ID: "uniq_ipv4", Name: "ipv4", Algo: module.Absolute}, 258 {ID: "uniq_ipv6", Name: "ipv6", Algo: module.Absolute}, 259 }, 260 } 261 ) 262 263 // Request By N 264 var ( 265 reqByVhost = Chart{ 266 ID: "requests_by_vhost", 267 Title: "Requests By Vhost", 268 Units: "requests/s", 269 Fam: "vhost", 270 Ctx: "web_log.vhost_requests", 271 Type: module.Stacked, 272 Priority: prioReqVhost, 273 } 274 reqByPort = Chart{ 275 ID: "requests_by_port", 276 Title: "Requests By Port", 277 Units: "requests/s", 278 Fam: "port", 279 Ctx: "web_log.port_requests", 280 Type: module.Stacked, 281 Priority: prioReqPort, 282 } 283 reqByScheme = Chart{ 284 ID: "requests_by_scheme", 285 Title: "Requests By Scheme", 286 Units: "requests/s", 287 Fam: "scheme", 288 Ctx: "web_log.scheme_requests", 289 Type: module.Stacked, 290 Priority: prioReqScheme, 291 Dims: Dims{ 292 {ID: "req_http_scheme", Name: "http", Algo: module.Incremental}, 293 {ID: "req_https_scheme", Name: "https", Algo: module.Incremental}, 294 }, 295 } 296 reqByMethod = Chart{ 297 ID: "requests_by_http_method", 298 Title: "Requests By HTTP Method", 299 Units: "requests/s", 300 Fam: "http method", 301 Ctx: "web_log.http_method_requests", 302 Type: module.Stacked, 303 Priority: prioReqMethod, 304 } 305 reqByVersion = Chart{ 306 ID: "requests_by_http_version", 307 Title: "Requests By HTTP Version", 308 Units: "requests/s", 309 Fam: "http version", 310 Ctx: "web_log.http_version_requests", 311 Type: module.Stacked, 312 Priority: prioReqVersion, 313 } 314 reqByIPProto = Chart{ 315 ID: "requests_by_ip_proto", 316 Title: "Requests By IP Protocol", 317 Units: "requests/s", 318 Fam: "ip proto", 319 Ctx: "web_log.ip_proto_requests", 320 Type: module.Stacked, 321 Priority: prioReqIPProto, 322 Dims: Dims{ 323 {ID: "req_ipv4", Name: "ipv4", Algo: module.Incremental}, 324 {ID: "req_ipv6", Name: "ipv6", Algo: module.Incremental}, 325 }, 326 } 327 reqBySSLProto = Chart{ 328 ID: "requests_by_ssl_proto", 329 Title: "Requests By SSL Connection Protocol", 330 Units: "requests/s", 331 Fam: "ssl conn", 332 Ctx: "web_log.ssl_proto_requests", 333 Type: module.Stacked, 334 Priority: prioReqSSLProto, 335 } 336 reqBySSLCipherSuite = Chart{ 337 ID: "requests_by_ssl_cipher_suite", 338 Title: "Requests By SSL Connection Cipher Suite", 339 Units: "requests/s", 340 Fam: "ssl conn", 341 Ctx: "web_log.ssl_cipher_suite_requests", 342 Type: module.Stacked, 343 Priority: prioReqSSLCipherSuite, 344 } 345 ) 346 347 // Request By N Patterns 348 var ( 349 reqByURLPattern = Chart{ 350 ID: "requests_by_url_pattern", 351 Title: "URL Field Requests By Pattern", 352 Units: "requests/s", 353 Fam: "url ptn", 354 Ctx: "web_log.url_pattern_requests", 355 Type: module.Stacked, 356 Priority: prioReqURLPattern, 357 } 358 reqByCustomFieldPattern = Chart{ 359 ID: "custom_field_%s_requests_by_pattern", 360 Title: "Custom Field %s Requests By Pattern", 361 Units: "requests/s", 362 Fam: "custom field ptn", 363 Ctx: "web_log.custom_field_pattern_requests", 364 Type: module.Stacked, 365 Priority: prioReqCustomFieldPattern, 366 } 367 ) 368 369 // custom time field 370 var ( 371 reqByCustomTimeField = Chart{ 372 ID: "custom_time_field_%s_summary", 373 Title: `Custom Time Field "%s" Summary`, 374 Units: "milliseconds", 375 Fam: "custom time field", 376 Ctx: "web_log.custom_time_field_summary", 377 Priority: prioReqCustomTimeField, 378 Dims: Dims{ 379 {ID: "custom_time_field_%s_time_min", Name: "min", Div: 1000}, 380 {ID: "custom_time_field_%s_time_max", Name: "max", Div: 1000}, 381 {ID: "custom_time_field_%s_time_avg", Name: "avg", Div: 1000}, 382 }, 383 } 384 reqByCustomTimeFieldHist = Chart{ 385 ID: "custom_time_field_%s_histogram", 386 Title: `Custom Time Field "%s" Histogram`, 387 Units: "observations", 388 Fam: "custom time field", 389 Ctx: "web_log.custom_time_field_histogram", 390 Priority: prioReqCustomTimeFieldHist, 391 } 392 ) 393 394 var ( 395 customNumericFieldSummaryChartTmpl = Chart{ 396 ID: "custom_numeric_field_%s_summary", 397 Title: "Custom Numeric Field Summary", 398 Units: "", 399 Fam: "custom numeric fields", 400 Ctx: "web_log.custom_numeric_field_%s_summary", 401 Priority: prioReqCustomNumericFieldSummary, 402 Dims: Dims{ 403 {ID: "custom_numeric_field_%s_summary_min", Name: "min"}, 404 {ID: "custom_numeric_field_%s_summary_max", Name: "max"}, 405 {ID: "custom_numeric_field_%s_summary_avg", Name: "avg"}, 406 }, 407 } 408 ) 409 410 // URL pattern stats 411 var ( 412 urlPatternRespCodes = Chart{ 413 ID: "url_pattern_%s_responses_by_status_code", 414 Title: "Responses By Status Code", 415 Units: "responses/s", 416 Fam: "url ptn %s", 417 Ctx: "web_log.url_pattern_status_code_responses", 418 Type: module.Stacked, 419 Priority: prioURLPatternStats, 420 } 421 urlPatternReqMethods = Chart{ 422 ID: "url_pattern_%s_requests_by_http_method", 423 Title: "Requests By HTTP Method", 424 Units: "requests/s", 425 Fam: "url ptn %s", 426 Ctx: "web_log.url_pattern_http_method_requests", 427 Type: module.Stacked, 428 Priority: prioURLPatternStats + 1, 429 } 430 urlPatternBandwidth = Chart{ 431 ID: "url_pattern_%s_bandwidth", 432 Title: "Bandwidth", 433 Units: "kilobits/s", 434 Fam: "url ptn %s", 435 Ctx: "web_log.url_pattern_bandwidth", 436 Type: module.Area, 437 Priority: prioURLPatternStats + 2, 438 Dims: Dims{ 439 {ID: "url_ptn_%s_bytes_received", Name: "received", Algo: module.Incremental, Mul: 8, Div: 1000}, 440 {ID: "url_ptn_%s_bytes_sent", Name: "sent", Algo: module.Incremental, Mul: -8, Div: 1000}, 441 }, 442 } 443 urlPatternReqProcTime = Chart{ 444 ID: "url_pattern_%s_request_processing_time", 445 Title: "Request Processing Time", 446 Units: "milliseconds", 447 Fam: "url ptn %s", 448 Ctx: "web_log.url_pattern_request_processing_time", 449 Priority: prioURLPatternStats + 3, 450 Dims: Dims{ 451 {ID: "url_ptn_%s_req_proc_time_min", Name: "min", Div: 1000}, 452 {ID: "url_ptn_%s_req_proc_time_max", Name: "max", Div: 1000}, 453 {ID: "url_ptn_%s_req_proc_time_avg", Name: "avg", Div: 1000}, 454 }, 455 } 456 ) 457 458 func newReqProcTimeHistChart(histogram []float64) (*Chart, error) { 459 chart := reqProcTimeHist.Copy() 460 for i, v := range histogram { 461 dim := &Dim{ 462 ID: fmt.Sprintf("req_proc_time_hist_bucket_%d", i+1), 463 Name: fmt.Sprintf("%.3f", v), 464 Algo: module.Incremental, 465 } 466 if err := chart.AddDim(dim); err != nil { 467 return nil, err 468 } 469 } 470 if err := chart.AddDim(&Dim{ 471 ID: "req_proc_time_hist_count", 472 Name: "+Inf", 473 Algo: module.Incremental, 474 }); err != nil { 475 return nil, err 476 } 477 return chart, nil 478 } 479 480 func newUpsRespTimeHistChart(histogram []float64) (*Chart, error) { 481 chart := upsRespTimeHist.Copy() 482 for i, v := range histogram { 483 dim := &Dim{ 484 ID: fmt.Sprintf("upstream_resp_time_hist_bucket_%d", i+1), 485 Name: fmt.Sprintf("%.3f", v), 486 Algo: module.Incremental, 487 } 488 if err := chart.AddDim(dim); err != nil { 489 return nil, err 490 } 491 } 492 if err := chart.AddDim(&Dim{ 493 ID: "upstream_resp_time_hist_count", 494 Name: "+Inf", 495 Algo: module.Incremental, 496 }); err != nil { 497 return nil, err 498 } 499 return chart, nil 500 } 501 502 func newURLPatternChart(patterns []userPattern) (*Chart, error) { 503 chart := reqByURLPattern.Copy() 504 for _, p := range patterns { 505 dim := &Dim{ 506 ID: "req_url_ptn_" + p.Name, 507 Name: p.Name, 508 Algo: module.Incremental, 509 } 510 if err := chart.AddDim(dim); err != nil { 511 return nil, err 512 } 513 } 514 return chart, nil 515 } 516 517 func newURLPatternRespCodesChart(name string) *Chart { 518 chart := urlPatternRespCodes.Copy() 519 chart.ID = fmt.Sprintf(chart.ID, name) 520 chart.Fam = fmt.Sprintf(chart.Fam, name) 521 return chart 522 } 523 524 func newURLPatternReqMethodsChart(name string) *Chart { 525 chart := urlPatternReqMethods.Copy() 526 chart.ID = fmt.Sprintf(chart.ID, name) 527 chart.Fam = fmt.Sprintf(chart.Fam, name) 528 return chart 529 } 530 531 func newURLPatternBandwidthChart(name string) *Chart { 532 chart := urlPatternBandwidth.Copy() 533 chart.ID = fmt.Sprintf(chart.ID, name) 534 chart.Fam = fmt.Sprintf(chart.Fam, name) 535 for _, d := range chart.Dims { 536 d.ID = fmt.Sprintf(d.ID, name) 537 } 538 return chart 539 } 540 541 func newURLPatternReqProcTimeChart(name string) *Chart { 542 chart := urlPatternReqProcTime.Copy() 543 chart.ID = fmt.Sprintf(chart.ID, name) 544 chart.Fam = fmt.Sprintf(chart.Fam, name) 545 for _, d := range chart.Dims { 546 d.ID = fmt.Sprintf(d.ID, name) 547 } 548 return chart 549 } 550 551 func newCustomFieldCharts(fields []customField) (Charts, error) { 552 charts := Charts{} 553 for _, f := range fields { 554 chart, err := newCustomFieldChart(f) 555 if err != nil { 556 return nil, err 557 } 558 if err := charts.Add(chart); err != nil { 559 return nil, err 560 } 561 } 562 return charts, nil 563 } 564 565 func newCustomFieldChart(f customField) (*Chart, error) { 566 chart := reqByCustomFieldPattern.Copy() 567 chart.ID = fmt.Sprintf(chart.ID, f.Name) 568 chart.Title = fmt.Sprintf(chart.Title, f.Name) 569 for _, p := range f.Patterns { 570 dim := &Dim{ 571 ID: fmt.Sprintf("custom_field_%s_%s", f.Name, p.Name), 572 Name: p.Name, 573 Algo: module.Incremental, 574 } 575 if err := chart.AddDim(dim); err != nil { 576 return nil, err 577 } 578 } 579 return chart, nil 580 } 581 582 func newCustomTimeFieldCharts(fields []customTimeField) (Charts, error) { 583 charts := Charts{} 584 for i, f := range fields { 585 chartTime, err := newCustomTimeFieldChart(f) 586 if err != nil { 587 return nil, err 588 } 589 chartTime.Priority += i 590 if err := charts.Add(chartTime); err != nil { 591 return nil, err 592 } 593 if len(f.Histogram) < 1 { 594 continue 595 } 596 597 chartHist, err := newCustomTimeFieldHistChart(f) 598 if err != nil { 599 return nil, err 600 } 601 chartHist.Priority += i 602 603 if err := charts.Add(chartHist); err != nil { 604 return nil, err 605 } 606 } 607 return charts, nil 608 } 609 610 func newCustomTimeFieldChart(f customTimeField) (*Chart, error) { 611 chart := reqByCustomTimeField.Copy() 612 chart.ID = fmt.Sprintf(chart.ID, f.Name) 613 chart.Title = fmt.Sprintf(chart.Title, f.Name) 614 for _, d := range chart.Dims { 615 d.ID = fmt.Sprintf(d.ID, f.Name) 616 } 617 return chart, nil 618 } 619 620 func newCustomTimeFieldHistChart(f customTimeField) (*Chart, error) { 621 chart := reqByCustomTimeFieldHist.Copy() 622 chart.ID = fmt.Sprintf(chart.ID, f.Name) 623 chart.Title = fmt.Sprintf(chart.Title, f.Name) 624 for i, v := range f.Histogram { 625 dim := &Dim{ 626 ID: fmt.Sprintf("custom_time_field_%s_time_hist_bucket_%d", f.Name, i+1), 627 Name: fmt.Sprintf("%.3f", v), 628 Algo: module.Incremental, 629 } 630 if err := chart.AddDim(dim); err != nil { 631 return nil, err 632 } 633 } 634 if err := chart.AddDim(&Dim{ 635 ID: fmt.Sprintf("custom_time_field_%s_time_hist_count", f.Name), 636 Name: "+Inf", 637 Algo: module.Incremental, 638 }); err != nil { 639 return nil, err 640 } 641 return chart, nil 642 } 643 644 func (w *WebLog) createCharts(line *logLine) error { 645 if line.empty() { 646 return errors.New("empty line") 647 } 648 w.charts = nil 649 // Following charts are created during runtime: 650 // - reqBySSLProto, reqBySSLCipherSuite - it is likely line has no SSL stuff at this moment 651 charts := &Charts{ 652 reqTotal.Copy(), 653 reqExcluded.Copy(), 654 } 655 if line.hasVhost() { 656 if err := addVhostCharts(charts); err != nil { 657 return err 658 } 659 } 660 if line.hasPort() { 661 if err := addPortCharts(charts); err != nil { 662 return err 663 } 664 } 665 if line.hasReqScheme() { 666 if err := addSchemeCharts(charts); err != nil { 667 return err 668 } 669 } 670 if line.hasReqClient() { 671 if err := addClientCharts(charts); err != nil { 672 return err 673 } 674 } 675 if line.hasReqMethod() { 676 if err := addMethodCharts(charts, w.URLPatterns); err != nil { 677 return err 678 } 679 } 680 if line.hasReqURL() { 681 if err := addURLCharts(charts, w.URLPatterns); err != nil { 682 return err 683 } 684 } 685 if line.hasReqProto() { 686 if err := addReqProtoCharts(charts); err != nil { 687 return err 688 } 689 } 690 if line.hasRespCode() { 691 if err := addRespCodesCharts(charts, w.GroupRespCodes); err != nil { 692 return err 693 } 694 } 695 if line.hasReqSize() || line.hasRespSize() { 696 if err := addBandwidthCharts(charts, w.URLPatterns); err != nil { 697 return err 698 } 699 } 700 if line.hasReqProcTime() { 701 if err := addReqProcTimeCharts(charts, w.Histogram, w.URLPatterns); err != nil { 702 return err 703 } 704 } 705 if line.hasUpsRespTime() { 706 if err := addUpstreamRespTimeCharts(charts, w.Histogram); err != nil { 707 return err 708 } 709 } 710 if line.hasCustomFields() { 711 if len(w.CustomFields) > 0 { 712 if err := addCustomFieldsCharts(charts, w.CustomFields); err != nil { 713 return err 714 } 715 } 716 if len(w.CustomTimeFields) > 0 { 717 if err := addCustomTimeFieldsCharts(charts, w.CustomTimeFields); err != nil { 718 return err 719 } 720 } 721 if len(w.CustomNumericFields) > 0 { 722 if err := addCustomNumericFieldsCharts(charts, w.CustomNumericFields); err != nil { 723 return err 724 } 725 } 726 } 727 728 w.charts = charts 729 730 return nil 731 } 732 733 func addVhostCharts(charts *Charts) error { 734 return charts.Add(reqByVhost.Copy()) 735 } 736 737 func addPortCharts(charts *Charts) error { 738 return charts.Add(reqByPort.Copy()) 739 } 740 741 func addSchemeCharts(charts *Charts) error { 742 return charts.Add(reqByScheme.Copy()) 743 } 744 745 func addClientCharts(charts *Charts) error { 746 if err := charts.Add(reqByIPProto.Copy()); err != nil { 747 return err 748 } 749 return charts.Add(uniqIPsCurPoll.Copy()) 750 } 751 752 func addMethodCharts(charts *Charts, patterns []userPattern) error { 753 if err := charts.Add(reqByMethod.Copy()); err != nil { 754 return err 755 } 756 757 for _, p := range patterns { 758 chart := newURLPatternReqMethodsChart(p.Name) 759 if err := charts.Add(chart); err != nil { 760 return err 761 } 762 } 763 return nil 764 } 765 766 func addURLCharts(charts *Charts, patterns []userPattern) error { 767 if len(patterns) == 0 { 768 return nil 769 } 770 chart, err := newURLPatternChart(patterns) 771 if err != nil { 772 return err 773 } 774 if err := charts.Add(chart); err != nil { 775 return err 776 } 777 778 for _, p := range patterns { 779 chart := newURLPatternRespCodesChart(p.Name) 780 if err := charts.Add(chart); err != nil { 781 return err 782 } 783 } 784 return nil 785 } 786 787 func addReqProtoCharts(charts *Charts) error { 788 return charts.Add(reqByVersion.Copy()) 789 } 790 791 func addRespCodesCharts(charts *Charts, group bool) error { 792 if err := charts.Add(reqTypes.Copy()); err != nil { 793 return err 794 } 795 if err := charts.Add(respCodeClass.Copy()); err != nil { 796 return err 797 } 798 if !group { 799 return charts.Add(respCodes.Copy()) 800 } 801 for _, c := range []Chart{respCodes1xx, respCodes2xx, respCodes3xx, respCodes4xx, respCodes5xx} { 802 if err := charts.Add(c.Copy()); err != nil { 803 return err 804 } 805 } 806 return nil 807 } 808 809 func addBandwidthCharts(charts *Charts, patterns []userPattern) error { 810 if err := charts.Add(bandwidth.Copy()); err != nil { 811 return err 812 } 813 814 for _, p := range patterns { 815 chart := newURLPatternBandwidthChart(p.Name) 816 if err := charts.Add(chart); err != nil { 817 return err 818 } 819 } 820 return nil 821 } 822 823 func addReqProcTimeCharts(charts *Charts, histogram []float64, patterns []userPattern) error { 824 if err := charts.Add(reqProcTime.Copy()); err != nil { 825 return err 826 } 827 for _, p := range patterns { 828 chart := newURLPatternReqProcTimeChart(p.Name) 829 if err := charts.Add(chart); err != nil { 830 return err 831 } 832 } 833 if len(histogram) == 0 { 834 return nil 835 } 836 chart, err := newReqProcTimeHistChart(histogram) 837 if err != nil { 838 return err 839 } 840 return charts.Add(chart) 841 } 842 843 func addUpstreamRespTimeCharts(charts *Charts, histogram []float64) error { 844 if err := charts.Add(upsRespTime.Copy()); err != nil { 845 return err 846 } 847 if len(histogram) == 0 { 848 return nil 849 } 850 chart, err := newUpsRespTimeHistChart(histogram) 851 if err != nil { 852 return err 853 } 854 return charts.Add(chart) 855 } 856 857 func addCustomFieldsCharts(charts *Charts, fields []customField) error { 858 cs, err := newCustomFieldCharts(fields) 859 if err != nil { 860 return err 861 } 862 return charts.Add(cs...) 863 } 864 865 func addCustomTimeFieldsCharts(charts *Charts, fields []customTimeField) error { 866 cs, err := newCustomTimeFieldCharts(fields) 867 if err != nil { 868 return err 869 } 870 return charts.Add(cs...) 871 } 872 873 func addCustomNumericFieldsCharts(charts *module.Charts, fields []customNumericField) error { 874 for _, f := range fields { 875 chart := customNumericFieldSummaryChartTmpl.Copy() 876 chart.ID = fmt.Sprintf(chart.ID, f.Name) 877 chart.Units = f.Units 878 chart.Ctx = fmt.Sprintf(chart.Ctx, f.Name) 879 for _, dim := range chart.Dims { 880 dim.ID = fmt.Sprintf(dim.ID, f.Name) 881 dim.Div = f.Divisor 882 } 883 884 if err := charts.Add(chart); err != nil { 885 return err 886 } 887 } 888 889 return nil 890 }