1#[cfg(not(windows))]
16pub(crate) mod jemalloc;
17
18use std::task::{Context, Poll};
19use std::time::Instant;
20
21use axum::extract::{MatchedPath, Request};
22use axum::middleware::Next;
23use axum::response::IntoResponse;
24use lazy_static::lazy_static;
25use prometheus::{
26 Histogram, HistogramVec, IntCounter, IntCounterVec, IntGauge, register_histogram,
27 register_histogram_vec, register_int_counter, register_int_counter_vec, register_int_gauge,
28};
29use session::context::QueryContext;
30use tonic::body::Body;
31use tower::{Layer, Service};
32
33pub(crate) const METRIC_DB_LABEL: &str = "db";
34pub(crate) const METRIC_CODE_LABEL: &str = "code";
35pub(crate) const METRIC_TYPE_LABEL: &str = "type";
36pub(crate) const METRIC_PROTOCOL_LABEL: &str = "protocol";
37pub(crate) const METRIC_ERROR_COUNTER_LABEL_MYSQL: &str = "mysql";
38pub(crate) const METRIC_MYSQL_SUBPROTOCOL_LABEL: &str = "subprotocol";
39pub(crate) const METRIC_MYSQL_BINQUERY: &str = "binquery";
40pub(crate) const METRIC_MYSQL_TEXTQUERY: &str = "textquery";
41pub(crate) const METRIC_POSTGRES_SUBPROTOCOL_LABEL: &str = "subprotocol";
42pub(crate) const METRIC_POSTGRES_SIMPLE_QUERY: &str = "simple";
43pub(crate) const METRIC_POSTGRES_EXTENDED_QUERY: &str = "extended";
44pub(crate) const METRIC_METHOD_LABEL: &str = "method";
45pub(crate) const METRIC_PATH_LABEL: &str = "path";
46pub(crate) const METRIC_RESULT_LABEL: &str = "result";
47pub(crate) const METRIC_VERSION_LABEL: &str = "version";
48
49pub(crate) const METRIC_SUCCESS_VALUE: &str = "success";
50pub(crate) const METRIC_FAILURE_VALUE: &str = "failure";
51
52lazy_static! {
53
54 pub static ref HTTP_REQUEST_COUNTER: IntCounterVec = register_int_counter_vec!(
55 "greptime_servers_http_request_counter",
56 "servers http request counter",
57 &[METRIC_METHOD_LABEL, METRIC_PATH_LABEL, METRIC_CODE_LABEL, METRIC_DB_LABEL]
58 ).unwrap();
59
60 pub static ref METRIC_ERROR_COUNTER: IntCounterVec = register_int_counter_vec!(
61 "greptime_servers_error",
62 "servers error",
63 &[METRIC_PROTOCOL_LABEL]
64 )
65 .unwrap();
66 pub static ref METRIC_HTTP_SQL_ELAPSED: HistogramVec = register_histogram_vec!(
68 "greptime_servers_http_sql_elapsed",
69 "servers http sql elapsed",
70 &[METRIC_DB_LABEL],
71 vec![0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0, 60.0, 300.0]
72 )
73 .unwrap();
74 pub static ref METRIC_HTTP_PROMQL_ELAPSED: HistogramVec = register_histogram_vec!(
76 "greptime_servers_http_promql_elapsed",
77 "servers http promql elapsed",
78 &[METRIC_DB_LABEL],
79 vec![0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0, 60.0, 300.0]
80 )
81 .unwrap();
82 pub static ref METRIC_HTTP_LOGS_ELAPSED: HistogramVec = register_histogram_vec!(
84 "greptime_servers_http_logs_elapsed",
85 "servers http logs elapsed",
86 &[METRIC_DB_LABEL],
87 vec![0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0, 60.0, 300.0]
88 )
89 .unwrap();
90 pub static ref METRIC_AUTH_FAILURE: IntCounterVec = register_int_counter_vec!(
91 "greptime_servers_auth_failure_count",
92 "servers auth failure count",
93 &[METRIC_CODE_LABEL]
94 )
95 .unwrap();
96 pub static ref METRIC_HTTP_INFLUXDB_WRITE_ELAPSED: HistogramVec = register_histogram_vec!(
98 "greptime_servers_http_influxdb_write_elapsed",
99 "servers http influxdb write elapsed",
100 &[METRIC_DB_LABEL],
101 vec![0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0, 60.0, 300.0]
102 )
103 .unwrap();
104 pub static ref METRIC_HTTP_PROM_STORE_WRITE_ELAPSED: HistogramVec = register_histogram_vec!(
106 "greptime_servers_http_prometheus_write_elapsed",
107 "servers http prometheus write elapsed",
108 &[METRIC_DB_LABEL, METRIC_VERSION_LABEL],
109 vec![0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0, 60.0, 300.0]
110 )
111 .unwrap();
112 pub static ref METRIC_HTTP_PROM_STORE_CODEC_ELAPSED: HistogramVec = register_histogram_vec!(
114 "greptime_servers_http_prometheus_codec_elapsed",
115 "servers http prometheus request codec duration",
116 &["type", METRIC_VERSION_LABEL],
117 )
118 .unwrap();
119 pub static ref PROM_STORE_REMOTE_WRITE_SAMPLES: IntCounterVec = register_int_counter_vec!(
121 "greptime_servers_prometheus_remote_write_samples",
122 "frontend prometheus remote write samples",
123 &[METRIC_DB_LABEL, METRIC_VERSION_LABEL]
124 )
125 .unwrap();
126 pub static ref PROM_STORE_REMOTE_WRITE_EXEMPLARS: IntCounterVec = register_int_counter_vec!(
127 "greptime_servers_prometheus_remote_write_exemplars",
128 "Acknowledged Prometheus remote write exemplars",
129 &[METRIC_DB_LABEL, METRIC_VERSION_LABEL]
130 ).unwrap();
131 pub static ref EXEMPLARS_DROPPED_TOTAL: IntCounterVec = register_int_counter_vec!(
132 "greptime_servers_exemplars_dropped_total",
133 "Exemplars dropped during ingestion",
134 &["protocol"]
135 ).unwrap();
136 pub static ref PROM_STORE_REMOTE_WRITE_HISTOGRAMS: IntCounterVec = register_int_counter_vec!(
138 "greptime_servers_prometheus_remote_write_histograms",
139 "frontend prometheus remote write native histograms",
140 &[METRIC_DB_LABEL, METRIC_VERSION_LABEL]
141 )
142 .unwrap();
143 pub static ref OTLP_EXPONENTIAL_HISTOGRAM_REJECTED_DATA_POINTS: IntCounterVec = register_int_counter_vec!(
145 "greptime_servers_otlp_exponential_histogram_rejected_data_points_total",
146 "Number of OTLP exponential histogram data points rejected during conversion",
147 &["reason"]
148 )
149 .unwrap();
150 pub static ref PENDING_BATCHES: IntGauge = register_int_gauge!(
151 "greptime_prom_store_pending_batches",
152 "Number of pending batches waiting to be flushed"
153 )
154 .unwrap();
155 pub static ref PENDING_ROWS: IntGauge = register_int_gauge!(
156 "greptime_prom_store_pending_rows",
157 "Number of pending rows waiting to be flushed"
158 )
159 .unwrap();
160 pub static ref PENDING_WORKERS: IntGauge = register_int_gauge!(
161 "greptime_prom_store_pending_workers",
162 "Number of active pending rows batch workers"
163 )
164 .unwrap();
165 pub static ref FLUSH_TOTAL: IntCounter = register_int_counter!(
166 "greptime_prom_store_flush_total",
167 "Total number of successful batch flushes"
168 )
169 .unwrap();
170 pub static ref FLUSH_ROWS: Histogram = register_histogram!(
171 "greptime_prom_store_flush_rows",
172 "Number of rows per successful flush",
173 vec![100.0, 1000.0, 10000.0, 50000.0, 100000.0, 500000.0]
174 )
175 .unwrap();
176 pub static ref FLUSH_ELAPSED: Histogram = register_histogram!(
177 "greptime_prom_store_flush_elapsed",
178 "Elapsed time of pending rows batch flush in seconds",
179 vec![0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0, 60.0, 300.0]
180 )
181 .unwrap();
182 pub static ref FLUSH_DROPPED_ROWS: IntCounter = register_int_counter!(
183 "greptime_pending_rows_flush_dropped_rows",
184 "Total rows dropped due to pending rows flush failures"
185 )
186 .unwrap();
187 pub static ref FLUSH_FAILURES: IntCounter = register_int_counter!(
188 "greptime_pending_rows_flush_failures",
189 "Total pending rows flush failures"
190 )
191 .unwrap();
192 pub static ref FLOW_NOTIFICATION_DROPPED: IntCounterVec = register_int_counter_vec!(
193 "greptime_prom_store_flow_notification_dropped_total",
194 "Total flow notifications dropped by the pending rows batcher",
195 &["reason"]
196 )
197 .unwrap();
198 pub static ref PENDING_ROWS_BATCH_INGEST_STAGE_ELAPSED: HistogramVec = register_histogram_vec!(
199 "greptime_prom_store_pending_rows_batch_ingest_stage_elapsed",
200 "Elapsed time of pending rows batch ingestion stages in seconds",
201 &["stage"],
202 vec![0.0005, 0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0, 60.0]
203 )
204 .unwrap();
205 pub static ref PENDING_ROWS_BATCH_FLUSH_STAGE_ELAPSED: HistogramVec = register_histogram_vec!(
206 "greptime_prom_store_pending_rows_batch_flush_stage_elapsed",
207 "Elapsed time of pending rows batch flush stages in seconds",
208 &["stage"],
209 vec![0.0005, 0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0, 60.0]
210 )
211 .unwrap();
212 pub static ref METRIC_HTTP_PROM_STORE_READ_ELAPSED: HistogramVec = register_histogram_vec!(
214 "greptime_servers_http_prometheus_read_elapsed",
215 "servers http prometheus read elapsed",
216 &[METRIC_DB_LABEL]
217 )
218 .unwrap();
219 pub static ref METRIC_HTTP_PROMETHEUS_PROMQL_ELAPSED: HistogramVec = register_histogram_vec!(
221 "greptime_servers_http_prometheus_promql_elapsed",
222 "servers http prometheus promql elapsed",
223 &[METRIC_DB_LABEL, METRIC_METHOD_LABEL]
224 )
225 .unwrap();
226 pub static ref METRIC_HTTP_OPENTELEMETRY_METRICS_ELAPSED: HistogramVec =
227 register_histogram_vec!(
228 "greptime_servers_http_otlp_metrics_elapsed",
229 "servers_http_otlp_metrics_elapsed",
230 &[METRIC_DB_LABEL]
231 )
232 .unwrap();
233 pub static ref METRIC_HTTP_OPENTELEMETRY_TRACES_ELAPSED: HistogramVec =
234 register_histogram_vec!(
235 "greptime_servers_http_otlp_traces_elapsed",
236 "servers http otlp traces elapsed",
237 &[METRIC_DB_LABEL]
238 )
239 .unwrap();
240 pub static ref METRIC_HTTP_OPENTELEMETRY_LOGS_ELAPSED: HistogramVec =
241 register_histogram_vec!(
242 "greptime_servers_http_otlp_logs_elapsed",
243 "servers http otlp logs elapsed",
244 &[METRIC_DB_LABEL]
245 )
246 .unwrap();
247 pub static ref METRIC_HTTP_LOGS_INGESTION_COUNTER: IntCounterVec = register_int_counter_vec!(
248 "greptime_servers_http_logs_ingestion_counter",
249 "servers http logs ingestion counter",
250 &[METRIC_DB_LABEL]
251 )
252 .unwrap();
253 pub static ref METRIC_HTTP_LOGS_INGESTION_ELAPSED: HistogramVec =
254 register_histogram_vec!(
255 "greptime_servers_http_logs_ingestion_elapsed",
256 "servers http logs ingestion elapsed",
257 &[METRIC_DB_LABEL, METRIC_RESULT_LABEL]
258 )
259 .unwrap();
260 pub static ref METRIC_HTTP_LOGS_UTF8_RETRIES_TOTAL: IntCounterVec = register_int_counter_vec!(
261 "greptime_servers_http_logs_utf8_retries_total",
262 "UTF-8 parse retry attempts for HTTP logs and pipeline dry-runs, per JSON/JSON stream payload or NDJSON line, regardless of outcome",
263 &["format"]
264 )
265 .unwrap();
266
267 pub static ref METRIC_LOKI_LOGS_INGESTION_COUNTER: IntCounterVec = register_int_counter_vec!(
269 "greptime_servers_loki_logs_ingestion_counter",
270 "servers loki logs ingestion counter",
271 &[METRIC_DB_LABEL]
272 )
273 .unwrap();
274 pub static ref METRIC_LOKI_LOGS_INGESTION_ELAPSED: HistogramVec =
275 register_histogram_vec!(
276 "greptime_servers_loki_logs_ingestion_elapsed",
277 "servers loki logs ingestion elapsed",
278 &[METRIC_DB_LABEL, METRIC_RESULT_LABEL]
279 )
280 .unwrap();
281 pub static ref METRIC_ELASTICSEARCH_LOGS_INGESTION_ELAPSED: HistogramVec =
282 register_histogram_vec!(
283 "greptime_servers_elasticsearch_logs_ingestion_elapsed",
284 "servers elasticsearch logs ingestion elapsed",
285 &[METRIC_DB_LABEL]
286 )
287 .unwrap();
288
289 pub static ref METRIC_ELASTICSEARCH_LOGS_DOCS_COUNT: IntCounterVec = register_int_counter_vec!(
291 "greptime_servers_elasticsearch_logs_docs_count",
292 "servers elasticsearch ingest logs docs count",
293 &[METRIC_DB_LABEL]
294 )
295 .unwrap();
296
297 pub static ref METRIC_HTTP_LOGS_TRANSFORM_ELAPSED: HistogramVec =
298 register_histogram_vec!(
299 "greptime_servers_http_logs_transform_elapsed",
300 "servers http logs transform elapsed",
301 &[METRIC_DB_LABEL, METRIC_RESULT_LABEL]
302 )
303 .unwrap();
304 pub static ref METRIC_MYSQL_CONNECTIONS: IntGauge = register_int_gauge!(
305 "greptime_servers_mysql_connection_count",
306 "servers mysql connection count"
307 )
308 .unwrap();
309 pub static ref METRIC_MYSQL_QUERY_TIMER: HistogramVec = register_histogram_vec!(
310 "greptime_servers_mysql_query_elapsed",
311 "servers mysql query elapsed",
312 &[METRIC_MYSQL_SUBPROTOCOL_LABEL, METRIC_DB_LABEL],
313 vec![0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0, 60.0, 300.0]
314 )
315 .unwrap();
316 pub static ref METRIC_MYSQL_PREPARED_COUNT: IntCounterVec = register_int_counter_vec!(
317 "greptime_servers_mysql_prepared_count",
318 "servers mysql prepared count",
319 &[METRIC_DB_LABEL]
320 )
321 .unwrap();
322 pub static ref METRIC_POSTGRES_CONNECTIONS: IntGauge = register_int_gauge!(
323 "greptime_servers_postgres_connection_count",
324 "servers postgres connection count"
325 )
326 .unwrap();
327 pub static ref METRIC_POSTGRES_QUERY_TIMER: HistogramVec = register_histogram_vec!(
328 "greptime_servers_postgres_query_elapsed",
329 "servers postgres query elapsed",
330 &[METRIC_POSTGRES_SUBPROTOCOL_LABEL, METRIC_DB_LABEL],
331 vec![0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0, 60.0, 300.0]
332 )
333 .unwrap();
334 pub static ref METRIC_POSTGRES_PREPARED_COUNT: IntCounter = register_int_counter!(
335 "greptime_servers_postgres_prepared_count",
336 "servers postgres prepared count"
337 )
338 .unwrap();
339 pub static ref METRIC_POSTGRES_COPY_IN_ROWS: IntCounter = register_int_counter!(
340 "greptime_servers_postgres_copy_in_rows",
341 "servers postgres COPY FROM STDIN rows written"
342 )
343 .unwrap();
344 pub static ref METRIC_SERVER_GRPC_DB_REQUEST_TIMER: HistogramVec = register_histogram_vec!(
345 "greptime_servers_grpc_db_request_elapsed",
346 "servers grpc db request elapsed",
347 &[METRIC_DB_LABEL, METRIC_TYPE_LABEL, METRIC_CODE_LABEL]
348 )
349 .unwrap();
350 pub static ref METRIC_SERVER_GRPC_PROM_REQUEST_TIMER: HistogramVec = register_histogram_vec!(
351 "greptime_servers_grpc_prom_request_elapsed",
352 "servers grpc prom request elapsed",
353 &[METRIC_DB_LABEL],
354 vec![0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0, 60.0, 300.0]
355 )
356 .unwrap();
357 pub static ref METRIC_HTTP_REQUESTS_TOTAL: IntCounterVec = register_int_counter_vec!(
358 "greptime_servers_http_requests_total",
359 "servers http requests total",
360 &[METRIC_METHOD_LABEL, METRIC_PATH_LABEL, METRIC_CODE_LABEL, METRIC_DB_LABEL]
361 )
362 .unwrap();
363 pub static ref METRIC_HTTP_REQUESTS_ELAPSED: HistogramVec = register_histogram_vec!(
364 "greptime_servers_http_requests_elapsed",
365 "servers http requests elapsed",
366 &[METRIC_METHOD_LABEL, METRIC_PATH_LABEL, METRIC_CODE_LABEL, METRIC_DB_LABEL],
367 vec![0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0, 60.0, 300.0]
368 )
369 .unwrap();
370 pub static ref METRIC_GRPC_REQUESTS_TOTAL: IntCounterVec = register_int_counter_vec!(
371 "greptime_servers_grpc_requests_total",
372 "servers grpc requests total",
373 &[METRIC_PATH_LABEL, METRIC_CODE_LABEL]
374 )
375 .unwrap();
376 pub static ref METRIC_GRPC_REQUESTS_ELAPSED: HistogramVec = register_histogram_vec!(
377 "greptime_servers_grpc_requests_elapsed",
378 "servers grpc requests elapsed",
379 &[METRIC_PATH_LABEL, METRIC_CODE_LABEL],
380 vec![0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0, 60.0, 300.0]
381 )
382 .unwrap();
383 pub static ref METRIC_JAEGER_QUERY_ELAPSED: HistogramVec = register_histogram_vec!(
384 "greptime_servers_jaeger_query_elapsed",
385 "servers jaeger query elapsed",
386 &[METRIC_DB_LABEL, METRIC_PATH_LABEL]
387 ).unwrap();
388
389 pub static ref GRPC_BULK_INSERT_ELAPSED: Histogram = register_histogram!(
390 "greptime_servers_bulk_insert_elapsed",
391 "servers handle bulk insert elapsed",
392 ).unwrap();
393
394 pub static ref REQUEST_MEMORY_IN_USE: IntGauge = register_int_gauge!(
397 "greptime_servers_request_memory_in_use_bytes",
398 "bytes currently reserved for all concurrent request bodies and messages"
399 ).unwrap();
400
401 pub static ref REQUEST_MEMORY_LIMIT: IntGauge = register_int_gauge!(
403 "greptime_servers_request_memory_limit_bytes",
404 "maximum bytes allowed for all concurrent request bodies and messages"
405 ).unwrap();
406
407 pub static ref REQUEST_MEMORY_REJECTED: IntCounterVec = register_int_counter_vec!(
409 "greptime_servers_request_memory_rejected_total",
410 "number of requests rejected due to memory limit",
411 &["reason"]
412 ).unwrap();
413}
414
415#[derive(Debug, Clone, Default)]
419pub(crate) struct MetricsMiddlewareLayer;
420
421impl<S> Layer<S> for MetricsMiddlewareLayer {
422 type Service = MetricsMiddleware<S>;
423
424 fn layer(&self, service: S) -> Self::Service {
425 MetricsMiddleware { inner: service }
426 }
427}
428
429#[derive(Debug, Clone)]
430pub(crate) struct MetricsMiddleware<S> {
431 inner: S,
432}
433
434impl<S> Service<http::Request<Body>> for MetricsMiddleware<S>
435where
436 S: Service<http::Request<Body>, Response = http::Response<Body>> + Clone + Send + 'static,
437 S::Future: Send + 'static,
438{
439 type Response = S::Response;
440 type Error = S::Error;
441 type Future = futures::future::BoxFuture<'static, Result<Self::Response, Self::Error>>;
442
443 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
444 self.inner.poll_ready(cx)
445 }
446
447 fn call(&mut self, req: http::Request<Body>) -> Self::Future {
448 let clone = self.inner.clone();
452 let mut inner = std::mem::replace(&mut self.inner, clone);
453
454 Box::pin(async move {
455 let start = Instant::now();
456 let path = req.uri().path().to_string();
457
458 let response = inner.call(req).await?;
460
461 let latency = start.elapsed().as_secs_f64();
462 let status = response.status().as_u16().to_string();
463
464 let labels = [path.as_str(), status.as_str()];
465 METRIC_GRPC_REQUESTS_TOTAL.with_label_values(&labels).inc();
466 METRIC_GRPC_REQUESTS_ELAPSED
467 .with_label_values(&labels)
468 .observe(latency);
469
470 Ok(response)
471 })
472 }
473}
474
475pub(crate) async fn http_metrics_layer(req: Request, next: Next) -> impl IntoResponse {
478 let start = Instant::now();
479 let path = if let Some(matched_path) = req.extensions().get::<MatchedPath>() {
480 matched_path.as_str().to_string()
481 } else {
482 req.uri().path().to_string()
483 };
484 let method = req.method().clone();
485
486 let db = req
487 .extensions()
488 .get::<QueryContext>()
489 .map(|ctx| ctx.get_db_string())
490 .unwrap_or_else(|| "unknown".to_string());
491
492 let response = next.run(req).await;
493
494 let latency = start.elapsed().as_secs_f64();
495 let status = response.status();
496 let status = status.as_str();
497 let method_str = method.as_str();
498
499 let labels = [method_str, &path, status, db.as_str()];
500 METRIC_HTTP_REQUESTS_TOTAL.with_label_values(&labels).inc();
501 METRIC_HTTP_REQUESTS_ELAPSED
502 .with_label_values(&labels)
503 .observe(latency);
504
505 response
506}