Skip to content

Commit b593bd6

Browse files
committed
demonstrate using metrics
Signed-off-by: William Zhang <wtzhang23@gmail.com>
1 parent 43f6d2d commit b593bd6

3 files changed

Lines changed: 138 additions & 3 deletions

File tree

integration/envoy.yaml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
admin:
2+
address:
3+
socket_address: { address: 127.0.0.1, port_value: 9901 }
14
static_resources:
25
listeners:
36
- address:
@@ -16,7 +19,8 @@ static_resources:
1619
domains:
1720
- "*"
1821
routes:
19-
- match:
22+
- name: catch_all
23+
match:
2024
prefix: "/"
2125
route:
2226
cluster: httpbin
@@ -36,7 +40,14 @@ static_resources:
3640
dynamic_module_config:
3741
name: rust_module
3842
filter_name: passthrough
39-
- name: dynamic_modules/conditional_deply
43+
- name: dynamic_modules/metrics
44+
typed_config:
45+
# https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/dynamic_modules/v3/dynamic_modules.proto#envoy-v3-api-msg-extensions-dynamic-modules-v3-dynamicmoduleconfig
46+
"@type": type.googleapis.com/envoy.extensions.filters.http.dynamic_modules.v3.DynamicModuleFilter
47+
dynamic_module_config:
48+
name: rust_module
49+
filter_name: metrics
50+
- name: dynamic_modules/conditional_delay
4051
typed_config:
4152
# https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/dynamic_modules/v3/dynamic_modules.proto#envoy-v3-api-msg-extensions-dynamic-modules-v3-dynamicmoduleconfig
4253
"@type": type.googleapis.com/envoy.extensions.filters.http.dynamic_modules.v3.DynamicModuleFilter

