Skip to main content

OpenTelemetry Injector

Use the OpenTelemetry Injector to collect telemetry from applications that run directly on a Linux host, without changing application code, build pipelines, or start commands. It automatically loads the matching OpenTelemetry agent when an application starts. Depending on the language agent and its configuration, telemetry can include traces, metrics, and logs.

This page covers hosts managed with system packages: virtual machines, bare metal, and cloud instances. For Kubernetes workloads, use OpenTelemetry AutoInstrumentation for Kubernetes instead.

Note

The OpenTelemetry Injector and its system packages are maintained by the OpenTelemetry community. Test them in a staging environment before rolling them out to production hosts.

How it works​

Linux's dynamic loader loads shared libraries when a program starts. Preloading tells it to load an additional library before application code runs: LD_PRELOAD sets this for selected processes, while /etc/ld.so.preload applies it system-wide. The injector uses this mechanism to load libotelinject.so and set the environment variables that activate the language agents. See the Linux dynamic loader documentation.

You start your application as usual. The injector does not choose or launch a language runtime; it sets environment variables that tell the runtime to load its installed, enabled agent. For example, when you run java -jar myapp.jar, the injector adds -javaagent to JAVA_TOOL_OPTIONS. The JVM reads that option and loads the Java agent before your application's main() runs. Node.js, Python, and .NET use their own startup settings, listed under Supported runtimes.

For .NET, the injector also checks the application's target framework and existing OpenTelemetry dependencies before setting the agent's startup variables. See .NET application is skipped for the checks and configuration file locations.

  1. Install the injector and the agents for your application's languages on the host.
  2. Restart your applications. Each runtime loads its agent using the settings provided by the injector.
  3. The agents send telemetry to the Coralogix OpenTelemetry Collector on the same host. The collector forwards it to your Coralogix account, alongside the host data enabled in your integration.

Set a name, version, and custom attributes for each service to identify its telemetry in Coralogix. See Per-service settings.

Supported runtimes​

RuntimePackageVariable set by the injectorNotes
Javaopentelemetry-java-autoinstrumentationJAVA_TOOL_OPTIONSAppends -javaagent for the OpenTelemetry Java agent
Node.jsopentelemetry-nodejs-autoinstrumentationNODE_OPTIONSAppends --require for @opentelemetry/auto-instrumentations-node
.NETopentelemetry-dotnet-autoinstrumentationCORECLR_*, DOTNET_*, OTEL_DOTNET_AUTO_HOME.NET 8 and later. Skipped when the application already ships OpenTelemetry packages
Pythonopentelemetry-python-autoinstrumentationPYTHONPATHPython 3.10 and later. See Python dependency conflicts

The injector supports amd64 and arm64 hosts with glibc or musl. These are implementations of the C standard library (libc), which provides common functions such as memory allocation and file access. The injector detects which implementation the process uses. The system packages in this guide target glibc-based Debian and RHEL families.

What you need​

  • A Linux host running Debian, Ubuntu, RHEL, Fedora, Amazon Linux, or a derivative, with root access
  • The Coralogix OpenTelemetry Collector installed on the host with the OTLP receiver enabled. Follow Standalone complete observability: basic configuration first. The installer listens on 127.0.0.1:4317 (gRPC) and 127.0.0.1:4318 (HTTP) by default
  • Applications that use one of the supported runtimes: Java, Node.js, .NET, or Python

Install the injector​

:::warning Security considerations The preload library runs inside each affected process with that process's privileges, including root privileges for processes running as root. A faulty or compromised library can affect application behavior or startup across the host. Install packages only from a source you trust, and restrict write access to /etc/ld.so.preload, the injector configuration, and installed injector and agent files to administrators.

The repository commands below bypass repository authentication with trusted=yes and RPM package signature checks with gpgcheck=0. Review this trust requirement against your organization's software supply-chain policy before deployment. Per-service opt-out settings control instrumentation; they do not prevent the loader from loading the preload library. :::

