-
Notifications
You must be signed in to change notification settings - Fork 347
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
feat: Implement RFC for layering of runtime #845
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
18edb12
feat: Implement RFC for layering of runtime
borchero b3f4ddb
Add example
borchero ae9b576
Fix compilation errors
borchero b8efe93
Remove Send and 'static
borchero dff0ed2
Fix ci
borchero df39f6b
Reduce diff
borchero 2c3b144
Implement review comments
borchero File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
[package] | ||
name = "opentelemetry-tracing" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] | ||
# Library dependencies | ||
lambda_runtime = { path = "../../lambda-runtime" } | ||
pin-project = "1" | ||
opentelemetry-semantic-conventions = "0.14" | ||
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"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
use std::future::Future; | ||
use std::pin::Pin; | ||
use std::task; | ||
|
||
use lambda_runtime::LambdaInvocation; | ||
use opentelemetry_semantic_conventions::trace as traceconv; | ||
use pin_project::pin_project; | ||
use tower::{Layer, Service}; | ||
use tracing::instrument::Instrumented; | ||
use tracing::Instrument; | ||
|
||
/// Tower layer to add OpenTelemetry tracing to a Lambda function invocation. The layer accepts | ||
/// a function to flush OpenTelemetry after the end of the invocation. | ||
pub struct OpenTelemetryLayer<F> { | ||
flush_fn: F, | ||
} | ||
|
||
impl<F> OpenTelemetryLayer<F> | ||
where | ||
F: Fn() + Clone, | ||
{ | ||
pub fn new(flush_fn: F) -> Self { | ||
Self { flush_fn } | ||
} | ||
} | ||
|
||
impl<S, F> Layer<S> for OpenTelemetryLayer<F> | ||
where | ||
F: Fn() + Clone, | ||
{ | ||
type Service = OpenTelemetryService<S, F>; | ||
|
||
fn layer(&self, inner: S) -> Self::Service { | ||
OpenTelemetryService { | ||
inner, | ||
flush_fn: self.flush_fn.clone(), | ||
coldstart: true, | ||
} | ||
} | ||
} | ||
|
||
/// Tower service created by [OpenTelemetryLayer]. | ||
pub struct OpenTelemetryService<S, F> { | ||
inner: S, | ||
flush_fn: F, | ||
coldstart: bool, | ||
} | ||
|
||
impl<S, F> Service<LambdaInvocation> for OpenTelemetryService<S, F> | ||
where | ||
S: Service<LambdaInvocation, Response = ()>, | ||
F: Fn() + Clone, | ||
{ | ||
type Error = S::Error; | ||
type Response = (); | ||
type Future = OpenTelemetryFuture<Instrumented<S::Future>, F>; | ||
|
||
fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> task::Poll<Result<(), Self::Error>> { | ||
self.inner.poll_ready(cx) | ||
} | ||
|
||
fn call(&mut self, req: LambdaInvocation) -> Self::Future { | ||
let span = tracing::info_span!( | ||
"Lambda function invocation", | ||
"otel.name" = req.context.env_config.function_name, | ||
{ traceconv::FAAS_TRIGGER } = "http", | ||
{ traceconv::FAAS_INVOCATION_ID } = req.context.request_id, | ||
{ traceconv::FAAS_COLDSTART } = self.coldstart | ||
); | ||
|
||
// After the first execution, we can set 'coldstart' to false | ||
self.coldstart = false; | ||
|
||
let fut = self.inner.call(req).instrument(span); | ||
OpenTelemetryFuture { | ||
future: Some(fut), | ||
flush_fn: self.flush_fn.clone(), | ||
} | ||
} | ||
} | ||
|
||
/// Future created by [OpenTelemetryService]. | ||
#[pin_project] | ||
pub struct OpenTelemetryFuture<Fut, F> { | ||
#[pin] | ||
future: Option<Fut>, | ||
flush_fn: F, | ||
} | ||
|
||
impl<Fut, F> Future for OpenTelemetryFuture<Fut, F> | ||
where | ||
Fut: Future, | ||
F: Fn(), | ||
{ | ||
type Output = Fut::Output; | ||
|
||
fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> { | ||
// First, try to get the ready value of the future | ||
let ready = task::ready!(self | ||
.as_mut() | ||
.project() | ||
.future | ||
.as_pin_mut() | ||
.expect("future polled after completion") | ||
.poll(cx)); | ||
|
||
// If we got the ready value, we first drop the future: this ensures that the | ||
// OpenTelemetry span attached to it is closed and included in the subsequent flush. | ||
Pin::set(&mut self.as_mut().project().future, None); | ||
(self.project().flush_fn)(); | ||
task::Poll::Ready(ready) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
use lambda_runtime::{LambdaEvent, Runtime}; | ||
use opentelemetry::trace::TracerProvider; | ||
use opentelemetry_sdk::{runtime, trace}; | ||
use opentelemetry_tracing::OpenTelemetryLayer; | ||
use tower::{service_fn, BoxError}; | ||
use tracing_subscriber::prelude::*; | ||
|
||
async fn echo(event: LambdaEvent<serde_json::Value>) -> Result<serde_json::Value, &'static str> { | ||
Ok(event.payload) | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() -> Result<(), BoxError> { | ||
// Set up OpenTelemetry tracer provider that writes spans to stdout for debugging purposes | ||
let exporter = opentelemetry_stdout::SpanExporter::default(); | ||
let tracer_provider = trace::TracerProvider::builder() | ||
.with_batch_exporter(exporter, runtime::Tokio) | ||
.build(); | ||
|
||
// Set up link between OpenTelemetry and tracing crate | ||
tracing_subscriber::registry() | ||
.with(tracing_opentelemetry::OpenTelemetryLayer::new( | ||
tracer_provider.tracer("my-app"), | ||
)) | ||
.init(); | ||
|
||
// Initialize the Lambda runtime and add OpenTelemetry tracing | ||
let runtime = Runtime::new(service_fn(echo)).layer(OpenTelemetryLayer::new(|| { | ||
// Make sure that the trace is exported before the Lambda runtime is frozen | ||
tracer_provider.force_flush(); | ||
})); | ||
runtime.run().await?; | ||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a
src/main.rs
file with a lambda function that shows how to use this library?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a dummy implementation that logs traces to stdout. Unfortunately, OpenTelemetry setup in Rust isn't very trivial, hence, there are a bunch more dependencies in the
Cargo.toml
of the example. I attempted to clearly indicate which dependencies are required by the library portion of the example.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks!