記錄和監控 Node.js Lambda 函數 - AWS Lambda

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

記錄和監控 Node.js Lambda 函數

AWS Lambda 會自動代表您監控 Lambda 函數,並將日誌傳送至 Amazon CloudWatch。您的 Lambda 函數隨附一個 CloudWatch 日誌日誌群組,以及每個函數執行個體的日誌串流。Lambda 執行期環境會將每次調用的詳細資訊傳送至日誌串流,並且轉傳來自函數程式碼的日誌及其他輸出。如需詳細資訊,請參閱搭配 Lambda 使用日 CloudWatch 誌記錄

此頁面說明如何從 Lambda 函數的程式碼產生日誌輸出,並使用 AWS Command Line Interface、Lambda 主控台或 CloudWatch 主控台存取日誌。

建立傳回日誌的函數

若要由您的函式程式碼輸出日誌,您可以在主控台物件上使用方法,或任何能寫入 stdoutstderr 的記錄程式庫。下列範例會記錄環境變數和事件物件的值。

注意

我們建議您在記錄輸入時使用輸入驗證和輸出編碼等技術。如果您直接記錄輸入資料,攻擊者可能會使用您的程式碼,讓竄改難以偵測、偽造日誌項目或繞過日誌監控。如需詳細資訊,請參閱常見弱點列舉中的日誌輸出中和不當

範例 index.js 檔案 - 記錄
exports.handler = async function(event, context) { console.log("ENVIRONMENT VARIABLES\n" + JSON.stringify(process.env, null, 2)) console.info("EVENT\n" + JSON.stringify(event, null, 2)) console.warn("Event not processed.") return context.logStreamName }
範例 記錄格式
START RequestId: c793869b-ee49-115b-a5b6-4fd21e8dedac Version: $LATEST 2019-06-07T19:11:20.562Z c793869b-ee49-115b-a5b6-4fd21e8dedac INFO ENVIRONMENT VARIABLES { "AWS_LAMBDA_FUNCTION_VERSION": "$LATEST", "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/my-function", "AWS_LAMBDA_LOG_STREAM_NAME": "2019/06/07/[$LATEST]e6f4a0c4241adcd70c262d34c0bbc85c", "AWS_EXECUTION_ENV": "AWS_Lambda_nodejs12.x", "AWS_LAMBDA_FUNCTION_NAME": "my-function", "PATH": "/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", "NODE_PATH": "/opt/nodejs/node10/node_modules:/opt/nodejs/node_modules:/var/runtime/node_modules", ... } 2019-06-07T19:11:20.563Z c793869b-ee49-115b-a5b6-4fd21e8dedac INFO EVENT { "key": "value" } 2019-06-07T19:11:20.564Z c793869b-ee49-115b-a5b6-4fd21e8dedac WARN Event not processed. END RequestId: c793869b-ee49-115b-a5b6-4fd21e8dedac REPORT RequestId: c793869b-ee49-115b-a5b6-4fd21e8dedac Duration: 128.83 ms Billed Duration: 200 ms Memory Size: 128 MB Max Memory Used: 74 MB Init Duration: 166.62 ms XRAY TraceId: 1-5d9d007f-0a8c7fd02xmpl480aed55ef0 SegmentId: 3d752xmpl1bbe37e Sampled: true

Node.js 執行時間會記錄每次呼叫的 STARTENDREPORT 行。它會將時間戳記、請求 ID 和日誌層級新增到函式所記錄的每個項目。報告明細行提供下列詳細資訊。

REPORT 行資料欄位
  • RequestId – 調用的唯一請求 ID。

  • 持續時間 - 函數的處理常式方法處理事件所花費的時間量。

  • 計費持續時間 - 調用的計費時間量。

  • 記憶體大小 - 分配給函數的記憶體數量。

  • 使用的記憶體上限 - 函數所使用的記憶體數量。當調用共用執行環境時,Lambda 會報告在所有調用中使用的記憶體上限。此行為可能會導致高於預期的報告值。

  • 初始化持續時間 - 對於第一個提供的請求,這是執行期載入函數並在處理常式方法之外執行程式碼所花費的時間量。

  • XRAY TraceId – 對於追蹤的請求,AWS X-Ray 追蹤 ID

  • SegmentId – 對於追蹤請求,X-Ray 區段 ID。

  • 已取樣 - 對於追蹤的請求,這是取樣結果。