rust/src/http_metrics.rs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
use std::time::Instant;
2+
3+
use envoy_proxy_dynamic_modules_rust_sdk::*;
4+
5+
/// This implements the [`envoy_proxy_dynamic_modules_rust_sdk::HttpFilterConfig`] trait.
6+
///
7+
/// The trait corresponds to a Envoy filter chain configuration.
8+
pub struct FilterConfig {
9+
_filter_config: String,
10+
route_latency: EnvoyHistogramVecId,
11+
}
12+
13+
impl FilterConfig {
14+
/// This is the constructor for the [`FilterConfig`].
15+
///
16+
/// filter_config is the filter config from the Envoy config here:
17+
/// https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/dynamic_modules/v3/dynamic_modules.proto#envoy-v3-api-msg-extensions-dynamic-modules-v3-dynamicmoduleconfig
18+
pub fn new<EC: EnvoyHttpFilterConfig>(
19+
filter_config: &str,
20+
envoy_filter_config: &mut EC,
21+
) -> Self {
22+
Self {
23+
_filter_config: filter_config.to_string(),
24+
route_latency: envoy_filter_config
25+
.define_histogram_vec("route_latency_ms", &["route_name"])
26+
.unwrap(),
27+
}
28+
}
29+
}
30+
31+
impl<EHF: EnvoyHttpFilter> HttpFilterConfig<EHF> for FilterConfig {
32+
/// This is called for each new HTTP filter.
33+
fn new_http_filter(&mut self, _envoy: &mut EHF) -> Box<dyn HttpFilter<EHF>> {
34+
Box::new(Filter {
35+
start_time: None,
36+
route_name: None,
37+
route_latency: self.route_latency,
38+
})
39+
}
40+
}
41+
42+
/// This implements the [`envoy_proxy_dynamic_modules_rust_sdk::HttpFilter`] trait.
43+
///
44+
/// This is a metrics filter that records per-route metrics of the request.
45+
pub struct Filter {
46+
start_time: Option<Instant>,
47+
route_latency: EnvoyHistogramVecId,
48+
route_name: Option<String>,
49+
}
50+
51+
impl Filter {
52+
fn record_latency<EHF: EnvoyHttpFilter>(&mut self, envoy_filter: &mut EHF) {
53+
let Some(start_time) = self.start_time else {
54+
return;
55+
};
56+
let Some(route_name) = self.route_name.take() else {
57+
return;
58+
};
59+
envoy_filter
60+
.record_histogram_value_vec(
61+
self.route_latency,
62+
&[&route_name],
63+
start_time.elapsed().as_millis() as u64,
64+
)
65+
.unwrap();
66+
}
67+
}
68+
69+
/// This implements the [`envoy_proxy_dynamic_modules_rust_sdk::HttpFilter`] trait.
70+
impl<EHF: EnvoyHttpFilter> HttpFilter<EHF> for Filter {
71+
fn on_request_headers(
72+
&mut self,
73+
envoy_filter: &mut EHF,
74+
_end_of_stream: bool,
75+
) -> abi::envoy_dynamic_module_type_on_http_filter_request_headers_status {
76+
self.start_time = Some(Instant::now());
77+
self.route_name = Some(
78+
String::from_utf8(
79+
envoy_filter
80+
.get_attribute_string(abi::envoy_dynamic_module_type_attribute_id::XdsRouteName)
81+
.unwrap_or_default()
82+
.as_slice()
83+
.to_vec(),
84+
)
85+
.unwrap(),
86+
);
87+
abi::envoy_dynamic_module_type_on_http_filter_request_headers_status::Continue
88+
}
89+
90+
fn on_response_headers(
91+
&mut self,
92+
envoy_filter: &mut EHF,
93+
end_of_stream: bool,
94+
) -> abi::envoy_dynamic_module_type_on_http_filter_response_headers_status {
95+
if end_of_stream {
96+
self.record_latency(envoy_filter);
97+
}
98+
abi::envoy_dynamic_module_type_on_http_filter_response_headers_status::Continue
99+
}
100+
101+
fn on_response_body(
102+
&mut self,
103+
envoy_filter: &mut EHF,
104+
end_of_stream: bool,
105+
) -> abi::envoy_dynamic_module_type_on_http_filter_response_body_status {
106+
if end_of_stream {
107+
self.record_latency(envoy_filter);
108+
}
109+
abi::envoy_dynamic_module_type_on_http_filter_response_body_status::Continue
110+
}
111+
112+
fn on_request_trailers(
113+
&mut self,
114+
envoy_filter: &mut EHF,
115+
) -> abi::envoy_dynamic_module_type_on_http_filter_request_trailers_status {
116+
self.record_latency(envoy_filter);
117+
abi::envoy_dynamic_module_type_on_http_filter_request_trailers_status::Continue
118+
}
119+
}

rust/src/lib.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use envoy_proxy_dynamic_modules_rust_sdk::*;
22

33
mod http_access_logger;
44
mod http_header_mutation;
5+
mod http_metrics;
56
mod http_passthrough;
67
mod http_random_auth;
78
mod http_zero_copy_regex_waf;
@@ -29,7 +30,7 @@ fn init() -> bool {
2930
///
3031
/// Returns None if the filter name or config is determined to be invalid by each filter's `new` function.
3132
fn new_http_filter_config_fn<EC: EnvoyHttpFilterConfig, EHF: EnvoyHttpFilter>(
32-
_envoy_filter_config: &mut EC,
33+
envoy_filter_config: &mut EC,
3334
filter_name: &str,
3435
filter_config: &[u8],
3536
) -> Option<Box<dyn HttpFilterConfig<EHF>>> {
@@ -43,6 +44,10 @@ fn new_http_filter_config_fn<EC: EnvoyHttpFilterConfig, EHF: EnvoyHttpFilter>(
4344
.map(|config| Box::new(config) as Box<dyn HttpFilterConfig<EHF>>),
4445
"header_mutation" => http_header_mutation::FilterConfig::new(filter_config)
4546
.map(|config| Box::new(config) as Box<dyn HttpFilterConfig<EHF>>),
47+
"metrics" => Some(Box::new(http_metrics::FilterConfig::new(
48+
filter_config,
49+
envoy_filter_config,
50+
))),
4651
_ => panic!("Unknown filter name: {filter_name}"),
4752
}
4853
}

0 commit comments

Comments
 (0)