Repository: awslabs/aws-lambda-rust-runtime (language: rust)

Issue:
Lambda Logs API?
I've successfully used this project's [lambda-extension](https://github.com/awslabs/aws-lambda-rust-runtime/tree/master/lambda-extension) library to respond to Invoke and Shutdown events (as the examples demonstrate), but I'm struggling to figure out the best path to use the [Lambda Logs API](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-logs-api.html#runtimes-logs-api-msg-function).

My understanding of the `lambda-extension` library code (as a Rust novice) is that the `extension_id` is private.  In order to use the Lambda Logs API you must subscribe with the extension ID, which you get from registering the extension with the Extensions API.  But there's no way that I can see to get the `extension_id` after registering the extension.

So my question is: If I've used the `lambda-extension` library as the base for my extension, how can I use the Lambda Logs API if the extension ID is unavailable externally?  I could imagine a new `lambda-logs` library or additional functions in the `lambda-extension` library, but neither of those options exist currently.  What can I do in the meantime without essentially reimplementing the `lambda-extension` library myself?


Discussion / hints:
oh no! 🤦 that's unfortunate because when I started working on the extensions api, I exposed the ID, but we removed it because we didn't remember that the logs API uses it. See [this commit](https://github.com/awslabs/aws-lambda-rust-runtime/pull/376/commits/af95f363070646c914d7a1c38620c2e591062ca4).

I think it'd be worth considering a way to add it back, even if it's not backwards compatible.

PS: I'm glad that crate was useful for you 🎊 
Thanks for the quick response.  Regarding exposing the ID, I'm wondering if it would be sufficient to simply make the [`extension_id` field](https://github.com/awslabs/aws-lambda-rust-runtime/blob/master/lambda-extension/src/lib.rs#L133) public?  I like the idea of the library managing the extension registration for me so I can just read the ID afterwards.  I'm not well versed in Rust design patterns though, so I'm not sure if that would be an acceptable solution.
In term of backward compatibility, I think we can still add it back since we didn't publish a new crate version yet. As long as something is on the master branch but not yet publishes on crates.io, we should be flexible. Basically, I see the master branch as an unstable version. 😄

I think as a short term, we could expose the extension ID (maybe it could be useful for other things in the future - e.g. even just for logging purposes), but I'm unsure what the best way to expose it would be.

That said, long term, we should definitively have a high-level library to interact with the Logs API. For the latter, happy to draft an RFC once I'm back from the winter break.

Fix patch:
diff --git a/lambda-extension/examples/basic.rs b/lambda-extension/examples/basic.rs
index 6ed92652..aedc046b 100644
--- a/lambda-extension/examples/basic.rs
+++ b/lambda-extension/examples/basic.rs
@@ -1,7 +1,7 @@
-use lambda_extension::{extension_fn, Error, NextEvent};
+use lambda_extension::{extension_fn, Error, LambdaEvent, NextEvent};
 
-async fn my_extension(event: NextEvent) -> Result<(), Error> {
-    match event {
+async fn my_extension(event: LambdaEvent) -> Result<(), Error> {
+    match event.next {
         NextEvent::Shutdown(_e) => {
             // do something with the shutdown event
         }
diff --git a/lambda-extension/examples/custom_events.rs b/lambda-extension/examples/custom_events.rs
index cd3dae46..560fa295 100644
--- a/lambda-extension/examples/custom_events.rs
+++ b/lambda-extension/examples/custom_events.rs
@@ -1,7 +1,7 @@
-use lambda_extension::{extension_fn, Error, NextEvent, Runtime};
+use lambda_extension::{extension_fn, Error, LambdaEvent, NextEvent, Runtime};
 
-async fn my_extension(event: NextEvent) -> Result<(), Error> {
-    match event {
+async fn my_extension(event: LambdaEvent) -> Result<(), Error> {
+    match event.next {
         NextEvent::Shutdown(_e) => {
             // do something with the shutdown event
         }
diff --git a/lambda-extension/examples/custom_trait_implementation.rs b/lambda-extension/examples/custom_trait_implementation.rs
index 910a7e07..7f056957 100644
--- a/lambda-extension/examples/custom_trait_implementation.rs
+++ b/lambda-extension/examples/custom_trait_implementation.rs
@@ -1,4 +1,4 @@
-use lambda_extension::{run, Error, Extension, InvokeEvent, NextEvent};
+use lambda_extension::{run, Error, Extension, InvokeEvent, LambdaEvent, NextEvent};
 use std::{
     future::{ready, Future},
     pin::Pin,
@@ -11,8 +11,8 @@ struct MyExtension {
 
 impl Extension for MyExtension {
     type Fut = Pin<Box<dyn Future<Output = Result<(), Error>>>>;
-    fn call(&mut self, event: NextEvent) -> Self::Fut {
-        match event {
+    fn call(&mut self, event: LambdaEvent) -> Self::Fut {
+        match event.next {
             NextEvent::Shutdown(_e) => {
                 self.data.clear();
             }
diff --git a/lambda-extension/src/lib.rs b/lambda-extension/src/lib.rs
index f1d34a18..c38947e5 100644
--- a/lambda-extension/src/lib.rs
+++ b/lambda-extension/src/lib.rs
@@ -94,12 +94,21 @@ impl NextEvent {
     }
 }
 
+/// Wrapper with information about the next
+/// event that the Lambda Runtime is going to process
+pub struct LambdaEvent {
+    /// ID assigned to this extension by the Lambda Runtime
+    pub extension_id: String,
+    /// Next incoming event
+    pub next: NextEvent,
+}
+
 /// A trait describing an asynchronous extension.
 pub trait Extension {
     /// Response of this Extension.
     type Fut: Future<Output = Result<(), Error>>;
     /// Handle the incoming event.
-    fn call(&mut self, event: NextEvent) -> Self::Fut;
+    fn call(&mut self, event: LambdaEvent) -> Self::Fut;
 }
 
 /// Returns a new [`ExtensionFn`] with the given closure.
@@ -119,11 +128,11 @@ pub struct ExtensionFn<F> {
 
 impl<F, Fut> Extension for ExtensionFn<F>
 where
-    F: Fn(NextEvent) -> Fut,
+    F: Fn(LambdaEvent) -> Fut,
     Fut: Future<Output = Result<(), Error>>,
 {
     type Fut = Fut;
-    fn call(&mut self, event: NextEvent) -> Self::Fut {
+    fn call(&mut self, event: LambdaEvent) -> Self::Fut {
         (self.f)(event)
     }
 }
@@ -173,6 +182,11 @@ where
             let event: NextEvent = serde_json::from_slice(&body)?;
             let is_invoke = event.is_invoke();
 
+            let event = LambdaEvent {
+                extension_id: self.extension_id.clone(),
+                next: event,
+            };
+
             let res = extension.call(event).await;
             if let Err(error) = res {
                 let req = if is_invoke {


Test patch:
diff --git a/lambda-integration-tests/src/bin/extension-fn.rs b/lambda-integration-tests/src/bin/extension-fn.rs
index fabdb4cd..5835b0f7 100644
--- a/lambda-integration-tests/src/bin/extension-fn.rs
+++ b/lambda-integration-tests/src/bin/extension-fn.rs
@@ -1,8 +1,8 @@
-use lambda_extension::{extension_fn, Error, NextEvent};
+use lambda_extension::{extension_fn, Error, LambdaEvent, NextEvent};
 use tracing::info;
 
-async fn my_extension(event: NextEvent) -> Result<(), Error> {
-    match event {
+async fn my_extension(event: LambdaEvent) -> Result<(), Error> {
+    match event.next {
         NextEvent::Shutdown(e) => {
             info!("[extension-fn] Shutdown event received: {:?}", e);
         }
diff --git a/lambda-integration-tests/src/bin/extension-trait.rs b/lambda-integration-tests/src/bin/extension-trait.rs
index 62ab2dc7..bc4b3b32 100644
--- a/lambda-integration-tests/src/bin/extension-trait.rs
+++ b/lambda-integration-tests/src/bin/extension-trait.rs
@@ -1,4 +1,4 @@
-use lambda_extension::{Error, Extension, NextEvent};
+use lambda_extension::{Error, Extension, LambdaEvent, NextEvent};
 use std::{
     future::{ready, Future},
     pin::Pin,
@@ -13,8 +13,8 @@ struct MyExtension {
 impl Extension for MyExtension {
     type Fut = Pin<Box<dyn Future<Output = Result<(), Error>>>>;
 
-    fn call(&mut self, event: NextEvent) -> Self::Fut {
-        match event {
+    fn call(&mut self, event: LambdaEvent) -> Self::Fut {
+        match event.next {
             NextEvent::Shutdown(e) => {
                 info!("[extension] Shutdown event received: {:?}", e);
             }