Agentic AI AcademyAgentic AI Academy

Setup & Viewing Your Data

Transaction Search, the GenAI dashboard, and trace correlation

Intermediate 13 minBuilder
What you'll be able to do
  • Enable CloudWatch Transaction Search (console and CLI) and explain why it is the mandatory first step before any span is searchable
  • Deploy and invoke a Runtime-hosted agent that is auto-instrumented, and drive the Sessions view by passing a runtimeSessionId
  • Configure vended-log delivery for non-Runtime resources (Memory, Gateway, Tools, Identity) that do NOT get a log group for free
  • Navigate the GenAI Observability dashboard (Agents, Sessions, Trace views) and locate the raw CloudWatch log groups, span store, and metrics namespace
  • Correlate a single request across the stack using the session-ID header and the trace headers (X-Amzn-Trace-Id / traceparent / baggage)
  • Identify and prevent the APPLICATION_LOGS PII/secret-leak gotcha before payloads are emitted
At a glance

Observability data doesn't just appear — there's a concrete setup path. This lesson walks the one-time, REQUIRED prerequisite (enabling CloudWatch Transaction Search, or your spans are never searchable), shows why Runtime-hosted agents are automatic while Memory/Gateway/Tools/Identity need vended-log delivery wired up by hand, then teaches you where to actually find the data — the GenAI Observability dashboard's Agents/Sessions/Trace views, the raw CloudWatch locations, and how session and trace IDs stitch a single request across the whole stack.

  1. 1Step 1 (REQUIRED, one-time): enable Transaction Search
  2. 2Step 2: Runtime-hosted is automatic
  3. 3Step 3: non-Runtime resources need vended-log delivery
  4. 4Viewing data: the GenAI Observability dashboard
  5. 5Trace correlation: stitching one request across the stack
  6. 6The PII / secrets leak gotcha in APPLICATION_LOGS

Step 2: Runtime-hosted is automatic

If your agent runs on AgentCore Runtime, you are mostly done after Step 1. Deploying via the CLI auto-instruments the agent with OpenTelemetry — no extra libraries, no env vars, no log-group creation. You get baseline traces, spans, sessions, and metrics for free, and Runtime auto-creates its log group.

bash
# Deploy the auto-instrumented Runtime agent (starter toolkit verb shown; the
# newer @aws/agentcore CLI uses `agentcore deploy` the same way)
agentcore deploy

# Invoke it — pass a session id to group spans in the Sessions view
agentcore invoke '{"prompt":"summarize my open tickets"}' --session-id my-session-0001

The critical detail for viewing data is the session id. Passing runtimeSessionId (the --session-id flag on the CLI, or runtimeSessionId in a boto3 InvokeAgentRuntime call) is what drives the Sessions view — it's the key the dashboard groups spans under. Omit it and every invocation looks like an orphan; pass a stable id across turns of one conversation and you get a clean session timeline.

Under the hood the auto-instrumentation captures the agent invocation sequence, LLM calls and responses, tool invocations and results, error paths, and your framework integration (Strands, LangChain, LangGraph, etc.). The span operation for the invocation is InvokeAgentRuntime, carrying attributes including session.id, latency_ms, and error_type.

Tip

Session IDs are ≥ 33 characters

Runtime session IDs have a minimum length (commonly cited as 33 characters). A too-short id is a frequent invoke failure. Use a UUID-derived string and you'll never hit it. Verify the exact minimum in the API reference if you're generating ids programmatically.

Watch out

Don't double-instrument

Because Runtime already auto-instruments with ADOT, manually adding your own OTEL distro on top of a Runtime-hosted agent produces duplicate spans. Auto-instrumentation is for Runtime; the manual ADOT path (env vars + opentelemetry-instrument) is for agents running OUTSIDE Runtime.

Step 3: non-Runtime resources need vended-log delivery

Here is the asymmetry that trips people up. Runtime auto-creates a log group. The other resources do NOT. Memory, Gateway, Built-in Tools, and Identity will not deliver spans or logs anywhere until you configure vended-log delivery yourself. Enable nothing and you'll wonder why your Gateway shows metrics but no traces.

Vended-log delivery is a standard CloudWatch Logs mechanism made of three pieces, wired with the logs client:

python
import boto3

logs = boto3.client("logs")
resource_arn = "arn:aws:bedrock-agentcore:<region>:<account-id>:gateway/<gateway-id>"