您可以在 Lambda 主控台、日誌主控台或從命令列檢視 CloudWatch 日誌。

搭配 Node.js 使用 Lambda 進階日誌控制項

為了讓您更妥善地控制擷取、處理和使用函數日誌的方式,您可以針對支援的 Node.js 執行期設定下列記錄選項:

  • 日誌格式 - 在純文字和結構化JSON格式之間選取函數日誌

  • 日誌層級 - 針對JSON格式的日誌,選擇 Lambda 傳送至 Amazon 的日誌詳細資訊層級 CloudWatch,例如 ERROR、 DEBUG或 INFO

  • 日誌群組 - 選擇函數將 CloudWatch 日誌傳送至的日誌群組

如需這些日誌選項的詳細資訊,以及如何設定函數以使用這些選項的說明,請參閱 設定 Lambda 函數的進階記錄控制項

若要使用日誌格式和日誌層級選項與 Node.js Lambda 函數搭配使用,請參閱以下各章節中的指引。

搭配 Node.js 使用結構化JSON日誌

如果您JSON為函數的日誌格式選取 ,Lambda 將使用 console.traceconsole.debugconsole.error、、 console.log console.info和 的主控台方法 CloudWatch ,以結構化方式將日誌輸出console.warn傳送至 JSON。每個JSON日誌物件包含至少四個具有下列金鑰的金鑰值對:

  • "timestamp" - 產生日誌訊息的時間

  • "level" - 指派給訊息的日誌層級

  • "message" - 日誌訊息的內容

  • "requestId" - 進行調用的唯一請求 ID。

根據您的函數所使用的記錄方法,此JSON物件也可能包含其他金鑰對。例如,如果您的函數使用console方法來記錄使用多個引數的錯誤物件,則該JSON物件將包含與索引鍵 errorMessageerrorType和 的額外索引鍵值對stackTrace

如果您的程式碼已使用另一個記錄程式庫,例如 的 Powertools AWS Lambda,來產生JSON結構化日誌,則您不需要進行任何變更。Lambda JSON 不會對已編碼的任何日誌進行雙重編碼,因此您函數的應用程式日誌將繼續像以前一樣擷取。

如需使用 Powertools AWS Lambda 記錄套件在 Node.js 執行期中建立JSON結構化日誌的詳細資訊,請參閱 記錄和監控 TypeScript Lambda 數

JSON 格式化日誌輸出範例

下列範例顯示當您將函數的日誌格式設定為 時,如何使用具有單一和多個引數console的方法產生的各種日誌輸出,在 CloudWatch 日誌中擷取JSON。

第一個範例使用 console.error 方法輸出簡單字串。

範例 Node.js 日誌程式碼
export const handler = async (event) => { console.error("This is a warning message"); ... }
範例 JSON 日誌記錄
{ "timestamp":"2023-11-01T00:21:51.358Z", "level":"ERROR", "message":"This is a warning message", "requestId":"93f25699-2cbf-4976-8f94-336a0aa98c6f" }

您還可以透過 console 方法使用單個或多個引數輸出結構更複雜的日誌訊息。在下一個範例中,您將使用 console.log 與單個引數輸出兩個鍵值對。請注意,Lambda 傳送至 CloudWatch Logs 的JSON物件中的 "message" 欄位不會進行字串化。

範例 Node.js 日誌程式碼
export const handler = async (event) => { console.log({data: 12.3, flag: false}); ... }
範例 JSON 日誌記錄
{ "timestamp": "2023-12-08T23:21:04.664Z", "level": "INFO", "requestId": "405a4537-9226-4216-ac59-64381ec8654a", "message": { "data": 12.3, "flag": false } }

在下一個範例中,您要再次使用 console.log 方法建立日誌輸出。這一次,該方法使用兩個引數、一個包含兩個鍵值對的映射和一個識別字串。請注意,在這種情況下,由於您提供了兩個引數,Lambda 會對 "message" 欄位進行字串化。

