diff --git a/01-tutorials/06-AgentCore-observability/04-Agentcore-runtime-partner-observability/Datadog/images/datadog_dashboard.png b/01-tutorials/06-AgentCore-observability/04-Agentcore-runtime-partner-observability/Datadog/images/datadog_dashboard.png new file mode 100644 index 000000000..ada718edb Binary files /dev/null and b/01-tutorials/06-AgentCore-observability/04-Agentcore-runtime-partner-observability/Datadog/images/datadog_dashboard.png differ diff --git a/01-tutorials/06-AgentCore-observability/04-Agentcore-runtime-partner-observability/Datadog/requirements.txt b/01-tutorials/06-AgentCore-observability/04-Agentcore-runtime-partner-observability/Datadog/requirements.txt new file mode 100644 index 000000000..2f9c2f41f --- /dev/null +++ b/01-tutorials/06-AgentCore-observability/04-Agentcore-runtime-partner-observability/Datadog/requirements.txt @@ -0,0 +1,7 @@ +uv +boto3 +bedrock-agentcore +bedrock-agentcore-starter-toolkit +strands-agents[otel] +strands-agents-tools +aws-opentelemetry-distro diff --git a/01-tutorials/06-AgentCore-observability/04-Agentcore-runtime-partner-observability/Datadog/runtime_with_strands_and_datadog.ipynb b/01-tutorials/06-AgentCore-observability/04-Agentcore-runtime-partner-observability/Datadog/runtime_with_strands_and_datadog.ipynb new file mode 100644 index 000000000..6f7855f44 --- /dev/null +++ b/01-tutorials/06-AgentCore-observability/04-Agentcore-runtime-partner-observability/Datadog/runtime_with_strands_and_datadog.ipynb @@ -0,0 +1,366 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Strands Agent with Datadog Observability on Amazon Bedrock AgentCore Runtime\n", + "\n", + "## Overview\n", + "\n", + "This notebook demonstrates deploying a Strands agent to Amazon Bedrock AgentCore Runtime with **Datadog** observability. Traces are exported to Datadog's OTLP intake via ADOT (AWS Distro for OpenTelemetry) auto-instrumentation — no Datadog Agent sidecar required.\n", + "\n", + "## Key Components\n", + "\n", + "- **Strands Agents**: Python framework for building LLM-powered agents with built-in telemetry support\n", + "- **Amazon Bedrock AgentCore Runtime**: Managed runtime service for hosting and scaling agents on AWS\n", + "- **Datadog**: Full-stack observability platform with APM, tracing, and AI-focused monitoring\n", + "- **ADOT**: AWS Distro for OpenTelemetry — auto-instruments your agent and exports traces via OTLP\n", + "\n", + "## Prerequisites\n", + "\n", + "- Python 3.10+\n", + "- AWS credentials configured with Bedrock and AgentCore permissions\n", + "- Datadog account with an API key ([free trial](https://www.datadoghq.com/free-datadog-trial/))\n", + "- Docker installed locally (or use CodeBuild for remote builds)\n", + "- Access to Amazon Bedrock Claude models in your region" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 1: Install Dependencies\n", + "\n", + "Install the required packages from the `requirements.txt` file:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!pip install --force-reinstall -U -r requirements.txt --quiet" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 2: Set Datadog Configuration\n", + "\n", + "Set your Datadog API key and site. These will be passed as OTEL environment variables to the agent runtime at deploy time.\n", + "\n", + "Replace `` with your actual Datadog API key." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import boto3\n", + "from boto3.session import Session\n", + "\n", + "boto_session = Session()\n", + "region = boto_session.region_name\n", + "\n", + "DD_API_KEY = \"\" # Replace with your Datadog API key\n", + "DD_SITE = \"datadoghq.com\" # Change if using a different Datadog site (e.g. datadoghq.eu)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 3: Write the Agent Code\n", + "\n", + "The agent uses Strands with a calculator tool (built-in) and a custom weather tool. Traces are handled automatically by ADOT — no manual OpenTelemetry setup needed in the agent code." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%writefile strands_datadog.py\n", + "\"\"\"Strands agent with Datadog observability on Amazon Bedrock AgentCore Runtime.\n", + "\n", + "Traces are exported to Datadog via ADOT auto-instrumentation.\n", + "All OTEL config is passed as environment variables at deploy time.\n", + "\"\"\"\n", + "\n", + "import os\n", + "import logging\n", + "from bedrock_agentcore.runtime import BedrockAgentCoreApp\n", + "from strands import Agent, tool\n", + "from strands.models import BedrockModel\n", + "from strands_tools import calculator\n", + "\n", + "logging.basicConfig(level=logging.INFO, format=\"[%(levelname)s] %(message)s\")\n", + "logger = logging.getLogger(__name__)\n", + "\n", + "\n", + "@tool\n", + "def weather() -> str:\n", + " \"\"\"Get the current weather.\"\"\"\n", + " return \"sunny\"\n", + "\n", + "\n", + "model_id = os.getenv(\"BEDROCK_MODEL_ID\", \"us.anthropic.claude-sonnet-4-20250514-v1:0\")\n", + "model = BedrockModel(model_id=model_id)\n", + "\n", + "agent = Agent(\n", + " model=model,\n", + " tools=[calculator, weather],\n", + " system_prompt=\"You are a helpful assistant. You can do simple math calculations and tell the weather.\",\n", + ")\n", + "\n", + "app = BedrockAgentCoreApp()\n", + "\n", + "\n", + "@app.entrypoint\n", + "def handler(payload: dict, context=None) -> str:\n", + " \"\"\"Handle incoming agent invocations.\"\"\"\n", + " user_input = payload.get(\"prompt\", \"Hello!\")\n", + " logger.info(\"Processing prompt: %s\", user_input[:100])\n", + " response = agent(user_input)\n", + " return response.message[\"content\"][0][\"text\"]\n", + "\n", + "\n", + "if __name__ == \"__main__\":\n", + " app.run()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 4: Configure AgentCore Runtime Deployment\n", + "\n", + "Use the starter toolkit to configure the AgentCore Runtime deployment. ADOT auto-instrumentation is enabled by default — it reads the OTEL environment variables we pass at deploy time to route traces to Datadog." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from bedrock_agentcore_starter_toolkit import Runtime\n", + "\n", + "agentcore_runtime = Runtime()\n", + "agent_name = \"strands_datadog_observability\"\n", + "\n", + "response = agentcore_runtime.configure(\n", + " entrypoint=\"strands_datadog.py\",\n", + " auto_create_execution_role=True,\n", + " auto_create_ecr=True,\n", + " requirements_file=\"requirements.txt\",\n", + " region=region,\n", + " agent_name=agent_name,\n", + ")\n", + "response" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 5: Deploy to AgentCore Runtime\n", + "\n", + "Launch the agent with the OTEL environment variables that route traces to Datadog. ADOT reads these at container startup and auto-instruments all Bedrock model calls, tool invocations, and agent lifecycle spans." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "launch_result = agentcore_runtime.launch(\n", + " auto_update_on_conflict=True,\n", + " env_vars={\n", + " \"AGENT_OBSERVABILITY_ENABLED\": \"true\",\n", + " \"OTEL_EXPORTER_OTLP_PROTOCOL\": \"http/protobuf\",\n", + " \"OTEL_EXPORTER_OTLP_TRACES_ENDPOINT\": f\"https://otlp.{DD_SITE}/v1/traces\",\n", + " \"OTEL_EXPORTER_OTLP_TRACES_HEADERS\": f\"dd-api-key={DD_API_KEY},dd-otlp-source=llmobs\",\n", + " \"OTEL_EXPORTER_OTLP_TRACES_PROTOCOL\": \"http/protobuf\",\n", + " \"OTEL_PYTHON_CONFIGURATOR\": \"aws_configurator\",\n", + " \"OTEL_PYTHON_DISTRO\": \"aws_distro\",\n", + " \"OTEL_SERVICE_NAME\": \"agentcore-datadog-demo\",\n", + " }\n", + ")\n", + "launch_result" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 6: Wait for Deployment\n", + "\n", + "Poll the runtime status until the endpoint is ready." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "\n", + "status_response = agentcore_runtime.status()\n", + "status = status_response.endpoint[\"status\"]\n", + "end_status = [\"READY\", \"CREATE_FAILED\", \"DELETE_FAILED\", \"UPDATE_FAILED\"]\n", + "\n", + "while status not in end_status:\n", + " time.sleep(10)\n", + " status_response = agentcore_runtime.status()\n", + " status = status_response.endpoint[\"status\"]\n", + " print(status)\n", + "\n", + "print(f\"\\nFinal status: {status}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 7: Invoke the Agent\n", + "\n", + "Send prompts to the deployed agent. Each invocation generates traces that are exported to both CloudWatch (automatic) and Datadog (via ADOT OTLP export)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "invoke_response = agentcore_runtime.invoke({\"prompt\": \"What is the weather now?\"})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from IPython.display import Markdown, display\n", + "display(Markdown(\"\".join(invoke_response[\"response\"])))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "invoke_response = agentcore_runtime.invoke({\"prompt\": \"What is 42 * 17?\"})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "display(Markdown(\"\".join(invoke_response[\"response\"])))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 8: View Traces in Datadog\n", + "\n", + "Open your Datadog APM dashboard and filter by `service:agentcore-datadog-demo`.\n", + "\n", + "You should see traces for each agent invocation with spans for:\n", + "- Agent invocation lifecycle\n", + "- Model calls (Bedrock `InvokeModel`)\n", + "- Tool execution (calculator, weather)\n", + "- Token usage and latency metrics\n", + "\n", + "\n", + "![Datadog APM Dashboard](images/datadog_dashboard.png)\n", + "*Datadog APM showing AgentCore agent traces with LLM and tool spans.*" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cleanup (Optional)\n", + "\n", + "Delete the AgentCore Runtime and ECR repository." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Delete the AgentCore Runtime and ECR repository\n", + "agentcore_control_client = boto3.client(\"bedrock-agentcore-control\", region_name=region)\n", + "ecr_client = boto3.client(\"ecr\", region_name=region)\n", + "\n", + "# Delete the runtime\n", + "agentcore_control_client.delete_agent_runtime(\n", + " agentRuntimeId=launch_result.agent_id,\n", + ")\n", + "\n", + "# Delete the ECR repository\n", + "ecr_client.delete_repository(\n", + " repositoryName=launch_result.ecr_uri.split(\"/\")[1],\n", + " force=True,\n", + ")\n", + "\n", + "print(\"Cleanup completed\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Summary\n", + "\n", + "You have successfully deployed a Strands agent to Amazon Bedrock AgentCore Runtime with Datadog observability. The implementation demonstrates:\n", + "\n", + "- ADOT auto-instrumentation routing traces to Datadog via OTLP env vars\n", + "- Direct OTLP export to Datadog (no sidecar agent needed)\n", + "- Dual observability: CloudWatch (automatic from AgentCore) + Datadog (via ADOT)\n", + "- Deployment using the AgentCore starter toolkit\n", + "\n", + "The agent is now running in a managed, scalable environment with full observability through Datadog APM." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.14.2" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/01-tutorials/06-AgentCore-observability/04-Agentcore-runtime-partner-observability/Datadog/runtime_with_strands_and_datadog_agentcore_cli.ipynb b/01-tutorials/06-AgentCore-observability/04-Agentcore-runtime-partner-observability/Datadog/runtime_with_strands_and_datadog_agentcore_cli.ipynb new file mode 100644 index 000000000..4224adfed --- /dev/null +++ b/01-tutorials/06-AgentCore-observability/04-Agentcore-runtime-partner-observability/Datadog/runtime_with_strands_and_datadog_agentcore_cli.ipynb @@ -0,0 +1,426 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a0000001", + "metadata": {}, + "source": [ + "# Strands Agent with Datadog Observability on Amazon Bedrock AgentCore Runtime\n", + "\n", + "## Overview\n", + "\n", + "This notebook deploys a [Strands](https://strandsagents.com/) agent to **Amazon Bedrock AgentCore Runtime** using the **AgentCore CLI**, with traces exported to **Datadog** via ADOT (AWS Distro for OpenTelemetry) auto-instrumentation — no Datadog Agent sidecar required.\n", + "\n", + "## Key Components\n", + "\n", + "- **Strands Agents** — Python framework for building LLM-powered agents with built-in telemetry\n", + "- **Amazon Bedrock AgentCore Runtime** — Managed runtime for hosting and scaling agents on AWS\n", + "- **AgentCore CLI** — CLI tool to create, develop, and deploy agents to AgentCore\n", + "- **ADOT** — AWS Distro for OpenTelemetry, auto-instruments the agent and exports traces via OTLP\n", + "- **Datadog** — Full-stack observability platform with APM, tracing, and AI-focused monitoring\n", + "\n", + "## Prerequisites\n", + "\n", + "- **Node.js** 20.x+ and **AgentCore CLI** installed (`npm install -g @aws/agentcore`)\n", + "- **uv** for Python dependency management ([install](https://docs.astral.sh/uv/getting-started/installation/))\n", + "- **AWS credentials** configured with Bedrock and AgentCore permissions\n", + "- **Datadog account** with an API key ([free trial](https://www.datadoghq.com/free-datadog-trial/))\n", + "- Access to **Amazon Bedrock Claude models** in your region" + ] + }, + { + "cell_type": "markdown", + "id": "a0000002", + "metadata": {}, + "source": [ + "## Step 1: Configuration\n", + "\n", + "Set your project name, Datadog credentials, and detect AWS account/region from your environment." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4e35f983", + "metadata": {}, + "outputs": [], + "source": [ + "import subprocess, json, os, boto3\n", + "\n", + "PROJECT_NAME = \"DatadogDemo\"\n", + "WORK_DIR = os.getcwd()\n", + "DD_SITE = \"datadoghq.com\"\n", + "DD_API_KEY = os.getenv(\"DD_API_KEY\", \"\") # Replace or set DD_API_KEY env var\n", + "AGENTCORE = \"/usr/local/bin/agentcore\"\n", + "\n", + "sts = boto3.client(\"sts\")\n", + "AWS_ACCOUNT = sts.get_caller_identity()[\"Account\"]\n", + "AWS_REGION = boto3.session.Session().region_name or \"us-east-1\"\n", + "\n", + "def run(cmd, cwd=None):\n", + " r = subprocess.run(cmd, shell=True, capture_output=True, text=True, cwd=cwd)\n", + " print(r.stdout)\n", + " if r.returncode != 0:\n", + " print(r.stderr)\n", + " raise RuntimeError(f\"Command failed: {cmd}\")\n", + " return r\n", + "\n", + "project_dir = os.path.join(WORK_DIR, PROJECT_NAME)\n", + "agent_dir = os.path.join(project_dir, \"app\", PROJECT_NAME)\n", + "\n", + "print(f\"Project: {PROJECT_NAME}\")\n", + "print(f\"AWS: {AWS_ACCOUNT} / {AWS_REGION}\")\n", + "print(f\"Datadog: {DD_SITE}\")" + ] + }, + { + "cell_type": "markdown", + "id": "a0000003", + "metadata": {}, + "source": [ + "## Step 2: Create AgentCore Project\n", + "\n", + "Scaffold a new AgentCore project using the CLI. This generates:\n", + "- A **Strands** agent template with Amazon Bedrock as the model provider\n", + "- A **Container** build configuration (Dockerfile, pyproject.toml)\n", + "- CDK infrastructure code for deployment" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ea8e09fb", + "metadata": {}, + "outputs": [], + "source": [ + "run(\n", + " f\"{AGENTCORE} create --name {PROJECT_NAME} --framework Strands \"\n", + " f\"--model-provider Bedrock --build Container --memory none \"\n", + " f\"--skip-git --skip-python-setup --json\",\n", + " cwd=WORK_DIR\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "a0000004", + "metadata": {}, + "source": [ + "## Step 3: Configure AWS Deployment Target\n", + "\n", + "Write the `aws-targets.json` file with your AWS account ID and region. This tells the CLI where to deploy the CloudFormation stack." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8c207b64", + "metadata": {}, + "outputs": [], + "source": [ + "targets = [{\"name\": \"default\", \"account\": AWS_ACCOUNT, \"region\": AWS_REGION}]\n", + "with open(os.path.join(project_dir, \"agentcore\", \"aws-targets.json\"), \"w\") as f:\n", + " json.dump(targets, f, indent=2)\n", + "print(f\"Target: {AWS_ACCOUNT} / {AWS_REGION}\")" + ] + }, + { + "cell_type": "markdown", + "id": "a0000005", + "metadata": {}, + "source": [ + "## Step 4: Configure Datadog OTEL Export\n", + "\n", + "Inject OpenTelemetry environment variables into the agent configuration. At runtime, ADOT reads these variables and auto-instruments all Bedrock model calls, tool invocations, and agent lifecycle spans — exporting them directly to Datadog's OTLP intake.\n", + "\n", + "| Variable | Purpose |\n", + "|---|---|\n", + "| `AGENT_OBSERVABILITY_ENABLED` | Enables ADOT auto-instrumentation in AgentCore Runtime |\n", + "| `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` | Datadog's OTLP intake URL |\n", + "| `OTEL_EXPORTER_OTLP_TRACES_HEADERS` | API key and source tag for Datadog |\n", + "| `OTEL_PYTHON_DISTRO` / `OTEL_PYTHON_CONFIGURATOR` | Selects the AWS ADOT distro |\n", + "| `OTEL_SERVICE_NAME` | Service name shown in Datadog APM |" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0d50d8ca", + "metadata": {}, + "outputs": [], + "source": [ + "spec_path = os.path.join(project_dir, \"agentcore\", \"agentcore.json\")\n", + "with open(spec_path) as f:\n", + " spec = json.load(f)\n", + "\n", + "for agent in spec[\"agents\"]:\n", + " agent[\"envVars\"] = [\n", + " {\"name\": \"AGENT_OBSERVABILITY_ENABLED\", \"value\": \"true\"},\n", + " {\"name\": \"OTEL_EXPORTER_OTLP_PROTOCOL\", \"value\": \"http/protobuf\"},\n", + " {\"name\": \"OTEL_EXPORTER_OTLP_TRACES_ENDPOINT\", \"value\": f\"https://otlp.{DD_SITE}/v1/traces\"},\n", + " {\"name\": \"OTEL_EXPORTER_OTLP_TRACES_HEADERS\", \"value\": f\"dd-api-key={DD_API_KEY},dd-otlp-source=llmobs\"},\n", + " {\"name\": \"OTEL_EXPORTER_OTLP_TRACES_PROTOCOL\", \"value\": \"http/protobuf\"},\n", + " {\"name\": \"OTEL_PYTHON_CONFIGURATOR\", \"value\": \"aws_configurator\"},\n", + " {\"name\": \"OTEL_PYTHON_DISTRO\", \"value\": \"aws_distro\"},\n", + " {\"name\": \"OTEL_SERVICE_NAME\", \"value\": \"agentcore-datadog-demo\"},\n", + " ]\n", + "\n", + "with open(spec_path, \"w\") as f:\n", + " json.dump(spec, f, indent=2)\n", + "print(\"Updated agentcore.json with Datadog OTEL env vars\")" + ] + }, + { + "cell_type": "markdown", + "id": "a0000006", + "metadata": {}, + "source": [ + "## Step 5: Write Agent Code\n", + "\n", + "Replace the template agent with a custom Strands agent that includes:\n", + "- A **calculator** tool (built-in from `strands_tools`)\n", + "- A custom **weather** tool\n", + "- Claude Sonnet as the model via Amazon Bedrock\n", + "\n", + "The `@app.entrypoint` decorator is the AgentCore Runtime contract — it receives invocation payloads and returns the agent's response." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c75e7350", + "metadata": {}, + "outputs": [], + "source": [ + "with open(os.path.join(agent_dir, \"main.py\"), \"w\") as f:\n", + " f.write('''\\\n", + "\"\"\"Strands agent with Datadog observability on Amazon Bedrock AgentCore Runtime.\"\"\"\n", + "\n", + "import os\n", + "import logging\n", + "from bedrock_agentcore.runtime import BedrockAgentCoreApp\n", + "from strands import Agent, tool\n", + "from strands.models import BedrockModel\n", + "from strands_tools import calculator\n", + "\n", + "logging.basicConfig(level=logging.INFO, format=\"[%(levelname)s] %(message)s\")\n", + "logger = logging.getLogger(__name__)\n", + "\n", + "\n", + "@tool\n", + "def weather() -> str:\n", + " \"\"\"Get the current weather.\"\"\"\n", + " return \"sunny\"\n", + "\n", + "\n", + "model_id = os.getenv(\"BEDROCK_MODEL_ID\", \"us.anthropic.claude-sonnet-4-20250514-v1:0\")\n", + "model = BedrockModel(model_id=model_id)\n", + "\n", + "agent = Agent(\n", + " model=model,\n", + " tools=[calculator, weather],\n", + " system_prompt=\"You are a helpful assistant. You can do simple math calculations and tell the weather.\",\n", + ")\n", + "\n", + "app = BedrockAgentCoreApp()\n", + "\n", + "\n", + "@app.entrypoint\n", + "def handler(payload: dict, context=None) -> str:\n", + " \"\"\"Handle incoming agent invocations.\"\"\"\n", + " user_input = payload.get(\"prompt\", \"Hello!\")\n", + " logger.info(\"Processing prompt: %s\", user_input[:100])\n", + " response = agent(user_input)\n", + " return response.message[\"content\"][0][\"text\"]\n", + "\n", + "\n", + "if __name__ == \"__main__\":\n", + " app.run()\n", + "''')\n", + "print(\"Wrote main.py\")" + ] + }, + { + "cell_type": "markdown", + "id": "a0000007", + "metadata": {}, + "source": [ + "## Step 6: Add Dependencies\n", + "\n", + "Add `strands-agents-tools` (provides the `calculator` tool) to the project's `pyproject.toml`, then generate the `uv.lock` file required by the Container build's Dockerfile." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16fb29f1", + "metadata": {}, + "outputs": [], + "source": [ + "pyproject_path = os.path.join(agent_dir, \"pyproject.toml\")\n", + "with open(pyproject_path) as f:\n", + " content = f.read()\n", + "\n", + "if \"strands-agents-tools\" not in content:\n", + " content = content.replace(\n", + " '\"strands-agents >= 1.13.0\",',\n", + " '\"strands-agents >= 1.13.0\",\\n \"strands-agents-tools\",'\n", + " )\n", + " with open(pyproject_path, \"w\") as f:\n", + " f.write(content)\n", + " print(\"Added strands-agents-tools\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "45a65ee9", + "metadata": {}, + "outputs": [], + "source": [ + "run(\"uv lock\", cwd=agent_dir)" + ] + }, + { + "cell_type": "markdown", + "id": "a0000008", + "metadata": {}, + "source": [ + "## Step 7: Deploy to AgentCore Runtime\n", + "\n", + "Deploy the agent to AWS. The CLI will:\n", + "1. Package the agent code into a container image via **CodeBuild**\n", + "2. Push the image to **ECR**\n", + "3. Deploy the **CloudFormation** stack with the AgentCore Runtime, IAM roles, and observability configuration\n", + "\n", + "This typically takes 5–10 minutes on the first deploy." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f37d93c0", + "metadata": {}, + "outputs": [], + "source": [ + "run(f\"{AGENTCORE} deploy -y --json\", cwd=project_dir)" + ] + }, + { + "cell_type": "markdown", + "id": "a0000009", + "metadata": {}, + "source": [ + "## Step 8: Invoke the Agent\n", + "\n", + "Send prompts to the deployed agent. Each invocation generates traces that are exported to both **CloudWatch** (automatic from AgentCore) and **Datadog** (via ADOT OTLP export)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "65328fdf", + "metadata": {}, + "outputs": [], + "source": [ + "run(f'{AGENTCORE} invoke \"What is 42 * 17?\" --json', cwd=project_dir)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "65328fdf2", + "metadata": {}, + "outputs": [], + "source": [ + "run(f'{AGENTCORE} invoke \"What is the weather now?\" --json', cwd=project_dir)" + ] + }, + { + "cell_type": "markdown", + "id": "a0000010", + "metadata": {}, + "source": [ + "## Step 9: View Traces in Datadog\n", + "\n", + "Open your [Datadog APM dashboard](https://app.datadoghq.com/apm/traces) and filter by `service:agentcore-datadog-demo`.\n", + "\n", + "You should see traces for each agent invocation with spans for:\n", + "- Agent invocation lifecycle\n", + "- Model calls (Bedrock `InvokeModel`)\n", + "- Tool execution (calculator, weather)\n", + "- Token usage and latency metrics\n", + "\n", + "\n", + "![Datadog APM Dashboard](images/datadog_dashboard.png)\n", + "*Datadog APM showing AgentCore agent traces with LLM and tool spans.*" + ] + }, + { + "cell_type": "markdown", + "id": "a0000011", + "metadata": {}, + "source": [ + "## Cleanup\n", + "\n", + "Tear down the CloudFormation stack and remove the local project directory." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a0000012", + "metadata": {}, + "outputs": [], + "source": [ + "import shutil\n", + "try:\n", + " run(f\"{AGENTCORE} remove all -y --json\", cwd=project_dir)\n", + " run(f\"{AGENTCORE} deploy -y --json\", cwd=project_dir)\n", + "except RuntimeError:\n", + " print(\"Teardown via CLI failed, deleting stack directly...\")\n", + " run(f\"aws cloudformation delete-stack --stack-name AgentCore-{PROJECT_NAME}-default --region {AWS_REGION}\")\n", + " run(f\"aws cloudformation wait stack-delete-complete --stack-name AgentCore-{PROJECT_NAME}-default --region {AWS_REGION}\")\n", + "shutil.rmtree(project_dir, ignore_errors=True)\n", + "print(f\"Cleaned up {project_dir}\")" + ] + }, + { + "cell_type": "markdown", + "id": "a0000013", + "metadata": {}, + "source": [ + "## Summary\n", + "\n", + "This notebook demonstrated:\n", + "\n", + "- Deploying a **Strands agent** to **Amazon Bedrock AgentCore Runtime** using the **AgentCore CLI**\n", + "- **Container build** for full control over the runtime environment and reproducible deployments\n", + "- **ADOT auto-instrumentation** routing traces to **Datadog** via OTLP — no sidecar agent needed\n", + "- **Dual observability**: CloudWatch (automatic from AgentCore) + Datadog (via ADOT OTLP export)\n", + "- **Infrastructure-as-code** deployment via CDK/CloudFormation with drift detection and rollback" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.14.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/01-tutorials/06-AgentCore-observability/04-Agentcore-runtime-partner-observability/README.md b/01-tutorials/06-AgentCore-observability/04-Agentcore-runtime-partner-observability/README.md index c616c18d2..2e5adc4e1 100644 --- a/01-tutorials/06-AgentCore-observability/04-Agentcore-runtime-partner-observability/README.md +++ b/01-tutorials/06-AgentCore-observability/04-Agentcore-runtime-partner-observability/README.md @@ -50,6 +50,13 @@ Each platform requires specific configuration: - Public and secret keys - Project configuration +### Datadog +- API key from [Datadog dashboard](https://app.datadoghq.com/organization-settings/api-keys) +- Datadog site (e.g., `datadoghq.com`, `datadoghq.eu`) +- Two deployment options: + - **Starter Toolkit** (`runtime_with_strands_and_datadog.ipynb`) — uses the Python starter toolkit + - **AgentCore CLI** (`runtime_with_strands_and_datadog_agentcore_cli.ipynb`) — uses the AgentCore CLI with CDK/CloudFormation infrastructure-as-code + ## Cleanup After completing examples: @@ -64,9 +71,10 @@ After completing examples: - [Braintrust Documentation](https://www.braintrust.dev/docs) - [Instana Documentation](https://www.ibm.com/docs/en/instana-observability/1.0.308?topic=overview) - [Langfuse Documentation](https://langfuse.com/docs) +- [Datadog Documentation](https://docs.datadoghq.com/tracing/) - [AgentCore Runtime Guide](https://docs.aws.amazon.com/bedrock-agentcore/latest/userguide/runtime.html) # Third-Party Observability for Amazon Bedrock AgentCore Agents -This repository contains examples of using agents hosted on Amazon Bedrock AgentCore Runtime with third-party observability tools like Arize, Braintrust, Instana, Langfuse, and others. These examples demonstrate OpenTelemetry integration for monitoring agent performance, tracing LLM interactions, and debugging workflows. +This repository contains examples of using agents hosted on Amazon Bedrock AgentCore Runtime with third-party observability tools like Arize, Braintrust, Datadog, Instana, Langfuse, and others. These examples demonstrate OpenTelemetry integration for monitoring agent performance, tracing LLM interactions, and debugging workflows.