Rust-Lambda-Funktionen protokollieren und überwachen - AWS Lambda

Rust-Lambda-Funktionen protokollieren und überwachen

Anmerkung

Der Rust-Laufzeit-Client ist ein experimentelles Paket. Er kann sich ändern und ist nur zu Evaluierungszwecken gedacht.

AWS Lambda überwacht automatisch Lambda-Funktionen für Sie und sendet Protokolle an Amazon CloudWatch. Ihre Lambda-Funktion besitzt eine CloudWatch-Logs-Protokollgruppe und einen Protokollstream für jede Instance Ihrer Funktion. Die Lambda-Laufzeitumgebung sendet Details zu den einzelnen Aufrufen an den Protokollstream und leitet Protokolle und andere Ausgaben aus dem Code Ihrer Funktion weiter. Weitere Informationen finden Sie unter Senden von Lambda-Funktionsprotokollen an CloudWatch Logs. Auf dieser Seite wird beschrieben, wie Sie Protokollausgaben aus dem Code Ihrer Lambda-Funktion erstellen.

Erstellen einer Funktion, die Protokolle schreibt

Um Protokolle aus Ihrem Funktionscode auszugeben, können Sie jede Protokollierungsfunktion verwenden, die in stdout oder stderr schreibt, wie z. B. das println!-Makro. Das folgende Beispiel verwendet println!, um eine Nachricht zu drucken, wenn der Funktionshandler gestartet wird und bevor er beendet wird.

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 }

Implementierung der erweiterten Protokollierung mit der Tracing Crate

Tracing ist ein Framework zur Instrumentierung von Rust-Programmen zur Erfassung strukturierter, ereignisbasierter Diagnoseinformationen. Dieses Framework bietet Hilfsprogramme zum Anpassen der Logging-Ausgabestufen und -formate, wie zum Beispiel das Erstellen strukturierter JSON-Protokollnachrichten. Um dieses Framework verwenden zu können, müssen Sie einen subscriber initialisieren, bevor Sie den Funktionshandler implementieren. Anschließend können Sie Tracing-Makros wie debug, info und error verwenden, um die gewünschte Protokollierungsebene für jedes Szenario anzugeben.

Beispiel – Verwenden von Tracing Crate

Beachten Sie Folgendes:

  • tracing_subscriber::fmt().json(): Wenn diese Option enthalten ist, werden die Protokolle in JSON formatiert. Um diese Option verwenden zu können, müssen Sie das json-Feature in die tracing-subscriber-Abhängigkeit aufnehmen (z. B. tracing-subscriber = { version = "0.3.11", features = ["json"] }).

  • #[tracing::instrument(skip(event), fields(req_id = %event.context.request_id))]: Diese Annotation generiert bei jedem Aufruf des Handlers eine Spanne. Diese Spanne fügt jeder Protokollzeile die Anforderungs-ID hinzu.

  • { %first_name }: Dieses Konstrukt fügt das first_name-Feld der Protokollzeile hinzu, in der es verwendet wird. Der Wert für dieses Feld entspricht der Variablen mit dem gleichen Namen.

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 }

Wenn diese Rust-Funktion aufgerufen wird, druckt sie zwei Protokollzeilen, die den folgenden ähneln:

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