# 1) The delivery SOURCE: which resource + what kind of telemetry
logs.put_delivery_source(
    name="agentcore-gw-traces",
    resourceArn=resource_arn,
    logType="TRACES",          # or "APPLICATION_LOGS"
)

# 2) The delivery DESTINATION: where it goes (CloudWatch Logs / X-Ray / S3 / Firehose)
logs.put_delivery_destination(
    name="agentcore-gw-dest",
    deliveryDestinationType="XRAY",   # "CWL" for CloudWatch Logs, "XRAY" for traces
    deliveryDestinationConfiguration={
        "destinationResourceArn": "arn:aws:logs:<region>:<account-id>:log-group:/aws/vendedlogs/..."
    },
)

# 3) The DELIVERY: bind source to destination
logs.create_delivery(
    deliverySourceName="agentcore-gw-traces",
    deliveryDestinationArn="arn:aws:logs:<region>:<account-id>:delivery-destination:agentcore-gw-dest",
)

The two logType values you'll use are APPLICATION_LOGS (stdout/stderr + app logs, including full request/response payloads) and TRACES (spans). Destinations can be CloudWatch Logs (CWL), X-Ray (XRAY), S3, or Data Firehose. When delivered to CloudWatch Logs, the default group follows the pattern:

/aws/vendedlogs/bedrock-agentcore/{resource-type}/APPLICATION_LOGS/{resource-id}

Memory has an extra step: Memory spans require enabling Tracing on the Memory resource (a toggle in the console) — and, like everything else, that depends on Transaction Search already being on. So the order for Memory tracing is: Transaction Search → enable Tracing on the memory store → configure vended-log delivery for the spans.

Key insight

Why only Runtime is hands-off

Runtime owns the execution sandbox, so it can wire its own log group at deploy time and auto-instrument the process. Memory, Gateway, Tools, and Identity are managed control-plane services you call into — there's no process of yours to instrument, so AWS exposes their telemetry through the generic vended-log delivery plumbing instead. Same data store (CloudWatch), different on-ramp.

Viewing data: the GenAI Observability dashboard

With data flowing, the primary lens is the GenAI Observability dashboard in CloudWatch:

CloudWatch → #gen-ai-observabilityBedrock AgentCore tab → Agents View / Sessions View / Trace View

  • Agents View — your Runtime agents with rolled-up metrics: session count, latency, duration, token usage, error rates.
  • Sessions View — invocations grouped by session id. This is why passing runtimeSessionId matters; without it the grouping collapses.
  • Trace View — the per-request trace trajectory + timeline, with span details and error breakdowns. This is where you click into one slow request and see exactly which tool call or LLM step ate the latency.

A hard limit to internalize: only Agent (Runtime) shows up in the GenAI dashboard. (Policy also appears, but under the Gateway tab.) Memory, Gateway, and Built-in Tools live in plain CloudWatch only — you'll find their metrics and any spans/logs you enabled in regular CloudWatch Metrics and Logs, not in the GenAI dashboard.

Raw CloudWatch locations (when you need to grep logs or build a custom widget):

TelemetryWhere to look
Standard runtime logs/aws/bedrock-agentcore/runtimes/<agent_id>-<endpoint>/[runtime-logs]...
OTEL runtime logs.../runtime-logs (one doc shows .../otel-rt-logs — the suffix is inconsistent across docs; check the live page)
Spans / traces/aws/spans/default, surfaced via Transaction Search
MetricsCloudWatch Metrics namespace bedrock-agentcore
Non-Runtime vended logs/aws/vendedlogs/bedrock-agentcore/{resource-type}/APPLICATION_LOGS/{resource-id}

Watch out

"My Gateway/Memory traces aren't in the dashboard"

They never will be. The GenAI Observability dashboard surfaces Runtime (and Policy under the Gateway tab) only. For Memory, Gateway, and Tools, open plain CloudWatch Logs/Metrics and look under the bedrock-agentcore namespace and the /aws/vendedlogs/... groups.

Note

The OTEL log-group suffix is VOLATILE

AWS docs are inconsistent about whether OTEL runtime logs land under .../runtime-logs or .../otel-rt-logs. Don't hard-code either in tooling without confirming against your own account and the live observability-view documentation.

Trace correlation: stitching one request across the stack

A single user request might hop through Runtime → Gateway → a tool → Memory. To see it as one story, two kinds of identifiers must propagate: a session id (groups many requests in a conversation) and trace context (stitches the spans of one request together).

Session id. On Runtime, it rides the header X-Amzn-Bedrock-AgentCore-Runtime-Session-Id (the runtimeSessionId parameter in boto3). For code running outside Runtime, set it via OTEL baggage so it lands on the session.id span attribute:

python
from opentelemetry import baggage, context

# Outside Runtime: attach the session id so spans carry session.id
ctx = baggage.set_baggage("session.id", "my-session-0001")
context.attach(ctx)

Trace context. The headers AgentCore honors for trace propagation are:

text
X-Amzn-Trace-Id
traceparent
tracestate
baggage
X-Amzn-Bedrock-AgentCore-Runtime-Session-Id
mcp-session-id

X-Amzn-Trace-Id is the AWS-native form; traceparent / tracestate are the W3C Trace Context standard; baggage carries arbitrary key/values like session.id. These same custom headers are accepted on the Built-in Tools APIs (StartCodeInterpreterSession, InvokeCodeInterpreter, StartBrowserSession, StopBrowserSession) and the Identity APIs (GetWorkloadAccessToken*, GetResourceOauth2Token, GetResourceAPIKey) — so if you forward the trace headers when your agent calls those services, their spans join the same trace.

In the Trace View, correlation shows up as a single trajectory: the InvokeAgentRuntime span at the root, child spans for each LLM call and tool invocation, all sharing one trace id and tagged with the same session.id.

Tip

Forward the headers and you get correlation for free

The mechanics are just HTTP header propagation. If your agent passes traceparent / X-Amzn-Trace-Id / baggage through to its downstream calls (Gateway, tools, Identity), the spans automatically chain into one trace. Drop the headers and you get disconnected single-span traces that are far harder to debug.

The PII / secrets leak gotcha in APPLICATION_LOGS

AgentCore's APPLICATION_LOGS are deliberately rich for auditability: they capture the full request_payload and response_payload alongside trace_id, span_id, and session_id. That is exactly what you want when reconstructing what an agent did — and exactly the place a secret or a customer's PII leaks if you aren't careful.

The payloads are verbatim. If your prompt contains an API key, a Social Security number, a full email thread, or a bearer token a user pasted in, it lands in CloudWatch Logs (and, if you configured S3/Firehose delivery, anywhere those flow). Treat application logs as a data-classification surface, not just a debugging convenience.

The fix is to redact before emission, inside your entrypoint, before anything is logged:

python
import re
from bedrock_agentcore.runtime import BedrockAgentCoreApp

app = BedrockAgentCoreApp()

SECRET_RE = re.compile(r"(sk-[A-Za-z0-9]{20,}|Bearer\s+\S+|\b\d{3}-\d{2}-\d{4}\b)")

def redact(text: str) -> str:
    return SECRET_RE.sub("[REDACTED]", text)

@app.entrypoint
def handler(payload):
    prompt = redact(payload.get("prompt", ""))
    # ... run the agent on the sanitized prompt; never log the raw payload ...
    return {"result": prompt}

For a managed layer, combine this with Bedrock Guardrails (PII filters) so sensitive content is caught even when your regex misses it. The principle from the security model is blunt: filter PII/secrets before emission — once it's in the logs it's durable.

Watch out

Auditability cuts both ways

Full request/response capture is great for forensics and terrible for compliance if unmanaged. Logs are durable to CloudWatch Logs, S3, and Data Firehose and may be replicated cross-account. Decide what is allowed to land there BEFORE you ship, and redact at the entrypoint.

Try it: Turn on the lights: from blank dashboard to a correlated trace

