1
#include "source/common/stats/metric_impl.h"
2

            
3
#include "envoy/stats/tag.h"
4

            
5
#include "source/common/stats/symbol_table.h"
6

            
7
namespace Envoy {
8
namespace Stats {
9

            
10
39887828
MetricHelper::~MetricHelper() {
11
  // The storage must be cleaned by a subclass of MetricHelper in its
12
  // destructor, because the symbol-table is owned by the subclass.
13
  // Simply call MetricHelper::clear() in the subclass dtor.
14
39887828
  ASSERT(!stat_names_.populated());
15
39887828
}
16

            
17
MetricHelper::MetricHelper(StatName name, StatName tag_extracted_name,
18
39889229
                           const StatNameTagVector& stat_name_tags, SymbolTable& symbol_table) {
19
  // Encode all the names and tags into transient storage so we can count the
20
  // required bytes. 2 is added to account for the name and tag_extracted_name,
21
  // and we multiply the number of tags by 2 to account for the name and value
22
  // of each tag.
23
39889229
  const uint32_t num_names = 2 + 2 * stat_name_tags.size();
24
39889229
  absl::FixedArray<StatName> names(num_names);
25
39889229
  names[0] = name;
26
39889229
  names[1] = tag_extracted_name;
27
39889229
  int index = 1;
28
39889230
  for (auto& stat_name_tag : stat_name_tags) {
29
4505907
    names[++index] = stat_name_tag.first;
30
4505907
    names[++index] = stat_name_tag.second;
31
4505907
  }
32
39889229
  symbol_table.populateList(names.begin(), num_names, stat_names_);
33
39889229
}
34

            
35
219926383
StatName MetricHelper::statName() const {
36
219926383
  StatName stat_name;
37
219926747
  stat_names_.iterate([&stat_name](StatName s) -> bool {
38
219926458
    stat_name = s;
39
219926458
    return false; // Returning 'false' stops the iteration.
40
219926458
  });
41
219926383
  return stat_name;
42
219926383
}
43

            
44
7554
StatName MetricHelper::tagExtractedStatName() const {
45
  // The name is the first element in stat_names_. The second is the
46
  // tag-extracted-name. We don't have random access in that format,
47
  // so we iterate through them, skipping the first element (name),
48
  // and terminating the iteration after capturing the tag-extracted
49
  // name by returning false from the lambda.
50
7554
  StatName tag_extracted_stat_name;
51
7554
  bool skip = true;
52
15108
  stat_names_.iterate([&tag_extracted_stat_name, &skip](StatName s) -> bool {
53
15108
    if (skip) {
54
7554
      skip = false;
55
7554
      return true;
56
7554
    }
57
7554
    tag_extracted_stat_name = s;
58
7554
    return false; // Returning 'false' stops the iteration.
59
15108
  });
60
7554
  return tag_extracted_stat_name;
61
7554
}
62

            
63
6051
void MetricHelper::iterateTagStatNames(const Metric::TagStatNameIterFn& fn) const {
64
6051
  enum { Name, TagExtractedName, TagName, TagValue } state = Name;
65
6051
  StatName tag_name;
66

            
67
  // StatNameList maintains a linear ordered collection of StatNames, and we
68
  // are mapping that into a tag-extracted name (the first element), followed
69
  // by alternating TagName and TagValue. So we use a little state machine
70
  // as we iterate through the stat_names_.
71
21740
  stat_names_.iterate([&state, &tag_name, &fn](StatName stat_name) -> bool {
72
21740
    switch (state) {
73
6051
    case Name:
74
6051
      state = TagExtractedName;
75
6051
      break;
76
6051
    case TagExtractedName:
77
6051
      state = TagName;
78
6051
      break;
79
4819
    case TagName:
80
4819
      tag_name = stat_name;
81
4819
      state = TagValue;
82
4819
      break;
83
4819
    case TagValue:
84
4819
      state = TagName;
85
4819
      if (!fn(tag_name, stat_name)) {
86
3
        return false; // early exit.
87
3
      }
88
4816
      break;
89
21740
    }
90
21737
    return true;
91
21740
  });
92
6051
  ASSERT(state != TagValue);
93
6051
}
94

            
95
6047
TagVector MetricHelper::tags(const SymbolTable& symbol_table) const {
96
6047
  TagVector tags;
97
6060
  iterateTagStatNames([&tags, &symbol_table](StatName name, StatName value) -> bool {
98
4813
    tags.emplace_back(Tag{symbol_table.toString(name), symbol_table.toString(value)});
99
4813
    return true;
100
4813
  });
101
6047
  return tags;
102
6047
}
103

            
104
} // namespace Stats
105
} // namespace Envoy