I tried setting up correlation between traces and logs in CloudWatch Application Signals

I tried setting up correlation between traces and logs in CloudWatch Application Signals

Log correlation can be easily configured
2026.02.12

This page has been translated by machine translation. View original

Hello, this is nonPi (@non____97).

Have you ever wanted to easily check logs related to traces while using CloudWatch Application Signals? I have.

When you click on a metrics graph in Application Signals, up to 10 spans are displayed from the point you clicked.

8.相関するスパン.png

You can check trace details by clicking on the trace ID of one of these spans.

12.障害のトレース.png

By being able to check logs related to traces together, you can immediately see detailed error messages and stack traces without having to search for logs separately, reducing investigation time.

The implementation method is described in the following AWS official documentation:

You can enable trace log correlation in Application Signals. This automatically inserts trace IDs and span IDs into related application logs. Then, when you open a trace details page in the Application Signals console, if there are log entries related to the current trace, they are automatically displayed at the bottom of the page.

For example, you might notice a spike in a latency graph. You can select that point on the graph to load diagnostic information for that moment. Then, you can select a related trace to see detailed information. When you view the trace information, you can scroll down to see the logs associated with that trace. Examining these logs might help you identify the issue causing the latency spike and reveal related patterns or error codes.

Enable trace log correlation - Amazon CloudWatch

I actually tried it.

Summary

  • To correlate logs, follow these steps:
    • Embedding trace information in logs
      • Be careful whether the package and version you're using is supported by the zero-code instrumentation library
    • Specifying the log output destination
      • Specify with aws.log.group.names in OTEL_RESOURCE_ATTRIBUTES
  • CloudWatch Logs Insights operates behind the scenes for log correlation
    • It automatically queries log groups starting with /ecs/

What I Did

Testing Environment

The testing environment is as follows:

AWS Distro for OpenTelemetry (ADOT) Collector と ADOT SDKをとでCloudWatch Application Signalsを使ってみた.png

Logs are output using AWS FireLens (AWS for Fluent Bit), with error logs going to CloudWatch Logs and all logs being sent to an S3 bucket via Data Firehose.

テレメトリ.png

It's based on the following article:

https://dev.classmethod.jp/articles/cloudwatch-application-signals-with-adot-collector-and-sdk/

All resources are deployed with AWS CDK. The code used is:

https://github.com/non-97/ecs-native-blue-green/tree/v2.0.2

After deployment, the Open Telemetry and Application Signals related environment variables are:

Key Value
OTEL_AWS_APPLICATION_SIGNALS_ENABLED false
OTEL_EXPORTER_OTLP_ENDPOINT http://localhost:4318
OTEL_EXPORTER_OTLP_PROTOCOL http/protobuf
OTEL_LOGS_EXPORTER none
OTEL_METRICS_EXPORTER none
OTEL_PROPAGATORS tracecontext,baggage,xray
OTEL_RESOURCE_ATTRIBUTES service.name=ecs-express-app,deployment.environment=ecs:EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-4JfsTzadcWYq,aws.log.group.names=EcsNativeBlueGreenStack-FirelensConstructFirelensLogGroupD186C82F-Oieo4YPQifeI
OTEL_TRACES_EXPORTER otlp
OTEL_TRACES_SAMPLER xray
OTEL_TRACES_SAMPLER_ARG endpoint=http://localhost:2000,polling_interval=300

Embedding Trace Information in Logs

First, you need to embed trace information in logs.

Checking the AWS official documentation below, for Node.js, it recommends using zero-code instrumentation libraries for each logger:

Node.js

For details on how to enable trace context insertion in Node.js to work with Node.js-compatible logging libraries, see the documentation on using NPM for automatic instrumentation of either Pino, Winston, or Bunyan in Node.js.

Enable trace log correlation - Amazon CloudWatch

Since I'm using Pino in this case, I need to use @opentelemetry/instrumentation-pino.

As I'm using public.ecr.aws/aws-observability/adot-autoinstrumentation-node:v0.8.1 in an Init container, there's no need to install @opentelemetry/instrumentation-pino separately.

Checking the releases of aws-observability/aws-otel-js-instrumentation, you can see that this container image includes aws-otel-js-instrumentation:

See ADOT node auto-instrumentation Docker image v0.8.1 in our public ECR repository:
https://gallery.ecr.aws/aws-observability/adot-autoinstrumentation-node

Releases · aws-observability/aws-otel-js-instrumentation

And by checking the package-lock.json of aws-otel-js-instrumentation, you can see that the Pino zero-code instrumentation library version ^0.46.0 is included:

https://github.com/aws-observability/aws-otel-js-instrumentation/blob/v0.8.1/package-lock.json#L4269

The important thing to note is the Pino version.

For the zero-code instrumentation library version 0.46.0, the supported Pino versions are >=5.14.0 <10:

pino versions >=5.14.0 <10
The "log sending" feature is only supported in pino v7 and later.

@opentelemetry/instrumentation-pino - npm

The latest Pino version is 10.3.1. Therefore, if you don't specify a version, you'll be using a version of Pino that the zero-code instrumentation library doesn't support.

When Pino's zero-code instrumentation is working correctly, trace_id and span_id are added as follows:

Pinoのゼロコード計装が正常に行われている場合
{
    "level": "error",
    "time": "2026-02-11T00:42:49.466Z",
    "pid": 6,
    "hostname": "ip-10-10-8-112.ec2.internal",
    "req": {
        "id": 36,
        "method": "GET",
        "url": "/error/",
        "query": {},
        "params": {},
        "headers": {
            "host": "ecsnat-albco-qzyosxmqsim4-1634003559.us-east-1.elb.amazonaws.com",
            "x-real-ip": "10.10.8.10",
            "x-forwarded-for": "<送信元IPアドレス>, 10.10.8.10",
            "x-forwarded-proto": "http",
            "connection": "close",
            "x-forwarded-port": "80",
            "x-amzn-trace-id": "Root=1-698bd089-3e85c9ad79fddc8706f7ad7f",
            "cookie": "connect.sid=s%3Aa-rXSzyN-2POI_b5dkH4LkP6ijl68rve.zWuJDO786nBLrcXV3U70DxhwxfrFLqXFjPWwB9ATd%2FQ",
            "user-agent": "curl/8.7.1",
            "accept": "*/*"
        },
        "remoteAddress": "127.0.0.1",
        "remotePort": 57812
    },
    "trace_id": "698bd089673affe7e1c8a2add24be6a9",
    "span_id": "448e1d51d070a746",
    "trace_flags": "01",
    "res": {
        "statusCode": 500,
        "headers": {
            "x-powered-by": "Express",
            "content-type": "application/json; charset=utf-8",
            "content-length": "33",
            "etag": "W/\"21-Fau8GdrOCOyGNNH/IiTxy2DuMu0\""
        }
    },
    "err": {
        "type": "Error",
        "message": "failed with status code 500",
        "stack": "Error: failed with status code 500\n    at onResFinished (/app/node_modules/.pnpm/pino-http@10.5.0/node_modules/pino-http/logger.js:115:39)\n    at ServerResponse.onResponseComplete (/app/node_modules/.pnpm/pino-http@10.5.0/node_modules/pino-http/logger.js:178:14)\n    at /otel-auto-instrumentation/node_modules/@opentelemetry/context-async-hooks/build/src/AbstractAsyncHooksContextManager.js:50:55\n    at AsyncLocalStorage.run (node:internal/async_local_storage/async_context_frame:59:14)\n    at AsyncLocalStorageContextManager.with (/otel-auto-instrumentation/node_modules/@opentelemetry/context-async-hooks/build/src/AsyncLocalStorageContextManager.js:33:40)\n    at ServerResponse.contextWrapper (/otel-auto-instrumentation/node_modules/@opentelemetry/context-async-hooks/build/src/AbstractAsyncHooksContextManager.js:50:32)\n    at ServerResponse.emit (node:events:520:35)\n    at onFinish (node:_http_outgoing:1026:10)\n    at callback (node:internal/streams/writable:764:21)\n    at afterWrite (node:internal/streams/writable:708:5)"
    },
    "responseTime": 5,
    "msg": "request errored",
    "container_name": "app",
    "source": "stderr",
    "container_id": "6b8cc0c5e5f94ebe888e690dbb051168-0527074092",
    "ecs_cluster": "EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-zJnVnD9x7R6g",
    "ecs_task_arn": "arn:aws:ecs:us-east-1:<AWSアカウントID>:task/EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-zJnVnD9x7R6g/6b8cc0c5e5f94ebe888e690dbb051168",
    "ecs_task_definition": "EcsNativeBlueGreenStackEcsConstructTaskDefinitionF683F4B2:95"
}

On the other hand, when using Pino version 10 or later, trace information is not recorded:

Pinoのバージョンが10以上の場合
{
    "level": "error",
    "time": "2026-02-04T07:54:00.739Z",
    "pid": 6,
    "hostname": "ip-10-10-8-103.ec2.internal",
    "req": {
        "id": 63,
        "method": "GET",
        "url": "/error/",
        "query": {},
        "params": {},
        "headers": {
            "host": "ecsnat-albco-fgdpbvnooxwj-1973419334.us-east-1.elb.amazonaws.com",
            "x-real-ip": "10.10.8.57",
            "x-forwarded-for": "<送信元IPアドレス>, 10.10.8.57",
            "x-forwarded-proto": "http",
            "connection": "close",
            "x-forwarded-port": "80",
            "x-amzn-trace-id": "Root=1-6982fb18-3fb552d8541fd9151d48406f",
            "accept": "*/*",
            "user-agent": "curl/8.7.1"
        },
        "remoteAddress": "127.0.0.1",
        "remotePort": 53378
    },
    "res": {
        "statusCode": 500,
        "headers": {
            "x-powered-by": "Express",
            "content-type": "application/json; charset=utf-8",
            "content-length": "33",
            "etag": "W/\"21-Fau8GdrOCOyGNNH/IiTxy2DuMu0\"",
            "set-cookie": [
                "connect.sid=s%3An3YhhvIDKp6XWpVpDbx0U9F0GeNEHJxg.1HNNiMD4%2BhQEmjNdBO9NbQsADN67pKUccIeBYe%2Fp%2FVc; Path=/; Expires=Thu, 05 Feb 2026 07:54:00 GMT; HttpOnly"
            ]
        }
    },
    "err": {
        "type": "Error",
        "message": "failed with status code 500",
        "stack": "Error: failed with status code 500\n    at onResFinished (/app/node_modules/.pnpm/pino-http@11.0.0/node_modules/pino-http/logger.js:115:39)\n    at ServerResponse.onResponseComplete (/app/node_modules/.pnpm/pino-http@11.0.0/node_modules/pino-http/logger.js:178:14)\n    at /otel-auto-instrumentation/node_modules/@opentelemetry/context-async-hooks/build/src/AbstractAsyncHooksContextManager.js:50:55\n    at AsyncLocalStorage.run (node:internal/async_local_storage/async_context_frame:59:14)\n    at AsyncLocalStorageContextManager.with (/otel-auto-instrumentation/node_modules/@opentelemetry/context-async-hooks/build/src/AsyncLocalStorageContextManager.js:33:40)\n    at ServerResponse.contextWrapper (/otel-auto-instrumentation/node_modules/@opentelemetry/context-async-hooks/build/src/AbstractAsyncHooksContextManager.js:50:32)\n    at ServerResponse.emit (node:events:520:35)\n    at onFinish (node:_http_outgoing:1026:10)\n    at callback (node:internal/streams/writable:764:21)\n    at afterWrite (node:internal/streams/writable:708:5)"
    },
    "responseTime": 3,
    "msg": "request errored",
    "container_name": "app",
    "source": "stderr",
    "container_id": "0dfd495fff0048de92bd87f68daa8de1-0527074092",
    "ecs_cluster": "EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-s5tytpIiJ9VQ",
    "ecs_task_arn": "arn:aws:ecs:us-east-1:<AWSアカウントID>:task/EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-s5tytpIiJ9VQ/0dfd495fff0048de92bd87f68daa8de1",
    "ecs_task_definition": "EcsNativeBlueGreenStackEcsConstructTaskDefinitionF683F4B2:93"
}

