@@ -141,7 +141,7 @@ func (a *AggHistogram) ToPrometheusMetric() *prometheusgo.Metric {
141141 return a .h .ToPrometheusMetric ()
142142}
143143
144- // AddChild adds a Counter to this AggHistogram. This method panics if a Counter
144+ // AddChild adds a Histogram to this AggHistogram. This method panics if a Histogram
145145// already exists for this set of labelVals.
146146func (a * AggHistogram ) AddChild (labelVals ... string ) * Histogram {
147147 child := & Histogram {
@@ -153,37 +153,6 @@ func (a *AggHistogram) AddChild(labelVals ...string) *Histogram {
153153 return child
154154}
155155
156- // RecordValue adds the given value to the histogram for the given label values. If a
157- // histogram with the given label values doesn't exist yet, it creates a new
158- // histogram and increments it. Panics if the number of label values doesn't
159- // match the number of labels defined for this histogram.
160- // Recording a value in excess of the configured maximum value for that histogram
161- // results in recording the maximum value instead.
162- func (a * AggHistogram ) RecordValue (v int64 , labelVals ... string ) {
163- if len (a .labels ) != len (labelVals ) {
164- panic (errors .AssertionFailedf (
165- "cannot increment child with %d label values %v to a metric with %d labels %v" ,
166- len (labelVals ), labelVals , len (a .labels ), a .labels ))
167- }
168-
169- // If the child already exists, update it.
170- if child , ok := a .get (labelVals ... ); ok {
171- child .(* Histogram ).RecordValue (v )
172- return
173- }
174-
175- // Otherwise, create a new child and update it.
176- child := a .AddChild (labelVals ... )
177- child .RecordValue (v )
178- }
179-
180- // RemoveChild removes a Gauge from this AggGauge. This method panics if a Gauge
181- // does not exist for this set of labelVals.
182- func (g * AggHistogram ) RemoveChild (labelVals ... string ) {
183- key := & Histogram {labelValuesSlice : labelValuesSlice (labelVals )}
184- g .remove (key )
185- }
186-
187156// Histogram is a child of a AggHistogram. When values are recorded, so too is the
188157// parent. When metrics are collected by prometheus, each of the children will
189158// appear with a distinct label, however, when cockroach internally collects
@@ -218,3 +187,168 @@ func (g *Histogram) RecordValue(v int64) {
218187 g .h .RecordValue (v )
219188 g .parent .h .RecordValue (v )
220189}
190+
191+ // SQLHistogram maintains a histogram as the sum of its children. The histogram will
192+ // report to crdb-internal time series only the aggregate sum of all of its
193+ // children, while its children are additionally exported to prometheus via the
194+ // PrometheusIterable interface. SQLHistogram differs from AggHistogram in that
195+ // a SQLHistogram creates child metrics dynamically while AggHistogram needs the
196+ // child creation up front.
197+ type SQLHistogram struct {
198+ h metric.IHistogram
199+ create func () metric.IHistogram
200+ * SQLMetric
201+ ticker struct {
202+ // We use a RWMutex, because we don't want child histograms to contend when
203+ // recording values, unless we're rotating histograms for the parent & children.
204+ // In this instance, the "writer" for the RWMutex is the ticker, and the "readers"
205+ // are all the child histograms recording their values.
206+ syncutil.RWMutex
207+ * tick.Ticker
208+ }
209+ }
210+
211+ var _ metric.Iterable = (* SQLHistogram )(nil )
212+ var _ metric.PrometheusIterable = (* SQLHistogram )(nil )
213+ var _ metric.PrometheusExportable = (* SQLHistogram )(nil )
214+ var _ metric.WindowedHistogram = (* SQLHistogram )(nil )
215+ var _ metric.CumulativeHistogram = (* SQLHistogram )(nil )
216+
217+ func NewSQLHistogram (opts metric.HistogramOptions ) * SQLHistogram {
218+ create := func () metric.IHistogram {
219+ return metric .NewHistogram (opts )
220+ }
221+ s := & SQLHistogram {
222+ h : create (),
223+ create : create ,
224+ }
225+ s .SQLMetric = NewSQLMetric (LabelConfigDisabled )
226+ s .ticker .Ticker = tick .NewTicker (
227+ now (),
228+ opts .Duration / metric .WindowedHistogramWrapNum ,
229+ func () {
230+ // Atomically rotate the histogram window for the
231+ // parent histogram, and all the child histograms.
232+ s .h .Tick ()
233+ s .apply (func (childMetric ChildMetric ) {
234+ childHist , ok := childMetric .(* SQLChildHistogram )
235+ if ! ok {
236+ panic (errors .AssertionFailedf (
237+ "unable to assert type of child for histogram %q when rotating histogram windows" ,
238+ opts .Metadata .Name ))
239+ }
240+ childHist .h .Tick ()
241+ })
242+ })
243+ return s
244+ }
245+
246+ // apply applies the given applyFn to every item in children
247+ func (sh * SQLHistogram ) apply (applyFn func (childMetric ChildMetric )) {
248+ sh .mu .Lock ()
249+ defer sh .mu .Unlock ()
250+ sh .mu .children .Do (func (e interface {}) {
251+ applyFn (sh .mu .children .GetChildMetric (e ).(* SQLChildHistogram ))
252+ })
253+ }
254+
255+ // GetType is part of the metric.PrometheusExportable interface.
256+ func (sh * SQLHistogram ) GetType () * prometheusgo.MetricType {
257+ return sh .h .GetType ()
258+ }
259+
260+ // GetLabels is part of the metric.PrometheusExportable interface.
261+ func (sh * SQLHistogram ) GetLabels (useStaticLabels bool ) []* prometheusgo.LabelPair {
262+ return sh .h .GetLabels (useStaticLabels )
263+ }
264+
265+ // ToPrometheusMetric is part of the metric.PrometheusExportable interface.
266+ func (sh * SQLHistogram ) ToPrometheusMetric () * prometheusgo.Metric {
267+ return sh .h .ToPrometheusMetric ()
268+ }
269+
270+ // GetName is part of the metric.Iterable interface.
271+ func (sh * SQLHistogram ) GetName (useStaticLabels bool ) string {
272+ return sh .h .GetName (useStaticLabels )
273+ }
274+
275+ // GetHelp is part of the metric.Iterable interface.
276+ func (sh * SQLHistogram ) GetHelp () string {
277+ return sh .h .GetHelp ()
278+ }
279+
280+ // GetMeasurement is part of the metric.Iterable interface.
281+ func (sh * SQLHistogram ) GetMeasurement () string {
282+ return sh .h .GetMeasurement ()
283+ }
284+
285+ // GetUnit is part of the metric.Iterable interface.
286+ func (sh * SQLHistogram ) GetUnit () metric.Unit {
287+ return sh .h .GetUnit ()
288+ }
289+
290+ // GetMetadata is part of the metric.Iterable interface.
291+ func (sh * SQLHistogram ) GetMetadata () metric.Metadata {
292+ return sh .h .GetMetadata ()
293+ }
294+
295+ // Inspect is part of the metric.Iterable interface.
296+ func (sh * SQLHistogram ) Inspect (f func (interface {})) {
297+ f (sh )
298+ }
299+
300+ // RecordValue records the Histogram value for the given label values. If a
301+ // Histogram with the given label values doesn't exist yet, it creates a new
302+ // Histogram and record against it. RecordValue records value in parent metrics
303+ // irrespective of labelConfig.
304+ func (sh * SQLHistogram ) RecordValue (v int64 , db , app string ) {
305+ childMetric , isChildMetricEnabled := sh .getChildByLabelConfig (sh .createChildHistogram , db , app )
306+ sh .ticker .RLock ()
307+ defer sh .ticker .RUnlock ()
308+
309+ sh .h .RecordValue (v )
310+ if ! isChildMetricEnabled {
311+ return
312+ }
313+ childMetric .(* SQLChildHistogram ).RecordValue (v )
314+ }
315+
316+ // CumulativeSnapshot is part of the metric.CumulativeHistogram interface.
317+ func (sh * SQLHistogram ) CumulativeSnapshot () metric.HistogramSnapshot {
318+ return sh .h .CumulativeSnapshot ()
319+ }
320+
321+ // WindowedSnapshot is part of the metric.WindowedHistogram interface.
322+ func (sh * SQLHistogram ) WindowedSnapshot () metric.HistogramSnapshot {
323+ return sh .h .WindowedSnapshot ()
324+ }
325+
326+ func (sh * SQLHistogram ) createChildHistogram (labelValues labelValuesSlice ) ChildMetric {
327+ return & SQLChildHistogram {
328+ h : sh .create (),
329+ labelValuesSlice : labelValues ,
330+ }
331+ }
332+
333+ // SQLChildHistogram is a child of a SQLHistogram. When metrics are collected by prometheus,
334+ // each of the children will appear with a distinct label, however, when cockroach
335+ // internally collects metrics, only the parent is collected.
336+ type SQLChildHistogram struct {
337+ labelValuesSlice
338+ h metric.IHistogram
339+ }
340+
341+ // ToPrometheusMetric constructs a prometheus metric for this Histogram.
342+ func (sch * SQLChildHistogram ) ToPrometheusMetric () * prometheusgo.Metric {
343+ return sch .h .ToPrometheusMetric ()
344+ }
345+
346+ // RecordValue sets the histogram's value.
347+ func (sch * SQLChildHistogram ) RecordValue (v int64 ) {
348+ sch .h .RecordValue (v )
349+ }
350+
351+ // Value returns the SQLChildHistogram's current gauge.
352+ func (sch * SQLChildHistogram ) Value () metric.HistogramSnapshot {
353+ return sch .h .CumulativeSnapshot ()
354+ }
0 commit comments