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

Issue:
Add support for lambda advanced logging controls
https://aws.amazon.com/blogs/compute/introducing-advanced-logging-controls-for-aws-lambda-functions/

Additional details [here](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-cloudwatchlogs.html):

> Application log-level filtering with custom runtimes
> When you configure application log-level filtering for your function, behind the scenes Lambda sets the application log level in the runtime using the AWS_LAMBDA_LOG_LEVEL environment variable. Lambda also sets your function's log format using the AWS_LAMBDA_LOG_FORMAT environment variable. You can use these variables to integrate Lambda advanced logging controls into a [custom runtime](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html).
> 
> For the ability to configure logging settings for a function using a custom runtime with the Lambda console, AWS CLI, and Lambda APIs, configure your custom runtime to check the value of these environment variables. You can then configure your runtime's loggers in accordance with the log format and log levels you select.



Discussion / hints:
If we want to do this, it might be necessary for us provide some higher level functions to configure `tracing_subscriber`. By default, `tracing_subscriber` doesn't compile with support for JSON logs, and we would not be able to use the format variable without that support. We could expose an initializer for tracing like this:

```rust
fn main() {
  lambda_runtime::tracing::init();
  ...
}
```

However, it makes me wonder if we should create a different crate for utilities which could evolve into a similar concept than Lambda's PowerTools.
Yeah, I vote for a separate `lambda-powertools-rs`  crate. 

Copy @heitorlessa. This could be a good time to cooperate. 

Hey Harold, ping me mid this week for a call - I've got another idea we can do progressively to limit supply chain risks here.

---

**Why this is hard and not sustainable.**

We haven't received investments _(read: headcount)_ for a Rust implementation of Powertools for AWS Lambda. We would need a minimum of 2 to do this to meet the high bar docs quality, security, ops excellence, tenets, and the trademark we hold.

Non-intrusive usage tracking is the second impediment - main reason we didn't do Golang (much higher demand than Rust at the moment)

There is an alternative route that won't publish a crate but use Rust for a better purpose -- interop with Python and NodeJS. Maybe Java and .NET if proven stable too.

I've got some candidates for an experiment in this area. If successful, it's a low risk to do one at a time, build bindings for both progressively, eventually replace their respective AWS SDKs, and when investment is secured we can do a crate from the work mostly completed.


I've been thinking about this, and I don't think we need a new crate or project. When people start with Rust Lambda functions, they usually start with `cargo lambda new`, which already brings `tracing` and `tracing-subscriber` as dependencies. Instead of having to manage that in Cargo Lambda, it makes more sense for the runtime to provide the default logging configuration. This way we avoid dependency drift.

The changes to support this feature are actually tiny, and the documentation is straight forward. I'm going to open a PR soon with the implementation.