Similarly, be careful with other packages like Express to ensure you're using versions supported by zero-code instrumentation. The supported versions are documented in the source code as well:

https://github.com/open-telemetry/opentelemetry-js-contrib/blob/12adb4354f09ade438cd96340bdfd1f715b5fed3/plugins/node/opentelemetry-instrumentation-express/src/instrumentation.ts#L53-L62

Specifying Log Output Destination

To correlate traces and logs, you need to specify the log output destination.

Specifically, you add aws.log.group.names=<target log group name> to the OTEL_RESOURCE_ATTRIBUTES.

(Optional) To enable Application Signals log correlation, additionally set the environment variable aws.log.group.names to your application log's log group name. This allows traces and metrics generated by your application to be correlated with corresponding log entries in this log group. In this variable, replace $YOUR_APPLICATION_LOG_GROUP with your application's log group name. If you have multiple log groups, you can use ampersands (&) to separate them, as in this example: aws.log.group.names=log-group-1&log-group-2. To enable log correlation for metrics, just setting this current environment variable is sufficient. For more information, see Enable log correlation for metrics. To enable log correlation for traces, you also need to modify your application's logging configuration. For more information, see Enable log correlation for traces.

Deploy using the sidecar strategy - Amazon CloudWatch

With this configuration, the specified log group names will appear in the cloudwatch_logs property under the aws property of the span.

{
    "ecs.task.arn": "arn:aws:ecs:us-east-1:<AWSアカウントID>:task/EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-zJnVnD9x7R6g/015048a8181a46e4bbc15539e33568f7",
    "ecs.task.family": "EcsNativeBlueGreenStackEcsConstructTaskDefinitionF683F4B2",
    "ecs.cluster.arn": "arn:aws:ecs:us-east-1:<AWSアカウントID>:cluster/EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-zJnVnD9x7R6g",
    "ecs": {
        "container": "ip-10-10-8-74.ec2.internal",
        "container_id": "46e4bbc15539e33568f7/015048a8181a46e4bbc15539e33568f7-0527074092"
    },
    "ecs.container.arn": "arn:aws:ecs:us-east-1:<AWSアカウントID>:container/EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-zJnVnD9x7R6g/015048a8181a46e4bbc15539e33568f7/8059f724-8aeb-4554-afd9-bddf9f15b80e",
    "ecs.launchtype": "fargate",
    "span.kind": "CLIENT",
    "cloudwatch_logs": [
        {
            "log_group": "EcsNativeBlueGreenStack-FirelensConstructFirelensLogGroupD186C82F-wTQ4890Mp8e9"
        }
    ],
    "ecs.task.revision": "100"
},

Note that log correlation will not work if you include ECS Detectors in your resourcedetection processor in the Open Telemetry Collector trace pipeline:

processors:
.
.
(omitted)
.
.
  resourcedetection:
    detectors: [env, ecs]
    timeout: 5s
    override: false
.
.
(omitted)
.
.
service:
  extensions: [sigv4auth, awsproxy]
  pipelines:
    traces:
      receivers: [otlp]
      processors: [filter/exclude_health, resourcedetection, batch]
      exporters: [otlphttp]

Specifically, you'll see an error message like "Error occurred while retrieving data":

1.データの取得中にエラーが発生しました.png

Note: The same result occurs whether from "CloudWatch > Transaction Search" or "CloudWatch > Traces"

As mentioned later, CloudWatch Logs Insights runs behind the scenes for log correlation, but in this case there was no evidence that Logs Insights was executed.

By the way, in this case, the aws property of the span contained the log group and log stream for the container's log output destination using the awslogs log driver in cloudwatch_logs, log.stream.arns, and log.stream.names:

{
  "ecs.task.arn": "arn:aws:ecs:us-east-1:<AWSアカウントID>:task/EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-zJnVnD9x7R6g/2a9e9b028b6b4bd0b4edf85023bd9c3b",
  "ecs.task.family": "EcsNativeBlueGreenStackEcsConstructTaskDefinitionF683F4B2",
  "ecs.cluster.arn": "arn:aws:ecs:us-east-1:<AWSアカウントID>:cluster/EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-zJnVnD9x7R6g",
  "ecs": {
      "container": "ip-10-10-8-125.ec2.internal",
      "container_id": "4bd0b4edf85023bd9c3b/2a9e9b028b6b4bd0b4edf85023bd9c3b-0527074092"
  },
  "ecs.container.arn": "arn:aws:ecs:us-east-1:<AWSアカウントID>:container/EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-zJnVnD9x7R6g/2a9e9b028b6b4bd0b4edf85023bd9c3b/e8984edf-97c0-4e46-a8ea-23018b9537c6",
  "ecs.launchtype": "fargate",
  "span.kind": "CLIENT",
  "cloudwatch_logs": [
      {
          "log_group": "EcsNativeBlueGreenStack-FirelensConstructFirelensLogGroupD186C82F-wTQ4890Mp8e9"
      },
      {
          "log_group": "arn:aws:logs:us-east-1:<AWSアカウントID>:log-group:EcsNativeBlueGreenStack-EcsConstructTaskDefinitionAdotAutoInstrumentationInitContainerLogGroup8060A51D-TTDVP1HlaLC8"
      },
      {
          "log_group": "arn:aws:logs:us-east-1:<AWSアカウントID>:log-group:EcsNativeBlueGreenStack-EcsConstructTaskDefinitionlogRouterLogGroup27EC9B3C-OxmB1VpOf8SS"
      }
  ],
  "ecs.task.revision": "100",
  "log.stream.arns": [
      "arn:aws:logs:us-east-1:<AWSアカウントID>:log-group:EcsNativeBlueGreenStack-EcsConstructTaskDefinitionAdotAutoInstrumentationInitContainerLogGroup8060A51D-TTDVP1HlaLC8:log-stream:init/init/2a9e9b028b6b4bd0b4edf85023bd9c3b",
      "arn:aws:logs:us-east-1:<AWSアカウントID>:log-group:EcsNativeBlueGreenStack-EcsConstructTaskDefinitionlogRouterLogGroup27EC9B3C-OxmB1VpOf8SS:log-stream:firelens/EcsNativeBlueGreenStackEcsConstructTaskDefinitionF683F4B2/logRouter/2a9e9b028b6b4bd0b4edf85023bd9c3b"
  ],
  "log.stream.names": [
      "init/init/2a9e9b028b6b4bd0b4edf85023bd9c3b",
      "firelens/EcsNativeBlueGreenStackEcsConstructTaskDefinitionF683F4B2/logRouter/2a9e9b028b6b4bd0b4edf85023bd9c3b"
  ],
  "ecs.task.id": "2a9e9b028b6b4bd0b4edf85023bd9c3b"
},

Other than adding ecs.task.id, don't insert this in your pipeline.

Verification Test

I will verify functionality.

Application Signals service shows metric graph data points that can be clicked to display correlation spans.

4.相関スパン.png

Clicking on the trace ID within the correlation span.

As a result, I was able to see logs associated with the trace as shown below.

10.ログ相関の確認.png

{
    "level": "error",
    "time": "2026-02-11T05:39:13.085Z",
    "pid": 8,
    "hostname": "ip-10-10-8-89.ec2.internal",
    "req": {
        "id": 479,
        "method": "GET",
        "url": "/crash/",
        "query": {},
        "params": {},
        "headers": {
            "host": "ecsnat-albco-qzyosxmqsim4-1634003559.us-east-1.elb.amazonaws.com",
            "x-real-ip": "10.10.8.40",
            "x-forwarded-for": "<送信元IPアドレス>, 10.10.8.40",
            "x-forwarded-proto": "http",
            "connection": "close",
            "x-forwarded-port": "80",
            "x-amzn-trace-id": "Root=1-698c1601-5ec60d115f6377e539ba7666",
            "cookie": "connect.sid=s%3AkdwCTdPnOMbapxgvwkYpR3T2Y1Ykw_eW.cef%2Bw5X7jVYHTqDmz0m8XtFUePmZOE225Vy9JSE%2B4uQ",
            "user-agent": "curl/8.7.1",
            "accept": "*/*"
        },
        "remoteAddress": "127.0.0.1",
        "remotePort": 33256
    },
    "trace_id": "698c160176b2820f3142596543b58e08",
    "span_id": "84537a0cf5432a39",
    "trace_flags": "01",
    "msg": "Crash endpoint triggered - throwing exception",
    "container_id": "26510d3c39984a7cb58a1bf43dda452b-0527074092",
    "container_name": "app",
    "source": "stderr",
    "ecs_cluster": "EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-zJnVnD9x7R6g",
    "ecs_task_arn": "arn:aws:ecs:us-east-1:<AWSアカウントID>:task/EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-zJnVnD9x7R6g/26510d3c39984a7cb58a1bf43dda452b",
    "ecs_task_definition": "EcsNativeBlueGreenStackEcsConstructTaskDefinitionF683F4B2:98"
}
{
    "level": "error",
    "time": "2026-02-11T05:39:13.086Z",
    "pid": 8,
    "hostname": "ip-10-10-8-89.ec2.internal",
    "req": {
        "id": 479,
        "method": "GET",
        "url": "/crash/",
        "query": {},
        "params": {},
        "headers": {
            "host": "ecsnat-albco-qzyosxmqsim4-1634003559.us-east-1.elb.amazonaws.com",
            "x-real-ip": "10.10.8.40",
            "x-forwarded-for": "<送信元IPアドレス>, 10.10.8.40",
            "x-forwarded-proto": "http",
            "connection": "close",
            "x-forwarded-port": "80",
            "x-amzn-trace-id": "Root=1-698c1601-5ec60d115f6377e539ba7666",
            "cookie": "connect.sid=s%3AkdwCTdPnOMbapxgvwkYpR3T2Y1Ykw_eW.cef%2Bw5X7jVYHTqDmz0m8XtFUePmZOE225Vy9JSE%2B4uQ",
            "user-agent": "curl/8.7.1",
            "accept": "*/*"
        },
        "remoteAddress": "127.0.0.1",
        "remotePort": 33256
    },
    "trace_id": "698c160176b2820f3142596543b58e08",
    "span_id": "84537a0cf5432a39",
    "trace_flags": "01",
    "err": {
        "type": "Error",
        "message": "Application crash test - intentional exception",
        "stack": "Error: Application crash test - intentional exception\n    at /app/dist/router.js:218:11\n    at Layer.handle [as handle_request] (/app/node_modules/.pnpm/express@4.22.1/node_modules/express/lib/router/layer.js:95:5)\n    at next (/app/node_modules/.pnpm/express@4.22.1/node_modules/express/lib/router/route.js:149:13)\n    at Route.dispatch (/app/node_modules/.pnpm/express@4.22.1/node_modules/express/lib/router/route.js:119:3)\n    at patched (/otel-auto-instrumentation/node_modules/@opentelemetry/instrumentation-express/build/src/instrumentation.js:210:37)\n    at Layer.handle [as handle_request] (/app/node_modules/.pnpm/express@4.22.1/node_modules/express/lib/router/layer.js:95:5)\n    at /app/node_modules/.pnpm/express@4.22.1/node_modules/express/lib/router/index.js:284:15\n    at router.process_params (/app/node_modules/.pnpm/express@4.22.1/node_modules/express/lib/router/index.js:346:12)\n    at next (/app/node_modules/.pnpm/express@4.22.1/node_modules/express/lib/router/index.js:280:10)\n    at router.handle (/app/node_modules/.pnpm/express@4.22.1/node_modules/express/lib/router/index.js:175:3)"
    },
    "msg": "Error occurred",
    "container_id": "26510d3c39984a7cb58a1bf43dda452b-0527074092",
    "container_name": "app",
    "source": "stderr",
    "ecs_cluster": "EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-zJnVnD9x7R6g",
    "ecs_task_arn": "arn:aws:ecs:us-east-1:<AWSアカウントID>:task/EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-zJnVnD9x7R6g/26510d3c39984a7cb58a1bf43dda452b",
    "ecs_task_definition": "EcsNativeBlueGreenStackEcsConstructTaskDefinitionF683F4B2:98"
}
{
    "level": "error",
    "time": "2026-02-11T05:39:13.088Z",
    "pid": 8,
    "hostname": "ip-10-10-8-89.ec2.internal",
    "req": {
        "id": 479,
        "method": "GET",
        "url": "/crash/",
        "query": {},
        "params": {},
        "headers": {
            "host": "ecsnat-albco-qzyosxmqsim4-1634003559.us-east-1.elb.amazonaws.com",
            "x-real-ip": "10.10.8.40",
            "x-forwarded-for": "<送信元IPアドレス>, 10.10.8.40",
            "x-forwarded-proto": "http",
            "connection": "close",
            "x-forwarded-port": "80",
            "x-amzn-trace-id": "Root=1-698c1601-5ec60d115f6377e539ba7666",
            "cookie": "connect.sid=s%3AkdwCTdPnOMbapxgvwkYpR3T2Y1Ykw_eW.cef%2Bw5X7jVYHTqDmz0m8XtFUePmZOE225Vy9JSE%2B4uQ",
            "user-agent": "curl/8.7.1",
            "accept": "*/*"
        },
        "remoteAddress": "127.0.0.1",
        "remotePort": 33256
    },
    "trace_id": "698c160176b2820f3142596543b58e08",
    "span_id": "84537a0cf5432a39",
    "trace_flags": "01",
    "res": {
        "statusCode": 500,
        "headers": {
            "x-powered-by": "Express",
            "content-type": "application/json; charset=utf-8",
            "content-length": "33",
            "etag": "W/\"21-Fau8GdrOCOyGNNH/IiTxy2DuMu0\""
        }
    },
    "err": {
        "type": "Error",
        "message": "failed with status code 500",
        "stack": "Error: failed with status code 500\n    at onResFinished (/app/node_modules/.pnpm/pino-http@10.5.0/node_modules/pino-http/logger.js:115:39)\n    at ServerResponse.onResponseComplete (/app/node_modules/.pnpm/pino-http@10.5.0/node_modules/pino-http/logger.js:178:14)\n    at /otel-auto-instrumentation/node_modules/@opentelemetry/context-async-hooks/build/src/AbstractAsyncHooksContextManager.js:50:55\n    at AsyncLocalStorage.run (node:internal/async_local_storage/async_context_frame:59:14)\n    at AsyncLocalStorageContextManager.with (/otel-auto-instrumentation/node_modules/@opentelemetry/context-async-hooks/build/src/AsyncLocalStorageContextManager.js:33:40)\n    at ServerResponse.contextWrapper (/otel-auto-instrumentation/node_modules/@opentelemetry/context-async-hooks/build/src/AbstractAsyncHooksContextManager.js:50:32)\n    at ServerResponse.emit (node:events:520:35)\n    at onFinish (node:_http_outgoing:1026:10)\n    at callback (node:internal/streams/writable:764:21)\n    at afterWrite (node:internal/streams/writable:708:5)"
    },
    "responseTime": 5,
    "msg": "request errored",
    "container_id": "26510d3c39984a7cb58a1bf43dda452b-0527074092",
    "container_name": "app",
    "source": "stderr",
    "ecs_cluster": "EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-zJnVnD9x7R6g",
    "ecs_task_arn": "arn:aws:ecs:us-east-1:<AWSアカウントID>:task/EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-zJnVnD9x7R6g/26510d3c39984a7cb58a1bf43dda452b",
    "ecs_task_definition": "EcsNativeBlueGreenStackEcsConstructTaskDefinitionF683F4B2:98"
}

The logs contain the trace ID 698c160176b2820f3142596543b58e08 in W3C format and correlation works correctly. It seems there's no need to convert it to X-Ray format like 1-698c1601-76b2820f3142596543b58e08.

I can also see when dependency availability is low.

12.Rediの依存関係.png
13.Redis相関スパン.png
11.Redis接続失敗時のトレース.png

The logs for this event are as follows:

{
    "level": "error",
    "time": "2026-02-12T09:08:27.268Z",
    "pid": 7,
    "hostname": "ip-10-10-8-82.ec2.internal",
    "req": {
        "id": 15,
        "method": "GET",
        "url": "/health",
        "query": {},
        "params": {},
        "headers": {
            "host": "localhost:3000",
            "user-agent": "Wget",
            "accept": "*/*",
            "connection": "close"
        },
        "remoteAddress": "127.0.0.1",
        "remotePort": 57732
    },
    "trace_id": "698d988b0f2d820050ca5552c933f32d",
    "span_id": "f9ff425ef6931901",
    "trace_flags": "01",
    "err": {
        "type": "ReplyError",
        "message": "ERR syntax error",
        "stack": "ReplyError: ERR syntax error\n    at parseError (/app/node_modules/.pnpm/redis-parser@3.0.0/node_modules/redis-parser/lib/parser.js:179:12)\n    at parseType (/app/node_modules/.pnpm/redis-parser@3.0.0/node_modules/redis-parser/lib/parser.js:302:14)",
        "command": {
            "name": "set",
            "args": [
                "sess:st2zrsEzLyFlzb5i4XocReBSUhmyjgRz",
                "{\"cookie\":{\"originalMaxAge\":86400000,\"expires\":\"2026-02-13T09:08:27.265Z\",\"secure\":false,\"httpOnly\":true,\"path\":\"/\"}}",
                "[object Object]"
            ]
        }
    },
    "msg": "Error occurred",
    "container_id": "3d5c2659c6ad4d0587a43191759bd918-0527074092",
    "container_name": "app",
    "source": "stderr",
    "ecs_cluster": "EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-4JfsTzadcWYq",
    "ecs_task_arn": "arn:aws:ecs:us-east-1:<AWSアカウントID>:task/EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-4JfsTzadcWYq/3d5c2659c6ad4d0587a43191759bd918",
    "ecs_task_definition": "EcsNativeBlueGreenStackEcsConstructTaskDefinitionF683F4B2:103"
}

When checking the trace details by clicking on the trace ID, the Logs Insights execution history showed the following queries:

5.リロード後.png

aws/spans
fields @message, @log, traceId, spanId | filter traceId = "698c160176b2820f3142596543b58e08" | sort @timestamp desc | limit 10000
aws/spans
fields @message, @log, traceId, spanId, jsonparse(@message) as json_message | unnest json_message.links into link | filter link.traceId = "698c160176b2820f3142596543b58e08" | sort @timestamp desc | limit 10000
aws/spans
fields @message, @log, traceId, spanId | filter traceId = "698c160176b2820f3142596543b58e08" | sort @timestamp desc | limit 10000
aws/spans
fields @message, @log, traceId, spanId, jsonparse(@message) as json_message | unnest json_message.links into link | filter link.traceId = "698c160176b2820f3142596543b58e08" | sort @timestamp desc | limit 10000
/ecs/,/ecs/default-nginx-5d29,/ecs/ecs-aws-firelens-sidecar-container,/ecs/ecs-aws-otel-sidecar-collector,/ecs/nginx,EcsNativeBlueGreenStack-FirelensConstructFirelensLogGroupD186C82F-wTQ4890Mp8e9
fields @log, @timestamp, @message
| filter @message like "698c160176b2820f3142596543b58e08" or @message like "8c1601762820f3142596543b58e08"
| sort @timestamp, @message desc
/ecs/,/ecs/default-nginx-5d29,/ecs/ecs-aws-firelens-sidecar-container,/ecs/ecs-aws-otel-sidecar-collector,/ecs/nginx,EcsNativeBlueGreenStack-FirelensConstructFirelensLogGroupD186C82F-wTQ4890Mp8e9
fields @log, @timestamp, @message
| filter @message like "698c160176b2820f3142596543b58e08" or @message like "8c1601762820f3142596543b58e08"
| sort @timestamp, @message desc

In other words, three types of queries are being executed twice each.

Based on the log group names in the query, the last two queries are likely responsible for log correlation.

Here is the CloudTrail event for this:

