Skip to content

Add OpenTelemetry layer as optional #898

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 9 additions & 27 deletions examples/opentelemetry-tracing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,15 @@ version = "0.1.0"
edition = "2021"

[dependencies]
# Library dependencies
lambda_runtime = { path = "../../lambda-runtime" }
pin-project = "1"
lambda_runtime = { path = "../../lambda-runtime", features = ["opentelemetry"] }
opentelemetry-semantic-conventions = "0.14"
opentelemetry = "0.22"
opentelemetry_sdk = { version = "0.22", features = ["rt-tokio"] }
opentelemetry-stdout = { version = "0.3", features = ["trace"] }
pin-project = "1"
serde_json = "1.0"
tokio = "1"
tower = "0.4"
tracing = "0.1"

# Binary dependencies
opentelemetry = { version = "0.22", optional = true }
opentelemetry_sdk = { version = "0.22", features = ["rt-tokio"], optional = true }
opentelemetry-stdout = { version = "0.3", features = ["trace"], optional = true }
serde_json = { version = "1.0", optional = true }
tokio = { version = "1", optional = true }
tracing-opentelemetry = { version = "0.23", optional = true }
tracing-subscriber = { version = "0.3", optional = true }

[features]
build-binary = [
"opentelemetry",
"opentelemetry_sdk",
"opentelemetry-stdout",
"serde_json",
"tokio",
"tracing-opentelemetry",
"tracing-subscriber",
]

[[bin]]
name = "opentelemetry-tracing"
required-features = ["build-binary"]
tracing-opentelemetry = "0.23"
tracing-subscriber = "0.3"
5 changes: 2 additions & 3 deletions examples/opentelemetry-tracing/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use lambda_runtime::{LambdaEvent, Runtime};
use lambda_runtime::{layers::OpenTelemetryLayer as OtelLayer, LambdaEvent, Runtime};
use opentelemetry::trace::TracerProvider;
use opentelemetry_sdk::{runtime, trace};
use opentelemetry_tracing::OpenTelemetryLayer;
use tower::{service_fn, BoxError};
use tracing_subscriber::prelude::*;

Expand All @@ -25,7 +24,7 @@ async fn main() -> Result<(), BoxError> {
.init();

// Initialize the Lambda runtime and add OpenTelemetry tracing
let runtime = Runtime::new(service_fn(echo)).layer(OpenTelemetryLayer::new(|| {
let runtime = Runtime::new(service_fn(echo)).layer(OtelLayer::new(|| {
// Make sure that the trace is exported before the Lambda runtime is frozen
tracer_provider.force_flush();
}));
Expand Down
2 changes: 2 additions & 0 deletions lambda-runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ readme = "../README.md"
[features]
default = ["tracing"]
tracing = ["lambda_runtime_api_client/tracing"]
opentelemetry = ["opentelemetry-semantic-conventions"]

[dependencies]
async-stream = "0.3"
Expand All @@ -34,6 +35,7 @@ hyper-util = { workspace = true, features = [
"tokio",
] }
lambda_runtime_api_client = { version = "0.11.1", path = "../lambda-runtime-api-client", default-features = false }
opentelemetry-semantic-conventions = { version = "0.14", optional = true }
pin-project = "1"
serde = { version = "1", features = ["derive", "rc"] }
serde_json = "^1"
Expand Down
5 changes: 5 additions & 0 deletions lambda-runtime/src/layers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,8 @@ pub(crate) use api_client::RuntimeApiClientService;
pub(crate) use api_response::RuntimeApiResponseService;
pub(crate) use panic::CatchPanicService;
pub use trace::TracingLayer;

#[cfg(feature = "opentelemetry")]
mod otel;
#[cfg(feature = "opentelemetry")]
pub use otel::OpenTelemetryLayer;
Copy link
Contributor

@Oliboy50 Oliboy50 Jun 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line 67:

{ traceconv::FAAS_TRIGGER } = "http",

I think it should be configurable because the lambda_runtime crate can be used without using HTTP triggers (it could defaults to http when using the lambda_http crate though)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that sounds like a good idea. Feel free to open a PR with improvements

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 ➡️ #903

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::future::Future;
use std::pin::Pin;
use std::task;

use lambda_runtime::LambdaInvocation;
use crate::LambdaInvocation;
use opentelemetry_semantic_conventions::trace as traceconv;
use pin_project::pin_project;
use tower::{Layer, Service};
Expand All @@ -19,6 +19,7 @@ impl<F> OpenTelemetryLayer<F>
where
F: Fn() + Clone,
{
/// Create a new [OpenTelemetryLayer] with the provided flush function.
pub fn new(flush_fn: F) -> Self {
Self { flush_fn }
}
Expand Down Expand Up @@ -71,9 +72,14 @@ where
// After the first execution, we can set 'coldstart' to false
self.coldstart = false;

let fut = self.inner.call(req).instrument(span);
let future = {
// Enter the span before calling the inner service
// to ensure that it's assigned as parent of the inner spans.
let _guard = span.enter();
Comment on lines +76 to +78
Copy link
Contributor

@Oliboy50 Oliboy50 Jun 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't know that using .instrument(span) was not enough when calling a future (or maybe it's only useful in a "inner service" context?), where did you find docs about that?

And since the span is entered before starting to poll the future, it will increase the span duration, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See this PR: #896

self.inner.call(req)
};
OpenTelemetryFuture {
future: Some(fut),
future: Some(future.instrument(span)),
flush_fn: self.flush_fn.clone(),
}
}
Expand Down
2 changes: 2 additions & 0 deletions lambda-runtime/src/layers/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ where
fn call(&mut self, req: LambdaInvocation) -> Self::Future {
let span = request_span(&req.context);
let future = {
// Enter the span before calling the inner service
// to ensure that it's assigned as parent of the inner spans.
let _guard = span.enter();
self.inner.call(req)
};
Expand Down
Loading