OpenTelemetry Ingestion Gateway for AppDynamics: Collector-Exporter

Overview

OpenTelemetry (OTel) is a collection of tools, APIs, and SDKs used to instrument, generate, collect, and export telemetry data (metrics, logs, and traces). This helps you analyze software performance and behavior. OpenTelemetry Ingestion Gateway for AppDynamics (OTIG) is an ingestion and translation mechanism based on the OpenTelemetry Collector. By utilizing the Collector processing engine and the custom AppDynamics Exporter, OTIG translates native OpenTelemetry protocols and semantics into AppDynamics Controller-specific data models. This approach ensures that OTIG:

  • presents OpenTelemetry data, such as traces and metrics, within the Controller UI.

  • maintains a consistent user experience with existing AppDynamics concepts, including Business Transactions (BTs) and Tiers.

Prerequisites

Ensure that your environment meets the following requirements before deploying the OTIG Collector-Exporter:

  • Controller Compatibility: AppDynamics On-Premises or SaaS Controller from version 26.4.0.

    Note: 25.10.0 is the minimum version requirement. However, Node-level visibility and Metrics Browser are supported from 26.4.0.
  • Deployment Constraint: The component is supported in AppDynamics On-Premises Virtual Appliance (VA) and cSaaS.

  • Supported Operating Systems: Amazon Linux, Red Hat Enterprise Linux (RHEL), and Debian-based distributions.

  • Supported Architectures: amd64 (x86_64) and arm64 (ARM64/aarch64).

    • Recommended Resource Limits: The following table provides the resource limits:
      Profile Traces/sec Span/sec Metrics Datapoints/min Instances in Use OTel YAML Configuration Resources
      Demo 100 2000 15000 30
      CODE
      processors:
        tail_sampling:
          decision_wait: 30s
      CODE
      resources:
        limits:
          cpu: 500m
          memory: 1Gi
        requests:
          cpu: 250m
          memory: 512Mi
      Small 500 15000 15000 30
      CODE
      processors:
        tail_sampling:
          decision_wait: 30s
      CODE
      resources:
        limits:
          cpu: '1'
          memory: 6Gi
        requests:
          cpu: 512m
          memory: 2Gi
      Medium 3000 60000 125000 250
      CODE
      processors:
        tail_sampling:
          decision_wait: 30s
          num_traces: 120000
      CODE
      resources:
        limits:
          cpu: '5'
          memory: 28Gi
        requests:
          cpu: 2500m
          memory: 10Gi
      Large 10000 200000 500000 1000
      CODE
      processors:
        tail_sampling:
          decision_wait: 30s
          num_traces: 500000
          expected_new_traces_per_sec: 10000
      exporters:
        appd:
          spanbuffersize: 200000
          agentspanbuffersize: 25000
          metricbuffersize: 500
          maxagents: 2500
      CODE
      resources:
        limits:
          cpu: '12'
          memory: 75Gi
        requests:
          cpu: '3'
          memory: 30Gi
  • Kubernetes Environment: Cluster version 1.20+ with kubectl and docker installed.

AppDynamics Collector-Exporter

The Cisco OpenTelemetry Ingestion Gateway for AppDynamics: Collector-Exporter is a specialized distribution of the OpenTelemetry Collector. It acts as a gateway, receiving OTLP data from your applications and exporting it to the Virtual Appliance/Controller. The Collector-Exporter is available as a standalone package through the Downloads portal:
  1. Log in to the Downloads Portal.

  2. Select OpenTelemetry Ingestion Gateway for AppDynamics from the Type list.

  3. Download the appropriate package for your environment. You can view the following files after extracting the package:
    • VERSION: Current build version information.

    • README.md: Installation instructions.
    • otel-collector-k8s.yaml: Kubernetes manifests for deployment.
    • otel-collector-image: Compressed Docker image archive.
    • LICENSE: Pre-release license agreement.
  4. Follow the installation and set-up instructions provided in the README.md file to complete the setup.

Application Name in the OTel Collector

