Skip to content

Commit d9d0a0e

Browse files
committed
datacollector integration
1 parent 3149cb8 commit d9d0a0e

2 files changed

Lines changed: 160 additions & 10 deletions

File tree

asap-query-engine/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ lazy_static = "1.4"
5656
zstd = "0.13"
5757
reqwest = { version = "0.11", features = ["json"] }
5858
tracing-appender = "0.2"
59+
sketchlib-rust = { git = "https://github.com/ProjectASAP/sketchlib-rust", branch = "protobuf-xxh3-shared" }
5960

6061
[dev-dependencies]
6162
ctor = "0.2"

asap-query-engine/src/drivers/ingest/otel.rs

Lines changed: 159 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,18 @@
55
//! handoff to precompute engine as TODO.
66
77
use std::collections::HashMap;
8+
use std::io::Read;
89

910
use axum::{body::Bytes, extract::State, routing::post, Json, Router};
11+
use flate2::read::GzDecoder;
1012
use opentelemetry_proto::tonic::collector::metrics::v1::{
1113
metrics_service_server::MetricsService, ExportMetricsServiceRequest,
1214
ExportMetricsServiceResponse,
1315
};
16+
use opentelemetry_proto::tonic::common::v1::any_value::Value as AnyValueVariant;
1417
use opentelemetry_proto::tonic::metrics::v1::number_data_point::Value as NumberValue;
1518
use prost::Message;
19+
use sketchlib_rust::proto::sketchlib::{sketch_envelope, SketchEnvelope};
1620
use tonic::{Request, Response, Status};
1721
use tracing::{debug, error, info};
1822

@@ -80,25 +84,49 @@ impl MetricsService for MetricsServiceImpl {
8084
&self,
8185
request: Request<ExportMetricsServiceRequest>,
8286
) -> Result<Response<ExportMetricsServiceResponse>, Status> {
87+
debug!("OTLP received request via gRPC");
8388
let req = request.into_inner();
84-
process_otlp_request(&req);
89+
process_otlp_request(&req, "gRPC");
90+
debug!("OTLP sending response via gRPC");
8591
Ok(Response::new(ExportMetricsServiceResponse {
8692
partial_success: None,
8793
}))
8894
}
8995
}
9096

9197
async fn handle_otlp_http(
98+
headers: axum::http::HeaderMap,
9299
State(_state): State<()>,
93100
body: Bytes,
94101
) -> Result<Json<serde_json::Value>, (axum::http::StatusCode, String)> {
102+
debug!("OTLP received request via HTTP, body_bytes={}", body.len());
103+
let body = if let Some(enc) = headers.get(axum::http::header::CONTENT_ENCODING) {
104+
let enc = enc.to_str().unwrap_or("").trim().to_ascii_lowercase();
105+
if enc == "gzip" {
106+
let mut decoder = GzDecoder::new(body.as_ref());
107+
let mut out = Vec::new();
108+
decoder.read_to_end(&mut out).map_err(|e| {
109+
(
110+
axum::http::StatusCode::BAD_REQUEST,
111+
format!("Gzip decode error: {}", e),
112+
)
113+
})?;
114+
Bytes::from(out)
115+
} else {
116+
body
117+
}
118+
} else {
119+
body
120+
};
121+
95122
let req = ExportMetricsServiceRequest::decode(body.as_ref()).map_err(|e| {
96123
(
97124
axum::http::StatusCode::BAD_REQUEST,
98125
format!("Protobuf decode error: {}", e),
99126
)
100127
})?;
101-
process_otlp_request(&req);
128+
process_otlp_request(&req, "HTTP");
129+
debug!("OTLP sending response via HTTP");
102130
Ok(Json(serde_json::json!({"rejected": 0})))
103131
}
104132

@@ -111,15 +139,101 @@ pub struct MetricPoint {
111139
pub value: f64,
112140
}
113141

