> ## Documentation Index
> Fetch the complete documentation index at: https://agent-observability-docs.splunk.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Strands Agents

> Learn how to integrate a Strands Agents project with Splunk Agent Observability using OpenTelemetry

Splunk Agent Observability supports logging traces from [Strands Agents SDK](https://strandsagents.com/) applications using OpenTelemetry.

## Set up OpenTelemetry

To log Strands Agents using Splunk Agent Observability, the first step is to set up OpenTelemetry.

<Steps>
  <Step title="Installation">
    Add the OpenTelemetry packages to your project:

    <CodeGroup>
      ```bash Terminal theme={null}
      pip install opentelemetry-api opentelemetry-sdk \
                  opentelemetry-exporter-otlp
      ```
    </CodeGroup>

    The `opentelemetry-api` and `opentelemetry-sdk` packages provide the core OpenTelemetry functionality. The `opentelemetry-exporter-otlp` package enables sending traces to Splunk Agent Observability's OTLP endpoint.
  </Step>

  <Step title="Create environment variables for your Splunk Agent Observability settings">
    Set environment variables for your Splunk Agent Observability settings, for example in a `.env` file.
    These environment variables are consumed by the `SplunkAOSpanProcessor`to authenticate
    and route traces to the correct Splunk Agent Observability Project and Agent Stream:

    <CodeGroup>
      ```ini .env theme={null}
      # Provide your Splunk Agent Observability
      # API key and URL if you are using an
      # on-premises, standalone, or custom deployment
      # SPLUNK_AO_API_KEY="your-splunk-ao-api-key"
      # SPLUNK_AO_CONSOLE_URL="your-splunk-ao-url"

      # Your Splunk Agent Observability project name
      SPLUNK_AO_PROJECT="your-splunk-ao-project-name"

      # The name of the Agent Stream you want to use for logging
      SPLUNK_AO_AGENT_STREAM="your-splunk-ao-agent-stream"
      ```
    </CodeGroup>
  </Step>

  <Step title="Self hosted deployments: Set the OTel endpoint">
    <Note>
      Skip this step if you are using a hosted version.
    </Note>

    The OTel endpoint is different from Splunk Agent Observability's regular API endpoint and is specifically designed to receive telemetry data in the OTLP format.

    If you are using:

    * A cloud deployment, then you don't need to provide a custom OTel endpoint.
      The default endpoint `<your-splunk-ao-api-url>/otel/traces` will be used automatically.

    * A **self-hosted deployment**, replace the `<your-splunk-ao-api-url>/otel/traces` endpoint with your deployment URL. The format of this URL is based on your console URL, appending `/otel/traces`.

    The convention is to store this in the `SPLUNK_AO_CONSOLE_URL` environment variable. For example:

    <CodeGroup>
      ```python Python theme={null}
      os.environ["SPLUNK_AO_CONSOLE_URL"] = "<your-splunk-ao-url>"
      ```
    </CodeGroup>
  </Step>

  <Step title="Initialize and create the Splunk Agent Observability span processor">
    The `SplunkAOSpanProcessor` automatically configures authentication
    and metadata using your environment variables. It also:

    * Auto-builds OTLP headers using your Splunk Agent Observability credentials
    * Configures the correct OTLP trace endpoint
    * Registers a batch span processor that exports traces to Splunk Agent Observability

    <CodeGroup>
      ```python Python theme={null}
      from splunk_ao import otel  

      # SplunkAOSpanProcessor (no manual OTLP config required) loads the env vars for 
      # the Splunk Agent Observability API key, Project, and Agent Stream. Make sure to set them first. 
      splunk_ao_span_processor = otel.SplunkAOSpanProcessor(
          # Optional parameters if not set, uses env var
          # project=os.environ["SPLUNK_AO_PROJECT"], 
          # agentstream=os.environ.get("SPLUNK_AO_AGENT_STREAM"),  
      )
      ```
    </CodeGroup>
  </Step>
</Steps>

## Log a Strands ADK agent using OpenTelemetry

Once OpenTelemetry is configured, you can use the OTel capabilities of Strands to log traces.

<Steps>
  <Step title="Import the Strands Agent telemetry package">
    The Strands Agents SDK has telemetry support out of the box. Start by importing `StrandsTelemetry` with the following code:

    <CodeGroup>
      ```python Python theme={null}
      from strands.telemetry import StrandsTelemetry
      ```
    </CodeGroup>
  </Step>

  <Step title="Set up the exporter">
    You can now set up an OTel exporter for your Strands Agent:

    <CodeGroup>
      ```python Python theme={null}
      strands_telemetry = StrandsTelemetry()
      strands_telemetry.setup_otlp_exporter()
      ```
    </CodeGroup>

    When you run your Strands Agent code, traces will be logged to Splunk Agent Observability.
  </Step>
</Steps>

## Opt in to experimental OpenTelemetry semantic conventions

Starting in `strands-agents` v1.34.0, the Strands Agents SDK can emit generative AI traces using either the legacy OpenTelemetry semantic conventions or the newer experimental conventions:

* **Legacy mode** (default) — uses attributes such as `gen_ai.system` along with legacy event shapes.
* **Experimental mode** — follows the latest OpenTelemetry generative AI semantic conventions, using `gen_ai.provider.name` and structured `gen_ai.client.inference.operation.details` events that carry inputs, outputs, and system instructions.

Splunk Agent Observability automatically detects and maps both modes, so traces from either mode will appear in your Splunk Agent Observability Agent Stream without any changes to your Splunk Agent Observability setup.

If you want to opt in to the experimental conventions, set the following environment variable before your Strands Agent starts:

<CodeGroup>
  ```ini .env theme={null}
  OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental
  ```
</CodeGroup>

<Note>
  `OTEL_SEMCONV_STABILITY_OPT_IN` is read by the Strands Agents SDK at startup. Make sure it is exported in your process environment (or loaded from your `.env` file) before `StrandsTelemetry` is initialized.
</Note>

## Full example

Here is a full example based off the [Strands Agent quickstart](https://strandsagents.com/latest/documentation/docs/user-guide/quickstart/). You can find this project in the [Splunk Agent Observability SDK examples repo](https://github.com/splunk/splunk-ao-python/tree/main/examples/agent/strands-agents).

To run this example, create a `.env` file with the following values set, or set them as environment variables:

```ini .env theme={null}
# AWS environment variables
AWS_BEARER_TOKEN_BEDROCK=your-aws-bedrock-token

# Splunk Agent Observability environment variables
SPLUNK_AO_API_ENDPOINT=your-splunk-ao-otel-api-endpoint
SPLUNK_AO_PROJECT=your-splunk-ao-project
SPLUNK_AO_AGENT_STREAM=your-agent-stream
# Only required for on-premises, standalone, or custom deployments
# SPLUNK_AO_API_KEY=your-splunk-ao-api-key
```

Remember to update these to match your [Splunk Agent Observability API key](/references/faqs/find-keys#splunk-ao-api-key), AWS Bedrock token, [Splunk Agent Observability OTel endpoint](/sdk-api/third-party-integrations/opentelemetry-and-openinference#opentelemetry), project name, and Agent Stream name.

<CodeGroup>
  ```python Python theme={null}
  import os

  from strands import Agent, tool
  from strands.telemetry import StrandsTelemetry
  from strands_tools import calculator, current_time

  # Load environment variables from the .env file
  from dotenv import load_dotenv
  load_dotenv(override=True)

  # Export the Splunk Agent Observability OTel API endpoint for OTel
  os.environ["OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"] = os.environ.get(
      "SPLUNK_AO_API_ENDPOINT", 
      "<your-splunk-ao-api-url>/otel/traces"
  )

  # Export the Splunk Agent Observability OTel headers pointing to the correct API key,
  # project, and Agent Stream
  headers = {
      # Only required for on-premises, standalone, and custom deployments
      # "Splunk-AO-API-Key": os.environ["SPLUNK_AO_API_KEY"],
      "project": os.environ["SPLUNK_AO_PROJECT"],
      "agentstream": os.environ["SPLUNK_AO_AGENT_STREAM"],
  }

  os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = ",".join(
      [f"{k}={v}" for k, v in headers.items()]
  )

  # Setup telemetry for the Strands agent using Splunk Agent Observability as the OTel backend
  strands_telemetry = StrandsTelemetry()
  strands_telemetry.setup_otlp_exporter()

  # Define a custom tool as a Python function using the @tool decorator
  @tool
  def letter_counter(word: str, letter: str) -> int:
      """
      Count occurrences of a specific letter in a word.

      Args:
          word (str): The input word to search in
          letter (str): The specific letter to count

      Returns:
          int: The number of occurrences of the letter in the word
      """
      if not isinstance(word, str) or not isinstance(letter, str):
          return 0

      if len(letter) != 1:
          raise ValueError("The 'letter' parameter must be a single char")

      return word.lower().count(letter.lower())


  # Create an agent with tools from the community-driven strands-tools
  # package as well as our custom letter_counter tool
  agent = Agent(tools=[calculator, current_time, letter_counter])

  # Ask the agent a question that uses the available tools
  message = """
  I have 4 requests:

  1. What is the time right now?
  2. Calculate 3111696 / 74088
  3. Tell me how many letter R's are in the word "strawberry" 🍓
  """
  agent(message)
  ```
</CodeGroup>
