The OpenTelemetry injector is a shared library (written in Zig) that is intended to be
used via the environment variable LD_PRELOAD, the
/etc/ld.so.preload file, or similar mechanisms to inject
environment variables into processes at startup.
It serves two main purposes:
- Inject an OpenTelemetry auto-instrumentation agent into the process to capture and report distributed traces and metrics to the OpenTelemetry Collector for supported runtimes.
- Set resource attributes automatically (for example Kubernetes related resource attributes and service related resource attributes in environments where this is applicable).
The injector can be used to enable automatic zero-touch instrumentation of processes. For this to work, the injector binary needs to be bundled together with the OpenTelemetry auto-instrumentation agents for the target runtimes.
Official RPM and DEB packages that contain the injector as well as the auto-instrumentation agents are available, and
can be downloaded from the releases page.
The OpenTelemetry injector Debian/RPM packages install the OpenTelemetry auto-instrumentation agents, the
libotelinject.so shared object library, and a default configuration file to automatically instrument applications and
services to capture and report distributed traces and metrics to the
OpenTelemetry Collector.
The opentelemetry-injector deb/rpm package installs and supports configuration of the following auto-instrumentation
agents:
This method requires root privileges.
-
Add the path of the provided
/usr/lib/opentelemetry/libotelinject.soshared object library to the/etc/ld.so.preloadfile to activate auto- instrumentation for all supported processes on the system. For example:echo /usr/lib/opentelemetry/libotelinject.so >> /etc/ld.so.preloadAlternatively, set the environment variable
LD_PRELOAD=/usr/lib/opentelemetry/libotelinject.sofor a specific process to activate auto-instrumentation for that process. For example:LD_PRELOAD=/usr/lib/opentelemetry/libotelinject.so node myapp.js -
The default configuration file
/etc/opentelemetry/otelinject.confincludes the required settings, i.e. the paths to the respective auto-instrumentation agents per runtime:dotnet_auto_instrumentation_agent_path_prefix=/usr/lib/opentelemetry/dotnet jvm_auto_instrumentation_agent_path=/usr/lib/opentelemetry/javaagent.jar nodejs_auto_instrumentation_agent_path=/usr/lib/opentelemetry/otel-js/node_modules/@opentelemetry-js/otel/instrumentYou may want to modify this file for a couple of reasons:
-
You want to provide your own instrumentation files.
-
You want to selectively disable auto-instrumentation for a specific runtime, by setting the respective path to an empty string in the configuration file
/etc/opentelemetry/otelinject.conf. For example, the following file would leave JVM and Node.js auto-instrumentation active, while disabling .NET auto-instrumentation:dotnet_auto_instrumentation_agent_path_prefix= jvm_auto_instrumentation_agent_path=/usr/lib/opentelemetry/javaagent.jar nodejs_auto_instrumentation_agent_path=/usr/lib/opentelemetry/otel-js/node_modules/@opentelemetry-js/otel/instrument -
You want to selectively enable (or disable) auto-instrumentation for a subset of programs (services) on your system. For example, you may want to only enable instrumentation of services that match a specific executable path pattern, or to programs that do not contain certain arguments on the command line. See details on configuring the program inclusion and exclusion criteria for more information.
The values set in
/etc/opentelemetry/otelinject.confcan be overridden with environment variables. (This should usually not be necessary.)DOTNET_AUTO_INSTRUMENTATION_AGENT_PATH_PREFIX: the path to the directory containing the .NET auto-instrumentation agent filesJVM_AUTO_INSTRUMENTATION_AGENT_PATH: the path to the Java auto-instrumentation agent JAR fileNODEJS_AUTO_INSTRUMENTATION_AGENT_PATH: the path to the Node.js auto-instrumentation agent registration fileOTEL_INJECTOR_INCLUDE_PATHS: a comma-separated list of glob patterns to match executable pathsOTEL_INJECTOR_EXCLUDE_PATHS: a comma-separated list of glob patterns to exclude executable pathsOTEL_INJECTOR_INCLUDE_WITH_ARGUMENTS: a comma-separated list of glob patterns to match process argumentsOTEL_INJECTOR_EXCLUDE_WITH_ARGUMENTS: a comma-separated list of glob patterns to exclude process arguments
These aforementioned environment variables can also be used to selectively disable auto-instrumentation for a specific runtime, by setting the respective variable to an empty string, that is, set:
DOTNET_AUTO_INSTRUMENTATION_AGENT_PATH_PREFIX=""to disable .NET auto-instrumentationJVM_AUTO_INSTRUMENTATION_AGENT_PATH=""to disable JVM auto-instrumentationNODEJS_AUTO_INSTRUMENTATION_AGENT_PATH=""to disable Node.js auto-instrumentation
-
-
(Optional) The default env agent configuration file
/etc/opentelemetry/default_auto_instrumentation_env.confis empty (useall_auto_instrumentation_agents_env_pathoption to specify other path). Environment variables added to this file will be passed to all agents' environments. NOTE: environment variables which do not start withOTEL_are ignored.The
auto_instrumentation_env.conffile format is the same as other configurations:OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4317 OTEL_PROPAGATORS=tracecontext,baggage -
Reboot the system or restart the applications/services for any changes to take effect. The
libotelinject.soshared object library will then be preloaded for all subsequent processes and inject the environment variables from the/etc/opentelemetry/otelinjectconfiguration files for Java and Node.js processes.
When providing your own instrumentation files (for example via environment variables like DOTNET_AUTO_INSTRUMENTATION_AGENT_PATH_PREFIX) the following directory structure is expected:
JVM_AUTO_INSTRUMENTATION_AGENT_PATH: This path must point to the Java auto-instrumentation agent JAR fileopentelemetry-javaagent.jar.NODEJS_AUTO_INSTRUMENTATION_AGENT_PATH: The path to an installation of the npm module@opentelemetry/auto-instrumentations-node.DOTNET_AUTO_INSTRUMENTATION_AGENT_PATH_PREFIX: this path must be a directory that contains the following subdirectories and files:- For
x86_64systems usingglibc:glibc/linux-x64/OpenTelemetry.AutoInstrumentation.Native.soglibc/AdditionalDepsglibc/storeglibc/net/OpenTelemetry.AutoInstrumentation.StartupHook.dll
- For
x86_64systems usingmusl:musl/linux-musl-x64/OpenTelemetry.AutoInstrumentation.Native.somusl/AdditionalDepsmusl/storemusl/net/OpenTelemetry.AutoInstrumentation.StartupHook.dll
- For
arm64systems usingglibc:glibc/linux-arm64/OpenTelemetry.AutoInstrumentation.Native.soglibc/AdditionalDepsglibc/storeglibc/net/OpenTelemetry.AutoInstrumentation.StartupHook.dll
- For
armsystems usingmusl:musl/linux-musl-arm64/OpenTelemetry.AutoInstrumentation.Native.somusl/AdditionalDepsmusl/storemusl/net/OpenTelemetry.AutoInstrumentation.StartupHook.dll
- For
Note that the defaults provided by the RPM and Debian packages take care of all of that, and it is not necessary to
edit /etc/opentelemetry/otelinject.conf or set any of the above environment variables.
Check the following for details about the auto-instrumtation agents and further configuration options:
Here is an overview of the modifications that the injector will apply:
- It sets (or appends to)
NODE_OPTIONSto activate the Node.js instrumentation agent. - It adds a
-javaagentflag toJAVA_TOOL_OPTIONSto activate the Java OTel SDK. - It sets the required environment variables for activating the OpenTelemetry SDK for .NET:
CORECLR_ENABLE_PROFILINGCORECLR_PROFILERCORECLR_PROFILER_PATHDOTNET_ADDITIONAL_DEPSDOTNET_SHARED_STOREDOTNET_STARTUP_HOOKSOTEL_DOTNET_AUTO_HOME- Note that the injector will not append to existing environment variables but overwrite them unconditionally if they are already set. In contrast to other runtimes, .NET does not support adding multiple agents.
- It inspects specific existing environment variables and populates
OTEL_RESOURCE_ATTRIBUTESwith additional resource attributes. These environment variables need to be set externally (for example by a Kubernetes operator with a mutating webhook on the pod spec template of the workload). IfOTEL_RESOURCE_ATTRIBUTESis already set, the additional key-value pairs are appended to the existing value ofOTEL_RESOURCE_ATTRIBUTES. Existing key-value pairs are not overwritten, that is if e.g.OTEL_RESOURCE_ATTRIBUTESalready has a key-value pair fork8s.pod.name, the existing key-value pair takes priority. The following environment variables and resource attributes are supported:OTEL_INJECTOR_RESOURCE_ATTRIBUTESis expected to contain key-value pairs (e.g.my.resource.attribute=value,my.other.resource.attribute=another-value) and will be added as-is.OTEL_INJECTOR_SERVICE_NAMEwill be translated toservice.nameOTEL_INJECTOR_SERVICE_VERSIONwill be translated toservice.versionOTEL_INJECTOR_SERVICE_NAMESPACEwill be translated toservice.namespaceOTEL_INJECTOR_K8S_NAMESPACE_NAMEwill be translated tok8s.namespace.nameOTEL_INJECTOR_K8S_POD_NAMEwill be translated tok8s.pod.nameOTEL_INJECTOR_K8S_POD_UIDwill be translated tok8s.pod.uidOTEL_INJECTOR_K8S_CONTAINER_NAMEwill be translated tok8s.container.name
While you can set all resource attributes with OTEL_INJECTOR_RESOURCE_ATTRIBUTES, the additional environment
variables controlling individual resource attributes (like OTEL_INJECTOR_SERVICE_NAME or
OTEL_INJECTOR_K8S_NAMESPACE_NAME) are useful in Kubernetes for deriving resource attributes via
field selectors,
e.g. by adding a snippet like this to the pod spec template:
- name: OTEL_INJECTOR_SERVICE_NAME
valueFrom:
fieldRef:
fieldPath: metadata.labels['app.kubernetes.io/name']
The following provides an overview of the intended mappings:
| Environment Variable | Intended Mapping |
|---|---|
OTEL_INJECTOR_K8S_NAMESPACE_NAME |
valueFrom.fieldRef.fieldPath: metadata.namespace |
OTEL_INJECTOR_K8S_POD_NAME |
valueFrom.fieldRef.fieldPath: metadata.name |
OTEL_INJECTOR_K8S_POD_UID |
valueFrom.fieldRef.fieldPath: metadata.uid |
OTEL_INJECTOR_K8S_CONTAINER_NAME |
The container's name (no field selector) |
OTEL_INJECTOR_SERVICE_NAME |
valueFrom.fieldRef.fieldPath: metadata.labels['app.kubernetes.io/name'] |
OTEL_INJECTOR_SERVICE_VERSION |
valueFrom.fieldRef.fieldPath: metadata.labels['app.kubernetes.io/version'] |
OTEL_INJECTOR_SERVICE_NAMESPACE |
valueFrom.fieldRef.fieldPath: metadata.labels['app.kubernetes.io/part-of'] |
The environment variable OTEL_INJECTOR_RESOURCE_ATTRIBUTES can be set to key-value pairs derived from the
annotations resource.opentelemetry.io/*, to support mapping annotations like
resource.opentelemetry.io/service.namespace, resource.opentelemetry.io/service.name to their respective resource
attributes.
See also:
- https://opentelemetry.io/docs/specs/semconv/resource/k8s/
- https://opentelemetry.io/docs/specs/semconv/non-normative/k8s-attributes/
- https://kubernetes.io/docs/tasks/inject-data-application/environment-variable-expose-pod-information/#use-pod-fields-as-values-for-environment-variables
By default, the injector only logs errors.
Set the environment variable OTEL_INJECTOR_LOG_LEVEL to change the log level.
Valid values are:
debuginfowarnerror- this is the default valuenone- suppress all log output from the injector; this is useful for scenarios where you pipestderrinto another process and parse it.
The injector's log message will be written to stderr of the process that is being instrumented.
If you want to selectively enable (or disable) auto-instrumentation for a subset of programs (services) on your system, the configuration file provides a couple of settings which can be used alone or in combination to produce the desired outcome:
include_paths- A comma-separated list of glob patterns to match executable paths. If you do not specify anything here, the injector defaults to instrumenting all executables.exclude_paths- A comma-separated list of glob patterns to exclude executable paths.include_with_arguments- A comma-separated list of glob patterns to match process arguments. If you do not specify anything here, the injector defaults to instrumenting all executables.exclude_with_arguments- A comma-separated list of glob patterns to exclude process arguments.
If an executable matches both an inclusion and an exclusion criterion, the exclusion takes
precedence. For example, in the following configuration, all program executables in the
/app/system/ directory will not be instrumented, even though the /app directory is
included for instrumentation:
dotnet_auto_instrumentation_agent_path_prefix=/usr/lib/opentelemetry/dotnet
jvm_auto_instrumentation_agent_path=/usr/lib/opentelemetry/javaagent.jar
nodejs_auto_instrumentation_agent_path=/usr/lib/opentelemetry/otel-js/node_modules/@opentelemetry-js/otel/instrument
include_paths=/app/*,/utilities/*
exclude_paths=/app/system/*
To give you an idea of what types of inclusion and exclusion criteria can be defined, let's look at the following example:
dotnet_auto_instrumentation_agent_path_prefix=/usr/lib/opentelemetry/dotnet
jvm_auto_instrumentation_agent_path=/usr/lib/opentelemetry/javaagent.jar
nodejs_auto_instrumentation_agent_path=/usr/lib/opentelemetry/otel-js/node_modules/@opentelemetry-js/otel/instrument
include_paths=/app/*,/utilities/*,*.exe
exclude_with_arguments=-javaagent:*,*@opentelemetry-js*,-Xmx?m
include_with_arguments=*MyProject*.jar,*app.js
In the example above we'll instrument:
- any programs that run from the
/appand/utilitiesdirectories - any programs that have an
.exeextension - any programs that have a command line argument containing
MyProjectin the name and ending with the extension.jar - any programs that have a program argument ending in
app.js - however, for all included programs, the injector will avoid:
- all programs that have a command line argument starting with
-javaagent: - all programs that have a command line argument that contains
@opentelemetry-js - all
javaprograms that run with a single digit megabytes of maximum memory
- all programs that have a command line argument starting with
The example above illustrates how we avoid telemetry from unwanted applications or
injecting auto-instrumentation to programs that are already instrumented. If you have a
standard way of deploying all of your applications, you can create a default otelinject.conf
file that will ensure you get only the telemetry you want.
The include_paths, exclude_paths, include_with_arguments and exclude_with_arguments settings in
the configuration file are additive. This means that if you define multiple lines of these settings, the resulting
patterns list will be a union of all of the settings. This allows for easier manipulation of the configuration
file with automated tools. Essentially, you can list each include or exclude rule on a separate line.
For example, the following two configuration files have an identical outcome:
include_paths=/app/*,/utilities/*,*.exe
is the same as:
include_paths=/app/*
include_paths=/utilities/*
include_paths=*.exe
This is a short summary of how the injector works internally:
- Find out which libc the process binds, if any. This is usually either glibc or musl. (Some OpenTelemetry SDKs need to be injected differently, e.g. using different binaries depending on the libc flavor.)
- If the process does not bind a libc, or it cannot be identified, the injector aborts injection and hands back control to the host process.
- Find the location of the
dlsymfunction in the loaded libc (in memory), reading ELF metadata. - Use the libc's
dlsymhandle to look up more symbols in memory, in particular__environandsetenv. - Again, if looking up any of the symbols fails, the injector aborts injection and hands back control to the host process.
- Use the pointer to the
__environsymbol to read the current environment of the process (before adding or modifying any environment variables). - Use the pointer to the
setenvsymbol to add or modify environment variables to add and activate OpenTelemetry SDKs/auto-instrumentation agents for supported runtimes (e.g.NODE_OPTIONS,JAVA_TOOL_OPTIONS,CORECLR_PROFILER). - Use the pointer to the
setenvsymbol to add or modifyOTEL_RESOURCE_ATTRIBUTES.
There is a much more detailed explanation of this approach, and on alternative approaches and the intricate design constraints in DESIGN.md.
See CONTRIBUTING.md.
For more information about the maintainer role, see the community repository.
The code project was initially donated by Splunk and later replaced with another code donation by Dash0.