

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

# 串連多行或堆疊追蹤的 Amazon ECS 日誌訊息
<a name="firelens-concatanate-multiline"></a>

從 AWS for Fluent Bit 2.22.0 版開始，包含多行篩選條件。多行篩選條件有助於串連最初屬於一筆內容但分割到多筆記錄或日誌明細行的日誌訊息。如需有關多行篩選條件的詳細資訊，請參閱《[Fluent Bit 說明文件](https://docs.fluentbit.io/manual/pipeline/filters/multiline-stacktrace)》。

分割日誌訊息的常見範例有：
+ 堆疊追蹤。
+ 在多行上列印日誌的應用程式。
+ 因為日誌訊息長於指定的執行時間緩衝大小上限而分割的日誌訊息。您可以按照 GitHub 上的範例來串連由容器執行時間分割的日誌訊息：[FireLens 範例：串聯部分/分割容器日誌](https://github.com/aws-samples/amazon-ecs-firelens-examples/tree/mainline/examples/fluent-bit/filter-multiline-partial-message-mode)。

## 所需的 IAM 許可
<a name="iam-permissions"></a>

請務必先確定您擁有必要的 IAM 許可，讓容器代理程式可從 Amazon ECR 中提取容器映像，也讓容器可將日誌路由到 CloudWatch Logs。

對於這些許可，您必須具有下列角色：
+ 任務 IAM 角色。
+ 任務執行 IAM 角色。

您需要具備下列許可：
+ `logs:CreateLogStream`
+ `logs:CreateLogGroup`
+ `logs:PutLogEvents`

## 確定何時使用多行日誌設定
<a name="determine-filter"></a>

以下是您在 CloudWatch Logs 主控台中看到的範例日誌片段，其中包含預設日誌設定。您可以查看以 `log` 開頭的行，以確定是否需要多行篩選條件。當內容相同時，您可以使用多行日誌設定。在此範例中，內容為 "com.myproject.model.MyProject"。

```
2022-09-20T15:47:56:595-05-00                           {"container_id": "82ba37cada1d44d389b03e78caf74faa-EXAMPLE", "container_name": "example-app", "source=": "stdout", "log": ": "     at com.myproject.modele.(MyProject.badMethod.java:22)",
    {
      "container_id":  "82ba37cada1d44d389b03e78caf74faa-EXAMPLE",
      "container_name: ": "example-app",
      "source": "stdout",
      "log": ": "     at com.myproject.model.MyProject.badMethod(MyProject.java:22)",
      "ecs_cluster": "default",
      "ecs_task_arn": "arn:aws:region:123456789012:task/default/b23c940d29ed4714971cba72cEXAMPLE",
      "ecs_task_definition": "firelense-example-multiline:3"
     }
```

```
2022-09-20T15:47:56:595-05-00                           {"container_id": "82ba37cada1d44d389b03e78caf74faa-EXAMPLE", "container_name": "example-app", "stdout", "log": ": "     at com.myproject.modele.(MyProject.oneMoreMethod.java:18)",
    {
      "container_id":  "82ba37cada1d44d389b03e78caf74faa-EXAMPLE",
      "container_name: ": "example-app",
      "source": "stdout",
      "log": ": "     at com.myproject.model.MyProject.oneMoreMethod(MyProject.java:18)",
      "ecs_cluster": "default",
      "ecs_task_arn": "arn:aws:region:123456789012:task/default/b23c940d29ed4714971cba72cEXAMPLE,
      "ecs_task_definition": "firelense-example-multiline:3"
     }
```

使用多行日誌設定後，輸出看起來類似下列範例。

```
2022-09-20T15:47:56:595-05-00                           {"container_id": "82ba37cada1d44d389b03e78caf74faa-EXAMPLE", "container_name": "example-app", "stdout",...
    {
      "container_id":  "82ba37cada1d44d389b03e78caf74faa-EXAMPLE",
      "container_name: ": "example-app",
      "source": "stdout",
      "log:    "September 20, 2022 06:41:48 Exception in thread \"main\" java.lang.RuntimeException: Something has gone wrong, aborting!\n    
    at com.myproject.module.MyProject.badMethod(MyProject.java:22)\n    at   
    at com.myproject.model.MyProject.oneMoreMethod(MyProject.java:18) com.myproject.module.MyProject.main(MyProject.java:6)",
      "ecs_cluster": "default",
      "ecs_task_arn": "arn:aws:region:123456789012:task/default/b23c940d29ed4714971cba72cEXAMPLE",
      "ecs_task_definition": "firelense-example-multiline:2"
     }
```

## 剖析並串連選項
<a name="parse-multiline-log"></a>

若要剖析日誌並串連因新行而分割的行數，您可以使用這兩個選項中的任一選項。
+ 使用您自己的剖析器檔案 (包含要剖析的規則) 並串連屬於相同訊息的明細行。
+ 使用 Fluent Bit 內建剖析器。如需 Fluent Bit 內建剖析器所支援的語言清單，請參閱 [Fluent Bit 說明文件](https://docs.fluentbit.io/manual/pipeline/filters/multiline-stacktrace)。

下列教學會引導您逐步演練每個使用案例的步驟。這些步驟向您展示如何串聯多行並將日誌傳送到 Amazon CloudWatch。您可以為您的日誌指定其他目的地。

### 範例：使用您建立的剖析器
<a name="customer-parser"></a>

在本範例中，您會完成下列步驟：

1. 建置並上傳 Fluent Bit 容器的映像。

1. 建置並上傳可執行、失敗並產生多行堆疊追蹤之試用版多行應用程式的映像。

1. 建立任務定義並執行任務。

1. 檢視日誌以確認跨多行的訊息是否顯示為串連。

**建置並上傳 Fluent Bit 容器的映像**

此映像將包含您指定常規運算式的剖析器檔案和參照剖析器檔案的組態文件。

1. 建立名稱為 `FluentBitDockerImage` 的資料夾。

1. 在資料夾內，建立剖析器檔案 (包含要剖析日誌的規則) 並串連屬於相同訊息的明細行。

   1. 將以下內容貼到該剖析器檔案：

      ```
      [MULTILINE_PARSER]
          name          multiline-regex-test
          type          regex
          flush_timeout 1000
          #
          # Regex rules for multiline parsing
          # ---------------------------------
          #
          # configuration hints:
          #
          #  - first state always has the name: start_state
          #  - every field in the rule must be inside double quotes
          #
          # rules |   state name  | regex pattern                  | next state
          # ------|---------------|--------------------------------------------
          rule      "start_state"   "/(Dec \d+ \d+\:\d+\:\d+)(.*)/"  "cont"
          rule      "cont"          "/^\s+at.*/"                     "cont"
      ```

      當您自訂 Regex 運算式模式時，我們建議您使用常規運算式編輯器來測試運算式。

   1. 儲存檔案為 `parsers_multiline.conf`。

1. 在 `FluentBitDockerImage` 資料夾內，建立參照了您在前一個步驟中建立的剖析器檔案之自訂組態檔案。

   如需有關自訂組態檔案的詳細資訊，請參閱《[Amazon Elastic Container Service 開發人員指南](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/firelens-taskdef.html#firelens-taskdef-customconfig)》中的*指定自訂組態檔案* 

   1. 將以下內容貼到該檔案：

      ```
      [SERVICE]
          flush                 1
          log_level             info
          parsers_file          /parsers_multiline.conf
          
      [FILTER]
          name                  multiline
          match                 *
          multiline.key_content log
          multiline.parser      multiline-regex-test
      ```
**注意**  
您必須使用剖析器的絕對路徑。

   1. 儲存檔案為 `extra.conf`。

1. 在 `FluentBitDockerImage` 資料夾內，建立具有 Fluent Bit 映像與剖析器和您建立的組態檔案之 Dockerfile。

   1. 將以下內容貼到該檔案：

      ```
      FROM public.ecr.aws/aws-observability/aws-for-fluent-bit:latest
      
      ADD parsers_multiline.conf /parsers_multiline.conf
      ADD extra.conf /extra.conf
      ```

   1. 儲存檔案為 `Dockerfile`。

1. 使用 Dockerfile，建置內含剖析器與自訂組態檔案的自訂 Fluent Bit 映像。
**注意**  
您可以將剖析器檔案和組態檔案放置在 Docker 影像中除了 `/fluent-bit/etc/fluent-bit.conf` 以外的任何位置，因為該檔案路徑會由 FireLens 使用。

   1. 建置映像：`docker build -t fluent-bit-multiline-image.`

      其中：`fluent-bit-multiline-image` 是此範例中映像的名稱。

   1. 驗證映像已正確建立：`docker images —filter reference=fluent-bit-multiline-image`

      如果成功，輸出會顯示映像和 `latest` 標籤。

1. 將自訂 Fluent Bit 映像上傳至 Amazon Elastic 容器登錄檔。

   1. 建立 Amazon ECR 儲存庫，以便存放映像：`aws ecr create-repository --repository-name fluent-bit-multiline-repo --region us-east-1`

      其中：`fluent-bit-multiline-repo` 是此範例中儲存庫的名稱，`us-east-1` 是此範例中的區域。

      輸出為您提供了新儲存庫的詳細資訊。

   1. 使用來自先前輸出的 `repositoryUri` 值，標記您的映像：`docker tag fluent-bit-multiline-image repositoryUri`

      範例：`docker tag fluent-bit-multiline-image xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/fluent-bit-multiline-repo`

   1. 執行 Docker 影像以確認是否能正確執行：`docker images —filter reference=repositoryUri`

      在輸出中，儲存庫名稱從 fluent-bit-multiline-repo 變更為 `repositoryUri`。

   1. 透過執行 `aws ecr get-login-password` 命令並指定您要驗證的登錄 ID 來驗證 Amazon ECR：`aws ecr get-login-password | docker login --username AWS --password-stdin registry ID.dkr.ecr.region.amazonaws.com`

      範例：`ecr get-login-password | docker login --username AWS --password-stdin xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com`

      畫面上會顯示成功登入訊息。

   1. 將映像推送至 Amazon ECR：`docker push registry ID.dkr.ecr.region.amazonaws.com/repository name`

      範例：`docker push xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/fluent-bit-multiline-repo`

**建置並上傳試用版多行應用程式的映像**

此映像將包含執行應用程式的 Python 指令碼檔案和樣本日誌檔案。

當您執行任務時，應用程式會模擬執行，然後失敗並建立堆疊追蹤。

1. 建立名為 `multiline-app` 的資料夾：`mkdir multiline-app`

1. 建立 Python 指令碼檔案。

   1. 在 `multiline-app` 資料夾中，建立檔案，並將它命名為 `main.py`。

   1. 將以下內容貼到該檔案：

      ```
      import os
      import time
      file1 = open('/test.log', 'r')
      Lines = file1.readlines()
       
      count = 0
      
      for i in range(10):
          print("app running normally...")
          time.sleep(1)
      
      # Strips the newline character
      for line in Lines:
          count += 1
          print(line.rstrip())
      print(count)
      print("app terminated.")
      ```

   1. 儲存 `main.py` 檔案。

1. 建立範例日誌檔案。

   1. 在 `multiline-app` 資料夾中，建立檔案，並將它命名為 `test.log`。

   1. 將以下內容貼到該檔案：

      ```
      single line...
      Dec 14 06:41:08 Exception in thread "main" java.lang.RuntimeException: Something has gone wrong, aborting!
          at com.myproject.module.MyProject.badMethod(MyProject.java:22)
          at com.myproject.module.MyProject.oneMoreMethod(MyProject.java:18)
          at com.myproject.module.MyProject.anotherMethod(MyProject.java:14)
          at com.myproject.module.MyProject.someMethod(MyProject.java:10)
          at com.myproject.module.MyProject.main(MyProject.java:6)
      another line...
      ```

   1. 儲存 `test.log` 檔案。

1. 在 `multiline-app` 資料夾內，建立 Dockerfile。

   1. 將以下內容貼到該檔案：

      ```
      FROM public.ecr.aws/amazonlinux/amazonlinux:latest
      ADD test.log /test.log
      
      RUN yum upgrade -y && yum install -y python3
      
      WORKDIR /usr/local/bin
      
      COPY main.py .
      
      CMD ["python3", "main.py"]
      ```

   1. 儲存 `Dockerfile` 檔案。

1. 使用 Dockerfile，建置映像。

   1. 建置映像：`docker build -t multiline-app-image `

      其中：`multiline-app-image` 是此範例中映像的名稱。

   1. 驗證映像已正確建立：`docker images —filter reference=multiline-app-image`

      如果成功，輸出會顯示映像和 `latest` 標籤。

1. 將映像上傳至 Amazon Elastic 容器登錄檔。

   1. 建立 Amazon ECR 儲存庫，以便存放映像：`aws ecr create-repository --repository-name multiline-app-repo --region us-east-1`

      其中：`multiline-app-repo` 是此範例中儲存庫的名稱，`us-east-1` 是此範例中的區域。

      輸出為您提供了新儲存庫的詳細資訊。請記下 `repositoryUri` 值，因為您將在後續步驟用到它。

   1. 使用來自先前輸出的 `repositoryUri` 值，標記您的映像：`docker tag multiline-app-image repositoryUri`

      範例：`docker tag multiline-app-image xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/multiline-app-repo`

   1. 執行 Docker 影像以確認是否能正確執行：`docker images —filter reference=repositoryUri`

      在輸出中，儲存庫名稱會從 `multiline-app-repo` 變更為 `repositoryUri` 值。

   1. 將映像推送至 Amazon ECR：`docker push aws_account_id.dkr.ecr.region.amazonaws.com/repository name`

      範例：`docker push xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/multiline-app-repo`

**建立任務定義並執行任務**

1. 建立檔案名稱為 `multiline-task-definition.json` 的任務定義檔案。

1. 將以下內容貼到該 `multiline-task-definition.json` 檔案：

   ```
   {
       "family": "firelens-example-multiline",
       "taskRoleArn": "task role ARN,
       "executionRoleArn": "execution role ARN",
       "containerDefinitions": [
           {
               "essential": true,
               "image": "aws_account_id.dkr.ecr.us-east-1.amazonaws.com/fluent-bit-multiline-image:latest",
               "name": "log_router",
               "firelensConfiguration": {
                   "type": "fluentbit",
                   "options": {
                       "config-file-type": "file",
                       "config-file-value": "/extra.conf"
                   }
               },
               "memoryReservation": 50
           },
           {
               "essential": true,
               "image": "aws_account_id.dkr.ecr.us-east-1.amazonaws.com/multiline-app-image:latest",
               "name": "app",
               "logConfiguration": {
                   "logDriver": "awsfirelens",
                   "options": {
                       "Name": "cloudwatch_logs",
                       "region": "us-east-1",
                       "log_group_name": "multiline-test/application",
                       "auto_create_group": "true",
                       "log_stream_prefix": "multiline-"
                   }
               },
               "memoryReservation": 100
           }
       ],
       "requiresCompatibilities": ["FARGATE"],
       "networkMode": "awsvpc",
       "cpu": "256",
       "memory": "512"
   }
   ```

   取代下列在 `multiline-task-definition.json` 任務定義中的項目：

   1. `task role ARN`

      若要尋找任務角色 ARN，請前往 IAM 主控台。選擇 **Roles** (角色) 並尋找您建立的 `ecs-task-role-for-firelens` 任務角色。選擇角色並複製顯示於 **Summary** (摘要) 區段的 **ARN**。

   1. `execution role ARN`

      若要尋找執行角色 ARN，請前往 IAM 主控台。選擇 **Roles** (角色) 並尋找 `ecsTaskExecutionRole` 角色。選擇角色並複製顯示於 **Summary** (摘要) 區段的 **ARN**。

   1. `aws_account_id`

      若要尋找您的 `aws_account_id`，請登入 AWS 管理主控台。選擇右上角的使用者名稱並複製您的帳戶 ID。

   1. `us-east-1`

      如有必要，請取代該區域。

1. 註冊任務定義檔案：`aws ecs register-task-definition --cli-input-json file://multiline-task-definition.json --region region`

1. 開啟主控台，網址為 [https://console.aws.amazon.com/ecs/v2](https://console.aws.amazon.com/ecs/v2)。

1. 在導覽窗格中，選擇 **Task Definitions** (任務定義)，然後選擇 `firelens-example-multiline` 系列，因為我們已在上述任務定義的第一行中將任務定義註冊到此系列。

1. 選擇最新版本。

1. 選擇**部署**、**執行任務**。

1. 在**執行任務**頁面上，針對**叢集**選擇叢集，然後在**聯網**下，針對**子網路**選擇任務的可用子網路。

1. 選擇**建立**。

**確認 Amazon CloudWatch 中的多行日誌訊息是否顯示為串連**

1. 透過 [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/) 開啟 CloudWatch 主控台。

1. 在導覽窗格中，展開 **Logs** (日誌) 並選擇 **Log groups** (日誌群組)。

1. 選擇 `multiline-test/applicatio` 日誌群組。

1. 選擇日誌。檢視訊息。系統會串連與剖析器檔案中的規則相符之明細行，並顯示為單則訊息。

   下列日誌程式碼片段顯示了串連到單一 Java 堆疊追蹤事件的明細行：

   ```
   {
       "container_id": "xxxxxx",
       "container_name": "app",
       "source": "stdout",
       "log": "Dec 14 06:41:08 Exception in thread \"main\" java.lang.RuntimeException: Something has gone wrong, aborting!\n    at com.myproject.module.MyProject.badMethod(MyProject.java:22)\n    at com.myproject.module.MyProject.oneMoreMethod(MyProject.java:18)\n    at com.myproject.module.MyProject.anotherMethod(MyProject.java:14)\n    at com.myproject.module.MyProject.someMethod(MyProject.java:10)\n    at com.myproject.module.MyProject.main(MyProject.java:6)",
       "ecs_cluster": "default",
       "ecs_task_arn": "arn:aws:ecs:us-east-1:xxxxxxxxxxxx:task/default/xxxxxx",
       "ecs_task_definition": "firelens-example-multiline:2"
   }
   ```

   下列日誌程式碼片段顯示了相同訊息僅以單筆明細行顯示的方式 (如果您執行了未串連多行日誌訊息的 Amazon ECS 容器)。

   ```
   {
       "log": "Dec 14 06:41:08 Exception in thread \"main\" java.lang.RuntimeException: Something has gone wrong, aborting!",
       "container_id": "xxxxxx-xxxxxx",
       "container_name": "app",
       "source": "stdout",
       "ecs_cluster": "default",
       "ecs_task_arn": "arn:aws:ecs:us-east-1:xxxxxxxxxxxx:task/default/xxxxxx",
       "ecs_task_definition": "firelens-example-multiline:3"
   }
   ```

### 範例：使用 Fluent Bit 內建剖析器
<a name="fluent-bit-parser"></a>

在本範例中，您會完成下列步驟：

1. 建置並上傳 Fluent Bit 容器的映像。

1. 建置並上傳可執行、失敗並產生多行堆疊追蹤之試用版多行應用程式的映像。

1. 建立任務定義並執行任務。

1. 檢視日誌以確認跨多行的訊息是否顯示為串連。

**建置並上傳 Fluent Bit 容器的映像**

此映像將包含參照了 Fluent Bit 剖析器的組態檔案。

1. 建立名稱為 `FluentBitDockerImage` 的資料夾。

1. 在 `FluentBitDockerImage` 資料夾內，建立參照了 Fluent Bit 內建剖析器檔案的自訂組態檔案。

   如需有關自訂組態檔案的詳細資訊，請參閱《[Amazon Elastic Container Service 開發人員指南](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/firelens-taskdef.html#firelens-taskdef-customconfig)》中的*指定自訂組態檔案* 

   1. 將以下內容貼到該檔案：

      ```
      [FILTER]
          name                  multiline
          match                 *
          multiline.key_content log
          multiline.parser      go
      ```

   1. 儲存檔案為 `extra.conf`。

1. 在 `FluentBitDockerImage` 資料夾內，建立具有 Fluent Bit 映像與剖析器和您建立的組態檔案之 Dockerfile。

   1. 將以下內容貼到該檔案：

      ```
      FROM public.ecr.aws/aws-observability/aws-for-fluent-bit:latest
      ADD extra.conf /extra.conf
      ```

   1. 儲存檔案為 `Dockerfile`。

1. 使用 Dockerfile，建置內含自訂組態檔案的自訂 Fluent Bit 映像。
**注意**  
您可以將組態檔案放置在 Docker 影像中除了 `/fluent-bit/etc/fluent-bit.conf` 以外的任何位置，因為該檔案路徑會由 FireLens 使用。

   1. 建置映像：`docker build -t fluent-bit-multiline-image.`

      其中：`fluent-bit-multiline-image` 是此範例中映像的名稱。

   1. 驗證映像已正確建立：`docker images —filter reference=fluent-bit-multiline-image`

      如果成功，輸出會顯示映像和 `latest` 標籤。

1. 將自訂 Fluent Bit 映像上傳至 Amazon Elastic 容器登錄檔。

   1. 建立 Amazon ECR 儲存庫，以便存放映像：`aws ecr create-repository --repository-name fluent-bit-multiline-repo --region us-east-1`

      其中：`fluent-bit-multiline-repo` 是此範例中儲存庫的名稱，`us-east-1` 是此範例中的區域。

      輸出為您提供了新儲存庫的詳細資訊。

   1. 使用來自先前輸出的 `repositoryUri` 值，標記您的映像：`docker tag fluent-bit-multiline-image repositoryUri`

      範例：`docker tag fluent-bit-multiline-image xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/fluent-bit-multiline-repo`

   1. 執行 Docker 影像以確認是否能正確執行：`docker images —filter reference=repositoryUri`

      在輸出中，儲存庫名稱從 fluent-bit-multiline-repo 變更為 `repositoryUri`。

   1. 透過執行 `aws ecr get-login-password` 命令並指定您要驗證的登錄 ID 來驗證 Amazon ECR：`aws ecr get-login-password | docker login --username AWS --password-stdin registry ID.dkr.ecr.region.amazonaws.com`

      範例：`ecr get-login-password | docker login --username AWS --password-stdin xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com`

      畫面上會顯示成功登入訊息。

   1. 將映像推送至 Amazon ECR：`docker push registry ID.dkr.ecr.region.amazonaws.com/repository name`

      範例：`docker push xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/fluent-bit-multiline-repo`

**建置並上傳試用版多行應用程式的映像**

此映像將包含執行應用程式的 Python 指令碼檔案和樣本日誌檔案。

1. 建立名為 `multiline-app` 的資料夾：`mkdir multiline-app`

1. 建立 Python 指令碼檔案。

   1. 在 `multiline-app` 資料夾中，建立檔案，並將它命名為 `main.py`。

   1. 將以下內容貼到該檔案：

      ```
      import os
      import time
      file1 = open('/test.log', 'r')
      Lines = file1.readlines()
       
      count = 0
      
      for i in range(10):
          print("app running normally...")
          time.sleep(1)
      
      # Strips the newline character
      for line in Lines:
          count += 1
          print(line.rstrip())
      print(count)
      print("app terminated.")
      ```

   1. 儲存 `main.py` 檔案。

1. 建立範例日誌檔案。

   1. 在 `multiline-app` 資料夾中，建立檔案，並將它命名為 `test.log`。

   1. 將以下內容貼到該檔案：

      ```
      panic: my panic
      
      goroutine 4 [running]:
      panic(0x45cb40, 0x47ad70)
        /usr/local/go/src/runtime/panic.go:542 +0x46c fp=0xc42003f7b8 sp=0xc42003f710 pc=0x422f7c
      main.main.func1(0xc420024120)
        foo.go:6 +0x39 fp=0xc42003f7d8 sp=0xc42003f7b8 pc=0x451339
      runtime.goexit()
        /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc42003f7e0 sp=0xc42003f7d8 pc=0x44b4d1
      created by main.main
        foo.go:5 +0x58
      
      goroutine 1 [chan receive]:
      runtime.gopark(0x4739b8, 0xc420024178, 0x46fcd7, 0xc, 0xc420028e17, 0x3)
        /usr/local/go/src/runtime/proc.go:280 +0x12c fp=0xc420053e30 sp=0xc420053e00 pc=0x42503c
      runtime.goparkunlock(0xc420024178, 0x46fcd7, 0xc, 0x1000f010040c217, 0x3)
        /usr/local/go/src/runtime/proc.go:286 +0x5e fp=0xc420053e70 sp=0xc420053e30 pc=0x42512e
      runtime.chanrecv(0xc420024120, 0x0, 0xc420053f01, 0x4512d8)
        /usr/local/go/src/runtime/chan.go:506 +0x304 fp=0xc420053f20 sp=0xc420053e70 pc=0x4046b4
      runtime.chanrecv1(0xc420024120, 0x0)
        /usr/local/go/src/runtime/chan.go:388 +0x2b fp=0xc420053f50 sp=0xc420053f20 pc=0x40439b
      main.main()
        foo.go:9 +0x6f fp=0xc420053f80 sp=0xc420053f50 pc=0x4512ef
      runtime.main()
        /usr/local/go/src/runtime/proc.go:185 +0x20d fp=0xc420053fe0 sp=0xc420053f80 pc=0x424bad
      runtime.goexit()
        /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc420053fe8 sp=0xc420053fe0 pc=0x44b4d1
      
      goroutine 2 [force gc (idle)]:
      runtime.gopark(0x4739b8, 0x4ad720, 0x47001e, 0xf, 0x14, 0x1)
        /usr/local/go/src/runtime/proc.go:280 +0x12c fp=0xc42003e768 sp=0xc42003e738 pc=0x42503c
      runtime.goparkunlock(0x4ad720, 0x47001e, 0xf, 0xc420000114, 0x1)
        /usr/local/go/src/runtime/proc.go:286 +0x5e fp=0xc42003e7a8 sp=0xc42003e768 pc=0x42512e
      runtime.forcegchelper()
        /usr/local/go/src/runtime/proc.go:238 +0xcc fp=0xc42003e7e0 sp=0xc42003e7a8 pc=0x424e5c
      runtime.goexit()
        /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc42003e7e8 sp=0xc42003e7e0 pc=0x44b4d1
      created by runtime.init.4
        /usr/local/go/src/runtime/proc.go:227 +0x35
      
      goroutine 3 [GC sweep wait]:
      runtime.gopark(0x4739b8, 0x4ad7e0, 0x46fdd2, 0xd, 0x419914, 0x1)
        /usr/local/go/src/runtime/proc.go:280 +0x12c fp=0xc42003ef60 sp=0xc42003ef30 pc=0x42503c
      runtime.goparkunlock(0x4ad7e0, 0x46fdd2, 0xd, 0x14, 0x1)
        /usr/local/go/src/runtime/proc.go:286 +0x5e fp=0xc42003efa0 sp=0xc42003ef60 pc=0x42512e
      runtime.bgsweep(0xc42001e150)
        /usr/local/go/src/runtime/mgcsweep.go:52 +0xa3 fp=0xc42003efd8 sp=0xc42003efa0 pc=0x419973
      runtime.goexit()
        /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc42003efe0 sp=0xc42003efd8 pc=0x44b4d1
      created by runtime.gcenable
        /usr/local/go/src/runtime/mgc.go:216 +0x58
      one more line, no multiline
      ```

   1. 儲存 `test.log` 檔案。

1. 在 `multiline-app` 資料夾內，建立 Dockerfile。

   1. 將以下內容貼到該檔案：

      ```
      FROM public.ecr.aws/amazonlinux/amazonlinux:latest
      ADD test.log /test.log
      
      RUN yum upgrade -y && yum install -y python3
      
      WORKDIR /usr/local/bin
      
      COPY main.py .
      
      CMD ["python3", "main.py"]
      ```

   1. 儲存 `Dockerfile` 檔案。

1. 使用 Dockerfile，建置映像。

   1. 建置映像：`docker build -t multiline-app-image `

      其中：`multiline-app-image` 是此範例中映像的名稱。

   1. 驗證映像已正確建立：`docker images —filter reference=multiline-app-image`

      如果成功，輸出會顯示映像和 `latest` 標籤。

1. 將映像上傳至 Amazon Elastic 容器登錄檔。

   1. 建立 Amazon ECR 儲存庫，以便存放映像：`aws ecr create-repository --repository-name multiline-app-repo --region us-east-1`

      其中：`multiline-app-repo` 是此範例中儲存庫的名稱，`us-east-1` 是此範例中的區域。

      輸出為您提供了新儲存庫的詳細資訊。請記下 `repositoryUri` 值，因為您將在後續步驟用到它。

   1. 使用來自先前輸出的 `repositoryUri` 值，標記您的映像：`docker tag multiline-app-image repositoryUri`

      範例：`docker tag multiline-app-image xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/multiline-app-repo`

   1. 執行 Docker 影像以確認是否能正確執行：`docker images —filter reference=repositoryUri`

      在輸出中，儲存庫名稱會從 `multiline-app-repo` 變更為 `repositoryUri` 值。

   1. 將映像推送至 Amazon ECR：`docker push aws_account_id.dkr.ecr.region.amazonaws.com/repository name`

      範例：`docker push xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/multiline-app-repo`

**建立任務定義並執行任務**

1. 建立檔案名稱為 `multiline-task-definition.json` 的任務定義檔案。

1. 將以下內容貼到該 `multiline-task-definition.json` 檔案：

   ```
   {
       "family": "firelens-example-multiline",
       "taskRoleArn": "task role ARN,
       "executionRoleArn": "execution role ARN",
       "containerDefinitions": [
           {
               "essential": true,
               "image": "aws_account_id.dkr.ecr.us-east-1.amazonaws.com/fluent-bit-multiline-image:latest",
               "name": "log_router",
               "firelensConfiguration": {
                   "type": "fluentbit",
                   "options": {
                       "config-file-type": "file",
                       "config-file-value": "/extra.conf"
                   }
               },
               "memoryReservation": 50
           },
           {
               "essential": true,
               "image": "aws_account_id.dkr.ecr.us-east-1.amazonaws.com/multiline-app-image:latest",
               "name": "app",
               "logConfiguration": {
                   "logDriver": "awsfirelens",
                   "options": {
                       "Name": "cloudwatch_logs",
                       "region": "us-east-1",
                       "log_group_name": "multiline-test/application",
                       "auto_create_group": "true",
                       "log_stream_prefix": "multiline-"
                   }
               },
               "memoryReservation": 100
           }
       ],
       "requiresCompatibilities": ["FARGATE"],
       "networkMode": "awsvpc",
       "cpu": "256",
       "memory": "512"
   }
   ```

   取代下列在 `multiline-task-definition.json` 任務定義中的項目：

   1. `task role ARN`

      若要尋找任務角色 ARN，請前往 IAM 主控台。選擇 **Roles** (角色) 並尋找您建立的 `ecs-task-role-for-firelens` 任務角色。選擇角色並複製顯示於 **Summary** (摘要) 區段的 **ARN**。

   1. `execution role ARN`

      若要尋找執行角色 ARN，請前往 IAM 主控台。選擇 **Roles** (角色) 並尋找 `ecsTaskExecutionRole` 角色。選擇角色並複製顯示於 **Summary** (摘要) 區段的 **ARN**。

   1. `aws_account_id`

      若要尋找您的 `aws_account_id`，請登入 AWS 管理主控台。選擇右上角的使用者名稱並複製您的帳戶 ID。

   1. `us-east-1`

      如有必要，請取代該區域。

1. 註冊任務定義檔案：`aws ecs register-task-definition --cli-input-json file://multiline-task-definition.json --region us-east-1`

1. 開啟主控台，網址為 [https://console.aws.amazon.com/ecs/v2](https://console.aws.amazon.com/ecs/v2)。

1. 在導覽窗格中，選擇 **Task Definitions** (任務定義)，然後選擇 `firelens-example-multiline` 系列，因為我們已在上述任務定義的第一行中將任務定義註冊到此系列。

1. 選擇最新版本。

1. 選擇**部署**、**執行任務**。

1. 在**執行任務**頁面上，針對**叢集**選擇叢集，然後在**聯網**下，針對**子網路**選擇任務的可用子網路。

1. 選擇**建立**。

**確認 Amazon CloudWatch 中的多行日誌訊息是否顯示為串連**

1. 透過 [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/) 開啟 CloudWatch 主控台。

1. 在導覽窗格中，展開 **Logs** (日誌) 並選擇 **Log groups** (日誌群組)。

1. 選擇 `multiline-test/applicatio` 日誌群組。

1. 選擇日誌並檢視訊息。系統會串連與剖析器檔案中的規則相符之明細行，並顯示為單則訊息。

   下列日誌程式碼片段顯示了串連到單一事件的 Go 堆疊追蹤：

   ```
   {
       "log": "panic: my panic\n\ngoroutine 4 [running]:\npanic(0x45cb40, 0x47ad70)\n  /usr/local/go/src/runtime/panic.go:542 +0x46c fp=0xc42003f7b8 sp=0xc42003f710 pc=0x422f7c\nmain.main.func1(0xc420024120)\n  foo.go:6 +0x39 fp=0xc42003f7d8 sp=0xc42003f7b8 pc=0x451339\nruntime.goexit()\n  /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc42003f7e0 sp=0xc42003f7d8 pc=0x44b4d1\ncreated by main.main\n  foo.go:5 +0x58\n\ngoroutine 1 [chan receive]:\nruntime.gopark(0x4739b8, 0xc420024178, 0x46fcd7, 0xc, 0xc420028e17, 0x3)\n  /usr/local/go/src/runtime/proc.go:280 +0x12c fp=0xc420053e30 sp=0xc420053e00 pc=0x42503c\nruntime.goparkunlock(0xc420024178, 0x46fcd7, 0xc, 0x1000f010040c217, 0x3)\n  /usr/local/go/src/runtime/proc.go:286 +0x5e fp=0xc420053e70 sp=0xc420053e30 pc=0x42512e\nruntime.chanrecv(0xc420024120, 0x0, 0xc420053f01, 0x4512d8)\n  /usr/local/go/src/runtime/chan.go:506 +0x304 fp=0xc420053f20 sp=0xc420053e70 pc=0x4046b4\nruntime.chanrecv1(0xc420024120, 0x0)\n  /usr/local/go/src/runtime/chan.go:388 +0x2b fp=0xc420053f50 sp=0xc420053f20 pc=0x40439b\nmain.main()\n  foo.go:9 +0x6f fp=0xc420053f80 sp=0xc420053f50 pc=0x4512ef\nruntime.main()\n  /usr/local/go/src/runtime/proc.go:185 +0x20d fp=0xc420053fe0 sp=0xc420053f80 pc=0x424bad\nruntime.goexit()\n  /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc420053fe8 sp=0xc420053fe0 pc=0x44b4d1\n\ngoroutine 2 [force gc (idle)]:\nruntime.gopark(0x4739b8, 0x4ad720, 0x47001e, 0xf, 0x14, 0x1)\n  /usr/local/go/src/runtime/proc.go:280 +0x12c fp=0xc42003e768 sp=0xc42003e738 pc=0x42503c\nruntime.goparkunlock(0x4ad720, 0x47001e, 0xf, 0xc420000114, 0x1)\n  /usr/local/go/src/runtime/proc.go:286 +0x5e fp=0xc42003e7a8 sp=0xc42003e768 pc=0x42512e\nruntime.forcegchelper()\n  /usr/local/go/src/runtime/proc.go:238 +0xcc fp=0xc42003e7e0 sp=0xc42003e7a8 pc=0x424e5c\nruntime.goexit()\n  /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc42003e7e8 sp=0xc42003e7e0 pc=0x44b4d1\ncreated by runtime.init.4\n  /usr/local/go/src/runtime/proc.go:227 +0x35\n\ngoroutine 3 [GC sweep wait]:\nruntime.gopark(0x4739b8, 0x4ad7e0, 0x46fdd2, 0xd, 0x419914, 0x1)\n  /usr/local/go/src/runtime/proc.go:280 +0x12c fp=0xc42003ef60 sp=0xc42003ef30 pc=0x42503c\nruntime.goparkunlock(0x4ad7e0, 0x46fdd2, 0xd, 0x14, 0x1)\n  /usr/local/go/src/runtime/proc.go:286 +0x5e fp=0xc42003efa0 sp=0xc42003ef60 pc=0x42512e\nruntime.bgsweep(0xc42001e150)\n  /usr/local/go/src/runtime/mgcsweep.go:52 +0xa3 fp=0xc42003efd8 sp=0xc42003efa0 pc=0x419973\nruntime.goexit()\n  /usr/local/go/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc42003efe0 sp=0xc42003efd8 pc=0x44b4d1\ncreated by runtime.gcenable\n  /usr/local/go/src/runtime/mgc.go:216 +0x58",
       "container_id": "xxxxxx-xxxxxx",
       "container_name": "app",
       "source": "stdout",
       "ecs_cluster": "default",
       "ecs_task_arn": "arn:aws:ecs:us-east-1:xxxxxxxxxxxx:task/default/xxxxxx",
       "ecs_task_definition": "firelens-example-multiline:2"
   }
   ```

   下列日誌程式碼片段顯示了相同事件顯示的方式 (如果您執行了未串連多行日誌訊息的 ECS 容器)。日誌欄位包含單筆明細行。

   ```
   {
       "log": "panic: my panic",
       "container_id": "xxxxxx-xxxxxx",
       "container_name": "app",
       "source": "stdout",
       "ecs_cluster": "default",
       "ecs_task_arn": "arn:aws:ecs:us-east-1:xxxxxxxxxxxx:task/default/xxxxxx",
       "ecs_task_definition": "firelens-example-multiline:3"
   ```

**注意**  
如果您的日誌轉到日誌檔案而不是標準輸出，我們建議您在[結尾輸入外掛程式](https://docs.fluentbit.io/manual/pipeline/inputs/tail#multiline-support) (而非篩選條件) 中指定 `multiline.parser` 和 `multiline.key_content` 組態參數。