Skip to main content

frontend/instance/otlp/
trace_semconv.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use api::v1::ColumnDataType;
16use opentelemetry_semantic_conventions::{attribute, resource};
17
18/// Returns fixed scalar types for flattened trace semconv columns.
19///
20/// The mapping is maintained from the official OpenTelemetry semantic
21/// conventions docs under `docs/` and `docs/registry/attributes/` in:
22/// https://github.com/open-telemetry/semantic-conventions/tree/main/docs
23///
24/// Only attributes whose docs mark them as `Stable` or `Release Candidate` are
25/// included here. `Development` and lower-stability attributes must keep the
26/// dynamic reconciliation path instead.
27pub(super) fn trace_semconv_fixed_type(column_name: &str) -> Option<ColumnDataType> {
28    if let Some(resource_attribute) = column_name.strip_prefix("resource_attributes.") {
29        return match resource_attribute {
30            // Service resource attributes:
31            // https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/service.md
32            // https://github.com/open-telemetry/semantic-conventions/blob/main/docs/registry/attributes/service.md
33            resource::SERVICE_NAME
34            | resource::SERVICE_INSTANCE_ID
35            | resource::SERVICE_NAMESPACE
36            | resource::SERVICE_VERSION => Some(ColumnDataType::String),
37
38            // Telemetry SDK resource attributes:
39            // https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/README.md
40            // https://github.com/open-telemetry/semantic-conventions/blob/main/docs/registry/attributes/telemetry.md
41            resource::TELEMETRY_SDK_LANGUAGE
42            | resource::TELEMETRY_SDK_NAME
43            | resource::TELEMETRY_SDK_VERSION => Some(ColumnDataType::String),
44
45            // Container resource attributes:
46            // https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/container.md
47            resource::CONTAINER_ID => Some(ColumnDataType::String),
48
49            // Browser resource attributes:
50            // https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/browser.md
51            resource::USER_AGENT_ORIGINAL => Some(ColumnDataType::String),
52
53            // Kubernetes resource attributes:
54            // https://github.com/open-telemetry/semantic-conventions/blob/main/docs/resource/k8s/README.md
55            resource::K8S_CLUSTER_NAME
56            | resource::K8S_CLUSTER_UID
57            | resource::K8S_CONTAINER_NAME
58            | resource::K8S_CRONJOB_NAME
59            | resource::K8S_CRONJOB_UID
60            | resource::K8S_DAEMONSET_NAME
61            | resource::K8S_DAEMONSET_UID
62            | resource::K8S_DEPLOYMENT_NAME
63            | resource::K8S_DEPLOYMENT_UID
64            | resource::K8S_JOB_NAME
65            | resource::K8S_JOB_UID
66            | resource::K8S_NAMESPACE_NAME
67            | resource::K8S_NODE_NAME
68            | resource::K8S_NODE_UID
69            | resource::K8S_POD_NAME
70            | resource::K8S_POD_UID
71            | resource::K8S_REPLICASET_NAME
72            | resource::K8S_REPLICASET_UID
73            | resource::K8S_STATEFULSET_NAME
74            | resource::K8S_STATEFULSET_UID
75            // The current docs include these `k8s.pod.*` keys, but crate 0.31
76            // does not export constants for them yet.
77            | "k8s.pod.hostname"
78            | "k8s.pod.ip"
79            | "k8s.pod.start_time" => Some(ColumnDataType::String),
80            resource::K8S_CONTAINER_RESTART_COUNT => Some(ColumnDataType::Int64),
81
82            _ => None,
83        };
84    }
85
86    if let Some(span_attribute) = column_name.strip_prefix("span_attributes.") {
87        return match span_attribute {
88            // General client, server, and network attributes:
89            // https://github.com/open-telemetry/semantic-conventions/blob/main/docs/general/attributes.md
90            attribute::CLIENT_ADDRESS
91            | attribute::SERVER_ADDRESS
92            | attribute::NETWORK_LOCAL_ADDRESS
93            | attribute::NETWORK_PEER_ADDRESS
94            | attribute::NETWORK_PROTOCOL_NAME
95            | attribute::NETWORK_PROTOCOL_VERSION
96            | attribute::NETWORK_TRANSPORT
97            | attribute::NETWORK_TYPE => Some(ColumnDataType::String),
98            attribute::CLIENT_PORT
99            | attribute::SERVER_PORT
100            | attribute::NETWORK_LOCAL_PORT
101            | attribute::NETWORK_PEER_PORT => Some(ColumnDataType::Int64),
102
103            // HTTP attributes:
104            // https://github.com/open-telemetry/semantic-conventions/blob/main/docs/http/http-spans.md
105            // https://github.com/open-telemetry/semantic-conventions/blob/main/docs/registry/attributes/http.md
106            attribute::HTTP_REQUEST_METHOD
107            | attribute::HTTP_REQUEST_METHOD_ORIGINAL
108            | attribute::HTTP_ROUTE
109            | attribute::URL_FULL
110            | attribute::URL_PATH
111            | attribute::URL_QUERY
112            | attribute::URL_SCHEME
113            | attribute::USER_AGENT_ORIGINAL => Some(ColumnDataType::String),
114            attribute::HTTP_REQUEST_RESEND_COUNT | attribute::HTTP_RESPONSE_STATUS_CODE => {
115                Some(ColumnDataType::Int64)
116            }
117
118            // RPC attributes:
119            // https://github.com/open-telemetry/semantic-conventions/blob/main/docs/rpc/rpc-spans.md
120            // https://github.com/open-telemetry/semantic-conventions/blob/main/docs/registry/attributes/rpc.md
121            attribute::RPC_METHOD
122            | attribute::RPC_SYSTEM
123            // The current docs renamed this attribute to `rpc.system.name`,
124            // but crate 0.31 still exports `RPC_SYSTEM = "rpc.system"`.
125            | "rpc.system.name"
126            | "rpc.method_original"
127            | "rpc.response.status_code" => Some(ColumnDataType::String),
128
129            // General database attributes:
130            // https://github.com/open-telemetry/semantic-conventions/blob/main/docs/db/database-spans.md
131            // https://github.com/open-telemetry/semantic-conventions/blob/main/docs/registry/attributes/db.md
132            attribute::DB_COLLECTION_NAME
133            | attribute::DB_NAMESPACE
134            | attribute::DB_OPERATION_NAME
135            | attribute::DB_QUERY_SUMMARY
136            | attribute::DB_QUERY_TEXT
137            | attribute::DB_RESPONSE_STATUS_CODE
138            | attribute::DB_STORED_PROCEDURE_NAME
139            | attribute::DB_SYSTEM_NAME => Some(ColumnDataType::String),
140            attribute::DB_OPERATION_BATCH_SIZE => Some(ColumnDataType::Int64),
141
142            // Error attributes:
143            // https://github.com/open-telemetry/semantic-conventions/blob/main/docs/registry/attributes/error.md
144            attribute::ERROR_TYPE => Some(ColumnDataType::String),
145
146            _ => None,
147        };
148    }
149
150    None
151}
152
153#[cfg(test)]
154mod tests {
155    use api::v1::ColumnDataType;
156    use opentelemetry_semantic_conventions::{attribute, resource};
157
158    use super::trace_semconv_fixed_type;
159
160    fn resource_column(key: &str) -> String {
161        format!("resource_attributes.{key}")
162    }
163
164    fn span_column(key: &str) -> String {
165        format!("span_attributes.{key}")
166    }
167
168    #[test]
169    fn test_trace_semconv_fixed_type_includes_stable_service_key() {
170        assert_eq!(
171            trace_semconv_fixed_type(&resource_column(resource::SERVICE_NAME)),
172            Some(ColumnDataType::String)
173        );
174        assert_eq!(
175            trace_semconv_fixed_type(&resource_column(resource::SERVICE_VERSION)),
176            Some(ColumnDataType::String)
177        );
178        assert_eq!(
179            trace_semconv_fixed_type(&resource_column(resource::SERVICE_INSTANCE_ID)),
180            Some(ColumnDataType::String)
181        );
182        assert_eq!(
183            trace_semconv_fixed_type(&resource_column(resource::SERVICE_NAMESPACE)),
184            Some(ColumnDataType::String)
185        );
186    }
187
188    #[test]
189    fn test_trace_semconv_fixed_type_includes_http_server_and_error_keys() {
190        assert_eq!(
191            trace_semconv_fixed_type(&span_column(attribute::HTTP_RESPONSE_STATUS_CODE)),
192            Some(ColumnDataType::Int64)
193        );
194        assert_eq!(
195            trace_semconv_fixed_type(&span_column(attribute::SERVER_PORT)),
196            Some(ColumnDataType::Int64)
197        );
198        assert_eq!(
199            trace_semconv_fixed_type(&span_column(attribute::ERROR_TYPE)),
200            Some(ColumnDataType::String)
201        );
202        assert_eq!(
203            trace_semconv_fixed_type(&span_column(attribute::CLIENT_ADDRESS)),
204            Some(ColumnDataType::String)
205        );
206        assert_eq!(
207            trace_semconv_fixed_type(&span_column(attribute::CLIENT_PORT)),
208            Some(ColumnDataType::Int64)
209        );
210        assert_eq!(
211            trace_semconv_fixed_type(&span_column(attribute::URL_FULL)),
212            Some(ColumnDataType::String)
213        );
214        assert_eq!(
215            trace_semconv_fixed_type(&span_column(attribute::URL_PATH)),
216            Some(ColumnDataType::String)
217        );
218        assert_eq!(
219            trace_semconv_fixed_type(&span_column(attribute::URL_QUERY)),
220            Some(ColumnDataType::String)
221        );
222        assert_eq!(
223            trace_semconv_fixed_type(&span_column(attribute::URL_SCHEME)),
224            Some(ColumnDataType::String)
225        );
226        assert_eq!(
227            trace_semconv_fixed_type(&span_column(attribute::USER_AGENT_ORIGINAL)),
228            Some(ColumnDataType::String)
229        );
230    }
231
232    #[test]
233    fn test_trace_semconv_fixed_type_includes_rc_rpc_key() {
234        assert_eq!(
235            trace_semconv_fixed_type(&span_column(attribute::RPC_SYSTEM)),
236            Some(ColumnDataType::String)
237        );
238        assert_eq!(
239            trace_semconv_fixed_type("span_attributes.rpc.system.name"),
240            Some(ColumnDataType::String)
241        );
242        assert_eq!(
243            trace_semconv_fixed_type(&span_column("rpc.response.status_code")),
244            Some(ColumnDataType::String)
245        );
246    }
247
248    #[test]
249    fn test_trace_semconv_fixed_type_includes_db_and_network_keys() {
250        assert_eq!(
251            trace_semconv_fixed_type(&span_column(attribute::DB_SYSTEM_NAME)),
252            Some(ColumnDataType::String)
253        );
254        assert_eq!(
255            trace_semconv_fixed_type(&span_column(attribute::DB_OPERATION_BATCH_SIZE)),
256            Some(ColumnDataType::Int64)
257        );
258        assert_eq!(
259            trace_semconv_fixed_type(&span_column(attribute::NETWORK_PEER_PORT)),
260            Some(ColumnDataType::Int64)
261        );
262    }
263
264    #[test]
265    fn test_trace_semconv_fixed_type_includes_resource_semconv_keys() {
266        assert_eq!(
267            trace_semconv_fixed_type(&resource_column(resource::CONTAINER_ID)),
268            Some(ColumnDataType::String)
269        );
270        assert_eq!(
271            trace_semconv_fixed_type(&resource_column(resource::K8S_CONTAINER_RESTART_COUNT)),
272            Some(ColumnDataType::Int64)
273        );
274        assert_eq!(
275            trace_semconv_fixed_type(&resource_column(resource::TELEMETRY_SDK_LANGUAGE)),
276            Some(ColumnDataType::String)
277        );
278        assert_eq!(
279            trace_semconv_fixed_type(&resource_column(resource::TELEMETRY_SDK_NAME)),
280            Some(ColumnDataType::String)
281        );
282        assert_eq!(
283            trace_semconv_fixed_type(&resource_column(resource::TELEMETRY_SDK_VERSION)),
284            Some(ColumnDataType::String)
285        );
286    }
287
288    #[test]
289    fn test_trace_semconv_fixed_type_excludes_development_keys() {
290        assert_eq!(
291            trace_semconv_fixed_type(&span_column("messaging.system")),
292            None
293        );
294        assert_eq!(
295            trace_semconv_fixed_type(&span_column("rpc.request.metadata.x-request-id")),
296            None
297        );
298        assert_eq!(
299            trace_semconv_fixed_type(&resource_column("k8s.pod.label.app")),
300            None
301        );
302    }
303
304    #[test]
305    fn test_trace_semconv_fixed_type_unknown_key() {
306        assert_eq!(trace_semconv_fixed_type(&span_column("custom.attr")), None);
307    }
308}