-
Notifications
You must be signed in to change notification settings - Fork 361
feat(lambda-extension): Logs API processor #416
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
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
84dced9
Organize crate into modules.
calavera dd9f1d0
Initial logs processor implementation
calavera b67432d
Fix value returned by the register function.
calavera dfcbb9a
Add logs subcription call
calavera 2dd14c7
Clean logs file.
calavera 677099b
feat(lambda-extension): log processor server (DOES NOT WORK)
nmoutschen 6b6e71f
feat(lambda-extension): use MakeService for log processor (DOES NOT W…
nmoutschen 4d2ff7a
feat(lambda-extension): restrict trait bounds for Identity/MakeIdentity
nmoutschen 037432d
feat(lambda-extension): deserialize Vec<LambdaLog>
nmoutschen 2ee1bf5
test: add integration tests for Logs API handler
nmoutschen 4fb308c
chore: cargo fmt
nmoutschen eafc1eb
feat(lambda-extension): add tracing and customizable port number for …
nmoutschen f8e5180
feat(lambda-extension): implement LambdaLogRecord enum
nmoutschen 5222868
fix(lambda-extension): fix bounds for with_logs_processor()
nmoutschen a2efc30
feat(lambda-extension): use chrono::DateTime for LambdaLog time
nmoutschen b2be9bc
feat(lambda-extension): add combined example
nmoutschen 4728bd5
docs(lambda-extension): add example for logs processor
nmoutschen 02a3f6f
Merge branch 'master' into logs_api_connection
nmoutschen 8731f6f
feat(lambda-integration-tests): update log processor
nmoutschen 142996a
Merge branch 'logs_api_connection' of github.com:awslabs/aws-lambda-r…
nmoutschen 44bf723
fix(lambda-integration-tests): add tracing config to logs-trait
nmoutschen ece3576
chore: cargo fmt
nmoutschen 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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,51 @@ | ||
use lambda_extension::{ | ||
service_fn, Error, Extension, LambdaEvent, LambdaLog, LambdaLogRecord, NextEvent, SharedService, | ||
}; | ||
use tracing::info; | ||
|
||
async fn my_extension(event: LambdaEvent) -> Result<(), Error> { | ||
match event.next { | ||
NextEvent::Shutdown(_e) => { | ||
// do something with the shutdown event | ||
} | ||
NextEvent::Invoke(_e) => { | ||
// do something with the invoke event | ||
} | ||
} | ||
Ok(()) | ||
} | ||
|
||
async fn my_log_processor(logs: Vec<LambdaLog>) -> Result<(), Error> { | ||
for log in logs { | ||
match log.record { | ||
LambdaLogRecord::Function(record) => info!("[logs] [function] {}", record), | ||
LambdaLogRecord::Extension(record) => info!("[logs] [extension] {}", record), | ||
_ => (), | ||
} | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() -> Result<(), Error> { | ||
// The runtime logging can be enabled here by initializing `tracing` with `tracing-subscriber` | ||
// While `tracing` is used internally, `log` can be used as well if preferred. | ||
tracing_subscriber::fmt() | ||
.with_max_level(tracing::Level::INFO) | ||
// this needs to be set to false, otherwise ANSI color codes will | ||
// show up in a confusing manner in CloudWatch logs. | ||
.with_ansi(false) | ||
// disabling time is handy because CloudWatch will add the ingestion time. | ||
.without_time() | ||
.init(); | ||
|
||
let func = service_fn(my_extension); | ||
let logs_processor = SharedService::new(service_fn(my_log_processor)); | ||
|
||
Extension::new() | ||
.with_events_processor(func) | ||
.with_logs_processor(logs_processor) | ||
.run() | ||
.await | ||
} |
This file contains hidden or 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 hidden or 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,64 @@ | ||
use lambda_extension::{Error, Extension, LambdaLog, LambdaLogRecord, Service, SharedService}; | ||
use std::{ | ||
future::{ready, Future}, | ||
pin::Pin, | ||
sync::{ | ||
atomic::{AtomicUsize, Ordering::SeqCst}, | ||
Arc, | ||
}, | ||
task::Poll, | ||
}; | ||
use tracing::info; | ||
|
||
/// Custom log processor that increments a counter for each log record. | ||
/// | ||
/// This is a simple example of a custom log processor that can be used to | ||
/// count the number of log records that are processed. | ||
/// | ||
/// This needs to derive Clone (and store the counter in an Arc) as the runtime | ||
/// could need multiple `Service`s to process the logs. | ||
#[derive(Clone, Default)] | ||
struct MyLogsProcessor { | ||
counter: Arc<AtomicUsize>, | ||
} | ||
|
||
impl MyLogsProcessor { | ||
pub fn new() -> Self { | ||
Self::default() | ||
} | ||
} | ||
|
||
/// Implementation of the actual log processor | ||
/// | ||
/// This receives a `Vec<LambdaLog>` whenever there are new log entries available. | ||
impl Service<Vec<LambdaLog>> for MyLogsProcessor { | ||
type Response = (); | ||
type Error = Error; | ||
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>; | ||
|
||
fn poll_ready(&mut self, _cx: &mut core::task::Context<'_>) -> core::task::Poll<Result<(), Self::Error>> { | ||
Poll::Ready(Ok(())) | ||
} | ||
|
||
fn call(&mut self, logs: Vec<LambdaLog>) -> Self::Future { | ||
let counter = self.counter.fetch_add(1, SeqCst); | ||
for log in logs { | ||
match log.record { | ||
LambdaLogRecord::Function(record) => info!("[logs] [function] {}: {}", counter, record), | ||
LambdaLogRecord::Extension(record) => info!("[logs] [extension] {}: {}", counter, record), | ||
_ => (), | ||
} | ||
} | ||
|
||
Box::pin(ready(Ok(()))) | ||
} | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() -> Result<(), Error> { | ||
let logs_processor = SharedService::new(MyLogsProcessor::new()); | ||
|
||
Extension::new().with_logs_processor(logs_processor).run().await?; | ||
|
||
Ok(()) | ||
} |
File renamed without changes.
This file contains hidden or 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,23 @@ | ||
use lambda_extension::{service_fn, Error, Extension, LambdaLog, LambdaLogRecord, SharedService}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this example is so good! 🙀 |
||
use tracing::info; | ||
|
||
async fn handler(logs: Vec<LambdaLog>) -> Result<(), Error> { | ||
for log in logs { | ||
match log.record { | ||
LambdaLogRecord::Function(record) => info!("[logs] [function] {}", record), | ||
LambdaLogRecord::Extension(record) => info!("[logs] [extension] {}", record), | ||
_ => (), | ||
} | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() -> Result<(), Error> { | ||
let logs_processor = SharedService::new(service_fn(handler)); | ||
|
||
Extension::new().with_logs_processor(logs_processor).run().await?; | ||
|
||
Ok(()) | ||
} |
This file contains hidden or 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,23 @@ | ||
/// Error type that extensions may result in | ||
pub type Error = lambda_runtime_api_client::Error; | ||
|
||
/// Simple error that encapsulates human readable descriptions | ||
#[derive(Clone, Debug, PartialEq, Eq)] | ||
pub struct ExtensionError { | ||
err: String, | ||
} | ||
|
||
impl ExtensionError { | ||
pub(crate) fn boxed<T: Into<String>>(str: T) -> Box<ExtensionError> { | ||
Box::new(ExtensionError { err: str.into() }) | ||
} | ||
} | ||
|
||
impl std::fmt::Display for ExtensionError { | ||
#[inline] | ||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
self.err.fmt(f) | ||
} | ||
} | ||
|
||
impl std::error::Error for ExtensionError {} |
This file contains hidden or 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,71 @@ | ||
use serde::Deserialize; | ||
|
||
/// Request tracing information | ||
#[derive(Debug, Deserialize)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct Tracing { | ||
/// The type of tracing exposed to the extension | ||
pub r#type: String, | ||
/// The span value | ||
pub value: String, | ||
} | ||
/// Event received when there is a new Lambda invocation. | ||
#[derive(Debug, Deserialize)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct InvokeEvent { | ||
/// The time that the function times out | ||
pub deadline_ms: u64, | ||
/// The ID assigned to the Lambda request | ||
pub request_id: String, | ||
/// The function's Amazon Resource Name | ||
pub invoked_function_arn: String, | ||
/// The request tracing information | ||
pub tracing: Tracing, | ||
} | ||
|
||
/// Event received when a Lambda function shuts down. | ||
#[derive(Debug, Deserialize)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct ShutdownEvent { | ||
/// The reason why the function terminates | ||
/// It can be SPINDOWN, TIMEOUT, or FAILURE | ||
pub shutdown_reason: String, | ||
/// The time that the function times out | ||
pub deadline_ms: u64, | ||
} | ||
|
||
/// Event that the extension receives in | ||
/// either the INVOKE or SHUTDOWN phase | ||
#[derive(Debug, Deserialize)] | ||
#[serde(rename_all = "UPPERCASE", tag = "eventType")] | ||
pub enum NextEvent { | ||
/// Payload when the event happens in the INVOKE phase | ||
Invoke(InvokeEvent), | ||
/// Payload when the event happens in the SHUTDOWN phase | ||
Shutdown(ShutdownEvent), | ||
} | ||
|
||
impl NextEvent { | ||
/// Return whether the event is a [`NextEvent::Invoke`] event or not | ||
pub fn is_invoke(&self) -> bool { | ||
matches!(self, NextEvent::Invoke(_)) | ||
} | ||
} | ||
|
||
/// 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, | ||
} | ||
|
||
impl LambdaEvent { | ||
pub(crate) fn new(ex_id: &str, next: NextEvent) -> LambdaEvent { | ||
LambdaEvent { | ||
extension_id: ex_id.into(), | ||
next, | ||
} | ||
} | ||
} |
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.
another great example! 😻