tremor_otelapis/lib.rs
1// Copyright 2020-2021, The Tremor 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
15//! The code in the `gen` folder was seeded by [`tonic-build`].
16//!
17//! The code in the `src` folder extends the generated source with utility
18//! code to allow for convenient usage and definition of tonic-based gRPC
19//! servers. Specifically, this library is designed for use by the Tremor Project
20//! but has no dependencies on tremor and can be used standalone.
21//!
22//! This library does not provide an API or SDK designed for use as a tracing
23//! facility. The official [OpenTelemetry Rust](https://github.com/open-telemetry/opentelemetry-rust) project
24//! is a complete OpenTelemetry SDK designed for that purpose. It uses the same
25//! underlying protocol buffer definitions and will be a better target for projects that
26//! require OpenTelemetry based observability instrumentation and iteroperability with
27//! the wider observability ecosystem through third party crates.
28//!
29//! This library is designed for system integration and interoperability and is not
30//! recommended for use as a tracing SDK or for instrumentation as that is well covered
31//! already by the OpenTelemetry Rust crate. For instrumentation, use the official crate.
32//!
33//! For those projects that need basic interworking, interoperability or integration with
34//! OpenTelemetry based systems at a wire level, this project may be useful.
35//!
36//! ## Example
37//! The complete code can be found [here](https://github.com/tremor-rs/tremor-otelapis).
38//!
39//! Cargo.toml:
40//! ```toml
41//! [dependencies]
42//! tremor-otelapis = { version = "0.1", features = ["otel-all"] }
43//! tonic = { version = "0.8.2", features = ["tls"] }
44//! prost = "0.11"
45//! prost-types = "0.11"
46//! tokio = { version = "1.1", features = ["rt-multi-thread", "time", "fs", "macros"] }
47//! ```
48//!
49//! Example OpenTelemetry Log client. Note that clients simply use the generated
50//! client stub code from `tonic-build`. This library adds no extra utility or
51//! convenience.
52//!
53//! ```ignore
54//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
55//! let channel = Endpoint::from_static("http://0.0.0.0:4316")
56//! .connect()
57//! .await?;
58//!
59//! let mut client = LogsServiceClient::new(channel);
60//!
61//! let resource_logs = ResourceLogs {
62//! ...
63//! };
64//!
65//! client
66//! .export(ExportLogsServiceRequest {
67//! resource_logs: vec![resource_logs],
68//! })
69//! .await?;
70//!
71//! Ok(())
72//! }
73//! ```
74//!
75//! Example OpenTelemetry Log Server. Note that we use utility code
76//! to expose the server side functionality. We pass through the generated
77//! Protocol Buffer message data binding generated code unadorned. The
78//! data bindings for protocol buffer messages are generated by `tonic-build`.
79//! The `tonic-build` in turns builds on `prost-build`.
80//!
81//! ```ignore
82//! fn on_logs(
83//! request: tonic::Request<ExportLogsServiceRequest>,
84//! ) -> Result<tonic::Response<ExportLogsServiceResponse>, tonic::Status> {
85//! println!("Got a request from {:?}", request.remote_addr());
86//! let reply = ExportLogsServiceResponse::default();
87//! Ok(tonic::Response::new(reply))
88//! }
89//!
90//! #[tokio::main]
91//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
92//! let addr = "0.0.0.0:4317".parse()?;
93//! let svc = otelapis::logs::make_service(Box::new(on_logs));
94//! Server::builder().add_service(svc).serve(addr).await?;
95//!
96//! Ok(())
97//! }
98//! ```
99//!
100//! [`otelapis`]: https://github.com/open-telemetry/opentelemetry-specification
101//! [`tonic-build`]: https://github.com/hyperium/tonic/tree/master/tonic-build
102//!
103
104#![deny(warnings)] // this cannot be `forbid`, because the generated code uses `allow`
105#![deny(
106 clippy::all,
107 clippy::unwrap_used,
108 clippy::unnecessary_unwrap,
109 missing_docs
110 // clippy::pedantic - this makes the generated code unhappy
111)]
112
113extern crate prost;
114
115mod otelapis;
116
117/// Common facilities and conveniences
118pub mod common;
119
120pub use otelapis::opentelemetry;
121
122#[cfg(feature = "otel-trace")]
123/// This module defines a skeleton implementation of the open telemetry
124/// collector tracing service
125///
126pub mod trace;
127
128/// This module defines a skeleton implementation of the open telemetry
129/// collector logging service
130///
131#[cfg(feature = "otel-logs")]
132pub mod logs;
133
134/// This module defines a skeleton implementation of the open telemetry
135/// collector metrics service
136///
137#[cfg(feature = "otel-metrics")]
138pub mod metrics;
139
140/// A unified set of services that provide log, metrics and trace events
141#[cfg(feature = "otel-all")]
142pub mod all;
143
144#[cfg(test)]
145mod test {
146 use crate::opentelemetry::proto::collector::{
147 logs::v1::{ExportLogsPartialSuccess, ExportLogsServiceResponse},
148 metrics::v1::{ExportMetricsPartialSuccess, ExportMetricsServiceResponse},
149 trace::v1::{ExportTracePartialSuccess, ExportTraceServiceResponse},
150 };
151
152 use super::common::FallibleOtelResponse;
153
154 #[test]
155 pub fn make_fallible_error() {
156 let mut e = FallibleOtelResponse::new(0, 0, 0, "snot".to_string());
157 assert_eq!(e.error_message, "snot".to_string());
158 assert_eq!(e.rejected_logs, 0);
159 assert_eq!(e.rejected_metrics, 0);
160 assert_eq!(e.rejected_spans, 0);
161 assert!(e.is_ok());
162 e.rejected_logs = 1;
163 assert!(!e.is_ok());
164 e.rejected_logs = -1;
165 assert!(!e.is_ok());
166 e.rejected_logs = 0;
167 e.rejected_metrics = 1;
168 assert!(!e.is_ok());
169 e.rejected_metrics = -1;
170 assert!(!e.is_ok());
171 e.rejected_metrics = 0;
172 e.rejected_spans = 1;
173 assert!(!e.is_ok());
174 e.rejected_spans = -1;
175 assert!(!e.is_ok());
176 }
177
178 #[test]
179 pub fn fallible_from_log_response() {
180 let log = ExportLogsServiceResponse {
181 partial_success: Some(ExportLogsPartialSuccess {
182 rejected_log_records: 1,
183 error_message: "beep".to_string(),
184 }),
185 };
186 let e = FallibleOtelResponse::from(log);
187 assert_eq!(e.error_message, "beep".to_string());
188 assert_eq!(e.rejected_logs, 1);
189 assert_eq!(e.rejected_metrics, 0);
190 assert_eq!(e.rejected_spans, 0);
191 }
192
193 #[test]
194 pub fn fallible_from_metric_response() {
195 let metric = ExportMetricsServiceResponse {
196 partial_success: Some(ExportMetricsPartialSuccess {
197 rejected_data_points: 1,
198 error_message: "boop".to_string(),
199 }),
200 };
201 let e = FallibleOtelResponse::from(metric);
202 assert_eq!(e.error_message, "boop".to_string());
203 assert_eq!(e.rejected_logs, 0);
204 assert_eq!(e.rejected_metrics, 1);
205 assert_eq!(e.rejected_spans, 0);
206 }
207
208 #[test]
209 pub fn fallible_from_trace_response() {
210 let metric = ExportTraceServiceResponse {
211 partial_success: Some(ExportTracePartialSuccess {
212 rejected_spans: 1,
213 error_message: "fleek".to_string(),
214 }),
215 };
216 let e = FallibleOtelResponse::from(metric);
217 assert_eq!(e.error_message, "fleek".to_string());
218 assert_eq!(e.rejected_logs, 0);
219 assert_eq!(e.rejected_metrics, 0);
220 assert_eq!(e.rejected_spans, 1);
221 }
222}