1. Add the OpenTelemetry package repository​

On Debian and Ubuntu:

echo "deb [trusted=yes] https://open-telemetry.github.io/opentelemetry-packaging/debian stable main" \
| sudo tee /etc/apt/sources.list.d/opentelemetry.list
sudo apt update

On RHEL, Fedora, Amazon Linux, and derivatives:

cat <<EOT | sudo tee /etc/yum.repos.d/opentelemetry.repo
[opentelemetry]
name=OpenTelemetry Auto-Instrumentation System Packages
baseurl=https://open-telemetry.github.io/opentelemetry-packaging/rpm/packages
enabled=1
gpgcheck=0
EOT

2. Install the packages​

Install the opentelemetry metapackage to get the injector and all language agents:

sudo apt install opentelemetry # Debian, Ubuntu
sudo dnf install opentelemetry # RHEL, Fedora, Amazon Linux

To limit the install to the runtimes you use, install opentelemetry-injector plus the language packages you need. For example, for Java only:

sudo apt install opentelemetry-injector opentelemetry-java-autoinstrumentation

The package post-install step writes the library path to /etc/ld.so.preload. Confirm it:

cat /etc/ld.so.preload
# /usr/lib/opentelemetry/injector/libotelinject.so

3. Use the local collector​

Complete the Host OpenTelemetry integration setup first, including your Send-Your-Data API key, application name, and subsystem name. Deploy the generated collector configuration on the same host as your applications. Its default OTLP receiver accepts logs, metrics, and traces.

With the default agent settings, no exporter configuration is needed. Agents send telemetry to localhost on port 4317 (gRPC) or 4318 (HTTP), and the Host integration accepts both. If your applications already override OTLP settings, remove those overrides to use the defaults.

If you need to customize the endpoint or protocol, set the values in /etc/opentelemetry/injector/default_env.conf. For example, the following optional configuration explicitly selects the local HTTP receiver:

OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf

This file provides shared OTEL_ settings for all instrumented applications. The example is not required for the default Host integration. When customizing it, match the endpoint and protocol to your collector's receiver configuration, then restart the affected applications.

The collector handles authentication and forwarding to your Coralogix account. Keep the Coralogix API key in the integration's collector setup; agents do not need Coralogix authentication headers for this local endpoint.

Set OTEL_SERVICE_NAME separately for each application, for example checkout, as shown in Per-service settings. This makes each service identifiable in Coralogix. Use the agent configuration guides to enable or customize the signals supported by your language agent.

4. Restart the applications​

The injector only affects processes started after it was installed. Restart each service you want to instrument:

sudo systemctl restart <service-name>

New processes started from a shell are instrumented automatically.

Verify the instrumentation​

  1. Confirm that the injector modified the environment of a running service. For a Java service, the JVM prints the agent flag on startup:

    journalctl -u <service-name> | grep JAVA_TOOL_OPTIONS
    # Picked up JAVA_TOOL_OPTIONS: -javaagent:/usr/lib/opentelemetry/java/opentelemetry-javaagent.jar

    For any runtime, start a short-lived process and read its environment. The injector sets the variables with setenv after the process starts, so /proc/<pid>/environ does not show them.

    node -e 'console.log(process.env.NODE_OPTIONS)'
    # --require /usr/lib/opentelemetry/nodejs/register.js
  2. Generate traffic to the application.

  3. In Coralogix, open Explore and select the spans dataset. Set the time range to include your test traffic and filter by your service name. Confirm that spans from your application appear. See Get started with Explore spans.

Per-service settings​

The injector reads a set of OTEL_INJECTOR_* variables from the environment of each process. Set them where the service is defined, for example with Environment= in a systemd unit. They are not read from default_env.conf.

