

# Rust Lambda 函数日志记录和监控
<a name="rust-logging"></a>

AWS Lambda 将代表您自动监控 Lambda 函数并将日志记录发送至 Amazon CloudWatch。您的 Lambda 函数带有一个 CloudWatch Logs 日志组以及函数的每个实例的日志流。Lambda 运行时环境会将每个调用的详细信息发送到日志流，然后中继函数代码的日志和其他输出。有关更多信息，请参阅 [将 Lambda 函数日志发送到 CloudWatch Logs](monitoring-cloudwatchlogs.md)。有关配置日志格式的信息，请参阅 [配置 JSON 和纯文本日志格式](monitoring-cloudwatchlogs-logformat.md)。本页将介绍如何从 Lambda 函数的代码生成日志输出。

## 创建写入日志的函数
<a name="rust-logging-function"></a>

要从函数代码输出日志，您可以使用写入到 `stdout` 或 `stderr` 的任何日志记录函数，例如 `println!` 宏。以下示例使用 `println!` 在函数处理程序启动时和完成之前输出消息。

```
use lambda_runtime::{service_fn, LambdaEvent, Error};
use serde_json::{json, Value};
async fn handler(event: LambdaEvent<Value>) -> Result<Value, Error> {
    println!("Rust function invoked");
    let payload = event.payload;
    let first_name = payload["firstName"].as_str().unwrap_or("world");
    println!("Rust function responds to {}", &first_name);
    Ok(json!({ "message": format!("Hello, {first_name}!") }))
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    lambda_runtime::run(service_fn(handler)).await
}
```

## 使用 Tracing crate 实现高级日志记录
<a name="rust-logging-tracing"></a>

[跟踪](https://crates.io/crates/tracing)是一个框架，用于分析 Rust 程序以收集基于事件的结构化诊断信息。该框架提供了用于自定义日志记录输出级别和格式的实用程序，例如创建结构化 JSON 日志消息。要使用此框架，您必须在实现函数处理程序之前将其初始化为 `subscriber`。然后，您可以使用 `debug`、`info` 和 `error` 等跟踪宏来指定每个场景所需的日志记录级别。

**Example – 使用 Tracing crate**  
请注意以下几点：  
+ `tracing_subscriber::fmt().json()`：如果包含此选项，则日志将采用 JSON 格式。要使用此选项，您必须将 `json` 功能包含在 `tracing-subscriber` 依赖项中（例如 `tracing-subscriber = { version = "0.3.11", features = ["json"] }`）。
+ `#[tracing::instrument(skip(event), fields(req_id = %event.context.request_id))]`：每次调用处理程序时，此注释都会生成一个跨度。该跨度会将请求 ID 添加到每个日志行。
+ `{ %first_name }`：此构造会将 `first_name` 字段添加到使用该字段的日志行。此字段的值与同名变量对应。

```
use lambda_runtime::{service_fn, Error, LambdaEvent};
use serde_json::{json, Value};
#[tracing::instrument(skip(event), fields(req_id = %event.context.request_id))]
async fn handler(event: LambdaEvent<Value>) -> Result<Value, Error> {
    tracing::info!("Rust function invoked");
    let payload = event.payload;
    let first_name = payload["firstName"].as_str().unwrap_or("world");
    tracing::info!({ %first_name }, "Rust function responds to event");
    Ok(json!({ "message": format!("Hello, {first_name}!") }))
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing_subscriber::fmt().json()
        .with_max_level(tracing::Level::INFO)
        // this needs to be set to remove duplicated information in the log.
        .with_current_span(false)
        // this needs to be set to false, otherwise ANSI color codes will
        // show up in a confusing manner in CloudWatch logs.
        .with_ansi(false)
        // disabling time is handy because CloudWatch will add the ingestion time.
        .without_time()
        // remove the name of the function from every log entry
        .with_target(false)
        .init();
    lambda_runtime::run(service_fn(handler)).await
}
```

调用此 Rust 函数时，它会输出类似于以下内容的两个日志行：

```
{"level":"INFO","fields":{"message":"Rust function invoked"},"spans":[{"req_id":"45daaaa7-1a72-470c-9a62-e79860044bb5","name":"handler"}]}
{"level":"INFO","fields":{"message":"Rust function responds to event","first_name":"David"},"spans":[{"req_id":"45daaaa7-1a72-470c-9a62-e79860044bb5","name":"handler"}]}
```