The AppDynamics OpenTelemetry Collector determines the Application Name from resource attributes. The collector checks resource attributes in a specific order and uses the first available attribute it finds. The following are the detection priority:

  • appd.app.name (Highest priority)
  • service.namespace
  • deployment.environment.name
  • "unknown" (Default fallback)

Example 1: Set Default for Missing service.namespace

You must use this configuration to set a default application name only when service.namespace is missing, without overriding existing values.

CODE
processors:
  resource/set_default_app_name:
    attributes:
      - key: service.namespace
        action: insert
        value: "default-application"

service:
  pipelines:
    traces:
      processors: [resource/set_default_app_name, tail_sampling]
    metrics:
      processors: [resource/set_default_app_name]
Note:
  • Resources with `service.namespace` → Keep original value

  • Resources without `service.namespace` → Set to `"default-application"

Example 2: Custom Application Name

The following example demonstrates how to use conditional logic to set application names based on resource attributes. This illustrates one approach to dynamic application name assignment. You can customize these conditions to match your specific deployment patterns, service naming conventions, or organizational requirements using the OpenTelemetry Transformation Language (OTTL).

CODE
trace_statements:
 - conditions:
 # Payment services
   - IsMatch(resource.attributes["service.name"], ".*payment.*")
 statements:
   - set(resource.attributes["appd.app.name"], "payment-services")

 metric_statements:
 - conditions:
    - IsMatch(resource.attributes["service.name"], ".*payment.*")
 statements:
     - set(resource.attributes["appd.app.name"], "payment-services")

service:
  pipelines:
    traces:
      processors: [transform/set_custom_app_name, tail_sampling]
    metrics:
      processors: [transform/set_custom_app_name]
Note: "my-custom-application"` is used as the Application Name, taking precedence over all other attributes.

Collector Mapping Logic and Reference

You can configure the collector by using the following yaml file:

JSON
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  tail_sampling:
    decision_wait: 30s
    num_traces: 500000
    policies:
      [
        {
          name: everything,
          type: always_sample
        }
      ]
  transform/btnaming:
    trace_statements:
      - conditions:
          - span.attributes["http.route"] != nil and IsRootSpan()
        statements:
          - set(span.attributes[""], span.attributes["http.route"])
      - conditions:
          - span.name != "" and IsRootSpan() and span.attributes["appd.bt.name"] == nil
        statements:
          - set(span.attributes[""], span.name)
  # Example of setting a bt-wide error bit based on any span in the trace
  transform/bt_error:
    trace_statements:
      - conditions:
          - span.attributes["http.status_code"] >= 400
        statements:
          - set(span.attributes["appd.bt.error"], true)
  filter/allow_redis:
    metrics:
      metric:
        - not IsMatch(metric.name, "redis.*")
        - Len(metric.data_points) != 1
  transform/redis:
    metric_statements:
      - conditions:
          - IsMatch(metric.name, "redis.*")
        statements:
           - replace_pattern(metric.name, "\\.", "|")
           - set(metric.name, Concat(["Custom Metrics|", metric.name], ""))
exporters:
  appd:
    urlbase: "https://<your-controller-url>"
    account: "e2e-customer"
  	accesskey: "fa1ddb6b-****-44c9-9649-************"
  	# NOTE: Uncomment the below property if your controller is of version 26.1 or below
  	# agentproducttype: "open-telemetry"
    # tls:                        
      #  insecure: false           
      #  ca_file: /etc/otel-certs/ca.crt
    # snapshot limits
    snapshots:
    periodminutes: 1
    errors: 2
    slows: 5
    randoms: 20

service:
  telemetry:
    logs:
      level: "info"
  pipelines:
    traces:
      receivers: [otlp]
      processors: [transform/btnaming, transform/bt_error, tail_sampling]
      exporters: [appd]
    metrics:
      receivers: [otlp]
      processors: [filter/allow_redis, transform/redis]
      exporters: [appd]