範例 Node.js 日誌程式碼
export const handler = async (event) => { console.log('Some object - ', {data: 12.3, flag: false}); ... }
範例 JSON 日誌記錄
{ "timestamp": "2023-12-08T23:21:04.664Z", "level": "INFO", "requestId": "405a4537-9226-4216-ac59-64381ec8654a", "message": "Some object - { data: 12.3, flag: false }" }

Lambda console.log會指派使用日誌層級 產生的輸出INFO。

最後一個範例顯示如何使用 console方法將錯誤物件輸出至 CloudWatch 日誌。請注意,當您使用多個引數記錄錯誤物件時,Lambda 會新增 errorMessageerrorTypestackTrace 欄位至日誌輸出。

範例 Node.js 日誌程式碼
export const handler = async (event) => { let e1 = new ReferenceError("some reference error"); let e2 = new SyntaxError("some syntax error"); console.log(e1); console.log("errors logged - ", e1, e2); };
範例 JSON 日誌記錄
{ "timestamp": "2023-12-08T23:21:04.632Z", "level": "INFO", "requestId": "405a4537-9226-4216-ac59-64381ec8654a", "message": { "errorType": "ReferenceError", "errorMessage": "some reference error", "stackTrace": [ "ReferenceError: some reference error", " at Runtime.handler (file:///var/task/index.mjs:3:12)", " at Runtime.handleOnceNonStreaming (file:///var/runtime/index.mjs:1173:29)" ] } } { "timestamp": "2023-12-08T23:21:04.646Z", "level": "INFO", "requestId": "405a4537-9226-4216-ac59-64381ec8654a", "message": "errors logged - ReferenceError: some reference error\n at Runtime.handler (file:///var/task/index.mjs:3:12)\n at Runtime.handleOnceNonStreaming (file:///var/runtime/index.mjs:1173:29) SyntaxError: some syntax error\n at Runtime.handler (file:///var/task/index.mjs:4:12)\n at Runtime.handleOnceNonStreaming (file:///var/runtime/index.mjs:1173:29)", "errorType": "ReferenceError", "errorMessage": "some reference error", "stackTrace": [ "ReferenceError: some reference error", " at Runtime.handler (file:///var/task/index.mjs:3:12)", " at Runtime.handleOnceNonStreaming (file:///var/runtime/index.mjs:1173:29)" ] }

記錄多個錯誤類型時,會從提供給 console 方法的第一個錯誤類型中擷取額外欄位 errorMessageerrorTypestackTrace

使用內嵌指標格式 (EMF) 用戶端程式庫搭配結構化JSON日誌

AWS 提供 Node.js 的開放原始碼用戶端程式庫,可用來建立內嵌指標格式 (EMF) 日誌。如果您有使用這些程式庫的現有函數,且將函數的日誌格式變更為 JSON, CloudWatch 則可能無法再識別程式碼發出的指標。

如果您的程式碼目前直接使用 console.log或 為 AWS Lambda (TypeScript) 使用 Powertools 發出EMF日誌,當您將函數的日誌格式變更為 時 CloudWatch ,也無法剖析這些日誌JSON。

重要

若要確保函數的EMF日誌繼續由 正確剖析 CloudWatch,請將程式庫的 EMFPowertools AWS Lambda 更新至最新版本。如果切換至JSON日誌格式,我們也建議您進行測試,以確保與函數內嵌指標的相容性。如果您的程式碼直接使用 發出EMF日誌console.log,請變更您的程式碼以直接將這些指標輸出至 stdout,如下列程式碼範例所示。

範例 發出內嵌指標至 stdout 的程式碼
process.stdout.write(JSON.stringify( { "_aws": { "Timestamp": Date.now(), "CloudWatchMetrics": [{ "Namespace": "lambda-function-metrics", "Dimensions": [["functionVersion"]], "Metrics": [{ "Name": "time", "Unit": "Milliseconds", "StorageResolution": 60 }] }] }, "functionVersion": "$LATEST", "time": 100, "requestId": context.awsRequestId } ) + "\n")

搭配 Node.js 使用日誌層級篩選

