blob: dec2721dd95a11599b4a8e3a00ac8f7f1a0ba959 [file] [log] [blame]
amit.ghosh6ab2a982022-09-15 21:04:53 +02001/*
Joey Armstrong7f8436c2023-07-09 20:23:27 -04002* Copyright 2018-2023 Open Networking Foundation (ONF) and the ONF Contributors
amit.ghosh6ab2a982022-09-15 21:04:53 +02003
Joey Armstrong7f8436c2023-07-09 20:23:27 -04004* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
amit.ghosh6ab2a982022-09-15 21:04:53 +02007
Joey Armstrong7f8436c2023-07-09 20:23:27 -04008* http://www.apache.org/licenses/LICENSE-2.0
amit.ghosh6ab2a982022-09-15 21:04:53 +02009
Joey Armstrong7f8436c2023-07-09 20:23:27 -040010* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
amit.ghosh6ab2a982022-09-15 21:04:53 +020015 */
16package stats
17
18import (
19 "context"
20 "fmt"
21 "net/http"
22 "time"
23
24 "github.com/opencord/voltha-lib-go/v7/pkg/log"
25 "github.com/prometheus/client_golang/prometheus"
26 "github.com/prometheus/client_golang/prometheus/promhttp"
27)
28
29const (
30 cPrefix = "voltha"
31)
32
33type PromStatsServer struct {
34 // To hold the counters which are specific to devices
35 devCounters *prometheus.CounterVec
36 // To hold the counters which are NOT tied to specific devices
37 otherCounters *prometheus.CounterVec
38 // To hold the durations which are specific to devices
39 devDurations *prometheus.HistogramVec
40 // To hold the durations which are NOT tied to specific to devices
41 otherDurations *prometheus.HistogramVec
42}
43
44var StatsServer = PromStatsServer{}
45
46// Start starts the statistics manager with name and makes the collected stats available
47// at port p. All the statistics collected by this collector will be appended with "voltha_(name)_"
48// when they appear in Prometheus. The function starts a prometheus HTTP listener in the background and does not return
49// any errors, the listener is stopped on context cancellation
50func (ps *PromStatsServer) Start(ctx context.Context, p int, name CollectorName) {
51 //log.SetLogger(logging.New())
52 ps.initializeCollectors(ctx, name)
53
54 logger.Infow(ctx, "Starting Statistics HTTP Server", log.Fields{"listeningPort": p})
55
56 http.Handle("/metrics", promhttp.Handler())
57 server := &http.Server{Addr: fmt.Sprintf(":%d", p), Handler: nil}
58
59 go func() {
60 <-ctx.Done()
61 logger.Infof(ctx, "Shutting down the Statistics HTTP server")
62 err := server.Shutdown(ctx)
63 if err != nil {
64 logger.Errorw(ctx, "Statistics server shutting down failure", log.Fields{"error": err})
65 }
66 }()
67
68 go func() {
69 err := server.ListenAndServe()
70 if err != nil && err != http.ErrServerClosed {
71 logger.Errorw(ctx, "Starting Statistics HTTP server error", log.Fields{"error": err})
72 }
73 }()
74
75 logger.Infow(ctx, "Started Prometheus listener for statistics on port", log.Fields{"port": p})
76}
77
78func (ps *PromStatsServer) initializeCollectors(ctx context.Context, name CollectorName) {
79 logger.Infof(ctx, "Initializing statistics collector")
80
81 collectorName := cPrefix + "_" + name.String()
82
83 var (
84 // in milliseconds
85 defBuckets = []float64{2, 5, 10, 25, 50, 100, 300, 1000, 5000}
86 )
87
88 ps.devCounters = prometheus.NewCounterVec(
89 prometheus.CounterOpts{
90 Namespace: collectorName,
91 Name: "device_counters",
92 Help: "Device specific counters",
93 },
94 []string{"device_id", "serial_no", "counter"},
95 )
96
97 ps.otherCounters = prometheus.NewCounterVec(
98 prometheus.CounterOpts{
99 Namespace: collectorName,
100 Name: "counters",
101 Help: "Non device counters",
102 },
103 []string{"counter"},
104 )
105
106 ps.devDurations = prometheus.NewHistogramVec(
107 prometheus.HistogramOpts{
108 Namespace: collectorName,
109 Name: "device_durations",
110 Help: "Time taken in ms to complete a specific task for a specific device",
111 Buckets: defBuckets,
112 },
113 []string{"device_id", "serial_no", "duration"},
114 )
115
116 ps.otherDurations = prometheus.NewHistogramVec(
117 prometheus.HistogramOpts{
118 Namespace: collectorName,
119 Name: "durations",
120 Help: "Time taken in ms to complete a specific task not tied to a device",
121 Buckets: defBuckets,
122 },
123 []string{"duration"},
124 )
125
126 prometheus.MustRegister(ps.devCounters)
127 prometheus.MustRegister(ps.otherCounters)
128 prometheus.MustRegister(ps.devDurations)
129 prometheus.MustRegister(ps.otherDurations)
130}
131
Joey Armstrong7f8436c2023-07-09 20:23:27 -0400132// CountForDevice counts the number of times the counterName happens for device devId with serial number sn. Each call to Count increments it by one.
amit.ghosh6ab2a982022-09-15 21:04:53 +0200133func (ps *PromStatsServer) CountForDevice(devId, sn string, counterName DeviceCounter) {
134 if ps.devCounters != nil {
135 ps.devCounters.WithLabelValues(devId, sn, counterName.String()).Inc()
136 }
137}
138
Joey Armstrong7f8436c2023-07-09 20:23:27 -0400139// AddForDevice adds val to counter.
amit.ghosh6ab2a982022-09-15 21:04:53 +0200140func (ps *PromStatsServer) AddForDevice(devId, sn string, counter DeviceCounter, val float64) {
141 if ps.devCounters != nil {
142 ps.devCounters.WithLabelValues(devId, sn, counter.String()).Add(val)
143 }
144}
145
Joey Armstrong7f8436c2023-07-09 20:23:27 -0400146// CollectDurationForDevice calculates the duration from startTime to time.Now() for device devID with serial number sn.
amit.ghosh6ab2a982022-09-15 21:04:53 +0200147func (ps *PromStatsServer) CollectDurationForDevice(devID, sn string, dName DeviceDuration, startTime time.Time) {
148 if ps.otherDurations != nil {
149 timeSpent := time.Since(startTime)
150 ps.devDurations.WithLabelValues(devID, sn, dName.String()).Observe(float64(timeSpent.Milliseconds()))
151 }
152}
153
Joey Armstrong7f8436c2023-07-09 20:23:27 -0400154// Count counts the number of times the counterName happens. Each call to Count increments it by one.
amit.ghosh6ab2a982022-09-15 21:04:53 +0200155func (ps *PromStatsServer) Count(counter NonDeviceCounter) {
156 if ps.otherCounters != nil {
157 ps.otherCounters.WithLabelValues(counter.String()).Inc()
158 }
159}
160
Joey Armstrong7f8436c2023-07-09 20:23:27 -0400161// Add adds val to counter.
amit.ghosh6ab2a982022-09-15 21:04:53 +0200162func (ps *PromStatsServer) Add(counter NonDeviceCounter, val float64) {
163 if ps.otherCounters != nil {
164 ps.otherCounters.WithLabelValues(counter.String()).Add(val)
165 }
166}
167
Joey Armstrong7f8436c2023-07-09 20:23:27 -0400168// CollectDuration calculates the duration from startTime to time.Now().
amit.ghosh6ab2a982022-09-15 21:04:53 +0200169func (ps *PromStatsServer) CollectDuration(dName NonDeviceDuration, startTime time.Time) {
170 if ps.otherDurations != nil {
171 timeSpent := time.Since(startTime)
172 ps.otherDurations.WithLabelValues(dName.String()).Observe(float64(timeSpent.Milliseconds()))
173 }
174}