-
Notifications
You must be signed in to change notification settings - Fork 103
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
Add simple stats API #242
base: main
Are you sure you want to change the base?
Add simple stats API #242
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
[package] | ||
publish = false | ||
name = "proxy-wasm-example-metrics" | ||
version = "0.0.1" | ||
authors = ["José Ulises Niño Rivera <[email protected]>"] | ||
description = "Proxy-Wasm plugin example: Metrics" | ||
license = "Apache-2.0" | ||
edition = "2018" | ||
|
||
[lib] | ||
crate-type = ["cdylib"] | ||
|
||
[dependencies] | ||
log = "0.4" | ||
proxy-wasm = { path = "../../" } | ||
|
||
[profile.release] | ||
lto = true | ||
opt-level = 3 | ||
codegen-units = 1 | ||
panic = "abort" | ||
strip = "debuginfo" |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,32 @@ | ||||||
## Proxy-Wasm plugin example: HTTP headers | ||||||
|
||||||
Proxy-Wasm plugin that logs HTTP request/response headers. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please update this as well. |
||||||
|
||||||
### Building | ||||||
|
||||||
```sh | ||||||
$ cargo build --target wasm32-wasi --release | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
``` | ||||||
|
||||||
### Using in Envoy | ||||||
|
||||||
This example can be run with [`docker compose`](https://docs.docker.com/compose/install/) | ||||||
and has a matching Envoy configuration. | ||||||
|
||||||
```sh | ||||||
$ docker compose up | ||||||
``` | ||||||
|
||||||
Send HTTP request to `localhost:10000/`: | ||||||
|
||||||
```sh | ||||||
$ curl localhost:10000/ -H "x-envoy-wasm-metric-value: 100" -H "x-envoy-wasm-metric: gauge" | ||||||
``` | ||||||
|
||||||
For instance that request will set the example gauge to 100. Which you can see using the stats endpoint | ||||||
|
||||||
```sh | ||||||
& curl -s localhost:9001/stats | grep wasmcustom.wasm_gauge | ||||||
|
||||||
100 | ||||||
``` |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,28 @@ | ||||||
# Copyright 2022 Google LLC | ||||||
# | ||||||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
# you may not use this file except in compliance with the License. | ||||||
# You may obtain a copy of the License at | ||||||
# | ||||||
# http://www.apache.org/licenses/LICENSE-2.0 | ||||||
# | ||||||
# Unless required by applicable law or agreed to in writing, software | ||||||
# distributed under the License is distributed on an "AS IS" BASIS, | ||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
# See the License for the specific language governing permissions and | ||||||
# limitations under the License. | ||||||
|
||||||
services: | ||||||
envoy: | ||||||
image: envoyproxy/envoy:v1.24-latest | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
hostname: envoy | ||||||
ports: | ||||||
- "10000:10000" | ||||||
- "9001:9001" | ||||||
volumes: | ||||||
- ./envoy.yaml:/etc/envoy/envoy.yaml | ||||||
- ./target/wasm32-wasi/release:/etc/envoy/proxy-wasm-plugins | ||||||
networks: | ||||||
- envoymesh | ||||||
networks: | ||||||
envoymesh: {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# Copyright 2022 Google LLC | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
static_resources: | ||
listeners: | ||
address: | ||
socket_address: | ||
address: 0.0.0.0 | ||
port_value: 10000 | ||
filter_chains: | ||
- filters: | ||
- name: envoy.filters.network.http_connection_manager | ||
typed_config: | ||
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager | ||
stat_prefix: ingress_http | ||
codec_type: AUTO | ||
route_config: | ||
name: local_routes | ||
virtual_hosts: | ||
- name: local_service | ||
domains: | ||
- "*" | ||
routes: | ||
- match: | ||
prefix: "/" | ||
direct_response: | ||
status: 200 | ||
body: | ||
inline_string: "Request /hello and be welcomed!\n" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Leave a more specific helpful message that explains what header to set. In addition IMHO it might be useful to have the WASM filter return the current values of metrics in the response without having to check the |
||
http_filters: | ||
- name: envoy.filters.http.wasm | ||
typed_config: | ||
"@type": type.googleapis.com/udpa.type.v1.TypedStruct | ||
type_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm | ||
value: | ||
config: | ||
name: "http_headers" | ||
vm_config: | ||
runtime: "envoy.wasm.runtime.v8" | ||
code: | ||
local: | ||
filename: "/etc/envoy/proxy-wasm-plugins/proxy_wasm_example_metrics.wasm" | ||
- name: envoy.filters.http.router | ||
typed_config: | ||
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router | ||
|
||
admin: | ||
profile_path: /tmp/envoy.prof | ||
address: | ||
socket_address: { address: 0.0.0.0, port_value: 9001 } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
// Copyright 2020 Google LLC | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
use proxy_wasm::stats; | ||
use proxy_wasm::traits::*; | ||
use proxy_wasm::types::*; | ||
|
||
use std::convert::TryInto; | ||
|
||
proxy_wasm::main! {{ | ||
proxy_wasm::set_log_level(LogLevel::Trace); | ||
proxy_wasm::set_root_context(|_| -> Box<dyn RootContext> { Box::new( | ||
MetricsRootContext { | ||
metrics: WasmMetrics { | ||
counter: stats::Counter::new(String::from("wasm_counter")), | ||
gauge: stats::Gauge::new(String::from("wasm_gauge")), | ||
histogram: stats::Histogram::new(String::from("wasm_histogram")), | ||
} | ||
} | ||
)}); | ||
}} | ||
|
||
#[derive(Copy, Clone)] | ||
struct WasmMetrics { | ||
counter: stats::Counter, | ||
gauge: stats::Gauge, | ||
histogram: stats::Histogram, | ||
} | ||
|
||
struct MetricsRootContext { | ||
metrics: WasmMetrics, | ||
} | ||
|
||
impl Context for MetricsRootContext {} | ||
|
||
impl RootContext for MetricsRootContext { | ||
fn get_type(&self) -> Option<ContextType> { | ||
Some(ContextType::HttpContext) | ||
} | ||
|
||
fn create_http_context(&self, _: u32) -> Option<Box<dyn HttpContext>> { | ||
Some(Box::new(StreamContext { | ||
metrics: self.metrics, | ||
})) | ||
} | ||
} | ||
|
||
struct StreamContext { | ||
metrics: WasmMetrics, | ||
} | ||
|
||
impl Context for StreamContext {} | ||
|
||
impl HttpContext for StreamContext { | ||
fn on_http_request_headers(&mut self, _: usize, _: bool) -> Action { | ||
let value = match self.get_http_request_header("x-envoy-wasm-metric-value") { | ||
Some(value) => value.parse::<i64>().unwrap(), | ||
_ => 0, | ||
}; | ||
|
||
let metric_type = match self.get_http_request_header("x-envoy-wasm-metric") { | ||
Some(metric_type) => metric_type, | ||
_ => return Action::Continue, | ||
}; | ||
|
||
match metric_type.as_str() { | ||
"counter" => self.metrics.counter.increment(value), | ||
"gauge" => self.metrics.gauge.record(value.try_into().unwrap()), | ||
"histogram" => self.metrics.histogram.record(value.try_into().unwrap()), | ||
_ => return Action::Continue, | ||
} | ||
|
||
Action::Continue | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ | |
// limitations under the License. | ||
|
||
pub mod hostcalls; | ||
pub mod stats; | ||
pub mod traits; | ||
pub mod types; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// Copyright 2020 Google LLC | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
use crate::hostcalls; | ||
use crate::traits; | ||
use crate::types; | ||
|
||
#[derive(Copy, Clone)] | ||
pub struct Counter { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Like this abstraction 🚀 |
||
id: u32, | ||
} | ||
|
||
impl Counter { | ||
pub fn new(name: String) -> Counter { | ||
let returned_id = hostcalls::define_metric(types::MetricType::Counter, &name) | ||
.expect("failed to define counter '{}', name"); | ||
Counter { id: returned_id } | ||
} | ||
} | ||
|
||
impl traits::Metric for Counter { | ||
fn id(&self) -> u32 { | ||
self.id | ||
} | ||
} | ||
|
||
impl traits::IncrementingMetric for Counter {} | ||
|
||
#[derive(Copy, Clone)] | ||
pub struct Gauge { | ||
id: u32, | ||
} | ||
|
||
impl Gauge { | ||
pub fn new(name: String) -> Gauge { | ||
let returned_id = hostcalls::define_metric(types::MetricType::Gauge, &name) | ||
.expect("failed to define gauge '{}', name"); | ||
Gauge { id: returned_id } | ||
} | ||
} | ||
|
||
impl traits::Metric for Gauge { | ||
fn id(&self) -> u32 { | ||
self.id | ||
} | ||
} | ||
|
||
impl traits::RecordingMetric for Gauge {} | ||
|
||
#[derive(Copy, Clone)] | ||
pub struct Histogram { | ||
id: u32, | ||
} | ||
|
||
impl Histogram { | ||
pub fn new(name: String) -> Histogram { | ||
let returned_id = hostcalls::define_metric(types::MetricType::Histogram, &name) | ||
.expect("failed to define histogram '{}', name"); | ||
Histogram { id: returned_id } | ||
} | ||
} | ||
|
||
impl traits::Metric for Histogram { | ||
fn id(&self) -> u32 { | ||
self.id | ||
} | ||
} | ||
|
||
impl traits::RecordingMetric for Histogram {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.