Note:
  • This YAML is just for an example and must not be used as it is.

  • For the metric, Len(metric.data_points) != 1, the custom AppDynamics collector processes only those metrics where the number of data points (Len(data_points)) equals to exactly one. Metrics that contain multiple data points (due to multiple label or attribute combinations) are dropped by the collector. This behavior is a known limitation, particularly relevant when ingesting Redis metrics. Many Redis instrumentation libraries emit multi-dimensional metric series, for example, redis.commands{command="get", status="success"}, which include multiple label combinations.

    To comply with this limitation, metrics must encode dimension values directly into the metric name rather than as separate attributes. For instance, instead of emitting redis.commands{command="get", status="success"}, the metric should be named redis.commands.get.success. This approach guarantees exactly one data point per metric, ensuring that the collector to process it correctly.

    Additionally, the collector currently supports only the following metric types: Counter, UpDownCounter, and Observable Gauge (single-observation). Metric types such as Histograms and ExponentialHistograms are not processed and will be dropped.

The following are the example configurations based on the sample YAML:

Example1: Business Transaction Naming

The transform/btnaming processor ensures that traces are grouped into meaningful Business Transactions in the UI.
  • Logic: If an http.route attribute exists (example: /api/checkout), it is used as the BT name. If not, the span name is used as a fallback.
  • Attribute: http.route

Example 2: Error Reporting

The transform/bt_error processor identifies failed transactions.

  • Logic: Any span with an HTTP status code of 400 or higher is marked as an error.
  • Attribute: appd.bt.error

Configure Certificate (optional)

To enable secure HTTPS connections using a custom CA certificate, modify otel-collector-k8s.yaml before deployment.

  1. Create a ConfigMap with your CA certificate.

    kubectl create configmap otel-ca-cert --from-file=ca.crt=</path/to/your/ca.crt> -n appdynamics
    Note: Replace the /path/to/your/ca.crt with your system path where the certificate is available.
  2. Enable TLS in the Exporter Configuration. Uncomment the following tls block in the otel-collector-k8s.yaml

    CODE
    exporters:
      appd:
        urlbase: "https://<your-controller-url>"
        account: "e2e-customer"
      	accesskey: "fa1ddb6b-****-44c9-9649-************"
      	# NOTE: Uncomment the below property if your controller is of version 26.1 or below
      	# agentproducttype: "open-telemetry"
        tls:                        
          insecure: false           
          ca_file: /etc/otel-certs/ca.crt
        # snapshot limits
        snapshots:
        periodminutes: 1
        errors: 2
        slows: 5
        randoms: 20
  3. Mount the Certificate in the Deployment. Uncomment the following volumeMounts and volumes blocks in the otel-collector-k8s.yaml

    CODE
    volumeMounts:
    - name: otel-ca-cert
      mountPath: /etc/otel-certs
      readOnly: true
    CODE
    volumes:
    - name: otel-ca-cert
      configMap:
        name: otel-ca-cert
        items:
        - key: ca.crt
          path: ca.crt

Deploy OTel Collector

To deploy OTel Collector:

  1. Create a namespace appdynamics in the cluster. If you require to use a custom namespace, you can ignore this step and ensure to use the same namespace during installation. Here, we have used namespace as appdynamics.

    kubectl create namespace appdynamics
  2. Load the Docker Image:

    1. Load image to local docker: docker load -i otel-collector-image.tar
    2. Tag image to private registry: docker tag appdynamics/otel-collector:<version> <your-registry>/appdynamics/otel-collector:<version>
    3. Login to your private registry docker.

    4. Push the image to private registry: docker push <your-registry>/appdynamics/otel-collector:<version>.
  3. Configure and apply Manifests by updating the Exporters section in the otel-collector-k8s.yaml with your Controller URL, Account Name, and Access Key.

  4. Deploy the collector.

    kubectl apply -f otel-collector-k8s.yaml
  5. Validate the installation.

    kubectl get pods -n appdynamicskubectl logs -n appdynamics -l app=otel-collector -f

Node-Level Visibility