若要 AWS Lambda 讓 根據應用程式日誌層級篩選您的應用程式日誌,您的函數必須使用JSON格式化日誌。您可以透過兩種方式達成此操作:

  • 使用標準主控台方法建立日誌輸出,並將函數設定為使用JSON日誌格式。 AWS Lambda 然後,在 中描述的JSON物件中使用「層級」鍵值對來篩選日誌輸出搭配 Node.js 使用結構化JSON日誌。若要瞭解如何設定函數的日誌格式,請參閱 設定 Lambda 函數的進階記錄控制項

  • 使用另一個日誌程式庫或方法,在您的程式碼中建立JSON結構化日誌,其中包含定義日誌輸出層級的「層級」鍵值對。例如,您可以使用 Powertools for 從程式碼 AWS Lambda 產生JSON結構化日誌輸出。請參閱 記錄和監控 TypeScript Lambda 數 以瞭解有關在 Node.js 執行期使用 Powertools 的更多資訊。

    若要讓 Lambda 篩選函數的日誌,您還必須在JSON日誌輸出中包含"timestamp"索引鍵值對。時間必須以有效的 RFC 3339 時間戳記格式指定。如果您沒有提供有效的時間戳記,Lambda 會指派日誌層級,INFO並為您新增時間戳記。

當您將函數設定為使用日誌層級篩選時,請從下列選項中選取 AWS Lambda 您要傳送至 CloudWatch 日誌的日誌層級:

日誌層級 標準用量
TRACE (最詳細) 用於追蹤程式碼執行路徑的最精細資訊
DEBUG 系統偵錯的詳細資訊
INFO 記錄函數正常操作的訊息
WARN 有關可能導致未解決意外行為的潛在錯誤的消息
ERROR 有關阻止程式碼按預期執行的問題的訊息
FATAL (最少詳細資訊) 有關導致應用程式停止運作的嚴重錯誤訊息

Lambda 會將所選層級和更低層級的日誌傳送至 CloudWatch。例如,如果您設定 的日誌層級WARN,Lambda 將傳送對應至 WARN、 ERROR和 FATAL層級的日誌。

在 Lambda 主控台中檢視日誌

您可以在調用 Lambda 函數之後,使用 Lambda 主控台來檢視日誌輸出。

如果可以從內嵌程式碼編輯器測試您的程式碼,您會在執行結果中找到日誌。使用主控台測試功能以調用函數時,您會在詳細資訊區段找到日誌輸出

在 CloudWatch 主控台中檢視日誌

您可以使用 Amazon CloudWatch 主控台來檢視所有 Lambda 函數調用的日誌。

在 CloudWatch 主控台上檢視日誌
  1. 在 CloudWatch 主控台上開啟日誌群組頁面

  2. 選擇函數的日誌群組 (/aws/lambda/your-function-name).

  3. 選擇日誌串流

每個日誌串流都會對應至函式的執行個體。當您更新 Lambda 函數,以及建立額外執行個體以處理多個並行調用時,便會出現日誌串流。若要尋找特定調用的日誌,建議您使用 測試函數 AWS X-Ray。X-Ray 會在追蹤內記錄有關請求和日誌串流的詳細資訊。

使用 檢視日誌 AWS Command Line Interface (AWS CLI)

AWS CLI 是開放原始碼工具,可讓您使用命令列 Shell 中的命令與 AWS 服務互動。若要完成本節中的步驟,您必須執行下列各項:

您可以透過 AWS CLI,使用 --log-type 命令選項來擷取要調用的日誌。其回應將包含 LogResult 欄位,內含該次調用的 base64 編碼日誌 (最大達 4 KB)。

範例 擷取日誌 ID

下列範例顯示如何從名稱為 my-function 的函數的 LogResult 欄位來擷取日誌 ID

aws lambda invoke --function-name my-function out --log-type Tail

您應該會看到下列輸出:

{ "StatusCode": 200, "LogResult": "U1RBUlQgUmVxdWVzdElkOiA4N2QwNDRiOC1mMTU0LTExZTgtOGNkYS0yOTc0YzVlNGZiMjEgVmVyc2lvb...", "ExecutedVersion": "$LATEST" }
範例 解碼日誌

在相同的命令提示中,使用 base64 公用程式來解碼日誌。下列範例顯示如何擷取 my-function 的 base64 編碼日誌。