VariableEffect
OTEL_INJECTOR_SERVICE_NAMEAdds service.name to OTEL_RESOURCE_ATTRIBUTES. Setting OTEL_SERVICE_NAME directly works too
OTEL_INJECTOR_SERVICE_VERSIONAdds service.version
OTEL_INJECTOR_SERVICE_NAMESPACEAdds service.namespace, which the Coralogix Collector uses as the application name
OTEL_INJECTOR_RESOURCE_ATTRIBUTESComma-separated key=value pairs added as they are, for example deployment.environment.name=production
OTEL_INJECTOR_DISABLED=trueTurns the injector off for this process. No environment variable is changed
OTEL_INJECTOR_AUTO_INSTRUMENTATION_DISABLED* to skip all agents, or a comma-separated list of dotnet, jvm, nodejs, python. Resource attributes are still added

Example systemd unit for a Node.js service:

[Service]
ExecStart=/usr/bin/node /opt/checkout/server.js
Environment=OTEL_SERVICE_NAME=checkout
Environment=OTEL_INJECTOR_SERVICE_VERSION=2.4.1
Environment=OTEL_INJECTOR_RESOURCE_ATTRIBUTES=deployment.environment.name=production

To instrument only some programs on a host, set include or exclude patterns in /etc/opentelemetry/injector/injector.conf or as environment variables. Patterns are globs matched against the executable path or the command-line arguments:

SettingEnvironment variable
include_pathsOTEL_INJECTOR_INCLUDE_PATHS
exclude_pathsOTEL_INJECTOR_EXCLUDE_PATHS
include_with_argumentsOTEL_INJECTOR_INCLUDE_WITH_ARGUMENTS
exclude_with_argumentsOTEL_INJECTOR_EXCLUDE_WITH_ARGUMENTS

To disable a runtime for the whole host, add auto_instrumentation_disabled=<runtime> to injector.conf.

Troubleshooting​

No traces from a service​

  • Check that the service was restarted after the packages were installed.
  • Run the process once with OTEL_INJECTOR_LOG_LEVEL=debug to see what the injector decided. Keep the default level (error) on the host; at info or debug every process on the host logs to standard error.
  • Check the collector health status with curl -s http://127.0.0.1:13133.
  • Confirm that the application uses one of the supported runtimes and meets its version requirements.

Python dependency conflicts​

The Python agent ships its own pinned dependencies and refuses to activate when the interpreter already has a different version of one of them, to avoid breaking the application. The process then logs:

[opentelemetry-python-autoinstrumentation] WARN: cannot auto-instrument Python process: dependency conflicts: {...}

This happens on distribution interpreters that carry system packages such as python3-attr or python3-yaml. Run the application from its own virtual environment created with python3 -m venv, which excludes system site packages.

.NET application is skipped​

Before setting the .NET profiler and startup-hook environment variables, the injector checks two files beside the application:

  • <app-name>.runtimeconfig.json: Reads the target framework from runtimeOptions.tfm and skips injection when it identifies a version older than .NET 8 by default.
  • <app-name>.deps.json: Checks for OpenTelemetry* dependencies and skips injection when they are present, to reduce the risk of double instrumentation.

The .NET SDK generates these files from the project's framework settings and dependencies during the application build. For a standard deployment, dotnet publish includes them in the publish output alongside the application DLL. For example, Checkout.dll, Checkout.runtimeconfig.json, and Checkout.deps.json are deployed together in the application's directory. These are application files, not injector configuration files; you do not need to create them for the injector.

These checks are best-effort: missing, unreadable, or malformed files do not by themselves prevent injection. If neither check causes the injector to skip the application, it sets the startup variables and the .NET runtime loads the agent. See the upstream injector design.

Set DOTNET_AUTO_INSTRUMENTATION_MINIMUM_DOTNET_MAJOR_VERSION only if you ship a .NET auto-instrumentation build that supports older runtimes.

Limitations​

  • Linux only.
  • The system packages are built for Debian and RHEL families on amd64 and arm64. Alpine and other musl-based distributions are not packaged.
  • .NET does not support more than one agent. The injector overwrites the .NET profiler variables if they are already set.
Last updated on