opentelemetry

Instrumenting applications with EDOT SDKs on Kubernetes

Elastic Distributions of OpenTelemetry (EDOT) SDKs cover multiple languages:

This section provides guidance and examples for applications instrumentation in a Kubernetes environment for all supported languages.

In Kubernetes environments with the OpenTelemetry Operator, automatic (or zero-code) instrumentation simplifies the process by injecting and configuring instrumentation libraries into the targeted Pods.

On the other hand, manual instrumentation with OpenTelemetry involves adding specific OpenTelemetry SDKs and APIs directly into your application’s code. This approach provides more granular control over what and how data is captured, allowing you to customize trace spans, metrics, and logging based on your application’s logic.

Table of contents

Supported languages

The following table illustrates the different languages supported by OpenTelemetry (OTel) and the Elastic Stack, the type of SDK/API used for instrumentation (either zero-code or source code dependencies), and the corresponding deployment types (on-premises, ESS, or serverless) for each language.

Language OTel SDK/API Type Deployment Model Support
Java EDOT Java - zero-code instrumentation All deployment types
Node.js EDOT Node.js - zero-code instrumentation All deployment types
.NET EDOT .NET - zero-code instrumentation All deployment types
PHP EDOT PHP - source code dependencies All deployment types
Python EDOT Python - zero-code instrumentation All deployment types
Swift EDOT Swift - source code dependencies ESS, on-premises
Android EDOT Android - source code dependencies ESS, on-premises
Javascript Vanilla OTel RUM SDK/API - source code dependencies ESS, on-premises
Rust Vanilla OTel Rust SDK/API - source code dependencies All deployment types
Ruby Vanilla OTel Ruby SDK/API - source code dependencies All deployment types
Go Vanilla OTel Go SDK/API - zero-code instrumentation All deployment types
C++ Vanilla OTel C++ SDK/API - source code dependencies All deployment types

Prerequisites

Before starting with application auto-instrumentation, ensure the following prerequisites are in place for proper setup:  

Auto-instrumentation basics

Zero-code instrumentation is handled by the operator through Instrumentation objects, used to automatically inject the necessary SDKs and configuration into application workloads.

If you followed the getting started guide to install the operator, there should be an Instrumentation object with name elastic-instrumentation in namespace opentelemetry-operator-system:

kubectl get instrumentation -A
NAMESPACE                       NAME                      AGE     ENDPOINT                                                                                                SAMPLER                    SAMPLER ARG
opentelemetry-operator-system   elastic-instrumentation   5d20h   http://opentelemetry-kube-stack-daemon-collector.opentelemetry-operator-system.svc.cluster.local:4318   parentbased_traceidratio   1.0

The Instrumentation object stores important parameters:

  exporter:
    endpoint: http://opentelemetry-kube-stack-daemon-collector.opentelemetry-operator-system.svc.cluster.local:4318
  dotnet:
    image: docker.elastic.co/observability/elastic-otel-dotnet:edge
  java:
    image: docker.elastic.co/observability/elastic-otel-javaagent:1.0.0
  nodejs:
    image: docker.elastic.co/observability/elastic-otel-node:0.4.1
  python:
    image: docker.elastic.co/observability/elastic-otel-python:0.3.0

Configuring auto-instrumentation

To enable auto-instrumentation, add the corresponding language annotation to the Pods template (spec.template.metadata.annotations) in your Deployment or relevant workload object (StatefulSet, Job, CronJob, etc.).

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  ...
  template:
    metadata:
      annotations:
        instrumentation.opentelemetry.io/inject-<LANGUAGE>: "opentelemetry-operator-system/elastic-instrumentation"
      ...
    spec:
      containers:
      - image: myapplication-image
        name: app
      ...        

where <LANGUAGE> is one of: go , java, nodejs, python, dotnet

[!NOTE] Ensure you add the annotations at Pod level and not directly at the workload spec level (Deployment, Job, etc.). Ensure the annotation value must points to an existing Instrumentation object.

Alternatively, you can enable auto-instrumentation by adding the annotation at the namespace level. This approach automatically applies instrumentation to all Pods within the specified namespace.

apiVersion: v1
kind: Namespace
metadata:
  name: mynamespace
  annotations:
    instrumentation.opentelemetry.io/inject-<LANGUAGE>: "opentelemetry-operator-system/elastic-instrumentation"

After adding annotations to Pods or Namespaces, the applications must be restarted for the instrumentation injection to take effect:

kubectl rollout restart deployment/my-deployment

In case you have multiple Instrumentation objects with different settings or images, ensure you point your Pods to the the desired Instrumentation objects in the annotations.

The possible values for the annotation are detailed in the Operator documentation. For reference purposes, the values are:

Namespace based annotations example

The following example creates a namespace with an annotation to instrument all Pods of the namespace with java libraries.

kubectl create namespace java-apps

#Annotate app namespace
kubectl annotate namespace java-apps instrumentation.opentelemetry.io/inject-java="opentelemetry-operator-system/elastic-instrumentation"

# Run a java example application in the namespace
kubectl run otel-test -n java-apps --env OTEL_INSTRUMENTATION_METHODS_INCLUDE="test.Testing[methodB]" --image docker.elastic.co/demos/apm/k8s-webhook-test

Advanced configuration

You can apply OTEL specific configuration to your applications at two different levels:

Use cases:

Adding extra Instrumentation objects

Consider also the creation of different Instrumentation objects for different purposes, such as:

(TBD: add instructions and references about Instrumentation objects)

Manual instrumentation

(TBD, in-progress)

The manual instrumentation… Configuration requirements (does every language has its own requirements)? Exporter destination? HTTP vs OTLP? does each EDOT SDK support different protocols?