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}