-
Notifications
You must be signed in to change notification settings - Fork 62
Add low level WASM Stats support. (See the High Level Stats PR which supersedes this). #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -438,6 +438,30 @@ uint32_t httpCallHandler(void* raw_context, uint32_t uri_ptr, uint32_t uri_size, | |
| return context->httpCall(uri, headers, body, trailers, timeout_milliseconds); | ||
| } | ||
|
|
||
| uint32_t defineMetricHandler(void* raw_context, uint32_t metric_type, uint32_t name_ptr, | ||
| uint32_t name_size) { | ||
| if (metric_type > static_cast<uint32_t>(Context::MetricType::Max)) | ||
| return 0; | ||
| auto context = WASM_CONTEXT(raw_context); | ||
| auto name = context->wasmVm()->getMemory(name_ptr, name_size); | ||
| return context->defineMetric(static_cast<Context::MetricType>(metric_type), name); | ||
| } | ||
|
|
||
| void incrementMetricHandler(void* raw_context, uint32_t metric_id, int64_t offset) { | ||
| auto context = WASM_CONTEXT(raw_context); | ||
| context->incrementMetric(metric_id, offset); | ||
| } | ||
|
|
||
| void recordMetricHandler(void* raw_context, uint32_t metric_id, uint64_t value) { | ||
| auto context = WASM_CONTEXT(raw_context); | ||
| context->recordMetric(metric_id, value); | ||
| } | ||
|
|
||
| uint64_t getMetricHandler(void* raw_context, uint32_t metric_id) { | ||
| auto context = WASM_CONTEXT(raw_context); | ||
| return context->getMetric(metric_id); | ||
| } | ||
|
|
||
| uint32_t getTotalMemoryHandler(void*) { return 0x7FFFFFFF; } | ||
| uint32_t _emscripten_get_heap_sizeHandler(void*) { return 0x7FFFFFFF; } | ||
| void _llvm_trapHandler(void*) { throw WasmException("emscripten llvm_trap"); } | ||
|
|
@@ -928,10 +952,96 @@ void Context::onHttpCallResponse(uint32_t token, const Pairs& response_headers, | |
| trailers_ptr, trailers_size); | ||
| } | ||
|
|
||
| uint32_t Context::defineMetric(MetricType type, absl::string_view name) { | ||
|
||
| switch (type) { | ||
| case MetricType::Counter: { | ||
| auto id = wasm_->nextCounterMetricId(); | ||
| wasm_->counters_.emplace(id, &wasm_->scope_.counter(std::string( | ||
| name))); // This is inefficient, but it is the Scope API. | ||
| return id; | ||
| } | ||
| case MetricType::Gauge: { | ||
| auto id = wasm_->nextGaugeMetricId(); | ||
| wasm_->gauges_.emplace(id, &wasm_->scope_.gauge(std::string( | ||
| name))); // This is inefficient, but it is the Scope API. | ||
| return id; | ||
| } | ||
| case MetricType::Histogram: { | ||
| auto id = wasm_->nextHistogramMetricId(); | ||
| wasm_->histograms_.emplace(id, &wasm_->scope_.histogram(std::string( | ||
| name))); // This is inefficient, but it is the Scope API. | ||
| return id; | ||
| } | ||
| } | ||
| return 0; | ||
| } | ||
|
|
||
| void Context::incrementMetric(uint32_t metric_id, int64_t offset) { | ||
| auto type = static_cast<MetricType>(metric_id & Wasm::kMetricTypeMask); | ||
| if (type == MetricType::Counter) { | ||
| auto it = wasm_->counters_.find(metric_id); | ||
| if (it != wasm_->counters_.end()) { | ||
| if (offset > 0) | ||
| it->second->add(offset); | ||
| } | ||
| } else if (type == MetricType::Gauge) { | ||
| auto it = wasm_->gauges_.find(metric_id); | ||
| if (it != wasm_->gauges_.end()) { | ||
| if (offset > 0) | ||
| it->second->add(offset); | ||
| else | ||
| it->second->sub(-offset); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void Context::recordMetric(uint32_t metric_id, uint64_t value) { | ||
|
||
| switch (static_cast<MetricType>(metric_id & Wasm::kMetricTypeMask)) { | ||
| case MetricType::Counter: { | ||
| auto it = wasm_->counters_.find(metric_id); | ||
| if (it != wasm_->counters_.end()) { | ||
| it->second->add(value); | ||
| } | ||
| break; | ||
| } | ||
| case MetricType::Gauge: { | ||
| auto it = wasm_->gauges_.find(metric_id); | ||
| if (it != wasm_->gauges_.end()) { | ||
| it->second->set(value); | ||
| } | ||
| break; | ||
| } | ||
| case MetricType::Histogram: { | ||
| auto it = wasm_->histograms_.find(metric_id); | ||
| if (it != wasm_->histograms_.end()) { | ||
| it->second->recordValue(value); | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| uint64_t Context::getMetric(uint32_t metric_id) { | ||
| auto type = static_cast<MetricType>(metric_id & Wasm::kMetricTypeMask); | ||
| if (type == MetricType::Counter) { | ||
| auto it = wasm_->counters_.find(metric_id); | ||
| if (it != wasm_->counters_.end()) { | ||
| return it->second->value(); | ||
| } | ||
| } else if (type == MetricType::Gauge) { | ||
| auto it = wasm_->gauges_.find(metric_id); | ||
| if (it != wasm_->gauges_.end()) { | ||
| return it->second->value(); | ||
| } | ||
| } | ||
| return 0; | ||
| } | ||
|
|
||
| Wasm::Wasm(absl::string_view vm, absl::string_view id, absl::string_view initial_configuration, | ||
| Upstream::ClusterManager& cluster_manager, Event::Dispatcher& dispatcher) | ||
| : cluster_manager_(cluster_manager), dispatcher_(dispatcher), | ||
| initial_configuration_(initial_configuration) { | ||
| Upstream::ClusterManager& cluster_manager, Event::Dispatcher& dispatcher, | ||
| Stats::Scope& scope, Stats::ScopeSharedPtr owned_scope) | ||
| : cluster_manager_(cluster_manager), dispatcher_(dispatcher), scope_(scope), | ||
| owned_scope_(owned_scope), initial_configuration_(initial_configuration) { | ||
| wasm_vm_ = Common::Wasm::createWasmVm(vm); | ||
| id_ = std::string(id); | ||
| if (wasm_vm_) { | ||
|
|
@@ -992,6 +1102,11 @@ Wasm::Wasm(absl::string_view vm, absl::string_view id, absl::string_view initial | |
| _REGISTER_PROXY(httpCall); | ||
|
|
||
| _REGISTER_PROXY(setTickPeriodMilliseconds); | ||
|
|
||
| _REGISTER_PROXY(defineMetric); | ||
| _REGISTER_PROXY(incrementMetric); | ||
| _REGISTER_PROXY(recordMetric); | ||
| _REGISTER_PROXY(getMetric); | ||
| #undef _REGISTER_PROXY | ||
| } | ||
| } | ||
|
|
@@ -1020,7 +1135,7 @@ void Wasm::getFunctions() { | |
|
|
||
| Wasm::Wasm(const Wasm& wasm) | ||
| : std::enable_shared_from_this<Wasm>(), cluster_manager_(wasm.cluster_manager_), | ||
| dispatcher_(wasm.dispatcher_) { | ||
| dispatcher_(wasm.dispatcher_), scope_(wasm.scope_), owned_scope_(wasm.owned_scope_) { | ||
| wasm_vm_ = wasm.wasmVm()->clone(); | ||
| general_context_ = createContext(); | ||
| getFunctions(); | ||
|
|
@@ -1224,9 +1339,10 @@ std::unique_ptr<WasmVm> createWasmVm(absl::string_view wasm_vm) { | |
| std::shared_ptr<Wasm> createWasm(absl::string_view id, | ||
| const envoy::config::wasm::v2::VmConfig& vm_config, | ||
| Upstream::ClusterManager& cluster_manager, | ||
| Event::Dispatcher& dispatcher, Api::Api& api) { | ||
| Event::Dispatcher& dispatcher, Api::Api& api, Stats::Scope& scope, | ||
| Stats::ScopeSharedPtr scope_ptr) { | ||
| auto wasm = std::make_shared<Wasm>(vm_config.vm(), id, vm_config.initial_configuration(), | ||
| cluster_manager, dispatcher); | ||
| cluster_manager, dispatcher, scope, scope_ptr); | ||
| const auto& code = Config::DataSource::read(vm_config.code(), true, api); | ||
| const auto& path = Config::DataSource::getPath(vm_config.code()) | ||
| .value_or(code.empty() ? EMPTY_STRING : INLINE_STRING); | ||
|
|
@@ -1248,7 +1364,7 @@ std::shared_ptr<Wasm> createThreadLocalWasm(Wasm& base_wasm, absl::string_view c | |
| } else { | ||
| wasm = std::make_shared<Wasm>(base_wasm.wasmVm()->vm(), base_wasm.id(), | ||
| base_wasm.initial_configuration(), base_wasm.clusterManager(), | ||
| dispatcher); | ||
| dispatcher, base_wasm.scope()); | ||
| if (!wasm->initialize(base_wasm.code(), base_wasm.id(), base_wasm.allow_precompiled())) { | ||
| throw WasmException("Failed to initialize WASM code"); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,8 @@ | |
| #include "envoy/config/wasm/v2/wasm.pb.validate.h" | ||
| #include "envoy/http/filter.h" | ||
| #include "envoy/server/wasm.h" | ||
| #include "envoy/stats/scope.h" | ||
| #include "envoy/stats/stats.h" | ||
| #include "envoy/thread_local/thread_local.h" | ||
| #include "envoy/upstream/cluster_manager.h" | ||
|
|
||
|
|
@@ -196,6 +198,18 @@ class Context : public Http::StreamFilter, | |
| virtual void httpRespond(const Pairs& response_headers, absl::string_view body, | ||
| const Pairs& response_trailers); | ||
|
|
||
| // Stats/Metrics | ||
| enum class MetricType : uint32_t { | ||
| Counter = 0, | ||
| Gauge = 1, | ||
| Histogram = 2, | ||
| Max = 2, | ||
| }; | ||
| virtual uint32_t defineMetric(MetricType type, absl::string_view name); | ||
| virtual void incrementMetric(uint32_t metric_id, int64_t offset); | ||
| virtual void recordMetric(uint32_t metric_id, uint64_t value); | ||
| virtual uint64_t getMetric(uint32_t metric_id); | ||
|
|
||
| // Connection | ||
| virtual bool isSsl(); | ||
|
|
||
|
|
@@ -253,7 +267,8 @@ class Wasm : public Envoy::Server::Wasm, | |
| public std::enable_shared_from_this<Wasm> { | ||
| public: | ||
| Wasm(absl::string_view vm, absl::string_view id, absl::string_view initial_configuration, | ||
| Upstream::ClusterManager& cluster_manager, Event::Dispatcher& dispatcher); | ||
| Upstream::ClusterManager& cluster_manager, Event::Dispatcher& dispatcher, | ||
| Stats::Scope& scope, Stats::ScopeSharedPtr owned_scope = nullptr); | ||
| Wasm(const Wasm& other); | ||
| ~Wasm() {} | ||
|
|
||
|
|
@@ -268,6 +283,7 @@ class Wasm : public Envoy::Server::Wasm, | |
| WasmVm* wasmVm() const { return wasm_vm_.get(); } | ||
| Context* generalContext() const { return general_context_.get(); } | ||
| Upstream::ClusterManager& clusterManager() const { return cluster_manager_; } | ||
| Stats::Scope& scope() const { return scope_; } | ||
|
|
||
| std::shared_ptr<Context> createContext() { return std::make_shared<Context>(this); } | ||
|
|
||
|
|
@@ -296,11 +312,30 @@ class Wasm : public Envoy::Server::Wasm, | |
|
|
||
| private: | ||
| friend class Context; | ||
| static constexpr uint32_t kMetricTypeMask = 0x3; | ||
| static constexpr uint32_t kMetricTypeCounter = 0x0; | ||
| static constexpr uint32_t kMetricTypeGauge = 0x1; | ||
| static constexpr uint32_t kMetricTypeHistogram = 0x2; | ||
| static constexpr uint32_t kMetricIdIncrement = 0x4; | ||
|
|
||
| bool isCounterMetricId(uint32_t metric_id) { | ||
| return (metric_id & kMetricTypeMask) == kMetricTypeCounter; | ||
| } | ||
| bool isGaugeMetricId(uint32_t metric_id) { | ||
| return (metric_id & kMetricTypeMask) == kMetricTypeGauge; | ||
| } | ||
| bool isHistogramMetricId(uint32_t metric_id) { | ||
| return (metric_id & kMetricTypeMask) == kMetricTypeHistogram; | ||
| } | ||
| uint32_t nextCounterMetricId() { return next_counter_metric_id_ += kMetricIdIncrement; } | ||
| uint32_t nextGaugeMetricId() { return next_gauge_metric_id_ += kMetricIdIncrement; } | ||
| uint32_t nextHistogramMetricId() { return next_histogram_metric_id_ += kMetricIdIncrement; } | ||
|
|
||
| void getFunctions(); | ||
|
|
||
| Upstream::ClusterManager& cluster_manager_; | ||
| Event::Dispatcher& dispatcher_; | ||
| Stats::Scope& scope_; | ||
| std::string id_; | ||
| std::string context_id_filter_state_data_name_; | ||
| uint32_t next_context_id_ = 0; | ||
|
|
@@ -309,6 +344,8 @@ class Wasm : public Envoy::Server::Wasm, | |
| std::function<void(Common::Wasm::Context*)> tick_; | ||
| std::chrono::milliseconds tick_period_; | ||
| Event::TimerPtr timer_; | ||
| Stats::ScopeSharedPtr | ||
| owned_scope_; // When scope_ is not owned by a higher level (e.g. for WASM services). | ||
|
|
||
| // Calls into the VM. | ||
| WasmCall0Void onStart_; | ||
|
|
@@ -338,6 +375,14 @@ class Wasm : public Envoy::Server::Wasm, | |
| std::string code_; | ||
| std::string initial_configuration_; | ||
| bool allow_precompiled_ = false; | ||
|
|
||
| // Stats/Metrics | ||
| uint32_t next_counter_metric_id_ = kMetricTypeCounter; | ||
|
||
| uint32_t next_gauge_metric_id_ = kMetricTypeGauge; | ||
| uint32_t next_histogram_metric_id_ = kMetricTypeHistogram; | ||
| absl::flat_hash_map<uint32_t, Stats::Counter*> counters_; | ||
| absl::flat_hash_map<uint32_t, Stats::Gauge*> gauges_; | ||
| absl::flat_hash_map<uint32_t, Stats::Histogram*> histograms_; | ||
| }; | ||
|
|
||
| inline WasmVm* Context::wasmVm() const { return wasm_->wasmVm(); } | ||
|
|
@@ -456,7 +501,8 @@ std::unique_ptr<WasmVm> createWasmVm(absl::string_view vm); | |
| std::shared_ptr<Wasm> createWasm(absl::string_view id, | ||
| const envoy::config::wasm::v2::VmConfig& vm_config, | ||
| Upstream::ClusterManager& cluster_manager, | ||
| Event::Dispatcher& dispatcher, Api::Api& api); | ||
| Event::Dispatcher& dispatcher, Api::Api& api, Stats::Scope& scope, | ||
| Stats::ScopeSharedPtr owned_scope = nullptr); | ||
|
|
||
| // Create a ThreadLocal VM from an existing VM (e.g. from createWasm() above). | ||
| std::shared_ptr<Wasm> createThreadLocalWasm(Wasm& base_wasm, absl::string_view configuration, | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.