mirror of https://github.com/zino-rs/zino
Add http request metrics
This commit is contained in:
parent
21b323d5a1
commit
5b676373a0
|
@ -16,7 +16,6 @@ port = 6082
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
type = "postgres"
|
type = "postgres"
|
||||||
schema = "public"
|
|
||||||
namespace = "dc"
|
namespace = "dc"
|
||||||
|
|
||||||
[[postgres]]
|
[[postgres]]
|
||||||
|
@ -28,6 +27,8 @@ password = "QAx01wnh1i5ER713zfHmZi6dIUYn/Iq9ag+iUGtvKzEFJFYW"
|
||||||
|
|
||||||
[tracing]
|
[tracing]
|
||||||
filter = "info,sqlx=trace,tower_http=trace,zino=trace,zino_core=trace"
|
filter = "info,sqlx=trace,tower_http=trace,zino=trace,zino_core=trace"
|
||||||
|
display-filename = true
|
||||||
|
display-line-number = true
|
||||||
|
|
||||||
[metrics]
|
[metrics]
|
||||||
exporter = "prometheus"
|
exporter = "prometheus"
|
||||||
|
|
|
@ -16,7 +16,6 @@ port = 6082
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
type = "postgres"
|
type = "postgres"
|
||||||
schema = "public"
|
|
||||||
namespace = "dc"
|
namespace = "dc"
|
||||||
|
|
||||||
[[postgres]]
|
[[postgres]]
|
||||||
|
@ -27,7 +26,7 @@ username = "postgres"
|
||||||
password = "G76hTg8T5Aa+SZQFc+0QnsRLo1UOjqpkp/jUQ+lySc8QCt4B"
|
password = "G76hTg8T5Aa+SZQFc+0QnsRLo1UOjqpkp/jUQ+lySc8QCt4B"
|
||||||
|
|
||||||
[tracing]
|
[tracing]
|
||||||
filter = "info,sqlx=warn,tower_http=warn"
|
filter = "info,sqlx=warn"
|
||||||
|
|
||||||
[metrics]
|
[metrics]
|
||||||
exporter = "prometheus"
|
exporter = "prometheus"
|
||||||
|
|
|
@ -69,9 +69,18 @@ pub trait RequestContext {
|
||||||
header.split(':').nth(3).map(|s| s.to_string())
|
header.split(':').nth(3).map(|s| s.to_string())
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut ctx = Context::new(request_id);
|
let mut ctx = Context::new(request_id);
|
||||||
ctx.set_trace_id(trace_id);
|
ctx.set_trace_id(trace_id);
|
||||||
ctx.set_session_id(session_id);
|
ctx.set_session_id(session_id);
|
||||||
|
|
||||||
|
// Emit metrics.
|
||||||
|
metrics::increment_gauge!("zino_http_requests_pending", 1.0);
|
||||||
|
metrics::increment_counter!(
|
||||||
|
"zino_http_requests_total",
|
||||||
|
"method" => self.request_method().to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
ctx
|
ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -336,10 +336,11 @@ impl From<Validation> for Response<http::StatusCode> {
|
||||||
|
|
||||||
impl From<Response<http::StatusCode>> for http::Response<Full<Bytes>> {
|
impl From<Response<http::StatusCode>> for http::Response<Full<Bytes>> {
|
||||||
fn from(mut response: Response<http::StatusCode>) -> Self {
|
fn from(mut response: Response<http::StatusCode>) -> Self {
|
||||||
|
let status_code = response.status_code;
|
||||||
let mut res = match response.content_type {
|
let mut res = match response.content_type {
|
||||||
Some(ref content_type) => match serde_json::to_vec(&response.data) {
|
Some(ref content_type) => match serde_json::to_vec(&response.data) {
|
||||||
Ok(bytes) => http::Response::builder()
|
Ok(bytes) => http::Response::builder()
|
||||||
.status(response.status_code)
|
.status(status_code)
|
||||||
.header(header::CONTENT_TYPE, content_type.as_ref())
|
.header(header::CONTENT_TYPE, content_type.as_ref())
|
||||||
.body(Full::from(bytes))
|
.body(Full::from(bytes))
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
|
@ -357,7 +358,7 @@ impl From<Response<http::StatusCode>> for http::Response<Full<Bytes>> {
|
||||||
"application/problem+json"
|
"application/problem+json"
|
||||||
};
|
};
|
||||||
http::Response::builder()
|
http::Response::builder()
|
||||||
.status(response.status_code)
|
.status(status_code)
|
||||||
.header(header::CONTENT_TYPE, content_type)
|
.header(header::CONTENT_TYPE, content_type)
|
||||||
.body(Full::from(bytes))
|
.body(Full::from(bytes))
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
|
@ -377,7 +378,8 @@ impl From<Response<http::StatusCode>> for http::Response<Full<Bytes>> {
|
||||||
res.headers_mut().insert("traceparent", header_value);
|
res.headers_mut().insert("traceparent", header_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
response.record_server_timing("total", response.start_time.elapsed(), None);
|
let duration = response.start_time.elapsed();
|
||||||
|
response.record_server_timing("total", duration, None);
|
||||||
if let Ok(header_value) = HeaderValue::try_from(response.server_timing.value().as_str()) {
|
if let Ok(header_value) = HeaderValue::try_from(response.server_timing.value().as_str()) {
|
||||||
res.headers_mut().insert("server-timing", header_value);
|
res.headers_mut().insert("server-timing", header_value);
|
||||||
}
|
}
|
||||||
|
@ -388,6 +390,17 @@ impl From<Response<http::StatusCode>> for http::Response<Full<Bytes>> {
|
||||||
res.headers_mut().insert("x-request-id", header_value);
|
res.headers_mut().insert("x-request-id", header_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Emit metrics.
|
||||||
|
let labels = [("status", status_code.to_string())];
|
||||||
|
metrics::decrement_gauge!("zino_http_requests_pending", 1.0);
|
||||||
|
metrics::increment_counter!("zino_http_responses_total", &labels);
|
||||||
|
metrics::histogram!(
|
||||||
|
"zino_http_requests_duration_seconds",
|
||||||
|
duration.as_secs_f64(),
|
||||||
|
&labels,
|
||||||
|
);
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ pub fn schema_macro(item: TokenStream) -> TokenStream {
|
||||||
} else if INTEGER_TYPES.contains(&type_name.as_str()) {
|
} else if INTEGER_TYPES.contains(&type_name.as_str()) {
|
||||||
default_value = default_value.or_else(|| Some("0".to_string()));
|
default_value = default_value.or_else(|| Some("0".to_string()));
|
||||||
}
|
}
|
||||||
let quote_value = match default_value {
|
let value_quote = match default_value {
|
||||||
Some(value) => {
|
Some(value) => {
|
||||||
if value.contains("::") {
|
if value.contains("::") {
|
||||||
if let Some((type_name, type_fn)) = value.split_once("::") {
|
if let Some((type_name, type_fn)) = value.split_once("::") {
|
||||||
|
@ -94,12 +94,12 @@ pub fn schema_macro(item: TokenStream) -> TokenStream {
|
||||||
}
|
}
|
||||||
None => quote! { None },
|
None => quote! { None },
|
||||||
};
|
};
|
||||||
let quote_index = match index_type {
|
let index_quote = match index_type {
|
||||||
Some(index) => quote! { Some(#index) },
|
Some(index) => quote! { Some(#index) },
|
||||||
None => quote! { None },
|
None => quote! { None },
|
||||||
};
|
};
|
||||||
let column = quote! {
|
let column = quote! {
|
||||||
zino_core::database::Column::new(#name, #type_name, #quote_value, #not_null, #quote_index)
|
zino_core::database::Column::new(#name, #type_name, #value_quote, #not_null, #index_quote)
|
||||||
};
|
};
|
||||||
columns.push(column);
|
columns.push(column);
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,8 @@ impl RequestContext for AxumExtractor<Request<Body>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn matched_path(&self) -> &str {
|
fn matched_path(&self) -> &str {
|
||||||
|
// The `MatchedPath` extension is always accessible on handlers added via `Router::route`,
|
||||||
|
// but it is not accessible in middleware on nested routes.
|
||||||
if let Some(path) = self.extensions().get::<MatchedPath>() {
|
if let Some(path) = self.extensions().get::<MatchedPath>() {
|
||||||
path.as_str()
|
path.as_str()
|
||||||
} else {
|
} else {
|
||||||
|
@ -90,11 +92,11 @@ impl RequestContext for AxumExtractor<Request<Body>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn original_uri(&self) -> &Uri {
|
fn original_uri(&self) -> &Uri {
|
||||||
|
// The `OriginalUri` extension will always be present if using
|
||||||
|
// `Router` unless another extractor or middleware has removed it.
|
||||||
if let Some(original_uri) = self.extensions().get::<OriginalUri>() {
|
if let Some(original_uri) = self.extensions().get::<OriginalUri>() {
|
||||||
&original_uri.0
|
&original_uri.0
|
||||||
} else {
|
} else {
|
||||||
// The `OriginalUri` extension will always be present if using
|
|
||||||
// `Router` unless another extractor or middleware has removed it
|
|
||||||
self.uri()
|
self.uri()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue