-
Notifications
You must be signed in to change notification settings - Fork 361
[RFC] Lambda Logs API Integration #396
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
Comments
is there a way to have a builder pattern and still provide the HTTP server? I'm thinking about something like this, but I have not tested if this could be possible: async fn event_processor(event: LambdaEvent) -> Result<(), Error> {
Ok(())
}
async fn log_processor(log_events: &[LogEvent]) -> Result<(), Error> {
// Process a batch of log entries here
todo!();
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Error> {
let extension = lambda_extension::builder()
.with_event_processor(event_processor)
.with_logs_processor(log_processor)
.build()?;
lambda_extension::run(extension).await
} |
@calavera This is very similar to what I had in mind. I'd be in favor of this. Personally, I don't see a need to support bringing your own HTTP/TCP server, at least initially. It seems like boilerplate the majority of users won't want to bother with, similar to the extension registration which is hidden from the user entirely. Also the docs recommend using HTTP instead of TCP, so I think we would be justified in having HTTP implemented by default. |
@calavera I like the idea of using a builder pattern. I'd just make a small change so we can support a trait pattern (for future implementation of use lambda_extension::{service_fn, LambdaEvent, LogEvent};
async fn event_processor(event: LambdaEvent) -> Result<(), Error> {
Ok(())
}
async fn log_processor(log_events: &[LogEvent]) -> Result<(), Error> {
// Process a batch of log entries here
todo!();
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Error> {
let extension = lambda_extension::builder()
.with_event_processor(service_fn(event_processor))
.with_logs_processor(service_fn(log_processor))
.build()?;
lambda_extension::run(extension).await
} This way we could also do this in the long term: use lambda_extension::LogEvent;
use tower::Service;
#[derive(Default)]
struct MyLogProcessor;
impl Service<&[LogEvent]> for MyLogProcessor {
// implementation skipped
}
#[tokio::main]
async fn main() -> Result<(), Error> {
let extension = lambda_extension::builder()
// We could also skip the event processor - this could use a default one instead
.with_logs_processor(MyLogProcessor::default())
.build()?;
lambda_extension::run(extension).await
} |
that makes sense to me 👍 |
Small change to my previous comment: I've replaced |
yup, if you look at the examples in #407, I'm already using |
The purpose of this issue is to define and agree on an library implementation for the Lambda Logs API.
Before going into proposed user experiences, there are a few characteristics of the Logs API that are important to consider:
Challenges with current implementation
Right now, all libraries (
lambda_runtime
andlambda_extension
) abstract the registration process under the hood. That means developers don't have control between the registration process and the first invocation. However, to work correctly with the Lambda Logs API, a developer needs to first register the extension, then send a call to subscribe for logs.That means that to implement this feature, we either need to give more flexibility, or create a new abstraction just for the logs API. With the former, this would make it harder to move all handler traits to
tower::Service
(see #374) unless we implement a factory pattern. With the latter, we would remove the possibility of having an extension serving multiple purposes.Proposition 1: High-level library
The user experience would resemble the ones from other crates in this project. It would also take care of running a TCP server, and send log entries to a function or trait implementation provided.
Pros:
tower::Service
Cons:
Proposition 2: Low-level library with init function
This would provide a low-level library only. The developers would be responsible for starting an HTTP or TCP server, but would still benefit from a function that will subscribe for logs, and structs for log entries. Developers would still use
lambda_extension
to actually register the extension, and then subscribe to the logs.Pros:
Cons:
tower::Service
(extra init function)Proposition 3: Low-level library with factory pattern
TODO
Pros:
tower::Service
Cons:
Proposition 4: your idea here
If you have an idea that gives flexibility while providing a high-level interface, that'd be awesome, but I'm unsure what it would look like.
The text was updated successfully, but these errors were encountered: