1// Copyright 2015 The etcd Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package mvcc
16
17import (
18	"sync"
19
20	"github.com/prometheus/client_golang/prometheus"
21)
22
23var (
24	rangeCounter = prometheus.NewCounter(
25		prometheus.CounterOpts{
26			Namespace: "etcd_debugging",
27			Subsystem: "mvcc",
28			Name:      "range_total",
29			Help:      "Total number of ranges seen by this member.",
30		})
31
32	putCounter = prometheus.NewCounter(
33		prometheus.CounterOpts{
34			Namespace: "etcd_debugging",
35			Subsystem: "mvcc",
36			Name:      "put_total",
37			Help:      "Total number of puts seen by this member.",
38		})
39
40	deleteCounter = prometheus.NewCounter(
41		prometheus.CounterOpts{
42			Namespace: "etcd_debugging",
43			Subsystem: "mvcc",
44			Name:      "delete_total",
45			Help:      "Total number of deletes seen by this member.",
46		})
47
48	txnCounter = prometheus.NewCounter(
49		prometheus.CounterOpts{
50			Namespace: "etcd_debugging",
51			Subsystem: "mvcc",
52			Name:      "txn_total",
53			Help:      "Total number of txns seen by this member.",
54		})
55
56	keysGauge = prometheus.NewGauge(
57		prometheus.GaugeOpts{
58			Namespace: "etcd_debugging",
59			Subsystem: "mvcc",
60			Name:      "keys_total",
61			Help:      "Total number of keys.",
62		})
63
64	watchStreamGauge = prometheus.NewGauge(
65		prometheus.GaugeOpts{
66			Namespace: "etcd_debugging",
67			Subsystem: "mvcc",
68			Name:      "watch_stream_total",
69			Help:      "Total number of watch streams.",
70		})
71
72	watcherGauge = prometheus.NewGauge(
73		prometheus.GaugeOpts{
74			Namespace: "etcd_debugging",
75			Subsystem: "mvcc",
76			Name:      "watcher_total",
77			Help:      "Total number of watchers.",
78		})
79
80	slowWatcherGauge = prometheus.NewGauge(
81		prometheus.GaugeOpts{
82			Namespace: "etcd_debugging",
83			Subsystem: "mvcc",
84			Name:      "slow_watcher_total",
85			Help:      "Total number of unsynced slow watchers.",
86		})
87
88	totalEventsCounter = prometheus.NewCounter(
89		prometheus.CounterOpts{
90			Namespace: "etcd_debugging",
91			Subsystem: "mvcc",
92			Name:      "events_total",
93			Help:      "Total number of events sent by this member.",
94		})
95
96	pendingEventsGauge = prometheus.NewGauge(
97		prometheus.GaugeOpts{
98			Namespace: "etcd_debugging",
99			Subsystem: "mvcc",
100			Name:      "pending_events_total",
101			Help:      "Total number of pending events to be sent.",
102		})
103
104	indexCompactionPauseDurations = prometheus.NewHistogram(
105		prometheus.HistogramOpts{
106			Namespace: "etcd_debugging",
107			Subsystem: "mvcc",
108			Name:      "index_compaction_pause_duration_milliseconds",
109			Help:      "Bucketed histogram of index compaction pause duration.",
110			// 0.5ms -> 1second
111			Buckets: prometheus.ExponentialBuckets(0.5, 2, 12),
112		})
113
114	dbCompactionPauseDurations = prometheus.NewHistogram(
115		prometheus.HistogramOpts{
116			Namespace: "etcd_debugging",
117			Subsystem: "mvcc",
118			Name:      "db_compaction_pause_duration_milliseconds",
119			Help:      "Bucketed histogram of db compaction pause duration.",
120			// 1ms -> 4second
121			Buckets: prometheus.ExponentialBuckets(1, 2, 13),
122		})
123
124	dbCompactionTotalDurations = prometheus.NewHistogram(
125		prometheus.HistogramOpts{
126			Namespace: "etcd_debugging",
127			Subsystem: "mvcc",
128			Name:      "db_compaction_total_duration_milliseconds",
129			Help:      "Bucketed histogram of db compaction total duration.",
130			// 100ms -> 800second
131			Buckets: prometheus.ExponentialBuckets(100, 2, 14),
132		})
133
134	dbTotalSizeDebugging = prometheus.NewGaugeFunc(prometheus.GaugeOpts{
135		Namespace: "etcd_debugging",
136		Subsystem: "mvcc",
137		Name:      "db_total_size_in_bytes",
138		Help:      "Total size of the underlying database physically allocated in bytes. Use etcd_mvcc_db_total_size_in_bytes",
139	},
140		func() float64 {
141			reportDbTotalSizeInBytesMu.RLock()
142			defer reportDbTotalSizeInBytesMu.RUnlock()
143			return reportDbTotalSizeInBytes()
144		},
145	)
146	// overridden
147
148	dbTotalSize = prometheus.NewGaugeFunc(prometheus.GaugeOpts{
149		Namespace: "etcd",
150		Subsystem: "mvcc",
151		Name:      "db_total_size_in_bytes",
152		Help:      "Total size of the underlying database physically allocated in bytes.",
153	},
154		func() float64 {
155			reportDbTotalSizeInBytesMu.RLock()
156			defer reportDbTotalSizeInBytesMu.RUnlock()
157			return reportDbTotalSizeInBytes()
158		},
159	)
160	// overridden by mvcc initialization
161	reportDbTotalSizeInBytesMu sync.RWMutex
162	reportDbTotalSizeInBytes   = func() float64 { return 0 }
163
164	dbTotalSizeInUse = prometheus.NewGaugeFunc(prometheus.GaugeOpts{
165		Namespace: "etcd",
166		Subsystem: "mvcc",
167		Name:      "db_total_size_in_use_in_bytes",
168		Help:      "Total size of the underlying database logically in use in bytes.",
169	},
170		func() float64 {
171			reportDbTotalSizeInUseInBytesMu.RLock()
172			defer reportDbTotalSizeInUseInBytesMu.RUnlock()
173			return reportDbTotalSizeInUseInBytes()
174		},
175	)
176	// overridden by mvcc initialization
177	reportDbTotalSizeInUseInBytesMu sync.RWMutex
178	reportDbTotalSizeInUseInBytes   func() float64 = func() float64 { return 0 }
179
180	hashDurations = prometheus.NewHistogram(prometheus.HistogramOpts{
181		Namespace: "etcd",
182		Subsystem: "mvcc",
183		Name:      "hash_duration_seconds",
184		Help:      "The latency distribution of storage hash operation.",
185
186		// 100 MB usually takes 100 ms, so start with 10 MB of 10 ms
187		// lowest bucket start of upper bound 0.01 sec (10 ms) with factor 2
188		// highest bucket start of 0.01 sec * 2^14 == 163.84 sec
189		Buckets: prometheus.ExponentialBuckets(.01, 2, 15),
190	})
191)
192
193func init() {
194	prometheus.MustRegister(rangeCounter)
195	prometheus.MustRegister(putCounter)
196	prometheus.MustRegister(deleteCounter)
197	prometheus.MustRegister(txnCounter)
198	prometheus.MustRegister(keysGauge)
199	prometheus.MustRegister(watchStreamGauge)
200	prometheus.MustRegister(watcherGauge)
201	prometheus.MustRegister(slowWatcherGauge)
202	prometheus.MustRegister(totalEventsCounter)
203	prometheus.MustRegister(pendingEventsGauge)
204	prometheus.MustRegister(indexCompactionPauseDurations)
205	prometheus.MustRegister(dbCompactionPauseDurations)
206	prometheus.MustRegister(dbCompactionTotalDurations)
207	prometheus.MustRegister(dbTotalSizeDebugging)
208	prometheus.MustRegister(dbTotalSize)
209	prometheus.MustRegister(dbTotalSizeInUse)
210	prometheus.MustRegister(hashDurations)
211}
212
213// ReportEventReceived reports that an event is received.
214// This function should be called when the external systems received an
215// event from mvcc.Watcher.
216func ReportEventReceived(n int) {
217	pendingEventsGauge.Sub(float64(n))
218	totalEventsCounter.Add(float64(n))
219}
220