Fix patch:
diff --git a/README.md b/README.md
index 43c38586..8a5920b7 100644
--- a/README.md
+++ b/README.md
@@ -372,6 +372,24 @@ You can read more about how [cargo lambda watch](https://www.cargo-lambda.info/c
 
 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.
 
+## Tracing and Logging
+
+The Rust Runtime for Lambda integrates with the (Tracing)[https://tracing.rs] libraries to provide tracing and logging.
+
+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:
+
+```rust
+use lambda_runtime::{run, service_fn, tracing, Error};
+
+#[tokio::main]
+async fn main() -> Result<(), Error> {
+    tracing::init_default_subscriber();
+    run(service_fn(|event| tracing::info!(?event))).await
+}
+```
+
+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`.
+
 ## AWS event objects
 
 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.
diff --git a/examples/advanced-sqs-multiple-functions-shared-data/consumer/Cargo.toml b/examples/advanced-sqs-multiple-functions-shared-data/consumer/Cargo.toml
index 8555a073..69ec04a0 100644
--- a/examples/advanced-sqs-multiple-functions-shared-data/consumer/Cargo.toml
+++ b/examples/advanced-sqs-multiple-functions-shared-data/consumer/Cargo.toml
@@ -3,19 +3,14 @@ name = "consumer"
 version = "0.1.0"
 edition = "2021"
 
-
 [dependencies]
-#tracing
-tracing = "0.1.40"
-tracing-subscriber = "0.3.17"
-
 #aws dependencies
 aws-sdk-config = "0.35.0"
 aws-sdk-sqs = "0.35.0"
 aws_lambda_events = { version = "0.11.1", features = ["sqs"], default-features = false }
 
 #lambda runtime
-lambda_runtime = "0.8.1"
+lambda_runtime = { path = "../../../lambda-runtime" }
 tokio = { version = "1", features = ["macros"] }
 
 #shared lib
diff --git a/examples/advanced-sqs-multiple-functions-shared-data/consumer/src/main.rs b/examples/advanced-sqs-multiple-functions-shared-data/consumer/src/main.rs
index 42290192..c076a502 100644
--- a/examples/advanced-sqs-multiple-functions-shared-data/consumer/src/main.rs
+++ b/examples/advanced-sqs-multiple-functions-shared-data/consumer/src/main.rs
@@ -1,15 +1,10 @@
 use aws_lambda_events::event::sqs::SqsEventObj;
-use lambda_runtime::{service_fn, Error, LambdaEvent};
+use lambda_runtime::{service_fn, tracing, Error, LambdaEvent};
 use pizza_lib::Pizza;
 
 #[tokio::main]
 async fn main() -> Result<(), Error> {
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        .with_target(false)
-        .with_ansi(false)
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
     let func = service_fn(func);
     lambda_runtime::run(func).await?;
     Ok(())
@@ -18,7 +13,7 @@ async fn main() -> Result<(), Error> {
 async fn func(event: LambdaEvent<SqsEventObj<Pizza>>) -> Result<(), Error> {
     for record in event.payload.records.iter() {
         let pizza = &record.body;
-        println!("Pizza name: {} with toppings: {:?}", pizza.name, pizza.toppings);
+        tracing::info!(name = pizza.name, toppings = ?pizza.toppings, "pizza order received");
     }
     Ok(())
 }
diff --git a/examples/advanced-sqs-multiple-functions-shared-data/producer/Cargo.toml b/examples/advanced-sqs-multiple-functions-shared-data/producer/Cargo.toml
index 557ac6e5..83aa48ab 100644
--- a/examples/advanced-sqs-multiple-functions-shared-data/producer/Cargo.toml
+++ b/examples/advanced-sqs-multiple-functions-shared-data/producer/Cargo.toml
@@ -7,17 +7,13 @@ edition = "2021"
 env = { "QUEUE_URL" = "https://changeMe" } 
 
 [dependencies]
-#tracing
-tracing = "0.1.40"
-tracing-subscriber = "0.3.17"
-
 #aws dependencies
 aws-config = "0.57.1"
 aws-sdk-config = "0.35.0"
 aws-sdk-sqs = "0.35.0"
 
 #lambda runtime
-lambda_runtime = "0.8.1"
+lambda_runtime = { path = "../../../lambda-runtime" }
 serde_json = "1.0.108"
 tokio = { version = "1", features = ["macros"] }
 
diff --git a/examples/advanced-sqs-multiple-functions-shared-data/producer/src/main.rs b/examples/advanced-sqs-multiple-functions-shared-data/producer/src/main.rs
index 2cc2541b..2a70dce3 100644
--- a/examples/advanced-sqs-multiple-functions-shared-data/producer/src/main.rs
+++ b/examples/advanced-sqs-multiple-functions-shared-data/producer/src/main.rs
@@ -1,4 +1,4 @@
-use lambda_runtime::{service_fn, Error, LambdaEvent};
+use lambda_runtime::{service_fn, tracing, Error, LambdaEvent};
 use pizza_lib::Pizza;
 use serde_json::{json, Value};
 
@@ -15,12 +15,7 @@ impl SQSManager {
 
 #[tokio::main]
 async fn main() -> Result<(), Error> {
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        .with_target(false)
-        .with_ansi(false)
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     // read the queue url from the environment
     let queue_url = std::env::var("QUEUE_URL").expect("could not read QUEUE_URL");
@@ -31,9 +26,7 @@ async fn main() -> Result<(), Error> {
     let sqs_manager_ref = &sqs_manager;
 
     // no need to create a SQS Client for each incoming request, let's use a shared state
-    let handler_func_closure = |event: LambdaEvent<Value>| async move {
-        process_event(event, sqs_manager_ref).await
-    };
+    let handler_func_closure = |event: LambdaEvent<Value>| async move { process_event(event, sqs_manager_ref).await };
     lambda_runtime::run(service_fn(handler_func_closure)).await?;
     Ok(())
 }
diff --git a/examples/advanced-sqs-partial-batch-failures/Cargo.toml b/examples/advanced-sqs-partial-batch-failures/Cargo.toml
index 04158320..95050b9a 100644
--- a/examples/advanced-sqs-partial-batch-failures/Cargo.toml
+++ b/examples/advanced-sqs-partial-batch-failures/Cargo.toml
@@ -12,5 +12,3 @@ aws_lambda_events = { path = "../../lambda-events" }
 lambda_runtime = { path = "../../lambda-runtime" }
 tokio = { version = "1", features = ["macros"] }
 futures = "0.3"
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
diff --git a/examples/advanced-sqs-partial-batch-failures/src/main.rs b/examples/advanced-sqs-partial-batch-failures/src/main.rs
index 23faa68f..42bb2253 100644
--- a/examples/advanced-sqs-partial-batch-failures/src/main.rs
+++ b/examples/advanced-sqs-partial-batch-failures/src/main.rs
@@ -3,9 +3,12 @@ use aws_lambda_events::{
     sqs::{BatchItemFailure, SqsBatchResponse, SqsMessageObj},
 };
 use futures::Future;
-use lambda_runtime::{run, service_fn, Error, LambdaEvent};
+use lambda_runtime::{
+    run, service_fn,
+    tracing::{self, Instrument},
+    Error, LambdaEvent,
+};
 use serde::{de::DeserializeOwned, Deserialize, Serialize};
-use tracing::Instrument;
 
 /// [To customize] Your object definition, sent to the SQS queue triggering this lambda.
 #[derive(Deserialize, Serialize)]
@@ -29,13 +32,7 @@ async fn data_handler(data: Data) -> Result<(), Error> {
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     run_sqs_partial_batch_failure(data_handler).await
 }
diff --git a/examples/basic-error-handling/Cargo.toml b/examples/basic-error-handling/Cargo.toml
index e8699141..1039a139 100644
--- a/examples/basic-error-handling/Cargo.toml
+++ b/examples/basic-error-handling/Cargo.toml
@@ -3,20 +3,9 @@ name = "error-handling"
 version = "0.1.0"
 edition = "2021"
 
-
-# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
-# to manage dependencies.
-# Running `cargo add DEPENDENCY_NAME` will
-# add the latest version of a dependency to the list,
-# and it will keep the alphabetic ordering for you.
-
 [dependencies]
 lambda_runtime = { path = "../../lambda-runtime" }
 serde = "1.0.136"
 serde_json = "1.0.81"
 simple-error = "0.2.3"
 tokio = { version = "1", features = ["macros"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
-
-
diff --git a/examples/basic-error-handling/src/main.rs b/examples/basic-error-handling/src/main.rs
index 0939d2d0..528d6f02 100644
--- a/examples/basic-error-handling/src/main.rs
+++ b/examples/basic-error-handling/src/main.rs
@@ -1,5 +1,5 @@
 /// See https://github.com/awslabs/aws-lambda-rust-runtime for more info on Rust runtime for AWS Lambda
-use lambda_runtime::{service_fn, Error, LambdaEvent};
+use lambda_runtime::{service_fn, tracing, Error, LambdaEvent};
 use serde::{Deserialize, Serialize};
 use serde_json::{json, Value};
 use std::fs::File;
@@ -50,13 +50,7 @@ impl std::fmt::Display for CustomError {
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     // call the actual handler of the request
     let func = service_fn(func);
diff --git a/examples/basic-lambda-external-runtime/Cargo.toml b/examples/basic-lambda-external-runtime/Cargo.toml
index 0682efaf..d6d023d8 100644
--- a/examples/basic-lambda-external-runtime/Cargo.toml
+++ b/examples/basic-lambda-external-runtime/Cargo.toml
@@ -6,10 +6,9 @@ edition = "2021"
 [dependencies]
 async-channel = "1.8.0"
 futures-lite = "1.13.0"
-lambda_runtime = "0.8.0"
-lambda_runtime_api_client = "0.8.0"
+lambda_runtime = { path = "../../lambda-runtime" }
 serde = "1.0.163"
 tokio = "1.28.2"
+
+[dev-dependencies]
 tokio-test = "0.4.2"
-tracing = "0.1.37"
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
diff --git a/examples/basic-lambda-external-runtime/src/main.rs b/examples/basic-lambda-external-runtime/src/main.rs
index 9419b17b..bd3b4e6c 100644
--- a/examples/basic-lambda-external-runtime/src/main.rs
+++ b/examples/basic-lambda-external-runtime/src/main.rs
@@ -1,7 +1,7 @@
 use std::{io, thread};
 
 use futures_lite::future;
-use lambda_runtime::{service_fn, Error, LambdaEvent};
+use lambda_runtime::{service_fn, tracing, Error, LambdaEvent};
 use serde::{Deserialize, Serialize};
 use tokio::runtime::Builder;
 
@@ -25,13 +25,7 @@ struct Response {
 
 fn main() -> Result<(), io::Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     // Create a channel used to send and receive outputs from our lambda handler. Realistically, this would be either an unbounded channel
     // or a bounded channel with a higher capacity as needed.
diff --git a/examples/basic-lambda/Cargo.toml b/examples/basic-lambda/Cargo.toml
index cd2efa42..6fad6990 100644
--- a/examples/basic-lambda/Cargo.toml
+++ b/examples/basic-lambda/Cargo.toml
@@ -3,17 +3,10 @@ name = "basic-lambda"
 version = "0.1.0"
 edition = "2021"
 
-
-# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
-# to manage dependencies.
-# Running `cargo add DEPENDENCY_NAME` will
-# add the latest version of a dependency to the list,
-# and it will keep the alphabetic ordering for you.
-
 [dependencies]
 lambda_runtime = { path = "../../lambda-runtime" }
 serde = "1.0.136"
 tokio = { version = "1", features = ["macros"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
+
+[dev-dependencies]
 tokio-test = "0.4.2"
\ No newline at end of file
diff --git a/examples/basic-lambda/src/main.rs b/examples/basic-lambda/src/main.rs
index 09145bb3..8630e78c 100644
--- a/examples/basic-lambda/src/main.rs
+++ b/examples/basic-lambda/src/main.rs
@@ -1,7 +1,7 @@
 // This example requires the following input to succeed:
 // { "command": "do something" }
 
-use lambda_runtime::{service_fn, Error, LambdaEvent};
+use lambda_runtime::{service_fn, tracing, Error, LambdaEvent};
 use serde::{Deserialize, Serialize};
 
 /// This is also a made-up example. Requests come into the runtime as unicode
@@ -25,13 +25,7 @@ struct Response {
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     let func = service_fn(my_handler);
     lambda_runtime::run(func).await?;
diff --git a/examples/basic-s3-object-lambda-thumbnail/Cargo.toml b/examples/basic-s3-object-lambda-thumbnail/Cargo.toml
index 79640cc2..ba750df9 100644
--- a/examples/basic-s3-object-lambda-thumbnail/Cargo.toml
+++ b/examples/basic-s3-object-lambda-thumbnail/Cargo.toml
@@ -19,8 +19,6 @@ aws_lambda_events = "0.8.3"
 lambda_runtime = { path = "../../lambda-runtime" }
 serde = "1"
 tokio = { version = "1", features = ["macros"] }
-tracing = { version = "0.1" }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
 aws-config = "0.55.3"
 aws-sdk-s3 = "0.28.0"
 thumbnailer = "0.4.0"
diff --git a/examples/basic-s3-object-lambda-thumbnail/src/main.rs b/examples/basic-s3-object-lambda-thumbnail/src/main.rs
index 328e7500..bb1c4f9c 100644
--- a/examples/basic-s3-object-lambda-thumbnail/src/main.rs
+++ b/examples/basic-s3-object-lambda-thumbnail/src/main.rs
@@ -2,7 +2,7 @@ use std::error;
 
 use aws_lambda_events::s3::object_lambda::{GetObjectContext, S3ObjectLambdaEvent};
 use aws_sdk_s3::Client as S3Client;
-use lambda_runtime::{run, service_fn, Error, LambdaEvent};
+use lambda_runtime::{run, service_fn, tracing, Error, LambdaEvent};
 use s3::{GetFile, SendFile};
 
 mod s3;
@@ -57,13 +57,7 @@ fn get_thumbnail(vec: Vec<u8>, size: u32) -> Vec<u8> {
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::TRACE)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     let shared_config = aws_config::load_from_env().await;
     let client = S3Client::new(&shared_config);
diff --git a/examples/basic-s3-object-lambda-thumbnail/src/s3.rs b/examples/basic-s3-object-lambda-thumbnail/src/s3.rs
index 71e03ffc..daba3739 100644
--- a/examples/basic-s3-object-lambda-thumbnail/src/s3.rs
+++ b/examples/basic-s3-object-lambda-thumbnail/src/s3.rs
@@ -1,6 +1,7 @@
 use async_trait::async_trait;
 use aws_sdk_s3::{operation::write_get_object_response::WriteGetObjectResponseError, Client as S3Client};
 use aws_smithy_http::{byte_stream::ByteStream, result::SdkError};
+use lambda_runtime::tracing;
 use std::{error, io::Read};
 
 pub trait GetFile {
diff --git a/examples/basic-s3-thumbnail/Cargo.toml b/examples/basic-s3-thumbnail/Cargo.toml
index 6bbe11b7..1cd3b834 100644
--- a/examples/basic-s3-thumbnail/Cargo.toml
+++ b/examples/basic-s3-thumbnail/Cargo.toml
@@ -19,8 +19,6 @@ aws_lambda_events = { path = "../../lambda-events" }
 lambda_runtime = { path = "../../lambda-runtime" }
 serde = "1"
 tokio = { version = "1", features = ["macros"] }
-tracing = { version = "0.1" }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["ansi", "fmt"] }
 aws-config = "0.55"
 aws-smithy-http = "0.55.3"
 aws-sdk-s3 = "0.28"
diff --git a/examples/basic-s3-thumbnail/src/main.rs b/examples/basic-s3-thumbnail/src/main.rs
index d92c822b..3eb5bfe9 100644
--- a/examples/basic-s3-thumbnail/src/main.rs
+++ b/examples/basic-s3-thumbnail/src/main.rs
@@ -1,6 +1,6 @@
 use aws_lambda_events::{event::s3::S3Event, s3::S3EventRecord};
 use aws_sdk_s3::Client as S3Client;
-use lambda_runtime::{run, service_fn, Error, LambdaEvent};
+use lambda_runtime::{run, service_fn, tracing, Error, LambdaEvent};
 use s3::{GetFile, PutFile};
 
 mod s3;
@@ -109,13 +109,7 @@ fn get_thumbnail(vec: Vec<u8>, size: u32) -> Result<Vec<u8>, String> {
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     let shared_config = aws_config::load_from_env().await;
     let client = S3Client::new(&shared_config);
diff --git a/examples/basic-s3-thumbnail/src/s3.rs b/examples/basic-s3-thumbnail/src/s3.rs
index 17d7f975..0dd8629d 100644
--- a/examples/basic-s3-thumbnail/src/s3.rs
+++ b/examples/basic-s3-thumbnail/src/s3.rs
@@ -2,6 +2,7 @@ use async_trait::async_trait;
 use aws_sdk_s3::operation::get_object::GetObjectError;
 use aws_sdk_s3::Client as S3Client;
 use aws_smithy_http::byte_stream::ByteStream;
+use lambda_runtime::tracing;
 
 #[async_trait]
 pub trait GetFile {
diff --git a/examples/basic-sdk/Cargo.toml b/examples/basic-sdk/Cargo.toml
index 0e930f7c..454a970f 100644
--- a/examples/basic-sdk/Cargo.toml
+++ b/examples/basic-sdk/Cargo.toml
@@ -12,8 +12,6 @@ aws-sdk-s3 = "0.24"
 lambda_runtime = { path = "../../lambda-runtime" }
 serde = "1.0.136"
 tokio = { version = "1", features = ["macros"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
 
 [dev-dependencies]
 mockall = "0.11.3"
diff --git a/examples/basic-sdk/src/main.rs b/examples/basic-sdk/src/main.rs
index 6e2654a4..d49c84e1 100644
--- a/examples/basic-sdk/src/main.rs
+++ b/examples/basic-sdk/src/main.rs
@@ -1,6 +1,6 @@
 use async_trait::async_trait;
 use aws_sdk_s3::{output::ListObjectsV2Output, Client as S3Client};
-use lambda_runtime::{service_fn, Error, LambdaEvent};
+use lambda_runtime::{service_fn, tracing, Error, LambdaEvent};
 use serde::{Deserialize, Serialize};
 
 /// The request defines what bucket to list
@@ -34,13 +34,7 @@ impl ListObjects for S3Client {
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     let shared_config = aws_config::load_from_env().await;
     let client = S3Client::new(&shared_config);
diff --git a/examples/basic-shared-resource/Cargo.toml b/examples/basic-shared-resource/Cargo.toml
index b3e2faa5..2aad5886 100644
--- a/examples/basic-shared-resource/Cargo.toml
+++ b/examples/basic-shared-resource/Cargo.toml
@@ -3,17 +3,7 @@ name = "shared-resource"
 version = "0.1.0"
 edition = "2021"
 
-
-# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
-# to manage dependencies.
-# Running `cargo add DEPENDENCY_NAME` will
-# add the latest version of a dependency to the list,
-# and it will keep the alphabetic ordering for you.
-
 [dependencies]
 lambda_runtime = { path = "../../lambda-runtime" }
 serde = "1.0.136"
 tokio = { version = "1", features = ["macros"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
-
diff --git a/examples/basic-shared-resource/src/main.rs b/examples/basic-shared-resource/src/main.rs
index 15ababa0..795c2c97 100644
--- a/examples/basic-shared-resource/src/main.rs
+++ b/examples/basic-shared-resource/src/main.rs
@@ -4,7 +4,7 @@
 // Run it with the following input:
 // { "command": "do something" }
 
-use lambda_runtime::{service_fn, Error, LambdaEvent};
+use lambda_runtime::{service_fn, tracing, Error, LambdaEvent};
 use serde::{Deserialize, Serialize};
 
 /// This is also a made-up example. Requests come into the runtime as unicode
@@ -45,13 +45,7 @@ impl SharedClient {
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     let client = SharedClient::new("Shared Client 1 (perhaps a database)");
     let client_ref = &client;
diff --git a/examples/basic-sqs/Cargo.toml b/examples/basic-sqs/Cargo.toml
index 9d259218..0df7d8e2 100644
--- a/examples/basic-sqs/Cargo.toml
+++ b/examples/basic-sqs/Cargo.toml
@@ -19,5 +19,3 @@ aws_lambda_events = { path = "../../lambda-events" }
 lambda_runtime = { path = "../../lambda-runtime" }
 serde = "1.0.136"
 tokio = { version = "1", features = ["macros"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
diff --git a/examples/basic-sqs/src/main.rs b/examples/basic-sqs/src/main.rs
index 63967893..f04272be 100644
--- a/examples/basic-sqs/src/main.rs
+++ b/examples/basic-sqs/src/main.rs
@@ -1,5 +1,5 @@
 use aws_lambda_events::event::sqs::SqsEventObj;
-use lambda_runtime::{run, service_fn, Error, LambdaEvent};
+use lambda_runtime::{run, service_fn, tracing, Error, LambdaEvent};
 use serde::{Deserialize, Serialize};
 
 /// Object that you send to SQS and plan to process on the function.
@@ -21,13 +21,7 @@ async fn function_handler(event: LambdaEvent<SqsEventObj<Data>>) -> Result<(), E
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     run(service_fn(function_handler)).await
 }
diff --git a/examples/basic-streaming-response/Cargo.toml b/examples/basic-streaming-response/Cargo.toml
index e9b7499c..3f1bacac 100644
--- a/examples/basic-streaming-response/Cargo.toml
+++ b/examples/basic-streaming-response/Cargo.toml
@@ -8,6 +8,4 @@ edition = "2021"
 [dependencies]
 lambda_runtime = { path = "../../lambda-runtime" }
 tokio = { version = "1", features = ["macros"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
 serde_json = "1.0"
\ No newline at end of file
diff --git a/examples/basic-streaming-response/src/main.rs b/examples/basic-streaming-response/src/main.rs
index c8932554..8533c8e3 100644
--- a/examples/basic-streaming-response/src/main.rs
+++ b/examples/basic-streaming-response/src/main.rs
@@ -1,7 +1,7 @@
 use lambda_runtime::{
     service_fn,
     streaming::{channel, Body, Response},
-    Error, LambdaEvent,
+    tracing, Error, LambdaEvent,
 };
 use serde_json::Value;
 use std::{thread, time::Duration};
@@ -24,13 +24,7 @@ async fn func(_event: LambdaEvent<Value>) -> Result<Response<Body>, Error> {
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     lambda_runtime::run(service_fn(func)).await?;
     Ok(())
diff --git a/examples/extension-basic/Cargo.toml b/examples/extension-basic/Cargo.toml
index caf0818c..48e2ed51 100644
--- a/examples/extension-basic/Cargo.toml
+++ b/examples/extension-basic/Cargo.toml
@@ -3,18 +3,7 @@ name = "extension-basic"
 version = "0.1.0"
 edition = "2021"
 
-
-# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
-# to manage dependencies.
-# Running `cargo add DEPENDENCY_NAME` will
-# add the latest version of a dependency to the list,
-# and it will keep the alphabetic ordering for you.
-
 [dependencies]
 lambda-extension = { path = "../../lambda-extension" }
 serde = "1.0.136"
 tokio = { version = "1", features = ["macros"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
-
-
diff --git a/examples/extension-basic/src/main.rs b/examples/extension-basic/src/main.rs
index f9838c6b..e76d638f 100644
--- a/examples/extension-basic/src/main.rs
+++ b/examples/extension-basic/src/main.rs
@@ -1,4 +1,4 @@
-use lambda_extension::{service_fn, Error, LambdaEvent, NextEvent};
+use lambda_extension::{service_fn, tracing, Error, LambdaEvent, NextEvent};
 
 async fn my_extension(event: LambdaEvent) -> Result<(), Error> {
     match event.next {
@@ -15,13 +15,7 @@ async fn my_extension(event: LambdaEvent) -> Result<(), Error> {
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     let func = service_fn(my_extension);
     lambda_extension::run(func).await
diff --git a/examples/extension-combined/Cargo.toml b/examples/extension-combined/Cargo.toml
index d776f488..2a745c7b 100644
--- a/examples/extension-combined/Cargo.toml
+++ b/examples/extension-combined/Cargo.toml
@@ -3,18 +3,7 @@ name = "extension-combined"
 version = "0.1.0"
 edition = "2021"
 
-
-# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
-# to manage dependencies.
-# Running `cargo add DEPENDENCY_NAME` will
-# add the latest version of a dependency to the list,
-# and it will keep the alphabetic ordering for you.
-
 [dependencies]
 lambda-extension = { path = "../../lambda-extension" }
 serde = "1.0.136"
 tokio = { version = "1", features = ["macros"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
-
-
diff --git a/examples/extension-combined/src/main.rs b/examples/extension-combined/src/main.rs
index e05b1b7d..ce6054e8 100644
--- a/examples/extension-combined/src/main.rs
+++ b/examples/extension-combined/src/main.rs
@@ -1,7 +1,6 @@
 use lambda_extension::{
-    service_fn, Error, Extension, LambdaEvent, LambdaLog, LambdaLogRecord, NextEvent, SharedService,
+    service_fn, tracing, Error, Extension, LambdaEvent, LambdaLog, LambdaLogRecord, NextEvent, SharedService,
 };
-use tracing::info;
 
 async fn my_extension(event: LambdaEvent) -> Result<(), Error> {
     match event.next {
@@ -18,8 +17,8 @@ async fn my_extension(event: LambdaEvent) -> Result<(), Error> {
 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),
+            LambdaLogRecord::Function(record) => tracing::info!("[logs] [function] {}", record),
+            LambdaLogRecord::Extension(record) => tracing::info!("[logs] [extension] {}", record),
             _ => (),
         }
     }
@@ -30,13 +29,7 @@ async fn my_log_processor(logs: Vec<LambdaLog>) -> Result<(), Error> {
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     let func = service_fn(my_extension);
     let logs_processor = SharedService::new(service_fn(my_log_processor));
diff --git a/examples/extension-custom-events/Cargo.toml b/examples/extension-custom-events/Cargo.toml
index a826a137..c2f813c3 100644
--- a/examples/extension-custom-events/Cargo.toml
+++ b/examples/extension-custom-events/Cargo.toml
@@ -3,18 +3,7 @@ name = "extension-custom-events"
 version = "0.1.0"
 edition = "2021"
 
-
-# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
-# to manage dependencies.
-# Running `cargo add DEPENDENCY_NAME` will
-# add the latest version of a dependency to the list,
-# and it will keep the alphabetic ordering for you.
-
 [dependencies]
 lambda-extension = { path = "../../lambda-extension" }
 serde = "1.0.136"
 tokio = { version = "1", features = ["macros"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
-
-
diff --git a/examples/extension-custom-events/src/main.rs b/examples/extension-custom-events/src/main.rs
index 1d39e20f..1590e14a 100644
--- a/examples/extension-custom-events/src/main.rs
+++ b/examples/extension-custom-events/src/main.rs
@@ -1,4 +1,4 @@
-use lambda_extension::{service_fn, Error, Extension, LambdaEvent, NextEvent};
+use lambda_extension::{service_fn, tracing, Error, Extension, LambdaEvent, NextEvent};
 
 async fn my_extension(event: LambdaEvent) -> Result<(), Error> {
     match event.next {
@@ -17,13 +17,7 @@ async fn my_extension(event: LambdaEvent) -> Result<(), Error> {
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     Extension::new()
         .with_events(&["SHUTDOWN"])
diff --git a/examples/extension-custom-service/Cargo.toml b/examples/extension-custom-service/Cargo.toml
index c9ff789a..b51eae8e 100644
--- a/examples/extension-custom-service/Cargo.toml
+++ b/examples/extension-custom-service/Cargo.toml
@@ -3,18 +3,7 @@ name = "extension-custom-service"
 version = "0.1.0"
 edition = "2021"
 
-
-# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
-# to manage dependencies.
-# Running `cargo add DEPENDENCY_NAME` will
-# add the latest version of a dependency to the list,
-# and it will keep the alphabetic ordering for you.
-
 [dependencies]
 lambda-extension = { path = "../../lambda-extension" }
 serde = "1.0.136"
 tokio = { version = "1", features = ["macros"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
-
-
diff --git a/examples/extension-custom-service/src/main.rs b/examples/extension-custom-service/src/main.rs
index ec8ca68f..9a97732c 100644
--- a/examples/extension-custom-service/src/main.rs
+++ b/examples/extension-custom-service/src/main.rs
@@ -1,4 +1,4 @@
-use lambda_extension::{run, Error, InvokeEvent, LambdaEvent, NextEvent, Service};
+use lambda_extension::{run, tracing, Error, InvokeEvent, LambdaEvent, NextEvent, Service};
 use std::{
     future::{ready, Future},
     pin::Pin,
@@ -34,13 +34,7 @@ impl Service<LambdaEvent> for MyExtension {
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     run(MyExtension::default()).await
 }
diff --git a/examples/extension-internal-flush/src/main.rs b/examples/extension-internal-flush/src/main.rs
index 3706809d..ff1d10da 100644
--- a/examples/extension-internal-flush/src/main.rs
+++ b/examples/extension-internal-flush/src/main.rs
@@ -1,6 +1,6 @@
 use anyhow::anyhow;
 use aws_lambda_events::sqs::{SqsBatchResponse, SqsEventObj};
-use lambda_extension::{service_fn, Error, Extension, NextEvent};
+use lambda_extension::{service_fn, tracing, Error, Extension, NextEvent};
 use serde::{Deserialize, Serialize};
 use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
 use tokio::sync::Mutex;
@@ -81,6 +81,7 @@ impl EventHandler {
 
 #[tokio::main]
 async fn main() -> Result<(), Error> {
+    tracing::init_default_subscriber();
     let (request_done_sender, request_done_receiver) = unbounded_channel::<()>();
 
     let flush_extension = Arc::new(FlushExtension::new(request_done_receiver));
diff --git a/examples/extension-logs-basic/Cargo.toml b/examples/extension-logs-basic/Cargo.toml
index d1983db8..dccc1ec0 100644
--- a/examples/extension-logs-basic/Cargo.toml
+++ b/examples/extension-logs-basic/Cargo.toml
@@ -3,18 +3,7 @@ name = "extension-logs-basic"
 version = "0.1.0"
 edition = "2021"
 
-
-# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
-# to manage dependencies.
-# Running `cargo add DEPENDENCY_NAME` will
-# add the latest version of a dependency to the list,
-# and it will keep the alphabetic ordering for you.
-
 [dependencies]
 lambda-extension = { path = "../../lambda-extension" }
 serde = "1.0.136"
 tokio = { version = "1", features = ["macros", "rt"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
-
-
diff --git a/examples/extension-logs-basic/src/main.rs b/examples/extension-logs-basic/src/main.rs
index 77065cca..4d2662e4 100644
--- a/examples/extension-logs-basic/src/main.rs
+++ b/examples/extension-logs-basic/src/main.rs
@@ -1,4 +1,4 @@
-use lambda_extension::{service_fn, Error, Extension, LambdaLog, LambdaLogRecord, SharedService};
+use lambda_extension::{service_fn, tracing, Error, Extension, LambdaLog, LambdaLogRecord, SharedService};
 use tracing::info;
 
 async fn handler(logs: Vec<LambdaLog>) -> Result<(), Error> {
@@ -16,13 +16,7 @@ async fn handler(logs: Vec<LambdaLog>) -> Result<(), Error> {
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     let logs_processor = SharedService::new(service_fn(handler));
 
diff --git a/examples/extension-logs-custom-service/Cargo.toml b/examples/extension-logs-custom-service/Cargo.toml
index cbbe20f6..1b1eea0a 100644
--- a/examples/extension-logs-custom-service/Cargo.toml
+++ b/examples/extension-logs-custom-service/Cargo.toml
@@ -3,18 +3,7 @@ name = "extension-logs-custom-service"
 version = "0.1.0"
 edition = "2021"
 
-
-# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
-# to manage dependencies.
-# Running `cargo add DEPENDENCY_NAME` will
-# add the latest version of a dependency to the list,
-# and it will keep the alphabetic ordering for you.
-
 [dependencies]
 lambda-extension = { path = "../../lambda-extension" }
 serde = "1.0.136"
 tokio = { version = "1", features = ["macros"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
-
-
diff --git a/examples/extension-logs-custom-service/src/main.rs b/examples/extension-logs-custom-service/src/main.rs
index ebe1330d..ad2db5bc 100644
--- a/examples/extension-logs-custom-service/src/main.rs
+++ b/examples/extension-logs-custom-service/src/main.rs
@@ -1,4 +1,4 @@
-use lambda_extension::{Error, Extension, LambdaLog, LambdaLogRecord, Service, SharedService};
+use lambda_extension::{tracing, Error, Extension, LambdaLog, LambdaLogRecord, Service, SharedService};
 use std::{
     future::{ready, Future},
     pin::Pin,
@@ -8,7 +8,6 @@ use std::{
     },
     task::Poll,
 };
-use tracing::info;
 
 /// Custom log processor that increments a counter for each log record.
 ///
@@ -44,8 +43,8 @@ impl Service<Vec<LambdaLog>> for MyLogsProcessor {
         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),
+                LambdaLogRecord::Function(record) => tracing::info!("[logs] [function] {}: {}", counter, record),
+                LambdaLogRecord::Extension(record) => tracing::info!("[logs] [extension] {}: {}", counter, record),
                 _ => (),
             }
         }
@@ -57,13 +56,7 @@ impl Service<Vec<LambdaLog>> for MyLogsProcessor {
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     let logs_processor = SharedService::new(MyLogsProcessor::new());
 
diff --git a/examples/extension-logs-kinesis-firehose/Cargo.toml b/examples/extension-logs-kinesis-firehose/Cargo.toml
index 0e056b1c..c6675e5a 100644
--- a/examples/extension-logs-kinesis-firehose/Cargo.toml
+++ b/examples/extension-logs-kinesis-firehose/Cargo.toml
@@ -3,17 +3,8 @@ name = "lambda-logs-firehose-extension"
 version = "0.1.0"
 edition = "2021"
 
-# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
-# to manage dependencies.
-# Running `cargo add DEPENDENCY_NAME` will
-# add the latest version of a dependency to the list,
-# and it will keep the alphabetic ordering for you.
-
 [dependencies]
 lambda-extension = { path = "../../lambda-extension" }
 tokio = { version = "1.17.0", features = ["full"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
 aws-config = "0.13.0"
 aws-sdk-firehose = "0.13.0"
-
diff --git a/examples/extension-logs-kinesis-firehose/src/main.rs b/examples/extension-logs-kinesis-firehose/src/main.rs
index 8586e1a9..7871ce52 100644
--- a/examples/extension-logs-kinesis-firehose/src/main.rs
+++ b/examples/extension-logs-kinesis-firehose/src/main.rs
@@ -1,5 +1,5 @@
 use aws_sdk_firehose::{model::Record, types::Blob, Client};
-use lambda_extension::{Error, Extension, LambdaLog, LambdaLogRecord, Service, SharedService};
+use lambda_extension::{tracing, Error, Extension, LambdaLog, LambdaLogRecord, Service, SharedService};
 use std::{future::Future, pin::Pin, task::Poll};
 
 #[derive(Clone)]
@@ -54,13 +54,7 @@ impl Service<Vec<LambdaLog>> for FirehoseLogsProcessor {
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     let config = aws_config::load_from_env().await;
     let logs_processor = SharedService::new(FirehoseLogsProcessor::new(Client::new(&config)));
diff --git a/examples/extension-telemetry-basic/Cargo.toml b/examples/extension-telemetry-basic/Cargo.toml
index 869b604d..1b8b1ba4 100644
--- a/examples/extension-telemetry-basic/Cargo.toml
+++ b/examples/extension-telemetry-basic/Cargo.toml
@@ -3,18 +3,7 @@ name = "extension-telemetry-basic"
 version = "0.1.0"
 edition = "2021"
 
-
-# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
-# to manage dependencies.
-# Running `cargo add DEPENDENCY_NAME` will
-# add the latest version of a dependency to the list,
-# and it will keep the alphabetic ordering for you.
-
 [dependencies]
 lambda-extension = { path = "../../lambda-extension" }
 serde = "1.0.136"
 tokio = { version = "1", features = ["macros", "rt"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
-
-
diff --git a/examples/extension-telemetry-basic/src/main.rs b/examples/extension-telemetry-basic/src/main.rs
index 03974bf6..7159cf93 100644
--- a/examples/extension-telemetry-basic/src/main.rs
+++ b/examples/extension-telemetry-basic/src/main.rs
@@ -1,28 +1,27 @@
-use lambda_extension::{service_fn, Error, Extension, LambdaTelemetry, LambdaTelemetryRecord, SharedService};
-use tracing::info;
+use lambda_extension::{service_fn, tracing, Error, Extension, LambdaTelemetry, LambdaTelemetryRecord, SharedService};
 
 async fn handler(events: Vec<LambdaTelemetry>) -> Result<(), Error> {
     for event in events {
         match event.record {
-            LambdaTelemetryRecord::Function(record) => info!("[logs] [function] {}", record),
+            LambdaTelemetryRecord::Function(record) => tracing::info!("[logs] [function] {}", record),
             LambdaTelemetryRecord::PlatformInitStart {
                 initialization_type: _,
                 phase: _,
                 runtime_version: _,
                 runtime_version_arn: _,
-            } => info!("[platform] Initialization started"),
+            } => tracing::info!("[platform] Initialization started"),
             LambdaTelemetryRecord::PlatformInitRuntimeDone {
                 initialization_type: _,
                 phase: _,
                 status: _,
                 error_type: _,
                 spans: _,
-            } => info!("[platform] Initialization finished"),
+            } => tracing::info!("[platform] Initialization finished"),
             LambdaTelemetryRecord::PlatformStart {
                 request_id,
                 version: _,
                 tracing: _,
-            } => info!("[platform] Handling of request {} started", request_id),
+            } => tracing::info!("[platform] Handling of request {} started", request_id),
             LambdaTelemetryRecord::PlatformRuntimeDone {
                 request_id,
                 status: _,
@@ -30,7 +29,7 @@ async fn handler(events: Vec<LambdaTelemetry>) -> Result<(), Error> {
                 metrics: _,
                 spans: _,
                 tracing: _,
-            } => info!("[platform] Handling of request {} finished", request_id),
+            } => tracing::info!("[platform] Handling of request {} finished", request_id),
             _ => (),
         }
     }
@@ -41,13 +40,7 @@ async fn handler(events: Vec<LambdaTelemetry>) -> Result<(), Error> {
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     let telemetry_processor = SharedService::new(service_fn(handler));
 
diff --git a/examples/http-axum-apigw-authorizer/Cargo.toml b/examples/http-axum-apigw-authorizer/Cargo.toml
index 5c3e806e..c757aa94 100644
--- a/examples/http-axum-apigw-authorizer/Cargo.toml
+++ b/examples/http-axum-apigw-authorizer/Cargo.toml
@@ -10,5 +10,3 @@ lambda_runtime = { path = "../../lambda-runtime" }
 serde = "1.0.196"
 serde_json = "1.0"
 tokio = { version = "1", features = ["macros"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
diff --git a/examples/http-axum-apigw-authorizer/src/main.rs b/examples/http-axum-apigw-authorizer/src/main.rs
index bb03de07..513a6cd8 100644
--- a/examples/http-axum-apigw-authorizer/src/main.rs
+++ b/examples/http-axum-apigw-authorizer/src/main.rs
@@ -6,7 +6,7 @@ use axum::{
     routing::get,
     Router,
 };
-use lambda_http::{run, Error, RequestExt};
+use lambda_http::{run, tracing, Error, RequestExt};
 use serde_json::{json, Value};
 use std::{collections::HashMap, env::set_var};
 
@@ -76,13 +76,7 @@ async fn main() -> Result<(), Error> {
     set_var("AWS_LAMBDA_HTTP_IGNORE_STAGE_IN_PATH", "true");
 
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     let app = Router::new()
         .route("/extract-field", get(extract_field))
diff --git a/examples/http-axum-diesel-ssl/Cargo.toml b/examples/http-axum-diesel-ssl/Cargo.toml
index 006a82ce..69366957 100755
--- a/examples/http-axum-diesel-ssl/Cargo.toml
+++ b/examples/http-axum-diesel-ssl/Cargo.toml
@@ -3,13 +3,6 @@ name = "http-axum-diesel"
 version = "0.1.0"
 edition = "2021"
 
-
-# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
-# to manage dependencies.
-# Running `cargo add DEPENDENCY_NAME` will
-# add the latest version of a dependency to the list,
-# and it will keep the alphabetic ordering for you.
-
 [dependencies]
 axum = "0.7"
 bb8 = "0.8.0"
@@ -18,8 +11,6 @@ diesel-async = { version = "0.2.1", features = ["postgres", "bb8"] }
 lambda_http = { path = "../../lambda-http" }
 lambda_runtime = { path = "../../lambda-runtime" }
 serde = "1.0.159"
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
 futures-util = "0.3.21"
 rustls = "0.20.8"
 rustls-native-certs = "0.6.2"
diff --git a/examples/http-axum-diesel-ssl/src/main.rs b/examples/http-axum-diesel-ssl/src/main.rs
index c2f6b933..b340b44d 100755
--- a/examples/http-axum-diesel-ssl/src/main.rs
+++ b/examples/http-axum-diesel-ssl/src/main.rs
@@ -12,7 +12,7 @@ use axum::{
 use bb8::Pool;
 use diesel::prelude::*;
 use diesel_async::{pooled_connection::AsyncDieselConnectionManager, AsyncPgConnection, RunQueryDsl};
-use lambda_http::{http::StatusCode, run, Error};
+use lambda_http::{http::StatusCode, run, tracing, Error};
 use serde::{Deserialize, Serialize};
 
 table! {
@@ -98,22 +98,13 @@ fn internal_server_error<E: std::error::Error>(err: E) -> ServerError {
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     // Set up the database connection
     // Format for DATABASE_URL=postgres://your_username:your_password@your_host:5432/your_db?sslmode=require
     let db_url = std::env::var("DATABASE_URL").expect("Env var `DATABASE_URL` not set");
 
-    let mgr = AsyncDieselConnectionManager::<AsyncPgConnection>::new_with_setup(
-        db_url,
-        establish_connection,
-    );
+    let mgr = AsyncDieselConnectionManager::<AsyncPgConnection>::new_with_setup(db_url, establish_connection);
 
     let pool = Pool::builder()
         .max_size(10)
@@ -122,7 +113,7 @@ async fn main() -> Result<(), Error> {
         .idle_timeout(Some(Duration::from_secs(60 * 2)))
         .build(mgr)
         .await?;
-        
+
     // Set up the API routes
     let posts_api = Router::new()
         .route("/", get(list_posts).post(create_post))
@@ -134,7 +125,6 @@ async fn main() -> Result<(), Error> {
     run(app).await
 }
 
-
 fn establish_connection(config: &str) -> BoxFuture<ConnectionResult<AsyncPgConnection>> {
     let fut = async {
         // We first set up the way we want rustls to work.
diff --git a/examples/http-axum-diesel/Cargo.toml b/examples/http-axum-diesel/Cargo.toml
index 0366f32d..39fc813e 100644
--- a/examples/http-axum-diesel/Cargo.toml
+++ b/examples/http-axum-diesel/Cargo.toml
@@ -3,13 +3,6 @@ name = "http-axum-diesel"
 version = "0.1.0"
 edition = "2021"
 
-
-# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
-# to manage dependencies.
-# Running `cargo add DEPENDENCY_NAME` will
-# add the latest version of a dependency to the list,
-# and it will keep the alphabetic ordering for you.
-
 [dependencies]
 axum = "0.7"
 bb8 = "0.8.0"
@@ -19,5 +12,3 @@ lambda_http = { path = "../../lambda-http" }
 lambda_runtime = { path = "../../lambda-runtime" }
 serde = "1.0.159"
 tokio = { version = "1", features = ["macros"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
diff --git a/examples/http-axum-diesel/src/main.rs b/examples/http-axum-diesel/src/main.rs
index bb47152d..b7247be4 100644
--- a/examples/http-axum-diesel/src/main.rs
+++ b/examples/http-axum-diesel/src/main.rs
@@ -7,7 +7,7 @@ use axum::{
 use bb8::Pool;
 use diesel::prelude::*;
 use diesel_async::{pooled_connection::AsyncDieselConnectionManager, AsyncPgConnection, RunQueryDsl};
-use lambda_http::{http::StatusCode, run, Error};
+use lambda_http::{http::StatusCode, run, tracing, Error};
 use serde::{Deserialize, Serialize};
 
 table! {
@@ -93,13 +93,7 @@ fn internal_server_error<E: std::error::Error>(err: E) -> ServerError {
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     // Set up the database connection
     let db_url = std::env::var("DATABASE_URL").expect("missing DATABASE_URL environment variable");
diff --git a/examples/http-axum-middleware/Cargo.toml b/examples/http-axum-middleware/Cargo.toml
index ea437052..228fc0ae 100644
--- a/examples/http-axum-middleware/Cargo.toml
+++ b/examples/http-axum-middleware/Cargo.toml
@@ -6,13 +6,8 @@ edition = "2021"
 [dependencies]
 axum = "0.7"
 lambda_http = { path = "../../lambda-http", default-features = false, features = [
-  "apigw_rest",
+  "apigw_rest", "tracing"
 ] }
 lambda_runtime = { path = "../../lambda-runtime" }
 serde_json = "1.0"
 tokio = { version = "1", features = ["macros"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = [
-  "fmt",
-] }
-
diff --git a/examples/http-axum-middleware/src/main.rs b/examples/http-axum-middleware/src/main.rs
index 41c5bf4b..b1e92811 100644
--- a/examples/http-axum-middleware/src/main.rs
+++ b/examples/http-axum-middleware/src/main.rs
@@ -11,7 +11,7 @@
 
 use axum::{response::Json, routing::post, Router};
 use lambda_http::request::RequestContext::ApiGatewayV1;
-use lambda_http::{run, Error};
+use lambda_http::{run, tracing, Error};
 use serde_json::{json, Value};
 
 // Sample middleware that logs the request id
@@ -29,11 +29,7 @@ async fn handler_sample(body: Json<Value>) -> Json<Value> {
 
 #[tokio::main]
 async fn main() -> Result<(), Error> {
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        .with_target(false)
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     let app = Router::new()
         .route("/testStage/hello/world", post(handler_sample))
diff --git a/examples/http-axum/Cargo.toml b/examples/http-axum/Cargo.toml
index 5257bdb0..7ab3c0ec 100644
--- a/examples/http-axum/Cargo.toml
+++ b/examples/http-axum/Cargo.toml
@@ -3,13 +3,6 @@ name = "http-axum"
 version = "0.1.0"
 edition = "2021"
 
-
-# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
-# to manage dependencies.
-# Running `cargo add DEPENDENCY_NAME` will
-# add the latest version of a dependency to the list,
-# and it will keep the alphabetic ordering for you.
-
 [dependencies]
 axum = "0.7"
 lambda_http = { path = "../../lambda-http" }
@@ -17,5 +10,3 @@ lambda_runtime = { path = "../../lambda-runtime" }
 serde = "1.0.196"
 serde_json = "1.0"
 tokio = { version = "1", features = ["macros"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
diff --git a/examples/http-axum/src/main.rs b/examples/http-axum/src/main.rs
index ae7b0921..dcd5d154 100644
--- a/examples/http-axum/src/main.rs
+++ b/examples/http-axum/src/main.rs
@@ -14,7 +14,7 @@ use axum::{
     routing::{get, post},
     Router,
 };
-use lambda_http::{run, Error};
+use lambda_http::{run, tracing, Error};
 use serde::{Deserialize, Serialize};
 use serde_json::{json, Value};
 use std::env::set_var;
@@ -65,13 +65,7 @@ async fn main() -> Result<(), Error> {
     set_var("AWS_LAMBDA_HTTP_IGNORE_STAGE_IN_PATH", "true");
 
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     let app = Router::new()
         .route("/", get(root))
diff --git a/examples/http-basic-lambda/Cargo.toml b/examples/http-basic-lambda/Cargo.toml
index 1a218330..c7a51507 100644
--- a/examples/http-basic-lambda/Cargo.toml
+++ b/examples/http-basic-lambda/Cargo.toml
@@ -3,18 +3,7 @@ name = "http-basic-lambda"
 version = "0.1.0"
 edition = "2021"
 
-
-# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
-# to manage dependencies.
-# Running `cargo add DEPENDENCY_NAME` will
-# add the latest version of a dependency to the list,
-# and it will keep the alphabetic ordering for you.
-
 [dependencies]
 lambda_http = { path = "../../lambda-http" }
 lambda_runtime = { path = "../../lambda-runtime" }
 tokio = { version = "1", features = ["macros"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
-
-
diff --git a/examples/http-basic-lambda/src/main.rs b/examples/http-basic-lambda/src/main.rs
index 5794dc8b..d0e41561 100644
--- a/examples/http-basic-lambda/src/main.rs
+++ b/examples/http-basic-lambda/src/main.rs
@@ -1,4 +1,4 @@
-use lambda_http::{run, service_fn, Body, Error, Request, Response};
+use lambda_http::{run, service_fn, tracing, Body, Error, Request, Response};
 
 /// This is the main body for the function.
 /// Write your code inside it.
@@ -20,13 +20,7 @@ async fn function_handler(_event: Request) -> Result<Response<Body>, Error> {
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     run(service_fn(function_handler)).await
 }
diff --git a/examples/http-cors/Cargo.toml b/examples/http-cors/Cargo.toml
index 059a3f63..b8e51031 100644
--- a/examples/http-cors/Cargo.toml
+++ b/examples/http-cors/Cargo.toml
@@ -3,19 +3,8 @@ name = "http-cors"
 version = "0.1.0"
 edition = "2021"
 
-
-# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
-# to manage dependencies.
-# Running `cargo add DEPENDENCY_NAME` will
-# add the latest version of a dependency to the list,
-# and it will keep the alphabetic ordering for you.
-
 [dependencies]
 lambda_http = { path = "../../lambda-http" }
 lambda_runtime = { path = "../../lambda-runtime" }
 tokio = { version = "1", features = ["macros"] }
 tower-http = { version = "0.5", features = ["cors"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
-
-
diff --git a/examples/http-cors/src/main.rs b/examples/http-cors/src/main.rs
index e60fb441..ffac0a9e 100644
--- a/examples/http-cors/src/main.rs
+++ b/examples/http-cors/src/main.rs
@@ -1,18 +1,12 @@
 use lambda_http::{
-    http::Method, service_fn, tower::ServiceBuilder, Body, Error, IntoResponse, Request, RequestExt, Response,
+    http::Method, service_fn, tower::ServiceBuilder, tracing, Body, Error, IntoResponse, Request, RequestExt, Response,
 };
 use tower_http::cors::{Any, CorsLayer};
 
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     // Define a layer to inject CORS headers
     let cors_layer = CorsLayer::new()
diff --git a/examples/http-dynamodb/Cargo.toml b/examples/http-dynamodb/Cargo.toml
index be95f867..f2b8db98 100644
--- a/examples/http-dynamodb/Cargo.toml
+++ b/examples/http-dynamodb/Cargo.toml
@@ -3,24 +3,12 @@ name = "http-dynamodb"
 version = "0.1.0"
 edition = "2021"
 
-
-# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
-# to manage dependencies.
-# Running `cargo add DEPENDENCY_NAME` will
-# add the latest version of a dependency to the list,
-# and it will keep the alphabetic ordering for you.
-
 [dependencies]
 simple-error = "0.3.0"
 serde_json = "1.0.107"
 serde = { version = "1.0.189", features = ["derive"] }
 serde_dynamo = {version = "^4.2.7", features = ["aws-sdk-dynamodb+0_33"]}
 lambda_http = { path = "../../lambda-http" }
-lambda_runtime = { path = "../../lambda-runtime" }
 aws-sdk-dynamodb = "0.33.0"
 aws-config = "0.56.1"
 tokio = { version = "1.33.0", features = ["macros"] }
-tracing = { version = "0.1.40", features = ["log"] }
-tracing-subscriber = { version = "0.3.17", default-features = false, features = ["fmt"] }
-
-
diff --git a/examples/http-dynamodb/src/main.rs b/examples/http-dynamodb/src/main.rs
index b2e8af20..e5cbb2a3 100644
--- a/examples/http-dynamodb/src/main.rs
+++ b/examples/http-dynamodb/src/main.rs
@@ -1,8 +1,7 @@
-use aws_sdk_dynamodb::{Client};
-use lambda_http::{run, service_fn, Body, Error, Request, Response};
+use aws_sdk_dynamodb::Client;
+use lambda_http::{run, service_fn, tracing, Body, Error, Request, Response};
 use serde::{Deserialize, Serialize};
 use serde_dynamo::to_attribute_value;
-use tracing::info;
 
 #[derive(Clone, Debug, Serialize, Deserialize)]
 pub struct Item {
@@ -22,7 +21,7 @@ async fn handle_request(db_client: &Client, event: Request) -> Result<Response<B
     let body = event.body();
     let s = std::str::from_utf8(body).expect("invalid utf-8 sequence");
     //Log into Cloudwatch
-    info!(payload = %s, "JSON Payload received");
+    tracing::info!(payload = %s, "JSON Payload received");
 
     //Serialze JSON into struct.
     //If JSON is incorrect, send back 400 with error.
@@ -56,13 +55,7 @@ async fn handle_request(db_client: &Client, event: Request) -> Result<Response<B
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     //Get config from environment.
     let config = aws_config::load_from_env().await;
@@ -93,7 +86,7 @@ pub async fn add_item(client: &Client, item: Item, table: &str) -> Result<(), Er
         .item("first_name", first_av)
         .item("last_name", last_av);
 
-    info!("adding item to DynamoDB");
+    tracing::info!("adding item to DynamoDB");
 
     let _resp = request.send().await?;
 
diff --git a/examples/http-query-parameters/Cargo.toml b/examples/http-query-parameters/Cargo.toml
index 7aeb1189..2cadda95 100644
--- a/examples/http-query-parameters/Cargo.toml
+++ b/examples/http-query-parameters/Cargo.toml
@@ -3,18 +3,7 @@ name = "http-query-parameters"
 version = "0.1.0"
 edition = "2021"
 
-
-# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
-# to manage dependencies.
-# Running `cargo add DEPENDENCY_NAME` will
-# add the latest version of a dependency to the list,
-# and it will keep the alphabetic ordering for you.
-
 [dependencies]
 lambda_http = { path = "../../lambda-http" }
 lambda_runtime = { path = "../../lambda-runtime" }
 tokio = { version = "1", features = ["macros"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
-
-
diff --git a/examples/http-query-parameters/src/main.rs b/examples/http-query-parameters/src/main.rs
index e189d12d..1f7110a5 100644
--- a/examples/http-query-parameters/src/main.rs
+++ b/examples/http-query-parameters/src/main.rs
@@ -1,4 +1,4 @@
-use lambda_http::{run, service_fn, Error, IntoResponse, Request, RequestExt, Response};
+use lambda_http::{run, service_fn, tracing, Error, IntoResponse, Request, RequestExt, Response};
 
 /// This is the main body for the function.
 /// Write your code inside it.
@@ -23,13 +23,7 @@ async fn function_handler(event: Request) -> Result<impl IntoResponse, Error> {
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     run(service_fn(function_handler)).await
 }
diff --git a/examples/http-raw-path/Cargo.toml b/examples/http-raw-path/Cargo.toml
index f4060428..f6c56526 100644
--- a/examples/http-raw-path/Cargo.toml
+++ b/examples/http-raw-path/Cargo.toml
@@ -3,18 +3,7 @@ name = "http-raw-path"
 version = "0.1.0"
 edition = "2021"
 
-
-# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
-# to manage dependencies.
-# Running `cargo add DEPENDENCY_NAME` will
-# add the latest version of a dependency to the list,
-# and it will keep the alphabetic ordering for you.
-
 [dependencies]
 lambda_http = { path = "../../lambda-http" }
 lambda_runtime = { path = "../../lambda-runtime" }
 tokio = { version = "1", features = ["macros"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
-
-
diff --git a/examples/http-raw-path/src/main.rs b/examples/http-raw-path/src/main.rs
index 7fa6e6d5..70b4df4d 100644
--- a/examples/http-raw-path/src/main.rs
+++ b/examples/http-raw-path/src/main.rs
@@ -1,15 +1,9 @@
-use lambda_http::{service_fn, Error, IntoResponse, Request, RequestExt};
+use lambda_http::{service_fn, tracing, Error, IntoResponse, Request, RequestExt};
 
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     lambda_http::run(service_fn(func)).await?;
     Ok(())
diff --git a/examples/http-shared-resource/Cargo.toml b/examples/http-shared-resource/Cargo.toml
index 207f253b..923ceecc 100644
--- a/examples/http-shared-resource/Cargo.toml
+++ b/examples/http-shared-resource/Cargo.toml
@@ -3,18 +3,7 @@ name = "http-shared-resource"
 version = "0.1.0"
 edition = "2021"
 
-
-# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
-# to manage dependencies.
-# Running `cargo add DEPENDENCY_NAME` will
-# add the latest version of a dependency to the list,
-# and it will keep the alphabetic ordering for you.
-
 [dependencies]
 lambda_http = { path = "../../lambda-http" }
 lambda_runtime = { path = "../../lambda-runtime" }
 tokio = { version = "1", features = ["macros"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
-
-
diff --git a/examples/http-shared-resource/src/main.rs b/examples/http-shared-resource/src/main.rs
index d76ccec4..cff9e785 100644
--- a/examples/http-shared-resource/src/main.rs
+++ b/examples/http-shared-resource/src/main.rs
@@ -1,4 +1,4 @@
-use lambda_http::{service_fn, Body, Error, IntoResponse, Request, RequestExt, Response};
+use lambda_http::{service_fn, tracing, Body, Error, IntoResponse, Request, RequestExt, Response};
 
 struct SharedClient {
     name: &'static str,
@@ -13,13 +13,7 @@ impl SharedClient {
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     // Create the "client" and a reference to it, so that we can pass this into the handler closure below.
     let shared_client = SharedClient {
diff --git a/examples/http-tower-trace/Cargo.toml b/examples/http-tower-trace/Cargo.toml
index 0b0c46a9..36389f0e 100644
--- a/examples/http-tower-trace/Cargo.toml
+++ b/examples/http-tower-trace/Cargo.toml
@@ -3,17 +3,8 @@ name = "http-tower-trace"
 version = "0.1.0"
 edition = "2021"
 
-
-# Use cargo-edit(https://github.com/killercup/cargo-edit#installation)
-# to manage dependencies.
-# Running `cargo add DEPENDENCY_NAME` will
-# add the latest version of a dependency to the list,
-# and it will keep the alphabetic ordering for you.
-
 [dependencies]
 lambda_http = { path = "../../lambda-http" }
 lambda_runtime = "0.5.1"
 tokio = { version = "1", features = ["macros"] }
 tower-http = { version = "0.5", features = ["trace"] }
-tracing = { version = "0.1", features = ["log"] }
-tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
diff --git a/examples/http-tower-trace/src/main.rs b/examples/http-tower-trace/src/main.rs
index 072f8256..df2b9007 100644
--- a/examples/http-tower-trace/src/main.rs
+++ b/examples/http-tower-trace/src/main.rs
@@ -1,7 +1,7 @@
+use lambda_http::tracing::{self, Level};
 use lambda_http::{run, tower::ServiceBuilder, Error};
 use lambda_http::{Request, Response};
 use tower_http::trace::{DefaultOnRequest, DefaultOnResponse, TraceLayer};
-use tracing::Level;
 
 async fn handler(_req: Request) -> Result<Response<String>, Error> {
     Ok(Response::new("Success".into()))
@@ -10,13 +10,7 @@ async fn handler(_req: Request) -> Result<Response<String>, Error> {
 #[tokio::main]
 async fn main() -> Result<(), Error> {
     // required to enable CloudWatch error logging by the runtime
-    tracing_subscriber::fmt()
-        .with_max_level(tracing::Level::INFO)
-        // disable printing the name of the module in every log line.
-        .with_target(false)
-        // disabling time is handy because CloudWatch will add the ingestion time.
-        .without_time()
-        .init();
+    tracing::init_default_subscriber();
 
     let layer = TraceLayer::new_for_http()
         .on_request(DefaultOnRequest::new().level(Level::INFO))
diff --git a/lambda-extension/Cargo.toml b/lambda-extension/Cargo.toml
index ba0898a3..aa11f1cb 100644
--- a/lambda-extension/Cargo.toml
+++ b/lambda-extension/Cargo.toml
@@ -13,6 +13,10 @@ categories = ["web-programming::http-server"]
 keywords = ["AWS", "Lambda", "API"]
 readme = "README.md"
 
+[features]
+default = ["tracing"]
+tracing = ["lambda_runtime_api_client/tracing"]
+
 [dependencies]
 async-stream = "0.3"
 bytes = { workspace = true }
@@ -24,7 +28,6 @@ hyper-util = { workspace = true }
 lambda_runtime_api_client = { version = "0.9", path = "../lambda-runtime-api-client" }
 serde = { version = "1", features = ["derive"] }
 serde_json = "^1"
-tracing = { version = "0.1", features = ["log"] }
 tokio = { version = "1.0", features = [
     "macros",
     "io-util",
@@ -33,3 +36,4 @@ tokio = { version = "1.0", features = [
 ] }
 tokio-stream = "0.1.2"
 tower = { version = "0.4", features = ["make", "util"] }
+tracing = { version = "0.1", features = ["log"] }
diff --git a/lambda-extension/src/lib.rs b/lambda-extension/src/lib.rs
index 796eb3ef..81c16337 100644
--- a/lambda-extension/src/lib.rs
+++ b/lambda-extension/src/lib.rs
@@ -23,6 +23,10 @@ pub use telemetry::*;
 /// Include several request builders to interact with the Extension API.
 pub mod requests;
 
+/// Utilities to initialize and use `tracing` and `tracing-subscriber` in Lambda Functions.
+#[cfg(feature = "tracing")]
+pub use lambda_runtime_api_client::tracing;
+
 /// Execute the given events processor
 pub async fn run<E>(events_processor: E) -> Result<(), Error>
 where
diff --git a/lambda-http/Cargo.toml b/lambda-http/Cargo.toml
index 9facc13d..8617e7ce 100644
--- a/lambda-http/Cargo.toml
+++ b/lambda-http/Cargo.toml
@@ -16,12 +16,13 @@ categories = ["web-programming::http-server"]
 readme = "README.md"
 
 [features]
-default = ["apigw_rest", "apigw_http", "apigw_websockets", "alb"]
+default = ["apigw_rest", "apigw_http", "apigw_websockets", "alb", "tracing"]
 apigw_rest = []
 apigw_http = []
 apigw_websockets = []
 alb = []
 pass_through = []
+tracing = ["lambda_runtime/tracing"]
 
 [dependencies]
 base64 = { workspace = true }
diff --git a/lambda-http/src/lib.rs b/lambda-http/src/lib.rs
index bc9e753d..265f5ef0 100644
--- a/lambda-http/src/lib.rs
+++ b/lambda-http/src/lib.rs
@@ -65,8 +65,10 @@
 extern crate maplit;
 
 pub use http::{self, Response};
-use lambda_runtime::LambdaEvent;
-pub use lambda_runtime::{self, service_fn, tower, Context, Error, Service};
+/// Utilities to initialize and use `tracing` and `tracing-subscriber` in Lambda Functions.
+#[cfg(feature = "tracing")]
+pub use lambda_runtime::tracing;
+pub use lambda_runtime::{self, service_fn, tower, Context, Error, LambdaEvent, Service};
 use request::RequestFuture;
 use response::ResponseFuture;
 
diff --git a/lambda-runtime-api-client/Cargo.toml b/lambda-runtime-api-client/Cargo.toml
index 12b26043..2fa13207 100644
--- a/lambda-runtime-api-client/Cargo.toml
+++ b/lambda-runtime-api-client/Cargo.toml
@@ -13,6 +13,10 @@ categories = ["web-programming::http-server"]
 keywords = ["AWS", "Lambda", "API"]
 readme = "README.md"
 
+[features]
+default = ["tracing"]
+tracing = ["dep:tracing", "dep:tracing-subscriber"]
+
 [dependencies]
 bytes = { workspace = true }
 futures-channel = { workspace = true }
@@ -30,3 +34,5 @@ hyper-util = { workspace = true, features = [
 tower = { workspace = true, features = ["util"] }
 tower-service = { workspace = true }
 tokio = { version = "1.0", features = ["io-util"] }
+tracing = { version = "0.1", features = ["log"], optional = true }
+tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt", "json", "env-filter"], optional = true }
diff --git a/lambda-runtime-api-client/src/lib.rs b/lambda-runtime-api-client/src/lib.rs
index ec7418ba..8e52d416 100644
--- a/lambda-runtime-api-client/src/lib.rs
+++ b/lambda-runtime-api-client/src/lib.rs
@@ -17,6 +17,9 @@ mod error;
 pub use error::*;
 pub mod body;
 
+#[cfg(feature = "tracing")]
+pub mod tracing;
+
 /// API client to interact with the AWS Lambda Runtime API.
 #[derive(Debug)]
 pub struct Client {
diff --git a/lambda-runtime-api-client/src/tracing.rs b/lambda-runtime-api-client/src/tracing.rs
new file mode 100644
index 00000000..babc817c
--- /dev/null
+++ b/lambda-runtime-api-client/src/tracing.rs
@@ -0,0 +1,41 @@
+//! This module provides primitives to work with `tracing`
+//! and `tracing-subscriber` in Lambda functions.
+//!
+//! The `tracing` and `tracing-subscriber` crates are re-exported
+//! so you don't have to include them as direct dependencies in
+//! your projects.
+
+use std::{env, str::FromStr};
+
+use subscriber::filter::{EnvFilter, LevelFilter};
+/// Re-export the `tracing` crate to have access to tracing macros
+/// like `info!`, `debug!`, `trace!` and so on.
+pub use tracing::*;
+
+/// Re-export the `tracing-subscriber` crate to build your own subscribers.
+pub use tracing_subscriber as subscriber;
+
+/// Initialize `tracing-subscriber` with default options.
+/// 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`.
+pub fn init_default_subscriber() {
+    let log_format = env::var("AWS_LAMBDA_LOG_FORMAT").unwrap_or_default();
+    let log_level = Level::from_str(&env::var("AWS_LAMBDA_LOG_LEVEL").unwrap_or_default()).unwrap_or(Level::INFO);
+
+    let collector = tracing_subscriber::fmt()
+        .with_target(false)
+        .without_time()
+        .with_env_filter(
+            EnvFilter::builder()
+                .with_default_directive(LevelFilter::from_level(log_level).into())
+                .from_env_lossy(),
+        );
+
+    if log_format.eq_ignore_ascii_case("json") {
+        collector.json().init()
+    } else {
+        collector.init()
+    }
+}
diff --git a/lambda-runtime/Cargo.toml b/lambda-runtime/Cargo.toml
index 94a3c201..1a34a67d 100644
--- a/lambda-runtime/Cargo.toml
+++ b/lambda-runtime/Cargo.toml
@@ -14,8 +14,8 @@ keywords = ["AWS", "Lambda", "API"]
 readme = "../README.md"
 
 [features]
-default = ["simulated"]
-simulated = []
+default = ["tracing"]
+tracing = ["lambda_runtime_api_client/tracing"]
 
 [dependencies]
 async-stream = "0.3"
diff --git a/lambda-runtime/src/lib.rs b/lambda-runtime/src/lib.rs
index b4964954..3fe56b03 100644
--- a/lambda-runtime/src/lib.rs
+++ b/lambda-runtime/src/lib.rs
@@ -7,6 +7,7 @@
 //! Create a type that conforms to the [`tower::Service`] trait. This type can
 //! then be passed to the the `lambda_runtime::run` function, which launches
 //! and runs the Lambda runtime.
+use ::tracing::{error, trace, Instrument};
 use bytes::Bytes;
 use futures::FutureExt;
 use http_body_util::BodyExt;
@@ -24,12 +25,16 @@ use std::{
 use tokio_stream::{Stream, StreamExt};
 pub use tower::{self, service_fn, Service};
 use tower::{util::ServiceFn, ServiceExt};
-use tracing::{error, trace, Instrument};
 
 mod deserializer;
 mod requests;
 /// Utilities for Lambda Streaming functions.
 pub mod streaming;
+
+/// Utilities to initialize and use `tracing` and `tracing-subscriber` in Lambda Functions.
+#[cfg(feature = "tracing")]
+pub use lambda_runtime_api_client::tracing;
+
 /// Types available to a Lambda function.
 mod types;
 


Test patch: