1#[cfg(test)]
16mod test {
17 use std::sync::Arc;
18
19 use client::{DEFAULT_CATALOG_NAME, OutputData};
20 use common_recordbatch::RecordBatches;
21 use frontend::instance::Instance;
22 use otel_arrow_rust::proto::opentelemetry::collector::metrics::v1::ExportMetricsServiceRequest;
23 use otel_arrow_rust::proto::opentelemetry::common::v1::any_value::Value as Val;
24 use otel_arrow_rust::proto::opentelemetry::common::v1::{
25 AnyValue, InstrumentationScope, KeyValue,
26 };
27 use otel_arrow_rust::proto::opentelemetry::metrics::v1::number_data_point::Value;
28 use otel_arrow_rust::proto::opentelemetry::metrics::v1::{
29 Gauge, Histogram, HistogramDataPoint, Metric, NumberDataPoint, ResourceMetrics,
30 ScopeMetrics, metric,
31 };
32 use otel_arrow_rust::proto::opentelemetry::resource::v1::Resource;
33 use servers::query_handler::OpenTelemetryProtocolHandler;
34 use servers::query_handler::sql::SqlQueryHandler;
35 use session::context::QueryContext;
36
37 use crate::standalone::GreptimeDbStandaloneBuilder;
38 use crate::tests;
39
40 #[tokio::test(flavor = "multi_thread")]
41 pub async fn test_otlp_on_standalone() {
42 let standalone = GreptimeDbStandaloneBuilder::new("test_standalone_otlp")
43 .build()
44 .await;
45 let instance = standalone.fe_instance();
46
47 test_otlp(instance).await;
48 }
49
50 #[tokio::test(flavor = "multi_thread")]
51 pub async fn test_otlp_on_distributed() {
52 let instance = tests::create_distributed_instance("test_standalone_otlp").await;
53
54 test_otlp(&instance.frontend()).await;
55 }
56
57 async fn test_otlp(instance: &Arc<Instance>) {
58 let req = build_request();
59 let db = "otlp";
60 let ctx = Arc::new(QueryContext::with(DEFAULT_CATALOG_NAME, db));
61
62 assert!(
63 SqlQueryHandler::do_query(
64 instance.as_ref(),
65 &format!("CREATE DATABASE IF NOT EXISTS {db}"),
66 ctx.clone(),
67 )
68 .await
69 .first()
70 .unwrap()
71 .is_ok()
72 );
73
74 let resp = instance.metrics(req, ctx.clone()).await;
75 assert!(resp.is_ok());
76
77 let mut output = instance
78 .do_query(
79 "SELECT * FROM my_test_metric_my_ignored_unit ORDER BY greptime_timestamp",
80 ctx.clone(),
81 )
82 .await;
83 let output = output.remove(0).unwrap();
84 let OutputData::Stream(stream) = output.data else {
85 unreachable!()
86 };
87 let recordbatches = RecordBatches::try_collect(stream).await.unwrap();
88 assert_eq!(
89 recordbatches.pretty_print().unwrap(),
90 "\
91+----------------+---------------------+----------------+
92| container_name | greptime_timestamp | greptime_value |
93+----------------+---------------------+----------------+
94| testserver | 1970-01-01T00:00:00 | 105.0 |
95| testsevrer | 1970-01-01T00:00:00 | 100.0 |
96+----------------+---------------------+----------------+",
97 );
98
99 let mut output = instance
100 .do_query(
101 "SELECT le, greptime_value FROM my_test_histo_my_ignored_unit_bucket order by le",
102 ctx.clone(),
103 )
104 .await;
105 let output = output.remove(0).unwrap();
106 let OutputData::Stream(stream) = output.data else {
107 unreachable!()
108 };
109 let recordbatches = RecordBatches::try_collect(stream).await.unwrap();
110 assert_eq!(
111 recordbatches.pretty_print().unwrap(),
112 "\
113+-----+----------------+
114| le | greptime_value |
115+-----+----------------+
116| 1 | 1.0 |
117| 5 | 3.0 |
118| inf | 4.0 |
119+-----+----------------+",
120 );
121
122 let mut output = instance
123 .do_query(
124 "SELECT * FROM my_test_histo_my_ignored_unit_sum",
125 ctx.clone(),
126 )
127 .await;
128 let output = output.remove(0).unwrap();
129 let OutputData::Stream(stream) = output.data else {
130 unreachable!()
131 };
132 let recordbatches = RecordBatches::try_collect(stream).await.unwrap();
133 assert_eq!(
134 recordbatches.pretty_print().unwrap(),
135 "\
136+------------+---------------------+----------------+
137| host | greptime_timestamp | greptime_value |
138+------------+---------------------+----------------+
139| testserver | 1970-01-01T00:00:00 | 51.0 |
140+------------+---------------------+----------------+",
141 );
142
143 let mut output = instance
144 .do_query(
145 "SELECT * FROM my_test_histo_my_ignored_unit_count",
146 ctx.clone(),
147 )
148 .await;
149 let output = output.remove(0).unwrap();
150 let OutputData::Stream(stream) = output.data else {
151 unreachable!()
152 };
153 let recordbatches = RecordBatches::try_collect(stream).await.unwrap();
154 assert_eq!(
155 recordbatches.pretty_print().unwrap(),
156 "\
157+------------+---------------------+----------------+
158| host | greptime_timestamp | greptime_value |
159+------------+---------------------+----------------+
160| testserver | 1970-01-01T00:00:00 | 4.0 |
161+------------+---------------------+----------------+",
162 );
163 }
164
165 fn build_request() -> ExportMetricsServiceRequest {
166 let data_points = vec![
167 NumberDataPoint {
168 attributes: vec![keyvalue("container.name", "testsevrer")],
169 time_unix_nano: 100,
170 value: Some(Value::AsInt(100)),
171 ..Default::default()
172 },
173 NumberDataPoint {
174 attributes: vec![keyvalue("container.name", "testserver")],
175 time_unix_nano: 105,
176 value: Some(Value::AsInt(105)),
177 ..Default::default()
178 },
179 ];
180 let gauge = Gauge { data_points };
181
182 let histo_data_points = vec![HistogramDataPoint {
183 attributes: vec![keyvalue("host", "testserver")],
184 time_unix_nano: 100,
185 count: 4,
186 bucket_counts: vec![1, 2, 1],
187 explicit_bounds: vec![1.0f64, 5.0f64],
188 sum: Some(51f64),
189 ..Default::default()
190 }];
191
192 let histo = Histogram {
193 data_points: histo_data_points,
194 aggregation_temporality: 0,
195 };
196
197 ExportMetricsServiceRequest {
198 resource_metrics: vec![ResourceMetrics {
199 scope_metrics: vec![ScopeMetrics {
200 metrics: vec![
201 Metric {
202 name: "my.test.metric".into(),
203 description: "my ignored desc".into(),
204 unit: "my ignored unit".into(),
205 metadata: vec![],
206 data: Some(metric::Data::Gauge(gauge)),
207 },
208 Metric {
209 name: "my.test.histo".into(),
210 description: "my ignored desc".into(),
211 unit: "my ignored unit".into(),
212 metadata: vec![],
213 data: Some(metric::Data::Histogram(histo)),
214 },
215 ],
216 scope: Some(InstrumentationScope {
217 attributes: vec![
218 keyvalue("scope", "otel"),
219 keyvalue("telemetry.sdk.name", "java"),
220 ],
221 ..Default::default()
222 }),
223 ..Default::default()
224 }],
225 resource: Some(Resource {
226 attributes: vec![keyvalue("resource", "greptimedb")],
227 dropped_attributes_count: 0,
228 entity_refs: vec![],
229 }),
230 ..Default::default()
231 }],
232 }
233 }
234
235 fn keyvalue(key: &str, value: &str) -> KeyValue {
236 KeyValue {
237 key: key.into(),
238 value: Some(AnyValue {
239 value: Some(Val::StringValue(value.into())),
240 }),
241 }
242 }
243}