1use std::collections::HashMap;
16use std::sync::Arc;
17
18use common_plugins::GREPTIME_EXEC_PREFIX;
19use datafusion::physical_plan::metrics::MetricValue;
20use datafusion::physical_plan::ExecutionPlan;
21use headers::{Header, HeaderName, HeaderValue};
22use hyper::HeaderMap;
23use serde_json::Value;
24
25pub mod constants {
26 pub const GREPTIME_DB_HEADER_FORMAT: &str = "x-greptime-format";
42 pub const GREPTIME_DB_HEADER_TIMEOUT: &str = "x-greptime-timeout";
43 pub const GREPTIME_DB_HEADER_EXECUTION_TIME: &str = "x-greptime-execution-time";
44 pub const GREPTIME_DB_HEADER_METRICS: &str = "x-greptime-metrics";
45 pub const GREPTIME_DB_HEADER_NAME: &str = "x-greptime-db-name";
46 pub const GREPTIME_DB_HEADER_READ_PREFERENCE: &str = "x-greptime-read-preference";
47 pub const GREPTIME_TIMEZONE_HEADER_NAME: &str = "x-greptime-timezone";
48 pub const GREPTIME_DB_HEADER_ERROR_CODE: &str = common_error::GREPTIME_DB_HEADER_ERROR_CODE;
49
50 pub const GREPTIME_LOG_PIPELINE_NAME_HEADER_NAME: &str = "x-greptime-log-pipeline-name";
52 pub const GREPTIME_LOG_PIPELINE_VERSION_HEADER_NAME: &str = "x-greptime-log-pipeline-version";
53
54 pub const GREPTIME_PIPELINE_NAME_HEADER_NAME: &str = "x-greptime-pipeline-name";
56 pub const GREPTIME_PIPELINE_VERSION_HEADER_NAME: &str = "x-greptime-pipeline-version";
57
58 pub const GREPTIME_LOG_TABLE_NAME_HEADER_NAME: &str = "x-greptime-log-table-name";
59 pub const GREPTIME_LOG_EXTRACT_KEYS_HEADER_NAME: &str = "x-greptime-log-extract-keys";
60 pub const GREPTIME_TRACE_TABLE_NAME_HEADER_NAME: &str = "x-greptime-trace-table-name";
61
62 pub const GREPTIME_PIPELINE_PARAMS_HEADER: &str = "x-greptime-pipeline-params";
64}
65
66pub static GREPTIME_DB_HEADER_FORMAT: HeaderName =
67 HeaderName::from_static(constants::GREPTIME_DB_HEADER_FORMAT);
68pub static GREPTIME_DB_HEADER_EXECUTION_TIME: HeaderName =
69 HeaderName::from_static(constants::GREPTIME_DB_HEADER_EXECUTION_TIME);
70pub static GREPTIME_DB_HEADER_METRICS: HeaderName =
71 HeaderName::from_static(constants::GREPTIME_DB_HEADER_METRICS);
72
73pub static GREPTIME_DB_HEADER_NAME: HeaderName =
75 HeaderName::from_static(constants::GREPTIME_DB_HEADER_NAME);
76
77pub static GREPTIME_TIMEZONE_HEADER_NAME: HeaderName =
79 HeaderName::from_static(constants::GREPTIME_TIMEZONE_HEADER_NAME);
80
81pub static GREPTIME_DB_HEADER_READ_PREFERENCE: HeaderName =
83 HeaderName::from_static(constants::GREPTIME_DB_HEADER_READ_PREFERENCE);
84
85pub static CONTENT_TYPE_PROTOBUF_STR: &str = "application/x-protobuf";
86pub static CONTENT_TYPE_PROTOBUF: HeaderValue = HeaderValue::from_static(CONTENT_TYPE_PROTOBUF_STR);
87pub static CONTENT_ENCODING_SNAPPY: HeaderValue = HeaderValue::from_static("snappy");
88
89pub static CONTENT_TYPE_NDJSON_STR: &str = "application/x-ndjson";
90
91pub struct GreptimeDbName(Option<String>);
92
93impl Header for GreptimeDbName {
94 fn name() -> &'static HeaderName {
95 &GREPTIME_DB_HEADER_NAME
96 }
97
98 fn decode<'i, I>(values: &mut I) -> Result<Self, headers::Error>
99 where
100 Self: Sized,
101 I: Iterator<Item = &'i HeaderValue>,
102 {
103 if let Some(value) = values.next() {
104 let str_value = value.to_str().map_err(|_| headers::Error::invalid())?;
105 Ok(Self(Some(str_value.to_owned())))
106 } else {
107 Ok(Self(None))
108 }
109 }
110
111 fn encode<E: Extend<HeaderValue>>(&self, values: &mut E) {
112 if let Some(name) = &self.0 {
113 if let Ok(value) = HeaderValue::from_str(name) {
114 values.extend(std::iter::once(value));
115 }
116 }
117 }
118}
119
120impl GreptimeDbName {
121 pub fn value(&self) -> Option<&String> {
122 self.0.as_ref()
123 }
124}
125
126pub fn write_cost_header_map(cost: usize) -> HeaderMap {
128 let mut header_map = HeaderMap::new();
129 if cost > 0 {
130 let mut map: HashMap<String, Value> = HashMap::new();
131 map.insert(
132 common_plugins::GREPTIME_EXEC_WRITE_COST.to_string(),
133 Value::from(cost),
134 );
135 let _ = serde_json::to_string(&map)
136 .ok()
137 .and_then(|s| HeaderValue::from_str(&s).ok())
138 .and_then(|v| header_map.insert(&GREPTIME_DB_HEADER_METRICS, v));
139 }
140 header_map
141}
142
143fn collect_into_maps(name: &str, value: u64, maps: &mut [&mut HashMap<String, u64>]) {
144 if name.starts_with(GREPTIME_EXEC_PREFIX) && value > 0 {
145 maps.iter_mut().for_each(|map| {
146 map.entry(name.to_string())
147 .and_modify(|v| *v += value)
148 .or_insert(value);
149 });
150 }
151}
152
153pub fn collect_plan_metrics(plan: &Arc<dyn ExecutionPlan>, maps: &mut [&mut HashMap<String, u64>]) {
154 if let Some(m) = plan.metrics() {
155 m.iter().for_each(|m| match m.value() {
156 MetricValue::Count { name, count } => {
157 collect_into_maps(name, count.value() as u64, maps);
158 }
159 MetricValue::Gauge { name, gauge } => {
160 collect_into_maps(name, gauge.value() as u64, maps);
161 }
162 MetricValue::Time { name, time } => {
163 if name.starts_with(GREPTIME_EXEC_PREFIX) {
164 maps.iter_mut().for_each(|map| {
166 map.insert(name.to_string(), time.value() as u64);
167 });
168 }
169 }
170 _ => {}
171 });
172 }
173
174 for c in plan.children() {
175 collect_plan_metrics(c, maps);
176 }
177}