aws lambda invoke --function-name my-function out --log-type Tail \ --query 'LogResult' --output text --cli-binary-format raw-in-base64-out | base64 --decode

如果您使用的是 第 2 AWS CLI 版,則需要 cli-binary-format選項。若要讓此成為預設的設定,請執行 aws configure set cli-binary-format raw-in-base64-out。若要取得更多資訊,請參閱《AWS Command Line Interface 使用者指南第 2 版》AWS CLI 支援的全域命令列選項

您應該會看到下列輸出:

START RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8 Version: $LATEST "AWS_SESSION_TOKEN": "AgoJb3JpZ2luX2VjELj...", "_X_AMZN_TRACE_ID": "Root=1-5d02e5ca-f5792818b6fe8368e5b51d50;Parent=191db58857df8395;Sampled=0"",ask/lib:/opt/lib", END RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8 REPORT RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8 Duration: 79.67 ms Billed Duration: 80 ms Memory Size: 128 MB Max Memory Used: 73 MB

base64 公用程式可在 Linux、macOS 和 Ubuntu on Windows 上使用。macOS 使用者可能需要使用 base64 -D

範例 get-logs.sh 指令碼

在相同的命令提示中,使用下列指令碼下載最後五個日誌事件。該指令碼使用 sed 以從輸出檔案移除引述,並休眠 15 秒以使日誌可供使用。輸出包括來自 Lambda 的回應以及來自 get-log-events 命令的輸出。

複製下列程式碼範例的內容,並將您的 Lambda 專案目錄儲存為 get-logs.sh

如果您使用的是 第 2 AWS CLI 版,則需要 cli-binary-format選項。若要讓此成為預設的設定,請執行 aws configure set cli-binary-format raw-in-base64-out。若要取得更多資訊,請參閱《AWS Command Line Interface 使用者指南第 2 版》AWS CLI 支援的全域命令列選項

#!/bin/bash aws lambda invoke --function-name my-function --cli-binary-format raw-in-base64-out --payload '{"key": "value"}' out sed -i'' -e 's/"//g' out sleep 15 aws logs get-log-events --log-group-name /aws/lambda/my-function --log-stream-name stream1 --limit 5
範例 macOS 和 Linux (僅限)

在相同的命令提示中,macOS 和 Linux 使用者可能需要執行下列命令,以確保指令碼可執行。

chmod -R 755 get-logs.sh
範例 擷取最後五個記錄事件

在相同的命令提示中,執行下列指令碼以取得最後五個日誌事件。

./get-logs.sh

您應該會看到下列輸出:

{ "StatusCode": 200, "ExecutedVersion": "$LATEST" } { "events": [ { "timestamp": 1559763003171, "message": "START RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf Version: $LATEST\n", "ingestionTime": 1559763003309 }, { "timestamp": 1559763003173, "message": "2019-06-05T19:30:03.173Z\t4ce9340a-b765-490f-ad8a-02ab3415e2bf\tINFO\tENVIRONMENT VARIABLES\r{\r \"AWS_LAMBDA_FUNCTION_VERSION\": \"$LATEST\",\r ...", "ingestionTime": 1559763018353 }, { "timestamp": 1559763003173, "message": "2019-06-05T19:30:03.173Z\t4ce9340a-b765-490f-ad8a-02ab3415e2bf\tINFO\tEVENT\r{\r \"key\": \"value\"\r}\n", "ingestionTime": 1559763018353 }, { "timestamp": 1559763003218, "message": "END RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf\n", "ingestionTime": 1559763018353 }, { "timestamp": 1559763003218, "message": "REPORT RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf\tDuration: 26.73 ms\tBilled Duration: 27 ms \tMemory Size: 128 MB\tMax Memory Used: 75 MB\t\n", "ingestionTime": 1559763018353 } ], "nextForwardToken": "f/34783877304859518393868359594929986069206639495374241795", "nextBackwardToken": "b/34783877303811383369537420289090800615709599058929582080" }

刪除日誌

當您刪除函數時,不會自動刪除日誌群組。若要避免無限期地儲存日誌,請刪除日誌群組,或設定保留期間,系統會在該時間之後自動刪除日誌。