连接多行或堆栈跟踪日志消息 - Amazon Elastic Container Service
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 Amazon Web Services 服务入门

连接多行或堆栈跟踪日志消息

从 Amazon for Fluent Bit 版本 2.22.0 开始,包含多行筛选条件。多行筛选条件有助于连接原属于一个上下文但被分割为多个记录或日志行的日志消息。有关多行筛选条件的更多信息,请参阅 Fluent Bit 文档

拆分日志消息的常见示例有:

  • 堆栈跟踪。

  • 在多行上打印日志的应用程序。

  • 因为比指定的运行时间最大缓冲区大小长而拆分的日志消息。您可以按照 GitHub 中的以下示例来连接被容器运行时拆分的日志消息:FireLens Example: Concatenate Partial/Split Container Logs(FireLens 示例:连接部分/拆分的容器日志)。

所需的 IAM 权限

您拥有使用容器代理从 Amazon ECR 中提取容器镜像以及使用容器将日志路由到 CloudWatch Logs 的所需 IAM 权限。

对于这些权限,您还必须具有以下角色:

  • 任务 IAM 角色。

  • Amazon ECS 任务执行 IAM 角色。

创建任务 IAM 角色

此任务角色向 FireLens 日志路由器容器授予将日志路由到目标所需的权限。在此示例中,我们将日志路由到 CloudWatch Logs。要创建此角色,请创建具有创建日志流、日志组和录入事件的权限的策略。然后,将策略与角色关联。

  1. 通过以下网址打开 IAM 控制台:https://console.aws.amazon.com/iam/

  2. 在导航窗格中选择 Policies (策略),然后选择 Create Policy (创建策略)

  3. 选择 JSON 并粘贴以下权限:

    { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": [ "logs:CreateLogStream", "logs:CreateLogGroup", "logs:PutLogEvents" ], "Resource": "*" }] }
  4. 选择 Next: Tags(下一步:标签),然后向策略添加任何标签以帮助您组织它们。然后选择 Next: Review

  5. Review policy(查看策略)页面上,为 Name(名称)键入策略的唯一名称。在此示例中,我们将使用 ecs-policy-for-firelens。您也可以为策略指定可选描述。

  6. 选择 Create policy (创建策略) 以完成。

  7. 在导航窗格中,选择 Roles(角色),然后选择 Create Roles(创建角色)。

  8. Trusted entity type(受信任的实体类型)部分中,选择 Amazon Web Service

  9. 对于 Use case(使用案例),选择 Elastic Container Service

  10. 选择 Elastic Container Service Task(Elastic Container Service 任务),然后选择 Next(下一步)。

  11. 将角色与您创建的 ecs-policy-for-firelens 关联并选择 Next(下一步)。

  12. 为角色输入唯一名称。在此示例中,使用:ecs-task-role-for-firelens

请确认您拥有 Amazon ECS 任务执行 IAM 角色

您必须具有任务执行角色才能授予容器代理从 Amazon ECR 中提取容器镜像的权限。

  1. 通过以下网址打开 IAM 控制台:https://console.aws.amazon.com/iam/

  2. 在导航窗格中,选择 Roles(角色),然后搜索 ecsTaskExecutionRole

  3. 如果您没有看到 ecsTaskExecutionRole 角色,则必须创建该角色。有关如何创建角色的信息,请参阅《Amazon Elastic Container Service 开发人员指南》中的 Amazon ECS 任务执行 IAM 角色

确定何时使用多行日志设置

以下是您将在使用默认日志设置的 CloudWatch Logs 控制台中看到的示例日志片段。您可以查看以 log 开头的行,以确定是否需要多行筛选条件。当上下文相同时,您可以使用多行日志设置,在本例中,上下文是 "

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

解析和连接选项

要解析日志并连接因换行符而被拆分的行,您可以使用这两个选项之一。

  • 使用自己的解析器文件,该文件中包含用于解析和连接属于同一消息的行的规则。

  • 使用 Fluent Bit 内置解析器。有关 Fluent Bit 内置解析器支持的语言的列表,请参阅 Fluent Bit 文档。

以下教程将引导您完成每个使用案例的步骤。这些步骤向您展示了如何连接多行并将日志发送到 Amazon CloudWatch。您可以为日志指定其他目标。

示例:使用您创建的解析器

在本示例中,您将完成以下步骤:

  1. 为 Fluent Bit 容器生成并上传镜像。

  2. 为运行、失败和生成多行堆栈跟踪的演示多行应用程序生成并上传镜像。

  3. 创建任务定义并运行任务。

  4. 查看日志以验证跨越多行的消息是否连接起来。

为 Fluent Bit 容器生成并上传镜像

此镜像将包括您在其中指定正则表达式的解析器文件和引用解析器文件的配置文件。

  1. 使用名称 FluentBitDockerImage 创建文件夹。

  2. 在文件夹内,创建解析器文件,其中包含用于解析日志和连接属于同一消息的行的规则。

    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"

      自定义正则表达式模式时,我们建议您使用正则表达式编辑器来测试表达式。

    2. 将该文件保存为 parsers_multiline.conf

  3. FluentBitDockerImage 文件夹中,创建引用您在上一步中创建的解析器文件的自定义配置文件。

    有关自定义配置文件的更多信息,请参阅《Amazon Elastic Container Service 开发人员指南》中的指定自定义配置文件

    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
      注意

      您必须使用解析器的绝对路径。

    2. 将该文件保存为 extra.conf

  4. 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
    2. 将该文件保存为 Dockerfile

  5. 使用 Dockerfile,构建一个包含解析器和自定义配置文件的自定义 Fluent Bit 镜像。

    注意

    您可以将解析器文件和配置文件放置在 Docker 镜像中的任何位置,但 /fluent-bit/etc/fluent-bit.conf 除外,因为 FireLens 使用这个文件路径。

    1. 生成镜像:docker build -t fluent-bit-multiline-image .

      其中:fluent-bit-multiline-image 是此示例中镜像的名称。

    2. 验证是否已正确创建镜像:docker images —filter reference=fluent-bit-multiline-image

      如果成功,输出将显示该镜像和 latest 标签。

  6. 将自定义 Fluent Bit 镜像上传到 Amazon Elastic Container Registry。

    1. 创建用于存储镜像的 Amazon ECR 存储库:aws ecr create-repository --repository-name fluent-bit-multiline-repo --region us-east-1

      其中:fluent-bit-multiline-repo 是存储库的名称,us-east-1 是此示例中的区域。

      输出为您提供了新存储库的详细信息。

    2. 使用上一个输出中的 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

    3. 运行 Docker 镜像以验证它是否正确运行:docker images —filter reference=repositoryUri

      在输出中,存储库名称从 fluent-bit-multiline-repo 更改为 repositoryUri

    4. 通过运行 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

      此时会显示成功登录消息。

    5. 将镜像推送到 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

  2. 创建 Python 脚本文件。

    1. multiline-app 文件夹中,创建一个文件并将其命名为 main.py

    2. 将以下内容粘贴到该文件中:

      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.")
    3. 保存 main.py 文件。

  3. 创建示例日志文件。

    1. multiline-app 文件夹中,创建一个文件并将其命名为 test.log

    2. 将以下内容粘贴到该文件中:

      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...
    3. 保存 test.log 文件。

  4. 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"]
    2. 保存 Dockerfile 文件。

  5. 使用 Dockerfile 生成镜像。

    1. 生成镜像:docker build -t multiline-app-image .

      其中:multiline-app-image 是此示例中镜像的名称。

    2. 验证是否已正确创建镜像:docker images —filter reference=multiline-app-image

      如果成功,输出将显示该镜像和 latest 标签。

  6. 将镜像上载到 Amazon Elastic Container 注册表。

    1. 创建用于存储镜像的 Amazon ECR 存储库:aws ecr create-repository --repository-name multiline-app-repo --region us-east-1

      其中:multiline-app-repo 是存储库的名称,us-east-1 是此示例中的区域。

      输出为您提供了新存储库的详细信息。记下 repositoryUri 值,您将需要在后续步骤中使用该值。

    2. 使用上一个输出中的 repositoryUri 值标记您的镜像:docker tag multiline-app-image repositoryUri

      示例:docker tag multiline-app-image xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/multiline-app-repo

    3. 运行 Docker 镜像以验证它是否正确运行:docker images —filter reference=repositoryUri

      在输出中,存储库名称从 multiline-app-repo 更改为 repositoryUri 值。

    4. 将镜像推送到 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 创建任务定义文件。

  2. 将以下内容粘贴到 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

    2. execution role ARN

      要查找执行角色 ARN,请转到 IAM 控制台。选择 Roles(角色),然后查找 ecsTaskExecutionRole 角色。选择角色,然后复制 Summary(摘要)部分中显示的 ARN

    3. aws_account_id

      要查找您的 aws_account_id,登录 Amazon Web Services Management Console。在右上角选择您的用户名,然后复制您的账户 ID。

    4. us-east-1

      如有必要,请更换区域。

  3. 注册任务定义文件:aws ecs register-task-definition --cli-input-json file://multiline-task-definition.json --region region

  4. 打开 https://console.aws.amazon.com/ecs/ 上的 Amazon ECS 控制台。

  5. 在导航窗格中,选择 Task Definitions(任务定义),然后选择 firelens-example-multiline 系列,因为我们已在上面任务定义的第一行中将任务定义注册到这个系列。

  6. 选择最新版本。

  7. 选择 Actions(操作)、Run Task(运行任务)。

  8. 对于 Launch type(启动类型),选择 Fargate

  9. 对于 Subnets,请为您的任务选择可用子网。

  10. 选择 Run Task (运行任务)

验证 Amazon CloudWatch 中的多行日志消息是否已连接

  1. 通过以下网址打开 CloudWatch 控制台:https://console.aws.amazon.com/cloudwatch/

  2. 从导航窗格中,展开 Logs(日志)并选择 Log groups(日志组)。

  3. 选择 multiline-test/applicatio 日志组。

  4. 选择日志。查看消息。与解析器文件中的规则匹配的行将串联起来,并显示为单条消息。

    以下日志片段显示了在单个 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 内置解析器

在本示例中,您将完成以下步骤:

  1. 为 Fluent Bit 容器生成并上传镜像。

  2. 为运行、失败和生成多行堆栈跟踪的演示多行应用程序生成并上传镜像。

  3. 创建任务定义并运行任务。

  4. 查看日志以验证跨越多行的消息是否连接起来。

为 Fluent Bit 容器生成并上传镜像

此镜像将包含一个引用 Fluent Bit 解析器的配置文件。

  1. 使用名称 FluentBitDockerImage 创建文件夹。

  2. FluentBitDockerImage 文件夹中,创建引用 Fluent Bit 内置解析器文件的自定义配置文件。

    有关自定义配置文件的更多信息,请参阅《Amazon Elastic Container Service 开发人员指南》中的指定自定义配置文件

    1. 将以下内容粘贴到 文件中:

      [FILTER] name multiline match * multiline.key_content log multiline.parser go
    2. 将该文件保存为 extra.conf

  3. FluentBitDockerImage 文件夹中,使用 Fluent Bit 镜像以及您创建的解析器和配置文件创建 Dockerfile。

    1. 将以下内容粘贴到该文件中:

      FROM public.ecr.aws/aws-observability/aws-for-fluent-bit:latest ADD extra.conf /extra.conf
    2. 将该文件保存为 Dockerfile

  4. 使用 Dockerfile,构建一个包含自定义配置文件的自定义 Fluent Bit 镜像。

    注意

    您可以将配置文件放置在 Docker 镜像中的任何位置,但 /fluent-bit/etc/fluent-bit.conf 除外,因为 FireLens 使用这个文件路径。

    1. 生成镜像:docker build -t fluent-bit-multiline-image .

      其中:fluent-bit-multiline-image 是此示例中镜像的名称。

    2. 验证是否已正确创建镜像:docker images —filter reference=fluent-bit-multiline-image

      如果成功,输出将显示该镜像和 latest 标签。

  5. 将自定义 Fluent Bit 镜像上传到 Amazon Elastic Container Registry。

    1. 创建用于存储镜像的 Amazon ECR 存储库:aws ecr create-repository --repository-name fluent-bit-multiline-repo --region us-east-1

      其中:fluent-bit-multiline-repo 是存储库的名称,us-east-1 是此示例中的区域。

      输出为您提供了新存储库的详细信息。

    2. 使用上一个输出中的 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

    3. 运行 Docker 镜像以验证它是否正确运行:docker images —filter reference=repositoryUri

      在输出中,存储库名称从 fluent-bit-multiline-repo 更改为 repositoryUri

    4. 通过运行 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

      此时会显示成功登录消息。

    5. 将镜像推送到 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

  2. 创建 Python 脚本文件。

    1. multiline-app 文件夹中,创建一个文件并将其命名为 main.py

    2. 将以下内容粘贴到该文件中:

      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.")
    3. 保存 main.py 文件。

  3. 创建示例日志文件。

    1. multiline-app 文件夹中,创建一个文件并将其命名为 test.log

    2. 将以下内容粘贴到该文件中:

      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
    3. 保存 test.log 文件。

  4. 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"]
    2. 保存 Dockerfile 文件。

  5. 使用 Dockerfile 生成镜像。

    1. 生成镜像:docker build -t multiline-app-image .

      其中:multiline-app-image 是此示例中镜像的名称。

    2. 验证是否已正确创建镜像:docker images —filter reference=multiline-app-image

      如果成功,输出将显示该镜像和 latest 标签。

  6. 将镜像上载到 Amazon Elastic Container 注册表。

    1. 创建用于存储镜像的 Amazon ECR 存储库:aws ecr create-repository --repository-name multiline-app-repo --region us-east-1

      其中:multiline-app-repo 是存储库的名称,us-east-1 是此示例中的区域。

      输出为您提供了新存储库的详细信息。记下 repositoryUri 值,您将需要在后续步骤中使用该值。

    2. 使用上一个输出中的 repositoryUri 值标记您的镜像:docker tag multiline-app-image repositoryUri

      示例:docker tag multiline-app-image xxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/multiline-app-repo

    3. 运行 Docker 镜像以验证它是否正确运行:docker images —filter reference=repositoryUri

      在输出中,存储库名称从 multiline-app-repo 更改为 repositoryUri 值。

    4. 将镜像推送到 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 创建任务定义文件。

  2. 将以下内容粘贴到 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

    2. execution role ARN

      要查找执行角色 ARN,请转到 IAM 控制台。选择 Roles(角色),然后查找 ecsTaskExecutionRole 角色。选择角色,然后复制 Summary(摘要)部分中显示的 ARN

    3. aws_account_id

      要查找您的 aws_account_id,登录 Amazon Web Services Management Console。在右上角选择您的用户名,然后复制您的账户 ID。

    4. us-east-1

      如有必要,请更换区域。

  3. 注册任务定义文件:aws ecs register-task-definition --cli-input-json file://multiline-task-definition.json --region us-east-1

  4. 打开 https://console.aws.amazon.com/ecs/ 上的 Amazon ECS 控制台。

  5. 在导航窗格中,选择 Task Definitions(任务定义),然后选择 firelens-example-multiline 系列,因为我们已在上面任务定义的第一行中将任务定义注册到这个系列。

  6. 选择最新版本。

  7. 选择 Actions(操作)、Run Task(运行任务)。

  8. 对于 Launch type(启动类型),选择 Fargate

  9. 对于 Subnets,请为您的任务选择可用子网。

  10. 选择 Run Task (运行任务)

验证 Amazon CloudWatch 中的多行日志消息是否已连接

  1. 通过以下网址打开 CloudWatch 控制台:https://console.aws.amazon.com/cloudwatch/

  2. 从导航窗格中,展开 Logs(日志)并选择 Log groups(日志组)。

  3. 选择 multiline-test/applicatio 日志组。

  4. 选择日志并查看消息。与解析器文件中的规则匹配的行将串联起来,并显示为单条消息。

    以下日志代码段显示了在单个事件中连接的 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"
注意

如果您的日志转到日志文件而不是标准输出,我们建议在结尾输入插件中指定 multiline.parsermultiline.key_content 配置参数,而不是筛选条件。