

# 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>

関数コードからログを出力するには、`println!` マクロなどの `stdout` または `stderr` に書き込む任意のログ記録ライブラリを使用できます。次の例は、`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
}
```

## トレーシングクレートによる高度なログ記録機能の実装
<a name="rust-logging-tracing"></a>

[トレーシング](https://crates.io/crates/tracing)は、構造化されたイベントベースの診断情報を収集するために Rust プログラムをインストルメントするためのフレームワークです。このフレームワークには、構造化された JSON ログメッセージの作成など、ロギング出力レベルと形式をカスタマイズするユーティリティが用意されています。このフレームワークを使用するには、関数ハンドラーを実装する前に `subscriber` を初期化する必要があります。次に、`debug`、`info`、`error` などのトレースマクロを使用して、各シナリオに必要なログのレベルを指定できます。

**Example — トレーシングクレートの使用**  
次の点に注意してください。  
+ `tracing_subscriber::fmt().json()`: このオプションが含まれる場合、ログは JSON でフォーマットされます。このオプションを使用するには、`tracing-subscriber` の `json` 機能を依存関係に含める必要があります (例: `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 関数が呼び出されると、次のようなログ行が 2 行出力されます。

```
{"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"}]}
```