{
    "eventVersion": "1.11",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "<プリンシパルID>",
        "arn": "arn:aws:sts::<AWSアカウントID>:assumed-role/<IAMロール名>/<セッション名>",
        "accountId": "<AWSアカウントID>",
        "accessKeyId": "<アクセスキー>",
        "sessionContext": {
            "sessionIssuer": {
                "type": "Role",
                "principalId": "<プリンシパルID>",
                "arn": "arn:aws:iam::<AWSアカウントID>:role/<IAMロール名>",
                "accountId": "<AWSアカウントID>",
                "userName": "<IAMユーザー名>"
            },
            "attributes": {
                "creationDate": "2026-02-11T05:38:53Z",
                "mfaAuthenticated": "true"
            }
        }
    },
    "eventTime": "2026-02-11T05:45:59Z",
    "eventSource": "logs.amazonaws.com",
    "eventName": "StartQuery",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "<送信元IPアドレス>",
    "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
    "requestParameters": {
        "logGroupNames": [
            "arn:aws:logs:us-east-1:<AWSアカウントID>:log-group:/ecs/",
            "arn:aws:logs:us-east-1:<AWSアカウントID>:log-group:/ecs/default-nginx-5d29",
            "arn:aws:logs:us-east-1:<AWSアカウントID>:log-group:/ecs/ecs-aws-firelens-sidecar-container",
            "arn:aws:logs:us-east-1:<AWSアカウントID>:log-group:/ecs/ecs-aws-otel-sidecar-collector",
            "arn:aws:logs:us-east-1:<AWSアカウントID>:log-group:/ecs/nginx",
            "arn:aws:logs:us-east-1:<AWSアカウントID>:log-group:EcsNativeBlueGreenStack-FirelensConstructFirelensLogGroupD186C82F-wTQ4890Mp8e9"
        ],
        "startTime": 1770788338,
        "endTime": 1770788383,
        "queryString": "fields @log, @timestamp, @message\n| filter @message like \"698c160176b2820f3142596543b58e08\" or @message like \"8c1601762820f3142596543b58e08\"\n| sort @timestamp, @message desc",
        "dryRun": false
    },
    "responseElements": null,
    "additionalEventData": {
        "queryId": "5f79c759-30fa-45e5-adff-e68542d98ab0"
    },
    "requestID": "3f4c9697-9f6f-4213-891d-3f72959a2916",
    "eventID": "cc9165a8-ecda-4992-9498-dbe332ebce96",
    "readOnly": true,
    "resources": [
        {
            "accountId": "<AWSアカウントID>",
            "type": "AWS::Logs::LogGroup",
            "ARN": "arn:aws:logs:us-east-1:<AWSアカウントID>:log-group:/ecs/"
        },
        {
            "accountId": "<AWSアカウントID>",
            "type": "AWS::Logs::LogGroup",
            "ARN": "arn:aws:logs:us-east-1:<AWSアカウントID>:log-group:/ecs/default-nginx-5d29"
        },
        {
            "accountId": "<AWSアカウントID>",
            "type": "AWS::Logs::LogGroup",
            "ARN": "arn:aws:logs:us-east-1:<AWSアカウントID>:log-group:/ecs/ecs-aws-firelens-sidecar-container"
        },
        {
            "accountId": "<AWSアカウントID>",
            "type": "AWS::Logs::LogGroup",
            "ARN": "arn:aws:logs:us-east-1:<AWSアカウントID>:log-group:/ecs/ecs-aws-otel-sidecar-collector"
        },
        {
            "accountId": "<AWSアカウントID>",
            "type": "AWS::Logs::LogGroup",
            "ARN": "arn:aws:logs:us-east-1:<AWSアカウントID>:log-group:/ecs/nginx"
        },
        {
            "accountId": "<AWSアカウントID>",
            "type": "AWS::Logs::LogGroup",
            "ARN": "arn:aws:logs:us-east-1:<AWSアカウントID>:log-group:EcsNativeBlueGreenStack-FirelensConstructFirelensLogGroupD186C82F-wTQ4890Mp8e9"
        }
    ],
    "eventType": "AwsApiCall",
    "apiVersion": "20140328",
    "managementEvent": true,
    "recipientAccountId": "<AWSアカウントID>",
    "eventCategory": "Management",
    "tlsDetails": {
        "tlsVersion": "TLSv1.3",
        "cipherSuite": "TLS_AES_128_GCM_SHA256",
        "clientProvidedHostHeader": "logs.us-east-1.amazonaws.com"
    },
    "sessionCredentialFromConsole": "true"
}

From "startTime": 1770788338 and "endTime": 1770788383, we can see it's searching for relevant logs within a 45-second window in the specified log groups.

What's concerning is that log groups starting with /ecs/ like /ecs/ and /ecs/default-nginx-5d29 are included in the query targets even though this wasn't specified.

Checking CloudTrail, the system was searching for log groups starting with /ecs/ when performing log correlation:

{
    "eventVersion": "1.11",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "<プリンシパルID>",
        "arn": "arn:aws:sts::<AWSアカウントID>:assumed-role/<IAMロール名>/<セッション名>",
        "accountId": "<AWSアカウントID>",
        "accessKeyId": "<アクセスキー>",
        "sessionContext": {
            "sessionIssuer": {
                "type": "Role",
                "principalId": "<プリンシパルID>",
                "arn": "arn:aws:iam::<AWSアカウントID>:role/<IAMロール名>",
                "accountId": "<AWSアカウントID>",
                "userName": "<IAMユーザー名>"
            },
            "attributes": {
                "creationDate": "2026-02-11T05:38:53Z",
                "mfaAuthenticated": "true"
            }
        }
    },
    "eventTime": "2026-02-11T06:02:54Z",
    "eventSource": "logs.amazonaws.com",
    "eventName": "DescribeLogGroups",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "<送信元IPアドレス>",
    "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
    "requestParameters": {
        "logGroupNamePrefix": "/ecs/",
        "includeLinkedAccounts": true
    },
    "responseElements": null,
    "requestID": "c59cb761-d8cf-4c71-aa7e-24e7ca4a9cb7",
    "eventID": "46c30084-8d1d-4484-a167-0b4821b413fc",
    "readOnly": true,
    "resources": [
        {
            "accountId": "<AWSアカウントID>",
            "type": "AWS::Logs::LogGroup",
            "ARN": "arn:aws:logs:us-east-1:<AWSアカウントID>:log-group:/ecs/"
        },
        {
            "accountId": "<AWSアカウントID>",
            "type": "AWS::Logs::LogGroup",
            "ARN": "arn:aws:logs:us-east-1:<AWSアカウントID>:log-group:/ecs/default-nginx-5d29"
        },
        {
            "accountId": "<AWSアカウントID>",
            "type": "AWS::Logs::LogGroup",
            "ARN": "arn:aws:logs:us-east-1:<AWSアカウントID>:log-group:/ecs/ecs-aws-firelens-sidecar-container"
        },
        {
            "accountId": "<AWSアカウントID>",
            "type": "AWS::Logs::LogGroup",
            "ARN": "arn:aws:logs:us-east-1:<AWSアカウントID>:log-group:/ecs/ecs-aws-otel-sidecar-collector"
        },
        {
            "accountId": "<AWSアカウントID>",
            "type": "AWS::Logs::LogGroup",
            "ARN": "arn:aws:logs:us-east-1:<AWSアカウントID>:log-group:/ecs/nginx"
        }
    ],
    "eventType": "AwsApiCall",
    "apiVersion": "20140328",
    "managementEvent": true,
    "recipientAccountId": "<AWSアカウントID>",
    "eventCategory": "Management",
    "tlsDetails": {
        "tlsVersion": "TLSv1.3",
        "cipherSuite": "TLS_AES_128_GCM_SHA256",
        "clientProvidedHostHeader": "logs.us-east-1.amazonaws.com"
    },
    "sessionCredentialFromConsole": "true"
}

Personally, I'd prefer to disable this feature.

There are billing concerns for Logs Insights if large volumes of logs are flowing through log groups starting with /ecs/. Since it's using filter @message like "<traceID>" to search the entire message body, field indexing won't be effective.

If anyone knows how to opt out of including log groups starting with /ecs/ in log correlation, I'd appreciate the information.

Personally, I'm considering avoiding creating log groups that start with /ecs/ as a workaround.

Log correlation can be set up easily

I tried correlating traces and logs with CloudWatch Application Signals.

It was easier than I expected because you just need to use a supported logger and specify the log group name with an environment variable.

By the way, since I'm only sending error logs to CloudWatch Logs this time, log correlation isn't possible when an HTTP status code of 200 is returned.

All logs are output to S3 buckets via Data Firehose. If you want to find logs with HTTP status code 200, search using the trace ID. Logs are recorded as follows:

s3://ecsnativebluegreenstack-firelensconstructfirelensl-xwd5tetsrypf/ecs/EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-VoUD00RfbaSW/app/stdout/2026/02/12/01/EcsNativeBlueGreenStack-FirelensConstructDeliverySt-TCVIns4InZMR-1-2026-02-12-01-48-38-aabb7cef-5384-33e4-937c-40c34494cb1c.gz
{
  "level": "info",
  "time": "2026-02-12T01:48:36.868Z",
  "pid": 7,
  "hostname": "ip-10-10-8-104.ec2.internal",
  "req": {
    "id": 55,
    "method": "GET",
    "url": "/",
    "query": {},
    "params": {},
    "headers": {
      "host": "ecsnat-albco-shaasnih0xar-1652870936.us-east-1.elb.amazonaws.com",
      "x-real-ip": "10.10.8.43",
      "x-forwarded-for": "<source IP address>, 10.10.8.43",
      "x-forwarded-proto": "http",
      "connection": "close",
      "x-forwarded-port": "80",
      "x-amzn-trace-id": "Root=1-698d3174-5876cff8075b183978fe1d65",
      "accept": "*/*",
      "user-agent": "curl/8.7.1"
    },
    "remoteAddress": "127.0.0.1",
    "remotePort": 35448
  },
  "trace_id": "698d3174fa6d5a5d85e08988b96c738d",
  "span_id": "6f704133bb94ada4",
  "trace_flags": "01",
  "res": {
    "statusCode": 200,
    "headers": {
      "x-powered-by": "Express",
      "content-type": "application/json; charset=utf-8",
      "content-length": "427",
      "etag": "W/\"1ab-kBv3WE96jXCcAIdDtz3e81LLMik\"",
      "set-cookie": [
        "connect.sid=s%3A_ykD64hKoji4n7SB71zDtgljHN5UDJBx.7y5uIGbxZsGgM4knIOw1Pt7BAOhIo%2FA6NLGKotG6hoU; Path=/; Expires=Fri, 13 Feb 2026 01:48:36 GMT; HttpOnly"
      ]
    }
  },
  "responseTime": 292,
  "msg": "request completed",
  "container_id": "c9979e7d4b08471b8285c6b3ecfd5cfb-0527074092",
  "container_name": "app",
  "source": "stdout",
  "ecs_cluster": "EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-VoUD00RfbaSW",
  "ecs_task_arn": "arn:aws:ecs:us-east-1:<AWS Account ID>:task/EcsNativeBlueGreenStack-EcsConstructCluster14AE103B-VoUD00RfbaSW/c9979e7d4b08471b8285c6b3ecfd5cfb",
  "ecs_task_definition": "EcsNativeBlueGreenStackEcsConstructTaskDefinitionF683F4B2:102",
  "datetime": "2026-02-12T01:48:36.869Z"
}

I hope this article helps someone.

This was nonpi (@non____97) from the Consulting Department of the Cloud Business Division!

Share this article

FacebookHatena blogX

Related articles