114-
fn process_otlp_request(request: &ExportMetricsServiceRequest) {
142+
fn format_series_key(name: &str, labels: &HashMap<String, String>) -> String {
143+
let mut pairs: Vec<_> = labels.iter().collect();
144+
pairs.sort_by_key(|(k, _)| *k);
145+
let labels_str = pairs
146+
.iter()
147+
.map(|(k, v)| format!("{}={}", k, v))
148+
.collect::<Vec<_>>()
149+
.join(",");
150+
format!("{}{{{}}}", name, labels_str)
151+
}
152+
153+
fn get_sketch_payload_from_attrs(
154+
attrs: &[opentelemetry_proto::tonic::common::v1::KeyValue],
155+
) -> Option<(String, Vec<u8>)> {
156+
for kv in attrs {
157+
match kv.key.as_str() {
158+
"kll.sketch_payload" | "cms.sketch_payload" | "countsketch.sketch_payload" => {
159+
if let Some(value) = &kv.value {
160+
if let Some(AnyValueVariant::BytesValue(bytes)) = &value.value {
161+
return Some((kv.key.clone(), bytes.clone()));
162+
}
163+
}
164+
}
165+
_ => {}
166+
}
167+
}
168+
None
169+
}
170+
171+
fn log_sketch_envelope_type(attr_name: &str, payload: &[u8], metric_name: &str) {
172+
match SketchEnvelope::decode(payload) {
173+
Ok(env) => {
174+
let sketch_type = match env.sketch_state {
175+
Some(sketch_envelope::SketchState::Kll(_)) => "KLL",
176+
Some(sketch_envelope::SketchState::CountMin(_)) => "CountMin",
177+
Some(sketch_envelope::SketchState::CountSketch(_)) => "CountSketch",
178+
Some(_) => "Other",
179+
None => "Unknown",
180+
};
181+
debug!(
182+
"OTLP Sketches: metric='{}' attr='{}' payload_bytes={} sketch_type={}",
183+
metric_name,
184+
attr_name,
185+
payload.len(),
186+
sketch_type
187+
);
188+
}
189+
Err(e) => {
190+
debug!(
191+
"OTLP Sketches: metric='{}' attr='{}' payload_bytes={} decode_error='{}'",
192+
metric_name,
193+
attr_name,
194+
payload.len(),
195+
e
196+
);
197+
}
198+
}
199+
}
200+
201+
fn process_otlp_request(request: &ExportMetricsServiceRequest, transport: &str) {
115202
let resource_count = request.resource_metrics.len();
116203
let total_points = otlp_to_record_count(request);
117-
debug!(
118-
"OTLP ingest: received {} resource metrics, {} total data points",
119-
resource_count, total_points
120-
);
204+
if resource_count > 0 || total_points > 0 {
205+
debug!(
206+
"OTLP ingest: received {} resource metrics, {} total data points (transport={})",
207+
resource_count, total_points, transport
208+
);
209+
}
210+
211+
let (points, sketch_payloads) = otlp_to_metric_points_and_sketches(request);
212+
213+
for (metric_name, attr_name, payload) in &sketch_payloads {
214+
log_sketch_envelope_type(attr_name, payload, metric_name);
215+
}
216+
if !sketch_payloads.is_empty() {
217+
debug!(
218+
"OTLP Sketch Payload Flow: received {} sketch payload(s), decoded successfully",
219+
sketch_payloads.len()
220+
);
221+
}
121222

122-
let points = otlp_to_metric_points(request);
223+
let mut by_series: HashMap<String, usize> = HashMap::new();
224+
for point in &points {
225+
let key = format_series_key(&point.name, &point.labels);
226+
*by_series.entry(key).or_insert(0) += 1;
227+
}
228+
if !by_series.is_empty() {
229+
debug!(
230+
"OTLP Raw Metrics Flow: received {} raw metric series",
231+
by_series.len()
232+
);
233+
for (series, count) in by_series {
234+
debug!("OTLP Raw Metrics Flow: series {} count={}", series, count);
235+
}
236+
}
123237
if let Some(first) = points.first() {
124238
debug!(
125239
"OTLP parse example: {} {:?} @{}ns = {}",
@@ -178,8 +292,13 @@ fn otlp_to_record_count(request: &ExportMetricsServiceRequest) -> usize {
178292
}
179293

180294
/// Parse OTLP request and convert to metric data points (name, labels, timestamp, value).
181-
fn otlp_to_metric_points(request: &ExportMetricsServiceRequest) -> Vec<MetricPoint> {
295+
/// Data points with sketch payloads in attributes are excluded from points and returned
296+
/// separately for Sketch Payload Flow processing.
297+
fn otlp_to_metric_points_and_sketches(
298+
request: &ExportMetricsServiceRequest,
299+
) -> (Vec<MetricPoint>, Vec<(String, String, Vec<u8>)>) {
182300
let mut points = Vec::new();
301+
let mut sketch_payloads = Vec::new();
183302
for resource_metrics in &request.resource_metrics {
184303
let resource_attrs = resource_metrics
185304
.resource
@@ -209,6 +328,12 @@ fn otlp_to_metric_points(request: &ExportMetricsServiceRequest) -> Vec<MetricPoi
209328
match &metric.data {
210329
Some(Data::Gauge(g)) => {
211330
for dp in &g.data_points {
331+
if let Some((attr_name, payload)) =
332+
get_sketch_payload_from_attrs(&dp.attributes)
333+
{
334+
sketch_payloads.push((metric.name.clone(), attr_name, payload));
335+
continue;
336+
}
212337
let labels = merge_point_attributes(&base_labels, &dp.attributes);
213338
let value = number_value_to_f64(&dp.value);
214339
points.push(MetricPoint {
@@ -221,6 +346,12 @@ fn otlp_to_metric_points(request: &ExportMetricsServiceRequest) -> Vec<MetricPoi
221346
}
222347
Some(Data::Sum(s)) => {
223348
for dp in &s.data_points {
349+
if let Some((attr_name, payload)) =
350+
get_sketch_payload_from_attrs(&dp.attributes)
351+
{
352+
sketch_payloads.push((metric.name.clone(), attr_name, payload));
353+
continue;
354+
}
224355
let labels = merge_point_attributes(&base_labels, &dp.attributes);
225356
let value = number_value_to_f64(&dp.value);
226357
points.push(MetricPoint {
@@ -233,6 +364,12 @@ fn otlp_to_metric_points(request: &ExportMetricsServiceRequest) -> Vec<MetricPoi
233364
}
234365
Some(Data::Histogram(hist)) => {
235366
for dp in &hist.data_points {
367+
if let Some((attr_name, payload)) =
368+
get_sketch_payload_from_attrs(&dp.attributes)
369+
{
370+
sketch_payloads.push((metric.name.clone(), attr_name, payload));
371+
continue;
372+
}
236373
let labels = merge_point_attributes(&base_labels, &dp.attributes);
237374
if let Some(sum) = dp.sum {
238375
points.push(MetricPoint {
@@ -252,6 +389,12 @@ fn otlp_to_metric_points(request: &ExportMetricsServiceRequest) -> Vec<MetricPoi
252389
}
253390
Some(Data::ExponentialHistogram(eh)) => {
254391
for dp in &eh.data_points {
392+
if let Some((attr_name, payload)) =
393+
get_sketch_payload_from_attrs(&dp.attributes)
394+
{
395+
sketch_payloads.push((metric.name.clone(), attr_name, payload));
396+
continue;
397+
}
255398
let labels = merge_point_attributes(&base_labels, &dp.attributes);
256399
if let Some(sum) = dp.sum {
257400
points.push(MetricPoint {
@@ -271,6 +414,12 @@ fn otlp_to_metric_points(request: &ExportMetricsServiceRequest) -> Vec<MetricPoi
271414
}
272415
Some(Data::Summary(sm)) => {
273416
for dp in &sm.data_points {
417+
if let Some((attr_name, payload)) =
418+
get_sketch_payload_from_attrs(&dp.attributes)
419+
{
420+
sketch_payloads.push((metric.name.clone(), attr_name, payload));
421+
continue;
422+
}
274423
let labels = merge_point_attributes(&base_labels, &dp.attributes);
275424
points.push(MetricPoint {
276425
name: format!("{}_sum", metric.name),
@@ -291,7 +440,7 @@ fn otlp_to_metric_points(request: &ExportMetricsServiceRequest) -> Vec<MetricPoi
291440
}
292441
}
293442
}
294-
points
443+
(points, sketch_payloads)
295444
}
296445

297446
fn merge_point_attributes(

0 commit comments

Comments
 (0)