Node-level visibility enables you to move beyond simple tier-level monitoring. By registering OpenTelemetry-instrumented services as individual nodes within your tiers, you can have a granular control over performance tracking. This enables you to isolate issues to specific service instances, monitor individual node health, and maintain a clear hierarchy of your infrastructure, which is essential for complex, distributed environments.

Node Naming Strategies

  • Default Mode (Recommended): Uses a single aggregated node (appd.node.name: "default") per tier. Ideal for Kubernetes and auto-scaling environments.

  • Per-Instance Mode: Each service instance appears as a separate node. Ideal for VM deployments or troubleshooting specific instances.

How Nodes Are Created

The collector automatically creates nodes based on resource attributes:

  • Node Name: appd.node.name
  • Tier Name: appd.tier.name (Fallback: service.name)
  • Application Name: appd.app.name (Fallback: service.namespace)
CODE
# Node Mode: By default all instances share one node ("default") per tier.
 # A transformation like below could be added to enable multiple nodes per tier (one per host).
 # Then add transform/nodename to the traces and metrics pipelines below.
 # This can result in very high number of nodes, beyond 1000 nodes, additional tuning would be needed
processors:
  transform/nodename:
    trace_statements:
      - context: resource
        statements:
          - set(attributes["appd.node.name"], attributes["host.name"])
    metric_statements:
      - context: resource
        statements:
          - set(attributes["appd.node.name"], attributes["host.name"])

service:
  telemetry:
    logs:
      level: "info"
  pipelines:
    traces:
      receivers: [ otlp ]
      processors: [ transform/nodename, transform/btnaming, transform/bt_error, tail_sampling ]
      exporters: [ appd ]
    metrics:
      receivers: [ otlp ]
      processors: [ transform/nodename, filter/allow_redis, transform/redis ]
      exporters: [ appd ]

Metrics Browser

Metrics Browser enables you to analyze custom OpenTelemetry metrics along your standard AppDynamics performance data. This integration allows you to leverage the complete AppDynamics Metrics Browser to create complex visualizations, set thresholds, and perform statistical analysis on OTel-generated telemetry. Whether you are monitoring custom application metrics, container utilization, or infrastructure health, you can seamlessly integrate these data points into your existing AppDynamics dashboards.

You can view metrics by using:

  • Metrics Browser - Enables you to explore the entire metric tree, view statistical summaries, and see raw time-series data for debugging. To view metrics using the Metrics Browser:
    1. Select your application

    2. Click Metric Browser from the navigation menu.

    3. Expand: Application Infrastructure Performance > [Your Tier Name] > Custom Metrics.

    4. Select any metric to view its time-series graph and statistical summary (Observed, Min, Max, Sum, Count).

  • Dashboards - Enables you to create visual widgets to monitor specific metrics over time. To view metrics using the Dashboards:
    1. In the Controller GUI, navigate to Tiers & Nodes and create a new dashboard or select an existing one from the My Dashboards tab.

    2. Click Add Widget and select a chart type (Example: Time Series Graph).

    3. In the Add Series dialog, select Custom (use any metrics) from the list.

    4. Click Select a Metric and navigate through the hierarchy.

    5. Click Save to visualize the OTel data on your dashboard.

Visualize OpenTelemetry Apps

Data ingested through the Collector-Exporter is associated to standard AppDynamics components for a consistent monitoring experience.

Business Transactions (BTs)

OTel traces are automatically converted into BTs.

  • Naming: Use the attribute in your collector config to ensure BTs are named logically (Example: /api/checkout).
  • Scorecards: View health, response times, and error rates for OTel-based transactions.

Snapshots

When a transaction is slow or results in an error, AppDynamics generates a Snapshot. Drill down into specific span attributes and metadata for troubleshooting.

Third-Party Metrics

Metrics from services like Redis can be organized using prefixes (Example: Custom Metrics|Redis|...)

Uninstallation

To remove the OTel Collector and all associated resources from your cluster:

kubectl delete -f otel-collector-k8s.yaml