Skip to content

Commit f51589c

Browse files
authored
Advanced logging controls (#830)
* Implement Lambda's advance logging controls. Provide a feature that exposes a initialization function for `tracing-subscriber` that sets the right logging controls based on Lambda's configuration. The feature is enabled by default, but it can be disabled if a user doesn't want to use it. Signed-off-by: David Calavera <david.calavera@gmail.com> * Update examples to use the new tracing-subscriber feature. Signed-off-by: David Calavera <david.calavera@gmail.com> * Remove tracing from the runtime client. It makes logs too verbose. Signed-off-by: David Calavera <david.calavera@gmail.com> * Make the tracing dependency optional. Signed-off-by: David Calavera <david.calavera@gmail.com> * Fix ambiguous name in old versions of Rust. Identify the dependency as the top dependency. Signed-off-by: David Calavera <david.calavera@gmail.com> * Fix formatting. Signed-off-by: David Calavera <david.calavera@gmail.com> --------- Signed-off-by: David Calavera <david.calavera@gmail.com>
1 parent af4df1f commit f51589c

File tree

77 files changed

+187
-541
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+187
-541
lines changed

README.md

+18
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,24 @@ You can read more about how [cargo lambda watch](https://www.cargo-lambda.info/c
372372

373373
Lambdas can be run and debugged locally using a special [Lambda debug proxy](https://github.com/rimutaka/lambda-debug-proxy) (a non-AWS repo maintained by @rimutaka), which is a Lambda function that forwards incoming requests to one AWS SQS queue and reads responses from another queue. A local proxy running on your development computer reads the queue, calls your Lambda locally and sends back the response. This approach allows debugging of Lambda functions locally while being part of your AWS workflow. The Lambda handler code does not need to be modified between the local and AWS versions.
374374

375+
## Tracing and Logging
376+
377+
The Rust Runtime for Lambda integrates with the (Tracing)[https://tracing.rs] libraries to provide tracing and logging.
378+
379+
By default, the runtime emits `tracing` events that you can collect via `tracing-subscriber`. It also enabled a feature called `tracing` that exposes a default subsriber with sensible options to send logging information to AWS CloudWatch. Follow the next example that shows how to enable the default subscriber:
380+
381+
```rust
382+
use lambda_runtime::{run, service_fn, tracing, Error};
383+
384+
#[tokio::main]
385+
async fn main() -> Result<(), Error> {
386+
tracing::init_default_subscriber();
387+
run(service_fn(|event| tracing::info!(?event))).await
388+
}
389+
```
390+
391+
The subscriber uses `RUST_LOG` as the environment variable to determine the log level for your function. It also uses [Lambda's advance logging controls](https://aws.amazon.com/blogs/compute/introducing-advanced-logging-controls-for-aws-lambda-functions/) if they're configured for your function. By default, the log level to emit events is `INFO`.
392+
375393
## AWS event objects
376394

377395
This project includes Lambda event struct definitions, [`aws_lambda_events`](https://crates.io/crates/aws_lambda_events). This crate can be leveraged to provide strongly-typed Lambda event structs. You can create your own custom event objects and their corresponding structs as well.

examples/advanced-sqs-multiple-functions-shared-data/consumer/Cargo.toml

+1-6
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,14 @@ name = "consumer"
33
version = "0.1.0"
44
edition = "2021"
55

6-
76
[dependencies]
8-
#tracing
9-
tracing = "0.1.40"
10-
tracing-subscriber = "0.3.17"
11-
127
#aws dependencies
138
aws-sdk-config = "0.35.0"
149
aws-sdk-sqs = "0.35.0"
1510
aws_lambda_events = { version = "0.11.1", features = ["sqs"], default-features = false }
1611

1712
#lambda runtime
18-
lambda_runtime = "0.8.1"
13+
lambda_runtime = { path = "../../../lambda-runtime" }
1914
tokio = { version = "1", features = ["macros"] }
2015

2116
#shared lib
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
use aws_lambda_events::event::sqs::SqsEventObj;
2-
use lambda_runtime::{service_fn, Error, LambdaEvent};
2+
use lambda_runtime::{service_fn, tracing, Error, LambdaEvent};
33
use pizza_lib::Pizza;
44

55
#[tokio::main]
66
async fn main() -> Result<(), Error> {
7-
tracing_subscriber::fmt()
8-
.with_max_level(tracing::Level::INFO)
9-
.with_target(false)
10-
.with_ansi(false)
11-
.without_time()
12-
.init();
7+
tracing::init_default_subscriber();
138
let func = service_fn(func);
149
lambda_runtime::run(func).await?;
1510
Ok(())
@@ -18,7 +13,7 @@ async fn main() -> Result<(), Error> {
1813
async fn func(event: LambdaEvent<SqsEventObj<Pizza>>) -> Result<(), Error> {
1914
for record in event.payload.records.iter() {
2015
let pizza = &record.body;
21-
println!("Pizza name: {} with toppings: {:?}", pizza.name, pizza.toppings);
16+
tracing::info!(name = pizza.name, toppings = ?pizza.toppings, "pizza order received");
2217
}
2318
Ok(())
2419
}

examples/advanced-sqs-multiple-functions-shared-data/producer/Cargo.toml

+1-5
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,13 @@ edition = "2021"
77
env = { "QUEUE_URL" = "https://changeMe" }
88

99
[dependencies]
10-
#tracing
11-
tracing = "0.1.40"
12-
tracing-subscriber = "0.3.17"
13-
1410
#aws dependencies
1511
aws-config = "0.57.1"
1612
aws-sdk-config = "0.35.0"
1713
aws-sdk-sqs = "0.35.0"
1814

1915
#lambda runtime
20-
lambda_runtime = "0.8.1"
16+
lambda_runtime = { path = "../../../lambda-runtime" }
2117
serde_json = "1.0.108"
2218
tokio = { version = "1", features = ["macros"] }
2319

examples/advanced-sqs-multiple-functions-shared-data/producer/src/main.rs

+3-10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use lambda_runtime::{service_fn, Error, LambdaEvent};
1+
use lambda_runtime::{service_fn, tracing, Error, LambdaEvent};
22
use pizza_lib::Pizza;
33
use serde_json::{json, Value};
44

@@ -15,12 +15,7 @@ impl SQSManager {
1515

1616
#[tokio::main]
1717
async fn main() -> Result<(), Error> {
18-
tracing_subscriber::fmt()
19-
.with_max_level(tracing::Level::INFO)
20-
.with_target(false)
21-
.with_ansi(false)
22-
.without_time()
23-
.init();
18+
tracing::init_default_subscriber();
2419

2520
// read the queue url from the environment
2621
let queue_url = std::env::var("QUEUE_URL").expect("could not read QUEUE_URL");
@@ -31,9 +26,7 @@ async fn main() -> Result<(), Error> {
3126
let sqs_manager_ref = &sqs_manager;
3227

3328
// no need to create a SQS Client for each incoming request, let's use a shared state
34-
let handler_func_closure = |event: LambdaEvent<Value>| async move {
35-
process_event(event, sqs_manager_ref).await
36-
};
29+
let handler_func_closure = |event: LambdaEvent<Value>| async move { process_event(event, sqs_manager_ref).await };
3730
lambda_runtime::run(service_fn(handler_func_closure)).await?;
3831
Ok(())
3932
}

examples/advanced-sqs-partial-batch-failures/Cargo.toml

-2
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,3 @@ aws_lambda_events = { path = "../../lambda-events" }
1212
lambda_runtime = { path = "../../lambda-runtime" }
1313
tokio = { version = "1", features = ["macros"] }
1414
futures = "0.3"
15-
tracing = { version = "0.1", features = ["log"] }
16-
tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }

examples/advanced-sqs-partial-batch-failures/src/main.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ use aws_lambda_events::{
33
sqs::{BatchItemFailure, SqsBatchResponse, SqsMessageObj},
44
};
55
use futures::Future;
6-
use lambda_runtime::{run, service_fn, Error, LambdaEvent};
6+
use lambda_runtime::{
7+
run, service_fn,
8+
tracing::{self, Instrument},
9+
Error, LambdaEvent,
10+
};
711
use serde::{de::DeserializeOwned, Deserialize, Serialize};
8-
use tracing::Instrument;
912

1013
/// [To customize] Your object definition, sent to the SQS queue triggering this lambda.
1114
#[derive(Deserialize, Serialize)]
@@ -29,13 +32,7 @@ async fn data_handler(data: Data) -> Result<(), Error> {
2932
#[tokio::main]
3033
async fn main() -> Result<(), Error> {
3134
// required to enable CloudWatch error logging by the runtime
32-
tracing_subscriber::fmt()
33-
.with_max_level(tracing::Level::INFO)
34-
// disable printing the name of the module in every log line.
35-
.with_target(false)
36-
// disabling time is handy because CloudWatch will add the ingestion time.
37-
.without_time()
38-
.init();
35+
tracing::init_default_subscriber();
3936

4037
run_sqs_partial_batch_failure(data_handler).await
4138
}

examples/basic-error-handling/Cargo.toml

-11
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,9 @@ name = "error-handling"
33
version = "0.1.0"
44
edition = "2021"
55

6-
7-
# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
8-
# to manage dependencies.
9-
# Running `cargo add DEPENDENCY_NAME` will
10-
# add the latest version of a dependency to the list,
11-
# and it will keep the alphabetic ordering for you.
12-
136
[dependencies]
147
lambda_runtime = { path = "../../lambda-runtime" }
158
serde = "1.0.136"
169
serde_json = "1.0.81"
1710
simple-error = "0.2.3"
1811
tokio = { version = "1", features = ["macros"] }
19-
tracing = { version = "0.1", features = ["log"] }
20-
tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
21-
22-

examples/basic-error-handling/src/main.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/// See https://github.com/awslabs/aws-lambda-rust-runtime for more info on Rust runtime for AWS Lambda
2-
use lambda_runtime::{service_fn, Error, LambdaEvent};
2+
use lambda_runtime::{service_fn, tracing, Error, LambdaEvent};
33
use serde::{Deserialize, Serialize};
44
use serde_json::{json, Value};
55
use std::fs::File;
@@ -50,13 +50,7 @@ impl std::fmt::Display for CustomError {
5050
#[tokio::main]
5151
async fn main() -> Result<(), Error> {
5252
// required to enable CloudWatch error logging by the runtime
53-
tracing_subscriber::fmt()
54-
.with_max_level(tracing::Level::INFO)
55-
// disable printing the name of the module in every log line.
56-
.with_target(false)
57-
// disabling time is handy because CloudWatch will add the ingestion time.
58-
.without_time()
59-
.init();
53+
tracing::init_default_subscriber();
6054

6155
// call the actual handler of the request
6256
let func = service_fn(func);

examples/basic-lambda-external-runtime/Cargo.toml

+3-4
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@ edition = "2021"
66
[dependencies]
77
async-channel = "1.8.0"
88
futures-lite = "1.13.0"
9-
lambda_runtime = "0.8.0"
10-
lambda_runtime_api_client = "0.8.0"
9+
lambda_runtime = { path = "../../lambda-runtime" }
1110
serde = "1.0.163"
1211
tokio = "1.28.2"
12+
13+
[dev-dependencies]
1314
tokio-test = "0.4.2"
14-
tracing = "0.1.37"
15-
tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }

examples/basic-lambda-external-runtime/src/main.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::{io, thread};
22

33
use futures_lite::future;
4-
use lambda_runtime::{service_fn, Error, LambdaEvent};
4+
use lambda_runtime::{service_fn, tracing, Error, LambdaEvent};
55
use serde::{Deserialize, Serialize};
66
use tokio::runtime::Builder;
77

@@ -25,13 +25,7 @@ struct Response {
2525

2626
fn main() -> Result<(), io::Error> {
2727
// required to enable CloudWatch error logging by the runtime
28-
tracing_subscriber::fmt()
29-
.with_max_level(tracing::Level::INFO)
30-
// disable printing the name of the module in every log line.
31-
.with_target(false)
32-
// disabling time is handy because CloudWatch will add the ingestion time.
33-
.without_time()
34-
.init();
28+
tracing::init_default_subscriber();
3529

3630
// Create a channel used to send and receive outputs from our lambda handler. Realistically, this would be either an unbounded channel
3731
// or a bounded channel with a higher capacity as needed.

examples/basic-lambda/Cargo.toml

+2-9
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,10 @@ name = "basic-lambda"
33
version = "0.1.0"
44
edition = "2021"
55

6-
7-
# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
8-
# to manage dependencies.
9-
# Running `cargo add DEPENDENCY_NAME` will
10-
# add the latest version of a dependency to the list,
11-
# and it will keep the alphabetic ordering for you.
12-
136
[dependencies]
147
lambda_runtime = { path = "../../lambda-runtime" }
158
serde = "1.0.136"
169
tokio = { version = "1", features = ["macros"] }
17-
tracing = { version = "0.1", features = ["log"] }
18-
tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
10+
11+
[dev-dependencies]
1912
tokio-test = "0.4.2"

examples/basic-lambda/src/main.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// This example requires the following input to succeed:
22
// { "command": "do something" }
33

4-
use lambda_runtime::{service_fn, Error, LambdaEvent};
4+
use lambda_runtime::{service_fn, tracing, Error, LambdaEvent};
55
use serde::{Deserialize, Serialize};
66

77
/// This is also a made-up example. Requests come into the runtime as unicode
@@ -25,13 +25,7 @@ struct Response {
2525
#[tokio::main]
2626
async fn main() -> Result<(), Error> {
2727
// required to enable CloudWatch error logging by the runtime
28-
tracing_subscriber::fmt()
29-
.with_max_level(tracing::Level::INFO)
30-
// disable printing the name of the module in every log line.
31-
.with_target(false)
32-
// disabling time is handy because CloudWatch will add the ingestion time.
33-
.without_time()
34-
.init();
28+
tracing::init_default_subscriber();
3529

3630
let func = service_fn(my_handler);
3731
lambda_runtime::run(func).await?;

examples/basic-s3-object-lambda-thumbnail/Cargo.toml

-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ aws_lambda_events = "0.8.3"
1919
lambda_runtime = { path = "../../lambda-runtime" }
2020
serde = "1"
2121
tokio = { version = "1", features = ["macros"] }
22-
tracing = { version = "0.1" }
23-
tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
2422
aws-config = "0.55.3"
2523
aws-sdk-s3 = "0.28.0"
2624
thumbnailer = "0.4.0"

examples/basic-s3-object-lambda-thumbnail/src/main.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::error;
22

33
use aws_lambda_events::s3::object_lambda::{GetObjectContext, S3ObjectLambdaEvent};
44
use aws_sdk_s3::Client as S3Client;
5-
use lambda_runtime::{run, service_fn, Error, LambdaEvent};
5+
use lambda_runtime::{run, service_fn, tracing, Error, LambdaEvent};
66
use s3::{GetFile, SendFile};
77

88
mod s3;
@@ -57,13 +57,7 @@ fn get_thumbnail(vec: Vec<u8>, size: u32) -> Vec<u8> {
5757
#[tokio::main]
5858
async fn main() -> Result<(), Error> {
5959
// required to enable CloudWatch error logging by the runtime
60-
tracing_subscriber::fmt()
61-
.with_max_level(tracing::Level::TRACE)
62-
// disable printing the name of the module in every log line.
63-
.with_target(false)
64-
// disabling time is handy because CloudWatch will add the ingestion time.
65-
.without_time()
66-
.init();
60+
tracing::init_default_subscriber();
6761

6862
let shared_config = aws_config::load_from_env().await;
6963
let client = S3Client::new(&shared_config);

examples/basic-s3-object-lambda-thumbnail/src/s3.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use async_trait::async_trait;
22
use aws_sdk_s3::{operation::write_get_object_response::WriteGetObjectResponseError, Client as S3Client};
33
use aws_smithy_http::{byte_stream::ByteStream, result::SdkError};
4+
use lambda_runtime::tracing;
45
use std::{error, io::Read};
56

67
pub trait GetFile {

examples/basic-s3-thumbnail/Cargo.toml

-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ aws_lambda_events = { path = "../../lambda-events" }
1919
lambda_runtime = { path = "../../lambda-runtime" }
2020
serde = "1"
2121
tokio = { version = "1", features = ["macros"] }
22-
tracing = { version = "0.1" }
23-
tracing-subscriber = { version = "0.3", default-features = false, features = ["ansi", "fmt"] }
2422
aws-config = "0.55"
2523
aws-smithy-http = "0.55.3"
2624
aws-sdk-s3 = "0.28"

examples/basic-s3-thumbnail/src/main.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use aws_lambda_events::{event::s3::S3Event, s3::S3EventRecord};
22
use aws_sdk_s3::Client as S3Client;
3-
use lambda_runtime::{run, service_fn, Error, LambdaEvent};
3+
use lambda_runtime::{run, service_fn, tracing, Error, LambdaEvent};
44
use s3::{GetFile, PutFile};
55

66
mod s3;
@@ -109,13 +109,7 @@ fn get_thumbnail(vec: Vec<u8>, size: u32) -> Result<Vec<u8>, String> {
109109
#[tokio::main]
110110
async fn main() -> Result<(), Error> {
111111
// required to enable CloudWatch error logging by the runtime
112-
tracing_subscriber::fmt()
113-
.with_max_level(tracing::Level::INFO)
114-
// disable printing the name of the module in every log line.
115-
.with_target(false)
116-
// disabling time is handy because CloudWatch will add the ingestion time.
117-
.without_time()
118-
.init();
112+
tracing::init_default_subscriber();
119113

120114
let shared_config = aws_config::load_from_env().await;
121115
let client = S3Client::new(&shared_config);

examples/basic-s3-thumbnail/src/s3.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use async_trait::async_trait;
22
use aws_sdk_s3::operation::get_object::GetObjectError;
33
use aws_sdk_s3::Client as S3Client;
44
use aws_smithy_http::byte_stream::ByteStream;
5+
use lambda_runtime::tracing;
56

67
#[async_trait]
78
pub trait GetFile {

examples/basic-sdk/Cargo.toml

-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ aws-sdk-s3 = "0.24"
1212
lambda_runtime = { path = "../../lambda-runtime" }
1313
serde = "1.0.136"
1414
tokio = { version = "1", features = ["macros"] }
15-
tracing = { version = "0.1", features = ["log"] }
16-
tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
1715

1816
[dev-dependencies]
1917
mockall = "0.11.3"

examples/basic-sdk/src/main.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use async_trait::async_trait;
22
use aws_sdk_s3::{output::ListObjectsV2Output, Client as S3Client};
3-
use lambda_runtime::{service_fn, Error, LambdaEvent};
3+
use lambda_runtime::{service_fn, tracing, Error, LambdaEvent};
44
use serde::{Deserialize, Serialize};
55

66
/// The request defines what bucket to list
@@ -34,13 +34,7 @@ impl ListObjects for S3Client {
3434
#[tokio::main]
3535
async fn main() -> Result<(), Error> {
3636
// required to enable CloudWatch error logging by the runtime
37-
tracing_subscriber::fmt()
38-
.with_max_level(tracing::Level::INFO)
39-
// disable printing the name of the module in every log line.
40-
.with_target(false)
41-
// disabling time is handy because CloudWatch will add the ingestion time.
42-
.without_time()
43-
.init();
37+
tracing::init_default_subscriber();
4438

4539
let shared_config = aws_config::load_from_env().await;
4640
let client = S3Client::new(&shared_config);

0 commit comments

Comments
 (0)