Skip to content

Commit

Permalink
Add support for partially extending WASM stats/metrics. (envoyproxy#62)
Browse files Browse the repository at this point in the history
* Add support for partially extending WASM statst/metrics.
  • Loading branch information
jplevyak authored May 9, 2019
1 parent 34b0348 commit 724328c
Show file tree
Hide file tree
Showing 5 changed files with 5,812 additions and 3,202 deletions.
68 changes: 57 additions & 11 deletions api/wasm/cpp/proxy_wasm_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -972,11 +972,14 @@ struct MetricBase {

MetricType type;
std::string name;
std::string prefix;
std::vector<MetricTag> tags;
std::unordered_map<std::string, uint32_t> metric_ids;

std::string prefixWithFields(const std::vector<const std::string>& fields);
uint32_t resolveFullName(const std::string& n);
uint32_t resolveWithFields(const std::vector<const std::string>& fields);
void partiallyResolveWithFields(const std::vector<const std::string>& fields);
std::string nameFromIdSlow(uint32_t id);
};

Expand All @@ -988,30 +991,42 @@ struct Metric : public MetricBase {
template <typename... Fields> void record(uint64_t value, Fields... tags);
template <typename... Fields> uint64_t get(Fields... tags);
template <typename... Fields> uint32_t resolve(Fields... tags);
template <typename... Fields> Metric partiallyResolve(Fields... tags);
};

inline uint32_t MetricBase::resolveWithFields(const std::vector<const std::string>& fields) {
if (fields.size() != tags.size()) {
throw ProxyException("metric fields.size() != tags.size()");
}
size_t s = 0;
for (auto& t : tags) {
s += t.name.size() + 1; // 1 more for "."
inline std::string MetricBase::prefixWithFields(const std::vector<const std::string>& fields) {
size_t s = prefix.size();
for (int i = 0; i < fields.size(); i++) {
s += tags[i].name.size() + 1; // 1 more for "."
}
for (auto& f : fields) {
s += f.size() + 1; // 1 more for "."
}
s += name.size() + 2; // "." and "\0";
std::string n;
n.reserve(s);
for (int i = 0; i < tags.size(); i++) {
n.append(prefix);
for (int i = 0; i < fields.size(); i++) {
n.append(tags[i].name);
n.append(".");
n.append(fields[i]);
n.append(".");
}
n.append(name);
return resolveFullName(n);
return n;
}

inline uint32_t MetricBase::resolveWithFields(const std::vector<const std::string>& fields) {
if (fields.size() != tags.size()) {
throw ProxyException("metric fields.size() != tags.size()");
}
return resolveFullName(prefixWithFields(fields) + name);
}

inline void MetricBase::partiallyResolveWithFields(const std::vector<const std::string>& fields) {
if (fields.size() >= tags.size()) {
throw ProxyException("metric fields.size() >= tags.size()");
}
prefix = prefixWithFields(fields);
tags.erase(tags.begin(), tags.begin()+(fields.size()));
}

template <typename T> inline std::string ToString(T t) { return std::to_string(t); }
Expand Down Expand Up @@ -1044,6 +1059,13 @@ template <typename... Fields> inline uint32_t Metric::resolve(Fields... f) {
return resolveWithFields(fields);
}

template <typename... Fields> Metric Metric::partiallyResolve(Fields... f) {
std::vector<const std::string> fields{ToString(f)...};
Metric partial_metric(*this);
partial_metric.partiallyResolveWithFields(fields);
return partial_metric;
}

template <typename... Fields> inline void Metric::increment(int64_t offset, Fields... f) {
std::vector<const std::string> fields{ToString(f)...};
auto metric_id = resolveWithFields(fields);
Expand Down Expand Up @@ -1128,6 +1150,14 @@ template <typename... Tags> struct Counter : public MetricBase {
return SimpleCounter(resolveWithFields(fields));
}

template<typename... AdditionalTags>
Counter<AdditionalTags...>* resolveAndExtend(Tags... f, MetricTagDescriptor<AdditionalTags>... fieldnames) {
std::vector<const std::string> fields{ToString(f)...};
auto new_counter = Counter<AdditionalTags...>::New(name, fieldnames...);
new_counter->prefix = prefixWithFields(fields);
return new_counter;
}

void increment(int64_t offset, Tags... tags) {
std::vector<const std::string> fields{ToString(tags)...};
auto metric_id = resolveWithFields(fields);
Expand Down Expand Up @@ -1162,6 +1192,14 @@ template <typename... Tags> struct Gauge : public MetricBase {
return SimpleGauge(resolveWithFields(fields));
}

template<typename... AdditionalTags>
Gauge<AdditionalTags...>* resolveAndExtend(Tags... f, MetricTagDescriptor<AdditionalTags>... fieldnames) {
std::vector<const std::string> fields{ToString(f)...};
auto new_gauge = Gauge<AdditionalTags...>::New(name, fieldnames...);
new_gauge->prefix = prefixWithFields(fields);
return new_gauge;
}

void record(int64_t offset, Tags... tags) {
std::vector<const std::string> fields{ToString(tags)...};
auto metric_id = resolveWithFields(fields);
Expand Down Expand Up @@ -1194,6 +1232,14 @@ template <typename... Tags> struct Histogram : public MetricBase {
return SimpleHistogram(resolveWithFields(fields));
}

template<typename... AdditionalTags>
Histogram<AdditionalTags...>* resolveAndExtend(Tags... f, MetricTagDescriptor<AdditionalTags>... fieldnames) {
std::vector<const std::string> fields{ToString(f)...};
auto new_histogram = Histogram<AdditionalTags...>::New(name, fieldnames...);
new_histogram->prefix = prefixWithFields(fields);
return new_histogram;
}

void record(int64_t offset, Tags... tags) {
std::vector<const std::string> fields{ToString(tags)...};
auto metric_id = resolveWithFields(fields);
Expand Down
39 changes: 21 additions & 18 deletions test/extensions/wasm/test_data/stats_cpp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,37 +24,38 @@ extern "C" EMSCRIPTEN_KEEPALIVE void proxy_onStart() {

// Test the higher level interface.
extern "C" EMSCRIPTEN_KEEPALIVE void proxy_onTick() {
auto c = new Metric(MetricType::Counter, "test_counter",
Metric c(MetricType::Counter, "test_counter",
{MetricTag{"counter_tag", MetricTag::TagType::String}});
auto g = new Metric(MetricType::Gauge, "test_gauge",
Metric g(MetricType::Gauge, "test_gauge",
{MetricTag{"gauge_int_tag", MetricTag::TagType::Int}});
auto h = new Metric(MetricType::Gauge, "test_histogram",
Metric h(MetricType::Histogram, "test_histogram",
{MetricTag{"histogram_int_tag", MetricTag::TagType::Int},
MetricTag{"histogram_string_tag", MetricTag::TagType::String},
MetricTag{"histogram_bool_tag", MetricTag::TagType::Bool}});

c->increment(1, "test_tag");
g->record(2, 9);
h->record(3, 7, "test_tag", true);
c.increment(1, "test_tag");
g.record(2, 9);
h.record(3, 7, "test_tag", true);

logTrace(std::string("get counter = ") + std::to_string(c->get("test_tag")));
c->increment(1, "test_tag");
logDebug(std::string("get counter = ") + std::to_string(c->get("test_tag")));
c->record(3, "test_tag");
logInfo(std::string("get counter = ") + std::to_string(c->get("test_tag")));
logWarn(std::string("get gauge = ") + std::to_string(g->get(9)));
logTrace(std::string("get counter = ") + std::to_string(c.get("test_tag")));
c.increment(1, "test_tag");
logDebug(std::string("get counter = ") + std::to_string(c.get("test_tag")));
c.record(3, "test_tag");
logInfo(std::string("get counter = ") + std::to_string(c.get("test_tag")));
logWarn(std::string("get gauge = ") + std::to_string(g.get(9)));

auto h_id = h->resolve(7, "test_tag", true);
logError(std::string("resolved histogram name = ") + h->nameFromIdSlow(h_id));
auto hh = h.partiallyResolve(7);
auto h_id = hh.resolve("test_tag", true);
logError(std::string("resolved histogram name = ") + hh.nameFromIdSlow(h_id));
}

// Test the high level interface.
extern "C" EMSCRIPTEN_KEEPALIVE void proxy_onLog(uint32_t /* context_zero */) {
auto c =
Counter<std::string, int, bool>::New("test_counter", "string_tag", "int_tag", "bool_tag");
auto g = Counter<std::string, std::string>::New("test_counter", "string_tag1", "string_tag2");
auto g = Gauge<std::string, std::string>::New("test_gauge", "string_tag1", "string_tag2");
auto h =
Counter<int, std::string, bool>::New("test_histogram", "int_tag", "string_tag", "bool_tag");
Histogram<int, std::string, bool>::New("test_histogram", "int_tag", "string_tag", "bool_tag");

c->increment(1, "test_tag", 7, true);
logTrace(std::string("get counter = ") + std::to_string(c->get("test_tag", 7, true)));
Expand All @@ -68,6 +69,8 @@ extern "C" EMSCRIPTEN_KEEPALIVE void proxy_onLog(uint32_t /* context_zero */) {
logWarn(std::string("get gauge = ") + std::to_string(g->get("test_tag1", "test_tag2")));

h->record(3, 7, "test_tag", true);
auto simple_h = h->resolve(7, "test_tag", true);
logError(std::string("h_id = ") + h->nameFromIdSlow(simple_h.metric_id));
auto base_h = Counter<int>::New("test_histogram", "int_tag");
auto complete_h = base_h->resolveAndExtend<std::string, bool>(7, "string_tag", "bool_tag");
auto simple_h = complete_h->resolve("test_tag", true);
logError(std::string("h_id = ") + complete_h->nameFromIdSlow(simple_h.metric_id));
}
Binary file modified test/extensions/wasm/test_data/stats_cpp.wasm
Binary file not shown.
Loading

0 comments on commit 724328c

Please sign in to comment.