Skip to main content
This page covers capturing the telemetry an agent produces while running on the Amazon Bedrock AgentCore Runtime and sending it to Bronto. Where Amazon Bedrock LLM observability instruments a single Converse call, an agent on AgentCore runs a multi-step reasoning loop with tool calls — producing deep, nested traces following the OpenTelemetry GenAI semantic conventions.
AgentCore, Strands, and the GenAI conventions evolve quickly. The AgentCore CLI commands and agentcore.json settings here were checked on October 28, 2026 against AgentCore CLI 1.0.1 (@aws/agentcore). Instrumentation behavior was verified on July 17, 2026.
For the broader ingestion picture (direct OTLP vs. a Collector, and where AgentCore fits among AWS services), see Amazon Bedrock AgentCore Logs, Metrics and Traces. For the attributes Bronto surfaces and how to search them, see LLM Observability.
This page uses Python with the Strands agent framework, which emits GenAI spans through the tracer provider you configure. The same approach applies to any agent runtime: you disable AgentCore’s managed telemetry pipeline and point the OpenTelemetry SDK at Bronto.

How AgentCore observability works

AgentCore Runtime ships with a managed OpenTelemetry pipeline (the AWS Distro for OpenTelemetry) that, by default, delivers agent telemetry to Amazon CloudWatch GenAI Observability. To send logs, metrics, and traces to Bronto instead, you disable the managed pipeline and configure the OpenTelemetry SDK inside your agent to export OTLP to Bronto through an OTel Collector (or, where you don’t run one, directly).

Prerequisites

  • Node.js 20.12 or later, and uv for Python agent projects
  • AWS credentials for the account you deploy to
  • The AgentCore CLI: npm install -g @aws/agentcore. If the older Starter Toolkit is installed, uninstall it first, because both provide an agentcore command.
  • An agent project created with the CLI (this guide uses the Strands template and the bedrock-agentcore SDK):
    The agent code is in app/agent/, and the runtime is named agent in agentcore/agentcore.json.
  • A running OTel Collector configured to forward to Bronto — see Connect OpenTelemetry to Bronto or, on AWS, ADOT. In public network mode the runtime must reach it over a public endpoint; in VPC network mode it can reach a private Collector. Export directly to Bronto when you do not operate a reachable Collector.
  • A Bronto ingestion API key — held by the Collector, or sent as the x-bronto-api-key header when exporting directly. See API Keys for how to create one with ingestion permissions.

Disable the managed pipeline

Two settings on the runtime in agentcore/agentcore.json take AWS’s managed observability out of the way so your own exporters own the signal:
  • "instrumentation": { "enableOtel": false } stops the runtime starting your code under opentelemetry-instrument.
  • DISABLE_ADOT_OBSERVABILITY=true in the runtime’s envVars unsets the runtime’s default ADOT environment variables.
Both are shown in the agentcore.json example under Configure OTLP export.
For the container template (agent-python-strands-container), enableOtel doesn’t change the deployed image. Also remove opentelemetry-instrument from the CMD in app/agent/Dockerfile, so the container starts with python -m main.

Install dependencies

Add the OpenTelemetry packages to the agent’s pyproject.toml. The CLI builds the agent from pyproject.toml, not requirements.txt:
The Strands template already includes strands-agents and bedrock-agentcore.

Configure OTLP export

Point the agent’s OTLP exporters at your Collector, which holds the Bronto credential and forwards each signal to Bronto’s per-signal endpoints. Set the variables in the runtime’s envVars in agentcore/agentcore.json. The CLI applies them on every agentcore deploy, so they persist across redeploys. Leave the other generated fields as they are:
agentcore/agentcore.json
For local development with agentcore dev, override the endpoint in agentcore/.env.local. That file is gitignored and is applied on top of envVars when the agent runs locally:
agentcore/.env.local
Keeping the exporters pointed at a Collector keeps the agent code vendor-neutral and the Bronto API key out of the runtime config. If no Collector is reachable from the runtime, export straight to Bronto instead — see Direct export vs. a Collector below. Resource attributes such as service.name and service.namespace are set in code on a shared Resource, exactly as in the standard Python setup. StrandsTelemetry accepts a pre-configured tracer provider carrying that Resource, so all three signals share one identity with no environment variables to keep in sync. For logs only, Bronto also maps these attributes to the dataset and collection; metrics and traces remain outside datasets and collections. Bootstrap the three signal providers at startup — before the agent framework or any instrumented library is imported:
telemetry.py
Save this as app/agent/telemetry.py, and call setup_telemetry() at the very top of the entrypoint, app/agent/main.py, before importing Strands:
main.py

What you get on the trace

A single agent invocation becomes one trace with nested spans: Useful GenAI attributes on the model spans: These are first-class, queryable fields in Bronto. See LLM Observability for the full recommended attribute set.
Strands tool-call spans use standard attributes including gen_ai.tool.name and gen_ai.tool.call.id; exact coverage varies by Strands version. AgentCore-primitive spans from BotocoreInstrumentor (Memory, Code Interpreter, Gateway) instead carry AWS SDK attributes such as rpc.method and aws.request_id. Inspect a real trace before building version-sensitive dashboards.

Capturing prompt, response, and tool IO

Strands captures message content by default and does not use OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT. To put content directly on span attributes for backends that cannot read OTel events, add gen_ai_span_attributes_only to OTEL_SEMCONV_STABILITY_OPT_IN. Treat this data as sensitive. You can also log each agent result as structured GenAI attributes:
Avoid printf-style logging (log.info("tokens=%s", n)) for data you want to query — that produces a flat message string rather than structured fields. See LLM Observability for the recommended attribute names.

Verify in Bronto

Deploy the agent, then trigger an invocation:
To test locally first, run agentcore dev and add --local to the invoke command. Traces — open Explore Traces and filter by your service.name. Open the newest trace and confirm the nesting from the table above: the agent loop at the root, a chat span per model call, and tool-call / AgentCore-primitive spans beneath it. Logs — open Log Search and filter by the same service.name. Metrics — open Metric Explorer, select a recently emitted metric, and confirm that it carries the same service.name. Exponential histograms are not supported. For Sum, Summary, and Histogram metrics, the Metric Explorer provides per-second rate functions.
Bronto indexes log-record attributes with a $ prefix. Query the structured fields by name — for example "$event.name" or "$gen_ai.request.model".
Because the searchable body of a structured event is the event name, search agent content with field predicates rather than full-text:
Token usage is numeric, so you can aggregate it — for example average output tokens per model, or total tokens over time — in aggregate views and Visualizations.

Direct export vs. a Collector

  • Via an OTel Collector (recommended) — the agent exports OTLP to a Collector that holds the Bronto credential and forwards each signal. This keeps the agent code vendor-neutral, gives you a place to add processors / sampling / fan-out, and matches how Bronto ingests other AWS telemetry. See Amazon Bedrock AgentCore Logs, Metrics and Traces and ADOT.
  • Direct OTLP to Bronto — when no Collector is reachable from the runtime, or for short-lived jobs: set OTEL_EXPORTER_OTLP_ENDPOINT to the Bronto ingestion base (EU https://ingestion.eu.bronto.io, US https://ingestion.us.bronto.io) and add your API key as the x-bronto-api-key header. No Collector, VPC, or sidecar required.
    agentcore.json is committed to source control, so an API key in envVars is stored in plain text in your repository. Prefer the Collector route, or keep the key in AWS Secrets Manager and read it at startup.

References