Skip to content

Commit 514964f

Browse files
committed
Add metrics to legacy api
1 parent 5b2b268 commit 514964f

5 files changed

Lines changed: 134 additions & 145 deletions

File tree

src/api/common/metrics.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use prometheus_client::{
1616

1717
use crate::api::{
1818
common::{caching::CacheLabels, data::ApiData},
19+
legacy::metrics::ApiLegacyMetrics,
1920
v1::metrics::ApiV1Metrics
2021
};
2122

@@ -50,6 +51,8 @@ pub struct AppMetrics {
5051
pub registry: Registry,
5152
/// All of the global (application-wide) metrics
5253
pub global: GlobalMetrics,
54+
/// All of the legacy API metrics
55+
pub legacy: ApiLegacyMetrics,
5356
/// All of the API v1 metrics
5457
pub v1: ApiV1Metrics
5558
}
@@ -60,6 +63,7 @@ impl AppMetrics {
6063

6164
AppMetrics {
6265
global: GlobalMetrics::init_metrics(&mut registry),
66+
legacy: ApiLegacyMetrics::init_metrics(&mut registry),
6367
v1: ApiV1Metrics::init_metrics(&mut registry),
6468
registry
6569
}

src/api/legacy/metrics.rs

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
use std::fmt::Write;
2+
3+
use actix_web::{
4+
body::MessageBody,
5+
dev::{ServiceRequest, ServiceResponse},
6+
http::header,
7+
middleware::Next,
8+
web
9+
};
10+
use documented::DocumentedFields;
11+
use prometheus_client::{
12+
encoding::{EncodeLabelSet, EncodeLabelValue},
13+
metrics::{counter::Counter, family::Family},
14+
registry::Registry
15+
};
16+
use serde::{Deserialize, Serialize};
17+
18+
use crate::{
19+
api::common::{data::ApiData, metrics::MetricsGroup},
20+
make_api_metric
21+
};
22+
23+
macro_rules! impl_serde_variant_as_label_value {
24+
($enum:ty) => {
25+
impl EncodeLabelValue for $enum {
26+
fn encode(
27+
&self,
28+
encoder: &mut prometheus_client::encoding::LabelValueEncoder
29+
) -> Result<(), std::fmt::Error> {
30+
encoder.write_str(
31+
serde_variant::to_variant_name(self).map_err(|_| std::fmt::Error)?
32+
)
33+
}
34+
}
35+
};
36+
}
37+
38+
#[derive(Serialize, Deserialize, Debug, Hash, PartialEq, Eq, Clone)]
39+
#[serde(rename_all = "lowercase")]
40+
pub enum UserAgentType {
41+
Loader,
42+
Wrapper,
43+
Unknown
44+
}
45+
46+
#[derive(Serialize, Deserialize, Debug, Hash, PartialEq, Eq, Clone, EncodeLabelSet)]
47+
pub struct OneConfigRequest {
48+
pub version: String,
49+
pub loader: String,
50+
pub user_agent_type: UserAgentType
51+
}
52+
53+
impl_serde_variant_as_label_value!(UserAgentType);
54+
55+
/// A struct containing all of the metrics state for the API
56+
#[derive(DocumentedFields)]
57+
pub struct ApiLegacyMetrics {
58+
/// The amount of OneConfig requests, by version, loader, and user agent
59+
/// type
60+
oneconfig_requests: Family<OneConfigRequest, Counter>
61+
}
62+
63+
impl MetricsGroup for ApiLegacyMetrics {
64+
fn init_metrics(registry: &mut Registry) -> Self {
65+
let registry = registry.sub_registry_with_prefix("legacy");
66+
67+
make_api_metric!(registry, Self, oneconfig_requests);
68+
69+
Self { oneconfig_requests }
70+
}
71+
}
72+
73+
/// A middleware to increment all metrics per-request
74+
pub async fn middleware(
75+
mut service_request: ServiceRequest,
76+
next: Next<impl MessageBody>
77+
) -> Result<ServiceResponse<impl MessageBody>, actix_web::Error> {
78+
let data = service_request.extract::<web::Data<ApiData>>().await?;
79+
80+
#[allow(clippy::single_match)]
81+
match service_request
82+
.match_pattern()
83+
.unwrap_or("default".to_string())
84+
.as_str()
85+
{
86+
"/oneconfig/{version}-{loader}" => 'inner: {
87+
let Some((version, loader)) = service_request.uri().path()
88+
[(const { "/oneconfig/".len() })..]
89+
.split_once('-')
90+
else {
91+
break 'inner;
92+
};
93+
94+
data.metrics
95+
.legacy
96+
.oneconfig_requests
97+
.get_or_create(&OneConfigRequest {
98+
version: version.to_owned(),
99+
loader: loader.to_owned(),
100+
user_agent_type: match service_request
101+
.headers()
102+
.get(header::USER_AGENT)
103+
.and_then(|v| v.to_str().ok())
104+
{
105+
Some(s) if s.contains("OneConfigLoader") => UserAgentType::Loader,
106+
Some(s) if s.contains("OneConfigWrapper") =>
107+
UserAgentType::Wrapper,
108+
Some(_) | None => UserAgentType::Unknown
109+
}
110+
})
111+
.inc();
112+
}
113+
_ => ()
114+
};
115+
116+
// Let the real request handler continue
117+
next.call(service_request).await
118+
}

src/api/legacy/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
use actix_web::web::ServiceConfig;
22

33
pub mod endpoint;
4+
pub mod metrics;
45
pub mod types;
56
pub mod utils;
67

7-
pub fn configure(config: &mut ServiceConfig) { config.service(endpoint::oneconfig); }
8+
pub fn configure(config: &mut ServiceConfig) {
9+
config.service(endpoint::oneconfig);
10+
// Metrics middleware in main.rs due to github.com/actix/actix-web#414
11+
}

src/main.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,19 @@ async fn main() {
5252

5353
let mut server = HttpServer::new(move || {
5454
App::new()
55+
// Register app state
5556
.app_data(data.clone())
57+
// Register legacy routes and middleware
5658
.configure(api::legacy::configure)
59+
.wrap(actix_web::middleware::from_fn(api::legacy::metrics::middleware))
60+
// Register v1 routes and middleware
5761
.configure(api::v1::configure)
58-
.configure(api::common::metrics::configure)
62+
// Register caching middleware
5963
.wrap(actix_web::middleware::from_fn(
6064
api::common::caching::middleware
6165
))
66+
// Register metrics routes and middleware
67+
.configure(api::common::metrics::configure)
6268
.wrap(actix_web::middleware::from_fn(
6369
api::common::metrics::middleware
6470
))

src/maven.rs

Lines changed: 0 additions & 143 deletions
This file was deleted.

0 commit comments

Comments
 (0)