YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/util/metrics.cc
Line
Count
Source (jump to first uncovered line)
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
//
18
// The following only applies to changes made to this file as part of YugaByte development.
19
//
20
// Portions Copyright (c) YugaByte, Inc.
21
//
22
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
23
// in compliance with the License.  You may obtain a copy of the License at
24
//
25
// http://www.apache.org/licenses/LICENSE-2.0
26
//
27
// Unless required by applicable law or agreed to in writing, software distributed under the License
28
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
29
// or implied.  See the License for the specific language governing permissions and limitations
30
// under the License.
31
//
32
33
#include "yb/util/metrics.h"
34
35
#include <map>
36
#include <set>
37
38
#include "yb/gutil/atomicops.h"
39
#include "yb/gutil/casts.h"
40
#include "yb/gutil/map-util.h"
41
42
#include "yb/util/hdr_histogram.h"
43
#include "yb/util/histogram.pb.h"
44
#include "yb/util/jsonwriter.h"
45
#include "yb/util/locks.h"
46
#include "yb/util/status.h"
47
#include "yb/util/status_log.h"
48
49
DEFINE_bool(expose_metric_histogram_percentiles, true,
50
            "Should we expose the percentiles information for metrics histograms.");
51
52
DEFINE_int32(max_tables_metrics_breakdowns, INT32_MAX,
53
             "The maxmimum number of tables to retrieve metrics for");
54
55
// Process/server-wide metrics should go into the 'server' entity.
56
// More complex applications will define other entities.
57
METRIC_DEFINE_entity(server);
58
59
namespace yb {
60
61
void RegisterMetricPrototype(const MetricPrototype* prototype);
62
63
using std::string;
64
using std::vector;
65
using strings::Substitute;
66
67
//
68
// MetricUnit
69
//
70
71
35
const char* MetricUnit::Name(Type unit) {
72
35
  switch (unit) {
73
0
    case kCacheHits:
74
0
      return "hits";
75
0
    case kCacheQueries:
76
0
      return "queries";
77
9
    case kBytes:
78
9
      return "bytes";
79
1
    case kRequests:
80
1
      return "requests";
81
0
    case kEntries:
82
0
      return "entries";
83
0
    case kRows:
84
0
      return "rows";
85
0
    case kCells:
86
0
      return "cells";
87
0
    case kConnections:
88
0
      return "connections";
89
0
    case kOperations:
90
0
      return "operations";
91
0
    case kProbes:
92
0
      return "probes";
93
0
    case kNanoseconds:
94
0
      return "nanoseconds";
95
1
    case kMicroseconds:
96
1
      return "microseconds";
97
7
    case kMilliseconds:
98
7
      return "milliseconds";
99
0
    case kSeconds:
100
0
      return "seconds";
101
2
    case kThreads:
102
2
      return "threads";
103
0
    case kTransactions:
104
0
      return "transactions";
105
0
    case kUnits:
106
0
      return "units";
107
0
    case kMaintenanceOperations:
108
0
      return "operations";
109
7
    case kBlocks:
110
7
      return "blocks";
111
0
    case kLogBlockContainers:
112
0
      return "log block containers";
113
3
    case kTasks:
114
3
      return "tasks";
115
0
    case kMessages:
116
0
      return "messages";
117
2
    case kContextSwitches:
118
2
      return "context switches";
119
3
    case kFiles:
120
3
      return "files";
121
0
    default:
122
0
      return "UNKNOWN UNIT";
123
35
  }
124
35
}
125
126
//
127
// MetricType
128
//
129
130
const char* const MetricType::kGaugeType = "gauge";
131
const char* const MetricType::kCounterType = "counter";
132
const char* const MetricType::kHistogramType = "histogram";
133
35
const char* MetricType::Name(MetricType::Type type) {
134
35
  switch (type) {
135
17
    case kGauge:
136
17
      return kGaugeType;
137
15
    case kCounter:
138
15
      return kCounterType;
139
1
    case kHistogram:
140
1
      return kHistogramType;
141
2
    default:
142
2
      return "UNKNOWN TYPE";
143
35
  }
144
35
}
145
146
namespace {
147
148
35
const char* MetricLevelName(MetricLevel level) {
149
35
  switch (level) {
150
0
    case MetricLevel::kDebug:
151
0
      return "debug";
152
35
    case MetricLevel::kInfo:
153
35
      return "info";
154
0
    case MetricLevel::kWarn:
155
0
      return "warn";
156
0
    default:
157
0
      return "UNKNOWN LEVEL";
158
35
  }
159
35
}
160
161
} // anonymous namespace
162
163
//
164
// MetricRegistry
165
//
166
167
19.5k
MetricRegistry::MetricRegistry() {
168
19.5k
}
169
170
2.25k
MetricRegistry::~MetricRegistry() {
171
2.25k
}
172
173
646k
bool MetricRegistry::TabletHasBeenShutdown(const scoped_refptr<MetricEntity> entity) const {
174
646k
    if (strcmp(entity->prototype_->name(), "tablet") == 0 && tablets_shutdown_find(entity->id())) {
175
0
      DVLOG(5) << "Do not report metrics for shutdown tablet " << entity->id();
176
263
      return true;
177
263
    }
178
179
646k
    return false;
180
646k
}
181
182
Status MetricRegistry::WriteAsJson(JsonWriter* writer,
183
                                   const vector<string>& requested_metrics,
184
15.3k
                                   const MetricJsonOptions& opts) const {
185
15.3k
  EntityMap entities;
186
15.3k
  {
187
15.3k
    std::lock_guard<simple_spinlock> l(lock_);
188
15.3k
    entities = entities_;
189
15.3k
  }
190
191
15.3k
  writer->StartArray();
192
646k
  for (const EntityMap::value_type& e : entities) {
193
646k
    if (TabletHasBeenShutdown(e.second)) {
194
263
      continue;
195
263
    }
196
197
645k
    WARN_NOT_OK(e.second->WriteAsJson(writer, requested_metrics, opts),
198
645k
                Substitute("Failed to write entity $0 as JSON", e.second->id()));
199
645k
  }
200
15.3k
  writer->EndArray();
201
202
  // Rather than having a thread poll metrics periodically to retire old ones,
203
  // we'll just retire them here. The only downside is that, if no one is polling
204
  // metrics, we may end up leaving them around indefinitely; however, metrics are
205
  // small, and one might consider it a feature: if monitoring stops polling for
206
  // metrics, we should keep them around until the next poll.
207
15.3k
  entities.clear(); // necessary to deref metrics we just dumped before doing retirement scan.
208
15.3k
  const_cast<MetricRegistry*>(this)->RetireOldMetrics();
209
15.3k
  return Status::OK();
210
15.3k
}
211
212
CHECKED_STATUS MetricRegistry::WriteForPrometheus(PrometheusWriter* writer,
213
0
                                                  const MetricPrometheusOptions& opts) const {
214
0
  return WriteForPrometheus(writer, {""}, opts);  // Include all metrics.
215
0
}
216
217
CHECKED_STATUS MetricRegistry::WriteForPrometheus(PrometheusWriter* writer,
218
                                                  const vector<string>& requested_metrics,
219
19
                                                  const MetricPrometheusOptions& opts) const {
220
19
  EntityMap entities;
221
19
  {
222
19
    std::lock_guard<simple_spinlock> l(lock_);
223
19
    entities = entities_;
224
19
  }
225
226
226
  for (const EntityMap::value_type& e : entities) {
227
226
    if (TabletHasBeenShutdown(e.second)) {
228
0
      continue;
229
0
    }
230
231
226
    WARN_NOT_OK(e.second->WriteForPrometheus(writer, requested_metrics, opts),
232
226
                Substitute("Failed to write entity $0 as Prometheus", e.second->id()));
233
226
  }
234
19
  RETURN_NOT_OK(writer->FlushAggregatedValues(opts.max_tables_metrics_breakdowns,
235
19
                opts.priority_regex));
236
237
  // Rather than having a thread poll metrics periodically to retire old ones,
238
  // we'll just retire them here. The only downside is that, if no one is polling
239
  // metrics, we may end up leaving them around indefinitely; however, metrics are
240
  // small, and one might consider it a feature: if monitoring stops polling for
241
  // metrics, we should keep them around until the next poll.
242
19
  entities.clear(); // necessary to deref metrics we just dumped before doing retirement scan.
243
19
  const_cast<MetricRegistry*>(this)->RetireOldMetrics();
244
19
  return Status::OK();
245
19
}
246
247
17.0k
void MetricRegistry::RetireOldMetrics() {
248
17.0k
  std::lock_guard<simple_spinlock> l(lock_);
249
698k
  for (auto it = entities_.begin(); it != entities_.end();) {
250
681k
    it->second->RetireOldMetrics();
251
252
681k
    if (it->second->num_metrics() == 0 && it->second->HasOneRef()) {
253
      // No metrics and no external references to this entity, so we can retire it.
254
      // Unlike retiring the metrics themselves, we don't wait for any timeout
255
      // to retire them -- we assume that that timed retention has been satisfied
256
      // by holding onto the metrics inside the entity.
257
258
      // For a tablet that has been shutdown, metrics are being deleted. So do not track
259
      // the tablet anymore.
260
1.88k
      if (strcmp(it->second->prototype_->name(), "tablet") == 0) {
261
0
        DVLOG(3) << "T " << it->first << ": "
262
0
          << "Remove from set of tablets that have been shutdown so as to be freed";
263
1.52k
        tablets_shutdown_erase(it->first);
264
1.52k
      }
265
266
1.88k
      entities_.erase(it++);
267
679k
    } else {
268
679k
      ++it;
269
679k
    }
270
681k
  }
271
17.0k
}
272
273
//
274
// MetricPrototype
275
//
276
22.0M
MetricPrototype::MetricPrototype(CtorArgs args) : args_(std::move(args)) {
277
22.0M
  RegisterMetricPrototype(this);
278
22.0M
}
279
280
void MetricPrototype::WriteFields(JsonWriter* writer,
281
75.8M
                                  const MetricJsonOptions& opts) const {
282
75.8M
  writer->String("name");
283
75.8M
  writer->String(name());
284
285
75.8M
  if (opts.include_schema_info) {
286
35
    writer->String("label");
287
35
    writer->String(label());
288
289
35
    writer->String("type");
290
35
    writer->String(MetricType::Name(type()));
291
292
35
    writer->String("unit");
293
35
    writer->String(MetricUnit::Name(unit()));
294
295
35
    writer->String("description");
296
35
    writer->String(description());
297
298
35
    writer->String("level");
299
35
    writer->String(MetricLevelName(level()));
300
35
  }
301
75.8M
}
302
303
//
304
// FunctionGaugeDetacher
305
//
306
307
scoped_refptr<MetricEntity> MetricRegistry::FindOrCreateEntity(
308
    const MetricEntityPrototype* prototype,
309
    const std::string& id,
310
208k
    const MetricEntity::AttributeMap& initial_attributes) {
311
208k
  std::lock_guard<simple_spinlock> l(lock_);
312
208k
  scoped_refptr<MetricEntity> e = FindPtrOrNull(entities_, id);
313
208k
  if (!e) {
314
130k
    e = new MetricEntity(prototype, id, initial_attributes);
315
130k
    InsertOrDie(&entities_, id, e);
316
77.7k
  } else {
317
77.7k
    e->SetAttributes(initial_attributes);
318
77.7k
  }
319
208k
  return e;
320
208k
}
321
322
//
323
// Metric
324
//
325
Metric::Metric(const MetricPrototype* prototype)
326
20.1M
  : prototype_(prototype) {
327
20.1M
}
328
329
Metric::Metric(std::unique_ptr<MetricPrototype> prototype)
330
2.19M
  : prototype_holder_(std::move(prototype)), prototype_(prototype_holder_.get()) {
331
2.19M
}
332
333
1.93M
Metric::~Metric() {
334
1.93M
}
335
336
//
337
// Gauge
338
//
339
340
Status Gauge::WriteAsJson(JsonWriter* writer,
341
59.8M
                          const MetricJsonOptions& opts) const {
342
59.8M
  if (prototype_->level() < opts.level) {
343
0
    return Status::OK();
344
0
  }
345
346
59.8M
  writer->StartObject();
347
348
59.8M
  prototype_->WriteFields(writer, opts);
349
350
59.8M
  writer->String("value");
351
59.8M
  WriteValue(writer);
352
353
59.8M
  writer->EndObject();
354
59.8M
  return Status::OK();
355
59.8M
}
356
357
//
358
// StringGauge
359
//
360
361
StringGauge::StringGauge(const GaugePrototype<string>* proto,
362
                         string initial_value)
363
0
    : Gauge(proto), value_(std::move(initial_value)) {}
364
365
0
std::string StringGauge::value() const {
366
0
  std::lock_guard<simple_spinlock> l(lock_);
367
0
  return value_;
368
0
}
369
370
0
void StringGauge::set_value(const std::string& value) {
371
0
  std::lock_guard<simple_spinlock> l(lock_);
372
0
  value_ = value;
373
0
}
374
375
0
void StringGauge::WriteValue(JsonWriter* writer) const {
376
0
  writer->String(value());
377
0
}
378
379
CHECKED_STATUS StringGauge::WriteForPrometheus(
380
    PrometheusWriter* writer, const MetricEntity::AttributeMap& attr,
381
0
    const MetricPrometheusOptions& opts) const {
382
0
  if (prototype_->level() < opts.level) {
383
0
    return Status::OK();
384
0
  }
385
386
  // TODO(bogdan): don't think we need this?
387
  // return writer->WriteSingleEntry(attr, prototype_->name(), value());
388
0
  return Status::OK();
389
0
}
390
391
//
392
// Counter
393
//
394
// This implementation is optimized by using a striped counter. See LongAdder for details.
395
396
scoped_refptr<Counter> CounterPrototype::Instantiate(
397
12.3M
    const scoped_refptr<MetricEntity>& entity) const {
398
12.3M
  return entity->FindOrCreateCounter(this);
399
12.3M
}
400
401
7.69M
Counter::Counter(const CounterPrototype* proto) : Metric(proto) {
402
7.69M
}
403
404
15.4M
int64_t Counter::value() const {
405
15.4M
  return value_.Value();
406
15.4M
}
407
408
113M
void Counter::Increment() {
409
113M
  IncrementBy(1);
410
113M
}
411
412
289M
void Counter::IncrementBy(int64_t amount) {
413
289M
  value_.IncrementBy(amount);
414
289M
}
415
416
Status Counter::WriteAsJson(JsonWriter* writer,
417
15.4M
                            const MetricJsonOptions& opts) const {
418
15.4M
  if (prototype_->level() < opts.level) {
419
0
    return Status::OK();
420
0
  }
421
422
15.4M
  writer->StartObject();
423
424
15.4M
  prototype_->WriteFields(writer, opts);
425
426
15.4M
  writer->String("value");
427
15.4M
  writer->Int64(value());
428
429
15.4M
  writer->EndObject();
430
15.4M
  return Status::OK();
431
15.4M
}
432
433
CHECKED_STATUS Counter::WriteForPrometheus(
434
    PrometheusWriter* writer, const MetricEntity::AttributeMap& attr,
435
13.6k
    const MetricPrometheusOptions& opts) const {
436
13.6k
  if (prototype_->level() < opts.level) {
437
0
    return Status::OK();
438
0
  }
439
440
13.6k
  return writer->WriteSingleEntry(attr, prototype_->name(), value(),
441
13.6k
                                  prototype()->aggregation_function());
442
13.6k
}
443
444
//
445
// MillisLag
446
//
447
448
scoped_refptr<MillisLag> MillisLagPrototype::Instantiate(
449
0
    const scoped_refptr<MetricEntity>& entity) const {
450
0
  return entity->FindOrCreateMillisLag(this);
451
0
}
452
453
MillisLag::MillisLag(const MillisLagPrototype* proto)
454
  : Metric(proto),
455
    timestamp_ms_(static_cast<int64_t>(std::chrono::duration_cast<std::chrono::milliseconds>(
456
105k
        std::chrono::system_clock::now().time_since_epoch()).count())) {
457
105k
}
458
459
0
Status MillisLag::WriteAsJson(JsonWriter* writer, const MetricJsonOptions& opts) const {
460
0
  if (prototype_->level() < opts.level) {
461
0
    return Status::OK();
462
0
  }
463
464
0
  writer->StartObject();
465
466
0
  prototype_->WriteFields(writer, opts);
467
468
0
  writer->String("value");
469
0
  writer->Int64(lag_ms());
470
471
0
  writer->EndObject();
472
0
  return Status::OK();
473
0
}
474
475
Status MillisLag::WriteForPrometheus(
476
    PrometheusWriter* writer, const MetricEntity::AttributeMap& attr,
477
0
    const MetricPrometheusOptions& opts) const {
478
0
  if (prototype_->level() < opts.level) {
479
0
    return Status::OK();
480
0
  }
481
482
0
  return writer->WriteSingleEntry(attr, prototype_->name(), lag_ms(),
483
0
                                  prototype()->aggregation_function());
484
0
}
485
486
AtomicMillisLag::AtomicMillisLag(const MillisLagPrototype* proto)
487
  : MillisLag(proto),
488
    atomic_timestamp_ms_(static_cast<int64_t>(std::chrono::duration_cast<std::chrono::milliseconds>(
489
105k
        std::chrono::system_clock::now().time_since_epoch()).count())) {
490
105k
}
491
492
525k
Status AtomicMillisLag::WriteAsJson(JsonWriter* writer, const MetricJsonOptions& opts) const {
493
525k
  if (prototype_->level() < opts.level) {
494
0
    return Status::OK();
495
0
  }
496
497
525k
  writer->StartObject();
498
499
525k
  prototype_->WriteFields(writer, opts);
500
501
525k
  writer->String("value");
502
525k
  writer->Int64(this->lag_ms());
503
504
525k
  writer->EndObject();
505
525k
  return Status::OK();
506
525k
}
507
508
/////////////////////////////////////////////////
509
// HistogramPrototype
510
/////////////////////////////////////////////////
511
512
HistogramPrototype::HistogramPrototype(const MetricPrototype::CtorArgs& args,
513
                                       uint64_t max_trackable_value, int num_sig_digits,
514
                                       ExportPercentiles export_percentiles)
515
  : MetricPrototype(args),
516
    max_trackable_value_(max_trackable_value),
517
    num_sig_digits_(num_sig_digits),
518
4.37M
    export_percentiles_(export_percentiles) {
519
  // Better to crash at definition time that at instantiation time.
520
0
  CHECK(HdrHistogram::IsValidHighestTrackableValue(max_trackable_value))
521
0
      << Substitute("Invalid max trackable value on histogram $0: $1",
522
0
                    args.name_, max_trackable_value);
523
0
  CHECK(HdrHistogram::IsValidNumSignificantDigits(num_sig_digits))
524
0
      << Substitute("Invalid number of significant digits on histogram $0: $1",
525
0
                    args.name_, num_sig_digits);
526
4.37M
}
527
528
scoped_refptr<Histogram> HistogramPrototype::Instantiate(
529
7.50M
    const scoped_refptr<MetricEntity>& entity) const {
530
7.50M
  return entity->FindOrCreateHistogram(this);
531
7.50M
}
532
533
/////////////////////////////////////////////////
534
// Histogram
535
/////////////////////////////////////////////////
536
537
Histogram::Histogram(const HistogramPrototype* proto)
538
  : Metric(proto),
539
    histogram_(new HdrHistogram(proto->max_trackable_value(), proto->num_sig_digits())),
540
2.32M
    export_percentiles_(proto->export_percentiles()) {
541
2.32M
}
542
543
Histogram::Histogram(
544
  std::unique_ptr <HistogramPrototype> proto,  uint64_t highest_trackable_value,
545
  int num_significant_digits, ExportPercentiles export_percentiles)
546
  : Metric(std::move(proto)),
547
    histogram_(new HdrHistogram(highest_trackable_value, num_significant_digits)),
548
43.7k
    export_percentiles_(export_percentiles) {
549
43.7k
}
550
551
269M
void Histogram::Increment(int64_t value) {
552
269M
  histogram_->Increment(value);
553
269M
}
554
555
1
void Histogram::IncrementBy(int64_t value, int64_t amount) {
556
1
  histogram_->IncrementBy(value, amount);
557
1
}
558
559
Status Histogram::WriteAsJson(JsonWriter* writer,
560
4.92M
                              const MetricJsonOptions& opts) const {
561
4.92M
  if (prototype_->level() < opts.level) {
562
0
    return Status::OK();
563
0
  }
564
565
4.92M
  HistogramSnapshotPB snapshot;
566
4.92M
  RETURN_NOT_OK(GetAndResetHistogramSnapshotPB(&snapshot, opts));
567
4.92M
  writer->Protobuf(snapshot);
568
4.92M
  return Status::OK();
569
4.92M
}
570
571
CHECKED_STATUS Histogram::WriteForPrometheus(
572
    PrometheusWriter* writer, const MetricEntity::AttributeMap& attr,
573
3.91k
    const MetricPrometheusOptions& opts) const {
574
3.91k
  if (prototype_->level() < opts.level) {
575
0
    return Status::OK();
576
0
  }
577
578
3.91k
  HdrHistogram snapshot(*histogram_);
579
  // HdrHistogram reports percentiles based on all the data points from the
580
  // begining of time. We are interested in the percentiles based on just
581
  // the "newly-arrived" data. So, we will reset the histogram's percentiles
582
  // between each invocation.
583
3.91k
  histogram_->ResetPercentiles();
584
585
  // Representing the sum and count require suffixed names.
586
3.91k
  std::string hist_name = prototype_->name();
587
3.91k
  auto copy_of_attr = attr;
588
3.91k
  RETURN_NOT_OK(writer->WriteSingleEntry(
589
3.91k
        copy_of_attr, hist_name + "_sum", snapshot.TotalSum(),
590
3.91k
        prototype()->aggregation_function()));
591
3.91k
  RETURN_NOT_OK(writer->WriteSingleEntry(
592
3.91k
        copy_of_attr, hist_name + "_count", snapshot.TotalCount(),
593
3.91k
        prototype()->aggregation_function()));
594
595
  // Copy the label map to add the quatiles.
596
3.91k
  if (export_percentiles_ && FLAGS_expose_metric_histogram_percentiles) {
597
2.75k
    copy_of_attr["quantile"] = "p50";
598
2.75k
    RETURN_NOT_OK(writer->WriteSingleEntry(copy_of_attr, hist_name,
599
2.75k
                                           snapshot.ValueAtPercentile(50),
600
2.75k
                                           prototype()->aggregation_function()));
601
2.75k
    copy_of_attr["quantile"] = "p95";
602
2.75k
    RETURN_NOT_OK(writer->WriteSingleEntry(copy_of_attr, hist_name,
603
2.75k
                                           snapshot.ValueAtPercentile(95),
604
2.75k
                                           prototype()->aggregation_function()));
605
2.75k
    copy_of_attr["quantile"] = "p99";
606
2.75k
    RETURN_NOT_OK(writer->WriteSingleEntry(copy_of_attr, hist_name,
607
2.75k
                                           snapshot.ValueAtPercentile(99),
608
2.75k
                                           prototype()->aggregation_function()));
609
2.75k
    copy_of_attr["quantile"] = "mean";
610
2.75k
    RETURN_NOT_OK(writer->WriteSingleEntry(copy_of_attr, hist_name,
611
2.75k
                                           snapshot.MeanValue(),
612
2.75k
                                           prototype()->aggregation_function()));
613
2.75k
    copy_of_attr["quantile"] = "max";
614
2.75k
    RETURN_NOT_OK(writer->WriteSingleEntry(copy_of_attr, hist_name,
615
2.75k
                                           snapshot.MaxValue(),
616
2.75k
                                           prototype()->aggregation_function()));
617
2.75k
  }
618
3.91k
  return Status::OK();
619
3.91k
}
620
621
Status Histogram::GetAndResetHistogramSnapshotPB(HistogramSnapshotPB* snapshot_pb,
622
4.92M
                                                 const MetricJsonOptions& opts) const {
623
4.92M
  HdrHistogram snapshot(*histogram_);
624
  // HdrHistogram reports percentiles based on all the data points from the
625
  // begining of time. We are interested in the percentiles based on just
626
  // the "newly-arrived" data. So, we will reset the histogram's percentiles
627
  // between each invocation.
628
4.92M
  histogram_->ResetPercentiles();
629
630
4.92M
  snapshot_pb->set_name(prototype_->name());
631
4.92M
  if (opts.include_schema_info) {
632
0
    snapshot_pb->set_type(MetricType::Name(prototype_->type()));
633
0
    snapshot_pb->set_label(prototype_->label());
634
0
    snapshot_pb->set_unit(MetricUnit::Name(prototype_->unit()));
635
0
    snapshot_pb->set_description(prototype_->description());
636
0
    snapshot_pb->set_level(MetricLevelName(prototype_->level()));
637
0
    snapshot_pb->set_max_trackable_value(snapshot.highest_trackable_value());
638
0
    snapshot_pb->set_num_significant_digits(snapshot.num_significant_digits());
639
0
  }
640
4.92M
  snapshot_pb->set_total_count(snapshot.TotalCount());
641
4.92M
  snapshot_pb->set_total_sum(snapshot.TotalSum());
642
4.92M
  snapshot_pb->set_min(snapshot.MinValue());
643
4.92M
  snapshot_pb->set_mean(snapshot.MeanValue());
644
4.92M
  snapshot_pb->set_percentile_75(snapshot.ValueAtPercentile(75));
645
4.92M
  snapshot_pb->set_percentile_95(snapshot.ValueAtPercentile(95));
646
4.92M
  snapshot_pb->set_percentile_99(snapshot.ValueAtPercentile(99));
647
4.92M
  snapshot_pb->set_percentile_99_9(snapshot.ValueAtPercentile(99.9));
648
4.92M
  snapshot_pb->set_percentile_99_99(snapshot.ValueAtPercentile(99.99));
649
4.92M
  snapshot_pb->set_max(snapshot.MaxValue());
650
651
4.92M
  if (opts.include_raw_histograms) {
652
1
    RecordedValuesIterator iter(&snapshot);
653
101
    while (iter.HasNext()) {
654
100
      HistogramIterationValue value;
655
100
      RETURN_NOT_OK(iter.Next(&value));
656
100
      snapshot_pb->add_values(value.value_iterated_to);
657
100
      snapshot_pb->add_counts(value.count_at_value_iterated_to);
658
100
    }
659
1
  }
660
4.92M
  return Status::OK();
661
4.92M
}
662
663
0
uint64_t Histogram::CountInBucketForValueForTests(uint64_t value) const {
664
0
  return histogram_->CountInBucketForValue(value);
665
0
}
666
667
78.2k
uint64_t Histogram::TotalCount() const {
668
78.2k
  return histogram_->TotalCount();
669
78.2k
}
670
671
2
uint64_t Histogram::MinValueForTests() const {
672
2
  return histogram_->MinValue();
673
2
}
674
675
3
uint64_t Histogram::MaxValueForTests() const {
676
3
  return histogram_->MaxValue();
677
3
}
678
1
double Histogram::MeanValueForTests() const {
679
1
  return histogram_->MeanValue();
680
1
}
681
682
ScopedLatencyMetric::ScopedLatencyMetric(
683
    const scoped_refptr<Histogram>& latency_hist, Auto automatic)
684
27.9M
    : latency_hist_(latency_hist), auto_(automatic) {
685
27.9M
  Restart();
686
27.9M
}
687
688
ScopedLatencyMetric::ScopedLatencyMetric(ScopedLatencyMetric&& rhs)
689
    : latency_hist_(std::move(rhs.latency_hist_)), time_started_(rhs.time_started_),
690
0
      auto_(rhs.auto_) {
691
0
}
692
693
0
void ScopedLatencyMetric::operator=(ScopedLatencyMetric&& rhs) {
694
0
  if (auto_) {
695
0
    Finish();
696
0
  }
697
698
0
  latency_hist_ = std::move(rhs.latency_hist_);
699
0
  time_started_ = rhs.time_started_;
700
0
  auto_ = rhs.auto_;
701
0
}
702
703
27.9M
ScopedLatencyMetric::~ScopedLatencyMetric() {
704
27.9M
  if (auto_) {
705
27.9M
    Finish();
706
27.9M
  }
707
27.9M
}
708
709
27.9M
void ScopedLatencyMetric::Restart() {
710
27.9M
  if (latency_hist_) {
711
27.8M
    time_started_ = MonoTime::Now();
712
27.8M
  }
713
27.9M
}
714
715
27.9M
void ScopedLatencyMetric::Finish() {
716
27.9M
  if (latency_hist_ != nullptr) {
717
27.8M
    auto passed = (MonoTime::Now() - time_started_).ToMicroseconds();
718
27.8M
    latency_hist_->Increment(passed);
719
27.8M
  }
720
27.9M
}
721
722
// Replace specific chars with underscore to pass PrometheusNameRegex().
723
2.74M
void EscapeMetricNameForPrometheus(std::string *id) {
724
2.74M
  std::replace(id->begin(), id->end(), ' ', '_');
725
2.74M
  std::replace(id->begin(), id->end(), '.', '_');
726
2.74M
  std::replace(id->begin(), id->end(), '-', '_');
727
2.74M
}
728
729
} // namespace yb