code.vegaprotocol.io/vega@v0.79.0/datanode/metrics/prometheus.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package metrics 17 18 import ( 19 "fmt" 20 "log" 21 "net/http" 22 "net/url" 23 "strings" 24 "time" 25 26 "code.vegaprotocol.io/vega/core/events" 27 "code.vegaprotocol.io/vega/protos" 28 29 "github.com/pkg/errors" 30 "github.com/prometheus/client_golang/prometheus" 31 "github.com/prometheus/client_golang/prometheus/promhttp" 32 ) 33 34 const ( 35 // Gauge ... 36 Gauge instrument = iota 37 // Counter ... 38 Counter 39 // Histogram ... 40 Histogram 41 // Summary ... 42 Summary 43 ) 44 45 var ( 46 // ErrInstrumentNotSupported signals the specified instrument is not yet supported. 47 ErrInstrumentNotSupported = errors.New("instrument type unsupported") 48 // ErrInstrumentTypeMismatch signal the type of the instrument is not expected. 49 ErrInstrumentTypeMismatch = errors.New("instrument is not of the expected type") 50 ) 51 52 var ( 53 engineTime *prometheus.CounterVec 54 eventHandlingTime *prometheus.CounterVec 55 flushHandlingTime *prometheus.CounterVec 56 eventCounter *prometheus.CounterVec 57 sqlQueryTime *prometheus.CounterVec 58 sqlQueryCounter *prometheus.CounterVec 59 blockCounter prometheus.Counter 60 blockHandlingTime prometheus.Counter 61 blockHeight prometheus.Gauge 62 63 publishedEventsCounter *prometheus.CounterVec 64 eventBusPublishedEventsCounter *prometheus.CounterVec 65 66 // Subscription gauge for each type. 67 subscriptionGauge *prometheus.GaugeVec 68 eventBusSubscriptionGauge *prometheus.GaugeVec 69 eventBusConnectionGauge prometheus.Gauge 70 71 // Call counters for each request type per API. 72 apiRequestCallCounter *prometheus.CounterVec 73 // Total time counters for each request type per API. 74 apiRequestTimeCounter *prometheus.CounterVec 75 76 lastSnapshotRowcount prometheus.Gauge 77 lastSnapshotCurrentStateBytes prometheus.Gauge 78 lastSnapshotHistoryBytes prometheus.Gauge 79 lastSnapshotSeconds prometheus.Gauge 80 81 eventBufferWrittenCount prometheus.Counter 82 eventBufferReadCount prometheus.Counter 83 84 networkHistoryIpfsStoreBytes prometheus.Gauge 85 // Data Node HTTP bindings that we will check against when updating HTTP metrics. 86 httpBindings *protos.Bindings 87 88 // Per table segment creation time. 89 networkHistoryCopiedRowsCounter *prometheus.CounterVec 90 networkHistoryCopyTimeCounter *prometheus.CounterVec 91 92 batcherAddedEntities *prometheus.CounterVec 93 batcherFlushedEntities *prometheus.CounterVec 94 ) 95 96 // abstract prometheus types. 97 type instrument int 98 99 // combine all possible prometheus options + way to differentiate between regular or vector type. 100 type instrumentOpts struct { 101 opts prometheus.Opts 102 buckets []float64 103 objectives map[float64]float64 104 maxAge time.Duration 105 ageBuckets, bufCap uint32 106 vectors []string 107 } 108 109 type mi struct { 110 gaugeV *prometheus.GaugeVec 111 gauge prometheus.Gauge 112 counterV *prometheus.CounterVec 113 counter prometheus.Counter 114 histogramV *prometheus.HistogramVec 115 histogram prometheus.Histogram 116 summaryV *prometheus.SummaryVec 117 summary prometheus.Summary 118 } 119 120 // MetricInstrument - template interface for mi type return value - only mock if needed, and only mock the funcs you use. 121 type MetricInstrument interface { 122 Gauge() (prometheus.Gauge, error) 123 GaugeVec() (*prometheus.GaugeVec, error) 124 Counter() (prometheus.Counter, error) 125 CounterVec() (*prometheus.CounterVec, error) 126 Histogram() (prometheus.Histogram, error) 127 HistogramVec() (*prometheus.HistogramVec, error) 128 Summary() (prometheus.Summary, error) 129 SummaryVec() (*prometheus.SummaryVec, error) 130 } 131 132 // InstrumentOption - vararg for instrument options setting. 133 type InstrumentOption func(o *instrumentOpts) 134 135 // Vectors - configuration used to create a vector of a given interface, slice of label names. 136 func Vectors(labels ...string) InstrumentOption { 137 return func(o *instrumentOpts) { 138 o.vectors = labels 139 } 140 } 141 142 // Help - set the help field on instrument. 143 func Help(help string) InstrumentOption { 144 return func(o *instrumentOpts) { 145 o.opts.Help = help 146 } 147 } 148 149 // Namespace - set namespace. 150 func Namespace(ns string) InstrumentOption { 151 return func(o *instrumentOpts) { 152 o.opts.Namespace = ns 153 } 154 } 155 156 // Subsystem - set subsystem... obviously. 157 func Subsystem(s string) InstrumentOption { 158 return func(o *instrumentOpts) { 159 o.opts.Subsystem = s 160 } 161 } 162 163 // Labels set labels for instrument (similar to vector, but with given values). 164 func Labels(labels map[string]string) InstrumentOption { 165 return func(o *instrumentOpts) { 166 o.opts.ConstLabels = labels 167 } 168 } 169 170 // Buckets - specific to histogram type. 171 func Buckets(b []float64) InstrumentOption { 172 return func(o *instrumentOpts) { 173 o.buckets = b 174 } 175 } 176 177 // Objectives - specific to summary type. 178 func Objectives(obj map[float64]float64) InstrumentOption { 179 return func(o *instrumentOpts) { 180 o.objectives = obj 181 } 182 } 183 184 // MaxAge - specific to summary type. 185 func MaxAge(m time.Duration) InstrumentOption { 186 return func(o *instrumentOpts) { 187 o.maxAge = m 188 } 189 } 190 191 // AgeBuckets - specific to summary type. 192 func AgeBuckets(ab uint32) InstrumentOption { 193 return func(o *instrumentOpts) { 194 o.ageBuckets = ab 195 } 196 } 197 198 // BufCap - specific to summary type. 199 func BufCap(bc uint32) InstrumentOption { 200 return func(o *instrumentOpts) { 201 o.bufCap = bc 202 } 203 } 204 205 // addInstrument configure and register new metrics instrument 206 // this will, over time, be moved to use custom Registries, etc... 207 func addInstrument(t instrument, name string, opts ...InstrumentOption) (*mi, error) { 208 var col prometheus.Collector 209 ret := mi{} 210 opt := instrumentOpts{ 211 opts: prometheus.Opts{ 212 Name: name, 213 }, 214 } 215 // apply options 216 for _, o := range opts { 217 o(&opt) 218 } 219 switch t { 220 case Gauge: 221 o := opt.gauge() 222 if len(opt.vectors) == 0 { 223 ret.gauge = prometheus.NewGauge(o) 224 col = ret.gauge 225 } else { 226 ret.gaugeV = prometheus.NewGaugeVec(o, opt.vectors) 227 col = ret.gaugeV 228 } 229 case Counter: 230 o := opt.counter() 231 if len(opt.vectors) == 0 { 232 ret.counter = prometheus.NewCounter(o) 233 col = ret.counter 234 } else { 235 ret.counterV = prometheus.NewCounterVec(o, opt.vectors) 236 col = ret.counterV 237 } 238 case Histogram: 239 o := opt.histogram() 240 if len(opt.vectors) == 0 { 241 ret.histogram = prometheus.NewHistogram(o) 242 col = ret.histogram 243 } else { 244 ret.histogramV = prometheus.NewHistogramVec(o, opt.vectors) 245 col = ret.histogramV 246 } 247 case Summary: 248 o := opt.summary() 249 if len(opt.vectors) == 0 { 250 ret.summary = prometheus.NewSummary(o) 251 col = ret.summary 252 } else { 253 ret.summaryV = prometheus.NewSummaryVec(o, opt.vectors) 254 col = ret.summaryV 255 } 256 default: 257 return nil, ErrInstrumentNotSupported 258 } 259 if err := prometheus.Register(col); err != nil { 260 return nil, err 261 } 262 return &ret, nil 263 } 264 265 // Start enable metrics (given config). 266 func Start(conf Config) { 267 if !conf.Enabled { 268 return 269 } 270 err := setupMetrics() 271 if err != nil { 272 panic("could not set up metrics") 273 } 274 http.Handle(conf.Path, promhttp.Handler()) 275 go func() { 276 log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", conf.Port), nil)) 277 }() 278 } 279 280 func (i instrumentOpts) gauge() prometheus.GaugeOpts { 281 return prometheus.GaugeOpts(i.opts) 282 } 283 284 func (i instrumentOpts) counter() prometheus.CounterOpts { 285 return prometheus.CounterOpts(i.opts) 286 } 287 288 func (i instrumentOpts) summary() prometheus.SummaryOpts { 289 return prometheus.SummaryOpts{ 290 Name: i.opts.Name, 291 Namespace: i.opts.Namespace, 292 Subsystem: i.opts.Subsystem, 293 ConstLabels: i.opts.ConstLabels, 294 Help: i.opts.Help, 295 Objectives: i.objectives, 296 MaxAge: i.maxAge, 297 AgeBuckets: i.ageBuckets, 298 BufCap: i.bufCap, 299 } 300 } 301 302 func (i instrumentOpts) histogram() prometheus.HistogramOpts { 303 return prometheus.HistogramOpts{ 304 Name: i.opts.Name, 305 Namespace: i.opts.Namespace, 306 Subsystem: i.opts.Subsystem, 307 ConstLabels: i.opts.ConstLabels, 308 Help: i.opts.Help, 309 Buckets: i.buckets, 310 } 311 } 312 313 // Gauge returns a prometheus Gauge instrument. 314 func (m mi) Gauge() (prometheus.Gauge, error) { 315 if m.gauge == nil { 316 return nil, ErrInstrumentTypeMismatch 317 } 318 return m.gauge, nil 319 } 320 321 // GaugeVec returns a prometheus GaugeVec instrument. 322 func (m mi) GaugeVec() (*prometheus.GaugeVec, error) { 323 if m.gaugeV == nil { 324 return nil, ErrInstrumentTypeMismatch 325 } 326 return m.gaugeV, nil 327 } 328 329 // Counter returns a prometheus Counter instrument. 330 func (m mi) Counter() (prometheus.Counter, error) { 331 if m.counter == nil { 332 return nil, ErrInstrumentTypeMismatch 333 } 334 return m.counter, nil 335 } 336 337 // CounterVec returns a prometheus CounterVec instrument. 338 func (m mi) CounterVec() (*prometheus.CounterVec, error) { 339 if m.counterV == nil { 340 return nil, ErrInstrumentTypeMismatch 341 } 342 return m.counterV, nil 343 } 344 345 func (m mi) Histogram() (prometheus.Histogram, error) { 346 if m.histogram == nil { 347 return nil, ErrInstrumentTypeMismatch 348 } 349 return m.histogram, nil 350 } 351 352 func (m mi) HistogramVec() (*prometheus.HistogramVec, error) { 353 if m.histogramV == nil { 354 return nil, ErrInstrumentTypeMismatch 355 } 356 return m.histogramV, nil 357 } 358 359 func (m mi) Summary() (prometheus.Summary, error) { 360 if m.summary == nil { 361 return nil, ErrInstrumentTypeMismatch 362 } 363 return m.summary, nil 364 } 365 366 func (m mi) SummaryVec() (*prometheus.SummaryVec, error) { 367 if m.summaryV == nil { 368 return nil, ErrInstrumentTypeMismatch 369 } 370 return m.summaryV, nil 371 } 372 373 func setupMetrics() error { 374 // instrument with time histogram for blocks 375 h, err := addInstrument( 376 Counter, 377 "engine_seconds_total", 378 Namespace("datanode"), 379 Vectors("market", "engine", "fn"), 380 ) 381 if err != nil { 382 return err 383 } 384 est, err := h.CounterVec() 385 if err != nil { 386 return err 387 } 388 engineTime = est 389 390 h, err = addInstrument( 391 Counter, 392 "flush_handling_seconds_total", 393 Namespace("datanode"), 394 Vectors("subscriber"), 395 ) 396 if err != nil { 397 return err 398 } 399 fht, err := h.CounterVec() 400 if err != nil { 401 return err 402 } 403 flushHandlingTime = fht 404 405 // eventHandlingTime 406 h, err = addInstrument( 407 Counter, 408 "event_handling_seconds_total", 409 Namespace("datanode"), 410 Vectors("type", "subscriber", "event"), 411 ) 412 if err != nil { 413 return err 414 } 415 eht, err := h.CounterVec() 416 if err != nil { 417 return err 418 } 419 eventHandlingTime = eht 420 421 h, err = addInstrument( 422 Counter, 423 "published_event_count_total", 424 Namespace("datanode"), 425 Vectors("event"), 426 ) 427 if err != nil { 428 return err 429 } 430 sec, err := h.CounterVec() 431 if err != nil { 432 return err 433 } 434 publishedEventsCounter = sec 435 436 h, err = addInstrument( 437 Counter, 438 "event_bus_published_event_count_total", 439 Namespace("datanode"), 440 Vectors("event"), 441 ) 442 if err != nil { 443 return err 444 } 445 sec, err = h.CounterVec() 446 if err != nil { 447 return err 448 } 449 eventBusPublishedEventsCounter = sec 450 451 // eventCount 452 h, err = addInstrument( 453 Counter, 454 "event_count_total", 455 Namespace("datanode"), 456 Vectors("event"), 457 ) 458 if err != nil { 459 return err 460 } 461 ec, err := h.CounterVec() 462 if err != nil { 463 return err 464 } 465 eventCounter = ec 466 467 h, err = addInstrument( 468 Counter, 469 "network_history_copied_rows_total", 470 Namespace("datanode"), 471 Vectors("table"), 472 ) 473 if err != nil { 474 return err 475 } 476 cr, err := h.CounterVec() 477 if err != nil { 478 return err 479 } 480 networkHistoryCopiedRowsCounter = cr 481 482 h, err = addInstrument( 483 Counter, 484 "network_history_copy_time_total", 485 Namespace("datanode"), 486 Vectors("table"), 487 ) 488 if err != nil { 489 return err 490 } 491 ct, err := h.CounterVec() 492 if err != nil { 493 return err 494 } 495 networkHistoryCopyTimeCounter = ct 496 497 h, err = addInstrument( 498 Counter, 499 "batcher_added_entities", 500 Namespace("datanode"), 501 Vectors("table"), 502 ) 503 if err != nil { 504 return err 505 } 506 baet, err := h.CounterVec() 507 if err != nil { 508 return err 509 } 510 batcherAddedEntities = baet 511 512 h, err = addInstrument( 513 Counter, 514 "batcher_flushed_entities", 515 Namespace("datanode"), 516 Vectors("table"), 517 ) 518 if err != nil { 519 return err 520 } 521 bfe, err := h.CounterVec() 522 if err != nil { 523 return err 524 } 525 batcherFlushedEntities = bfe 526 527 // sqlQueryTime 528 h, err = addInstrument( 529 Counter, 530 "sql_query_seconds_total", 531 Namespace("datanode"), 532 Vectors("store", "query"), 533 ) 534 if err != nil { 535 return err 536 } 537 sqt, err := h.CounterVec() 538 if err != nil { 539 return err 540 } 541 sqlQueryTime = sqt 542 543 // sqlQueryCounter 544 h, err = addInstrument( 545 Counter, 546 "sql_query_count", 547 Namespace("datanode"), 548 Vectors("store", "query"), 549 ) 550 if err != nil { 551 return err 552 } 553 qc, err := h.CounterVec() 554 if err != nil { 555 return err 556 } 557 sqlQueryCounter = qc 558 559 h, err = addInstrument( 560 Counter, 561 "blocks_handling_time_seconds_total", 562 Namespace("datanode"), 563 Vectors(), 564 Help("Total time handling blocks"), 565 ) 566 if err != nil { 567 return err 568 } 569 bht, err := h.Counter() 570 if err != nil { 571 return err 572 } 573 blockHandlingTime = bht 574 575 h, err = addInstrument( 576 Counter, 577 "blocks_total", 578 Namespace("datanode"), 579 Vectors(), 580 Help("Number of blocks processed"), 581 ) 582 if err != nil { 583 return err 584 } 585 bt, err := h.Counter() 586 if err != nil { 587 return err 588 } 589 blockCounter = bt 590 591 h, err = addInstrument( 592 Counter, 593 "event_buffer_written_count", 594 Namespace("datanode"), 595 Vectors(), 596 Help("Total number of event written to the event buffer"), 597 ) 598 if err != nil { 599 return err 600 } 601 ebwc, err := h.Counter() 602 if err != nil { 603 return err 604 } 605 eventBufferWrittenCount = ebwc 606 607 h, err = addInstrument( 608 Counter, 609 "event_buffer_read_count", 610 Namespace("datanode"), 611 Vectors(), 612 Help("Total number of events read from the event buffer"), 613 ) 614 if err != nil { 615 return err 616 } 617 ebrc, err := h.Counter() 618 if err != nil { 619 return err 620 } 621 eventBufferReadCount = ebrc 622 623 h, err = addInstrument( 624 Gauge, 625 "block_height", 626 Namespace("datanode"), 627 Vectors(), 628 Help("Current block height"), 629 ) 630 if err != nil { 631 return err 632 } 633 bh, err := h.Gauge() 634 if err != nil { 635 return err 636 } 637 blockHeight = bh 638 639 h, err = addInstrument( 640 Gauge, 641 "last_snapshot_rowcount", 642 Namespace("datanode"), 643 Vectors(), 644 Help("Last Snapshot Row Count"), 645 ) 646 if err != nil { 647 return err 648 } 649 lsr, err := h.Gauge() 650 if err != nil { 651 return err 652 } 653 lastSnapshotRowcount = lsr 654 655 h, err = addInstrument( 656 Gauge, 657 "last_snapshot_history_bytes", 658 Namespace("datanode"), 659 Vectors(), 660 Help("The compressed byte size of the last snapshots history data"), 661 ) 662 if err != nil { 663 return err 664 } 665 lshb, err := h.Gauge() 666 if err != nil { 667 return err 668 } 669 lastSnapshotHistoryBytes = lshb 670 671 h, err = addInstrument( 672 Gauge, 673 "last_snapshot_current_state_bytes", 674 Namespace("datanode"), 675 Vectors(), 676 Help("The compressed byte size of the last snapshots current state data"), 677 ) 678 if err != nil { 679 return err 680 } 681 lscs, err := h.Gauge() 682 if err != nil { 683 return err 684 } 685 lastSnapshotCurrentStateBytes = lscs 686 687 h, err = addInstrument( 688 Gauge, 689 "last_snapshot_seconds", 690 Namespace("datanode"), 691 Vectors(), 692 Help("Last Snapshot Time Taken in Seconds"), 693 ) 694 if err != nil { 695 return err 696 } 697 lss, err := h.Gauge() 698 if err != nil { 699 return err 700 } 701 lastSnapshotSeconds = lss 702 703 h, err = addInstrument( 704 Gauge, 705 "networkhistory_ipfs_store_bytes", 706 Namespace("datanode"), 707 Vectors(), 708 Help("The size in bytes of the network history ipfs store"), 709 ) 710 if err != nil { 711 return err 712 } 713 dsb, err := h.Gauge() 714 if err != nil { 715 return err 716 } 717 networkHistoryIpfsStoreBytes = dsb 718 719 // 720 // API usage metrics start here 721 // 722 723 if h, err = addInstrument( 724 Gauge, 725 "active_subscriptions", 726 Namespace("datanode"), 727 Vectors("apiType", "eventType"), 728 Help("Number of active subscriptions"), 729 ); err != nil { 730 return err 731 } 732 733 if subscriptionGauge, err = h.GaugeVec(); err != nil { 734 return err 735 } 736 737 if h, err = addInstrument( 738 Gauge, 739 "event_bus_active_subscriptions", 740 Namespace("datanode"), 741 Vectors("eventType"), 742 Help("Number of active subscriptions by type to the event bus"), 743 ); err != nil { 744 return err 745 } 746 747 if eventBusSubscriptionGauge, err = h.GaugeVec(); err != nil { 748 return err 749 } 750 751 if h, err = addInstrument( 752 Gauge, 753 "event_bus_active_connections", 754 Namespace("datanode"), 755 Help("Number of active connections to the event bus"), 756 ); err != nil { 757 return err 758 } 759 ac, err := h.Gauge() 760 if err != nil { 761 return err 762 } 763 eventBusConnectionGauge = ac 764 765 httpBindings, err = protos.DataNodeBindings() 766 if err != nil { 767 return err 768 } 769 // Number of calls to each request type 770 h, err = addInstrument( 771 Counter, 772 "request_count_total", 773 Namespace("datanode"), 774 Vectors("apiType", "requestType"), 775 Help("Count of API requests"), 776 ) 777 if err != nil { 778 return err 779 } 780 rc, err := h.CounterVec() 781 if err != nil { 782 return err 783 } 784 apiRequestCallCounter = rc 785 786 // Total time for calls to each request type for each api type 787 h, err = addInstrument( 788 Counter, 789 "request_time_total", 790 Namespace("datanode"), 791 Vectors("apiType", "requestType"), 792 Help("Total time spent in each API request"), 793 ) 794 if err != nil { 795 return err 796 } 797 rpac, err := h.CounterVec() 798 if err != nil { 799 return err 800 } 801 apiRequestTimeCounter = rpac 802 803 return nil 804 } 805 806 func AddBlockHandlingTime(duration time.Duration) { 807 if blockHandlingTime != nil { 808 blockHandlingTime.Add(duration.Seconds()) 809 } 810 } 811 812 func EventBufferWrittenCountInc() { 813 if eventBufferWrittenCount == nil { 814 return 815 } 816 eventBufferWrittenCount.Inc() 817 } 818 819 func EventBufferReadCountInc() { 820 if eventBufferReadCount == nil { 821 return 822 } 823 eventBufferReadCount.Inc() 824 } 825 826 func BlockCounterInc(labelValues ...string) { 827 if blockCounter == nil { 828 return 829 } 830 blockCounter.Inc() 831 } 832 833 func EventCounterInc(labelValues ...string) { 834 if eventCounter == nil { 835 return 836 } 837 eventCounter.WithLabelValues(labelValues...).Inc() 838 } 839 840 func PublishedEventsAdd(event string, eventCount float64) { 841 if publishedEventsCounter == nil { 842 return 843 } 844 845 publishedEventsCounter.WithLabelValues(event).Add(eventCount) 846 } 847 848 func EventBusPublishedEventsAdd(event string, eventCount float64) { 849 if eventBusPublishedEventsCounter == nil { 850 return 851 } 852 853 eventBusPublishedEventsCounter.WithLabelValues(event).Add(eventCount) 854 } 855 856 func SetBlockHeight(height float64) { 857 if blockHeight == nil { 858 return 859 } 860 blockHeight.Set(height) 861 } 862 863 func SetLastSnapshotRowcount(count float64) { 864 if lastSnapshotRowcount == nil { 865 return 866 } 867 lastSnapshotRowcount.Set(count) 868 } 869 870 func SetLastSnapshotCurrentStateBytes(bytes float64) { 871 if lastSnapshotCurrentStateBytes == nil { 872 return 873 } 874 lastSnapshotCurrentStateBytes.Set(bytes) 875 } 876 877 func SetLastSnapshotHistoryBytes(bytes float64) { 878 if lastSnapshotHistoryBytes == nil { 879 return 880 } 881 lastSnapshotHistoryBytes.Set(bytes) 882 } 883 884 func SetLastSnapshotSeconds(seconds float64) { 885 if lastSnapshotSeconds == nil { 886 return 887 } 888 lastSnapshotSeconds.Set(seconds) 889 } 890 891 func SetNetworkHistoryIpfsStoreBytes(bytes float64) { 892 if networkHistoryIpfsStoreBytes == nil { 893 return 894 } 895 networkHistoryIpfsStoreBytes.Set(bytes) 896 } 897 898 // APIRequestAndTimeREST updates the metrics for REST API calls. 899 func APIRequestAndTimeREST(method, request string, time float64) { 900 if apiRequestCallCounter == nil || apiRequestTimeCounter == nil || httpBindings == nil { 901 return 902 } 903 904 const ( 905 invalid = "invalid route" 906 invalidURL = "invalid url" 907 prefix = "/api/v2/" 908 ) 909 910 if !httpBindings.HasRoute(method, request) { 911 apiRequestCallCounter.WithLabelValues("REST", invalid).Inc() 912 apiRequestTimeCounter.WithLabelValues("REST", invalid).Add(time) 913 return 914 } 915 916 parsed, err := url.Parse(request) 917 if err != nil { 918 apiRequestCallCounter.WithLabelValues("REST", invalidURL).Inc() 919 apiRequestTimeCounter.WithLabelValues("REST", invalidURL).Add(time) 920 return 921 } 922 923 trimmedPath := strings.TrimPrefix(parsed.Path, prefix) 924 925 // Trim the URI down to something useful 926 if strings.Count(trimmedPath, "/") >= 1 { 927 trimmedPath = trimmedPath[:strings.Index(trimmedPath, "/")] 928 } 929 930 apiRequestCallCounter.WithLabelValues("REST", trimmedPath).Inc() 931 apiRequestTimeCounter.WithLabelValues("REST", trimmedPath).Add(time) 932 } 933 934 // APIRequestAndTimeGraphQL updates the metrics for GraphQL API calls. 935 func APIRequestAndTimeGraphQL(request string, time float64) { 936 if apiRequestCallCounter == nil || apiRequestTimeCounter == nil { 937 return 938 } 939 apiRequestCallCounter.WithLabelValues("GraphQL", request).Inc() 940 apiRequestTimeCounter.WithLabelValues("GraphQL", request).Add(time) 941 } 942 943 // StartAPIRequestAndTimeGRPC updates the metrics for GRPC API calls. 944 func StartAPIRequestAndTimeGRPC(request string) func() { 945 startTime := time.Now() 946 return func() { 947 if apiRequestCallCounter == nil || apiRequestTimeCounter == nil { 948 return 949 } 950 apiRequestCallCounter.WithLabelValues("GRPC", request).Inc() 951 duration := time.Since(startTime).Seconds() 952 apiRequestTimeCounter.WithLabelValues("GRPC", request).Add(duration) 953 } 954 } 955 956 func IncrementBatcherAddedEntities(table string) { 957 if batcherAddedEntities == nil { 958 return 959 } 960 batcherAddedEntities.WithLabelValues(table).Add(1) 961 } 962 963 func BatcherFlushedEntitiesAdd(table string, flushed int) { 964 if batcherFlushedEntities == nil { 965 return 966 } 967 batcherFlushedEntities.WithLabelValues(table).Add(float64(flushed)) 968 } 969 970 func NetworkHistoryRowsCopied(table string, rowsCopied int64) { 971 if networkHistoryCopiedRowsCounter == nil { 972 return 973 } 974 networkHistoryCopiedRowsCounter.WithLabelValues(table).Add(float64(rowsCopied)) 975 } 976 977 func StartNetworkHistoryCopy(table string) func() { 978 startTime := time.Now() 979 return func() { 980 if networkHistoryCopyTimeCounter == nil { 981 return 982 } 983 duration := time.Since(startTime).Seconds() 984 networkHistoryCopyTimeCounter.WithLabelValues(table).Add(duration) 985 } 986 } 987 988 func StartSQLQuery(store string, query string) func() { 989 startTime := time.Now() 990 return func() { 991 if sqlQueryTime == nil || sqlQueryCounter == nil { 992 return 993 } 994 sqlQueryCounter.WithLabelValues(store, query).Inc() 995 duration := time.Since(startTime).Seconds() 996 sqlQueryTime.WithLabelValues(store, query).Add(duration) 997 } 998 } 999 1000 func StartActiveSubscriptionCountGRPC(subscribedToType string) func() { 1001 if subscriptionGauge == nil { 1002 return func() {} 1003 } 1004 1005 subscriptionGauge.WithLabelValues("GRPC", subscribedToType).Inc() 1006 return func() { 1007 subscriptionGauge.WithLabelValues("GRPC", subscribedToType).Dec() 1008 } 1009 } 1010 1011 func StartActiveEventBusConnection() func() { 1012 if eventBusConnectionGauge == nil { 1013 return func() {} 1014 } 1015 1016 eventBusConnectionGauge.Inc() 1017 return func() { 1018 eventBusConnectionGauge.Dec() 1019 } 1020 } 1021 1022 func StartEventBusActiveSubscriptionCount(eventTypes []events.Type) { 1023 if eventBusSubscriptionGauge == nil { 1024 return 1025 } 1026 1027 for _, eventType := range eventTypes { 1028 eventBusSubscriptionGauge.WithLabelValues(eventType.String()).Inc() 1029 } 1030 } 1031 1032 func StopEventBusActiveSubscriptionCount(eventTypes []events.Type) { 1033 if eventBusSubscriptionGauge == nil { 1034 return 1035 } 1036 1037 for _, eventType := range eventTypes { 1038 eventBusSubscriptionGauge.WithLabelValues(eventType.String()).Dec() 1039 } 1040 }