Goal: enable observability end-to-end, prove a Runtime agent is auto-instrumented, wire telemetry for one non-Runtime resource, and read a correlated trace — while keeping secrets out of your logs.

  1. Enable Transaction Search (once). In the console: CloudWatch → Settings → Account → X-Ray traces → Transaction Search → Enable, set the index percentage to 1%. (Or run the three CLI calls: aws logs put-resource-policy ..., aws xray update-trace-segment-destination --destination CloudWatchLogs, aws xray update-indexing-rule ....) Note the time — spans take about 10 minutes to become searchable.
  2. Deploy and invoke a Runtime agent. agentcore deploy, then agentcore invoke '{"prompt":"..."}' --session-id <a-33+char-id> three times with the SAME session id, then once more with a DIFFERENT id.
  3. Read the dashboard. Open CloudWatch → #gen-ai-observability → Bedrock AgentCore tab. In the Sessions view, confirm your three same-id invocations group into one session and the fourth is separate. Open the Trace view on one invocation and find the InvokeAgentRuntime root span, its session.id/latency_ms attributes, and the child LLM/tool spans.
  4. Locate the raw data. Find the standard log group under /aws/bedrock-agentcore/runtimes/<agent_id>-<endpoint>/..., confirm spans under /aws/spans/default, and find a metric in the bedrock-agentcore namespace.
  5. Wire a non-Runtime resource. For a Gateway (or Memory) in your account, call put_delivery_source (logType TRACES), put_delivery_destination (type XRAY), and create_delivery. For Memory, also enable Tracing on the resource. Confirm a new /aws/vendedlogs/bedrock-agentcore/... group (or X-Ray spans) appears — and confirm these do NOT show in the GenAI dashboard, only in plain CloudWatch.
  6. Prove correlation. Make your agent call the downstream resource forwarding the trace headers (traceparent / X-Amzn-Trace-Id / baggage). In the Trace view, verify the downstream span joins the same trace id.
  7. Close the leak. Add a redaction step in your @app.entrypoint that strips API-key/SSN/bearer-token patterns before anything is processed or logged. Send a prompt containing a fake sk-... token and confirm [REDACTED] (not the token) appears in APPLICATION_LOGS.
  8. Reflect. Write three sentences: which step would have left you with an empty dashboard if skipped, why Memory needed an extra toggle Runtime didn't, and one place a real secret could still slip into logs despite your redaction.

Key takeaways

  1. 1Step 1 is non-negotiable: enable CloudWatch Transaction Search once at the account level (console, or `aws logs put-resource-policy` + `aws xray update-trace-segment-destination --destination CloudWatchLogs` + `update-indexing-rule`). Spans aren't searchable until it's on, and it takes ~10 minutes; the first 1% of indexed spans is free.
  2. 2Runtime-hosted agents are auto-instrumented on `agentcore deploy` and auto-create their log group — no extra setup. Pass `runtimeSessionId` (the `--session-id` flag) to drive the Sessions view.
  3. 3Memory, Gateway, Built-in Tools, and Identity do NOT get a log group for free — configure vended-log delivery with `put_delivery_source` / `put_delivery_destination` / `create_delivery` (logType APPLICATION_LOGS or TRACES; destination CWL/XRAY/S3/Firehose). Memory spans additionally require enabling Tracing on the resource.
  4. 4View data in the GenAI Observability dashboard: CloudWatch → `#gen-ai-observability` → Bedrock AgentCore tab → Agents / Sessions / Trace views. Only Runtime (and Policy, under the Gateway tab) appears there; Memory/Gateway/Tools are in plain CloudWatch only.
  5. 5Raw locations: standard logs `/aws/bedrock-agentcore/runtimes/<agent_id>-<endpoint>/...`, spans `/aws/spans/default` via Transaction Search, metrics namespace `bedrock-agentcore`, non-Runtime vended logs `/aws/vendedlogs/bedrock-agentcore/{resource-type}/APPLICATION_LOGS/{resource-id}`.
  6. 6Correlate across the stack with the session id (`X-Amzn-Bedrock-AgentCore-Runtime-Session-Id`, or OTEL baggage `session.id` outside Runtime) and trace headers (`X-Amzn-Trace-Id`, `traceparent`/`tracestate`, `baggage`, `mcp-session-id`). Forward them downstream and spans chain into one trace.
  7. 7`APPLICATION_LOGS` capture full `request_payload`/`response_payload` — a PII/secret leak surface. Redact at the entrypoint before emission and pair with Bedrock Guardrails PII filters.

Quiz

Lock in what you learned

Check your understanding

0 / 4 answered

1.You deployed a Runtime agent, invoked it several times, but the Trace view in the GenAI dashboard is completely empty. Metrics show up fine. What's the most likely cause?

2.Your Gateway shows metrics in CloudWatch but produces no spans or application logs anywhere. Runtime agents in the same account trace perfectly. What do you need to do for the Gateway?

3.Your agent runs OUTSIDE AgentCore Runtime (on EKS) and you want its spans to be grouped by conversation in the Sessions view. How do you set the session id?

4.During a security review, a colleague finds customer API keys sitting in CloudWatch Logs from your agent. Where did they come from, and what's the correct fix?

Go deeper

Hand-picked sources to keep learning