<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title><![CDATA[Jack Shirazi - Elastic Observability Labs]]></title>
    <description><![CDATA[Trusted security news & research from the team at Elastic.]]></description>
    <copyright><![CDATA[© 2026. Elasticsearch B.V. All Rights Reserved]]></copyright>
    <image>
      <title><![CDATA[Jack Shirazi - Elastic Observability Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltad972c1c27dbefc6/6a88d9782904ea5e8511d473/observability-labs-thumbnail.png</url>
      <link>https://www.elastic.co/observability-labs/author/jack-shirazi</link>
    </image>
    <link>https://www.elastic.co/observability-labs/author/jack-shirazi</link>
    <atom:link href="https://www.elastic.co/observability-labs/rss/author/jack-shirazi.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[en]]></language>
    <lastBuildDate>Sat, 19 Sep 2026 15:07:12 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Telemetry Policy: change OpenTelemetry sampling and log levels at runtime, no restart]]></title>
    <description><![CDATA[Telemetry Policy says what you want to happen and leaves each component to work out how. Change an OpenTelemetry Java agent's trace sampling to 1% and the JVM keeps serving traffic.]]></description>
    <content:encoded><![CDATA[<p>Change the trace sampling rate of a running Java application from 5% to 1% without restarting the JVM. Telemetry Policy states what you want to happen and leaves each SDK, agent or collector to work out how, so a platform team defines it once and applies it everywhere. The screenshots below show a sampling rate of 0.1 set in the Elastic APM UI, and the Java agent logging that it received and applied the value. The rest of this post covers what a policy is and where the limits are. In the next one I'll walk through the first experimental implementation in the OpenTelemetry Java contrib repo.</p>
<h2 id="howtochangeopentelemetryjavaagentsamplingatruntime">How to change OpenTelemetry Java agent sampling at runtime</h2>
<p>Until now, with some proprietary exceptions, configuring that telemetry had to be done at startup of the telemetry-generating component (e.g., SDK, agent, or OpenTelemetry Collector).
Telemetry Policy is the emerging standard that will allow you to reconfigure some telemetry configurations without needing to restart the telemetry-generating component.</p>
<p>For example, let's say you want to:</p>
<ul>
<li>Change the trace sampling percentage to 1% during some special peak periods (eg special sales days), but keep it at 5% at all other times.</li>
<li>Change the log level (e.g., to debug level or back to info) temporarily.</li>
<li>Stop some instrumentations that are active.</li>
</ul>
<p>These are all straightforward requirements.
But applying any of them until now has meant changing the configuration of the component and restarting it.
For a Java application (and applications in most languages) that previously meant also restarting the application, as there was no way to change the agent configuration without restarting the JVM.</p>
<h3 id="whycentralmanagementneedsonepolicyformat">Why central management needs one policy format</h3>
<p>Central management adds another challenge.
A controlling system that requests a change such as "increase log level to debug" must know how to apply that change to every component it controls.
The configuration change for a collector will not look like the change for a Java SDK, even though both are applying the same decision.</p>
<p>Telemetry Policy addresses both problems by separating:</p>
<ol>
<li>what we want to happen</li>
<li>from how a particular SDK, agent, or collector makes it happen.</li>
</ol>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc16be960dd5485b9/6aabc0ab8e00eb71345ca476/setting-sample-rate.png" alt="Using the Elastic APM UI to set the Java agent sampling rate 0.1 (10%)" />
<em>Using the Elastic APM UI to set the Java agent sampling rate 0.1 (10%)</em></p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt503d7e688cc22630/6aabc101d1556f22f4728308/logged-sample-rate.png" alt="lastic APM Java agent log statements confirming that the sampling rate value of 0.1 was received and applie" />
<em>Elastic APM Java agent log statements confirming that the sampling rate value of 0.1 was received and applied</em></p>
<h2 id="whatisatelemetrypolicyinopentelemetry">What is a Telemetry Policy in OpenTelemetry?</h2>
<p>A Telemetry Policy is an independent rule describing the behaviour a user wants.</p>
<p>For example:</p>
<pre><code>Sample traces at 5%
</code></pre>
<p>A policy that says to sample traces at 5% does not say which sampler to install, where to add a processor, or how the telemetry pipeline is laid out.
Those are implementation details specific to each component.
The policy only states the intended result.</p>
<p>The draft specification defines a policy as a typed, standalone object.
Each policy has an ID, a name, and one target signal such as traces, logs, or metrics.
The target determines the matching fields and actions that can be used.</p>
<p>Here is an example of that 5% sampling policy:</p>
<pre><code>{
  "id": "sample-spans-5-percent",
  "name": "Sample traces at 5%",
  "trace": {
    "match": [
      {
        "exists": true
      }
    ],
    "keep": {
      "percentage": 5.0
    }
  }
}
</code></pre>
<p>The policy says to match every trace and apply 5% sampling using the policy with ID <code>sample-spans-5-percent</code>.
Each telemetry component that understands that ID will be able to apply the policy.
Any telemetry component that doesn't understand the policy will simply ignore it.</p>
<h3 id="whichsettingscantelemetrypolicychangeatruntime">Which settings can Telemetry Policy change at runtime?</h3>
<p>Policies are not expected to cover every configuration, or even <em>many</em> configurations of each component.
Telemetry Policies are not a general-purpose "reconfigure anything" tool.
Policies are specific to the things that users would most like to change without restarting.
For application agents, our experience at Elastic suggests there are only a dozen or so important policy types that most customers need to be able to change at runtime without restarting the application, including:</p>
<ul>
<li>Changing the trace sampling percentage.</li>
<li>Turning individual instrumentations or all instrumentations off and on.</li>
<li>Turning individual signal exporters (traces, metrics, logs, profiles) off and on.</li>
<li>Changing logging level.</li>
<li>Changing the configuration of a select few instrumentations.</li>
<li>Such as changing which HTTP routes to ignore when creating traces (eg ignore <code>/heartbeat</code>).</li>
<li>Or changing which methods to instrument.</li>
</ul>
<h2 id="howatelemetrypolicyreachesansdkagentorcollector">How a Telemetry Policy reaches an SDK, agent or collector</h2>
<p>The overall telemetry policy pipeline has certain components, and at minimum covers the sequence:</p>
<pre><code>Message -&gt; Provider -&gt; Policy -&gt; Policy aggregator -&gt; Implementer
</code></pre>
<p>A concrete example of changing the trace sampling percentage directed by central management using the <a href="https://github.com/open-telemetry/opamp-spec">Open Agent Management Protocol (OpAMP)</a> helps to understand this flow:</p>
<p>| Stage | What it does | In the 5% sampling example |
| --- | --- | --- |
| Message | Carries the requested change into the component | An OpAMP message specifying a trace sampling percentage of 5%, like the JSON above |
| Provider | Reads policies from an input stream | The OpAMP provider reads the message from the OpAMP data flow |
| Policy | The internal representation of the change | A <code>trace-sampling-percentage-policy</code> with a target value of 5%, which is how the ID <code>sample-spans-5-percent</code> is implemented in the component* |
| Policy aggregator | Combines the policy with others already applied or pending, handling source priority and merges | A pass-through, because there is only one provider |
| Implementer | Applies the change to the running component | Installs a new sampler set to 5% |</p>
<p>Source priority decides which policy wins when two sources disagree. A message from an OpAMP source has higher priority than one from an HTTP source.</p>
<p>The implementer installs a new sampler unless the sampler already running can have its sampling percentage changed at runtime, in which case it updates that one.</p>
<p>*Note that the policy type may become a required part of the message in future.
There is currently no standard mapping from a policy ID to a policy type, so the type must either be included in the message or supplied through an external mapping.</p>
<h3 id="deliveringpoliciesoveropamphttporalocalfile">Delivering policies over OpAMP, HTTP or a local file</h3>
<p>Telemetry Policy does not define a new transport mechanism or protocol.
Policies can be delivered through existing transports:</p>
<ul>
<li>OpAMP.</li>
<li>HTTP.</li>
<li>Local files.</li>
<li>Custom sources.</li>
</ul>
<p>The same trace sampling policy could be read from a local file while testing, supplied over HTTP, or sent from a central management system using OpAMP.
OpAMP is not a requirement for Telemetry Policy; it is a supported provider and is likely to be a common transport for centrally managed systems.</p>
<h2 id="telemetrypolicystatusinopentelemetry">Telemetry Policy status in OpenTelemetry</h2>
<p>Telemetry Policy is currently an accepted developing project. 
The schema, policy types, and implementation details are still being developed before they will become
accepted OpenTelemetry standards.</p>
<h3 id="thefirstexperimentaljavasdkimplementation">The first experimental Java SDK implementation</h3>
<p>The first experimental Java SDK implementation starts with dynamically changing the trace sampling probability.
This is deliberately narrow, providing a simple practical way to test the complete policy flow.</p>
<p>Telemetry Policy separates observability decisions from the internal configuration of the component applying them.
This allows a platform team to define a policy once and apply it consistently in SDKs, agents, and collectors.</p>
<p>In the next blog, I'll walk through the first experimental implementation in the OpenTelemetry Java contrib repo, 
including how it receives policies through OpAMP and changes trace sampling in a running Java application without requiring a restart.</p>]]></content:encoded>
    <link>https://www.elastic.co/observability-labs/blog/opentelemetry-java-agent-telemetry-policy</link>
    <guid isPermaLink="false">opentelemetry-java-agent-telemetry-policy</guid>
    <category><![CDATA[OpenTelemetry]]></category>
    <category><![CDATA[APM]]></category>
    <category><![CDATA[What's New]]></category>
    <dc:creator><![CDATA[Jack Shirazi]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt06ef200647ccab50/6aabbf6c5ef72dab76c95196/good_oone.png" length="0" type="image/png"/>
    <pubDate>Thu, 17 Sep 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Using a custom agent with the OpenTelemetry Operator for Kubernetes]]></title>
    <description><![CDATA[]]></description>
    <content:encoded><![CDATA[<p>This is the second part of a two part series. The first part is available at <a href="https://www.elastic.co/observability-labs/blog/using-the-otel-operator-for-injecting-java-agents">Zero config OpenTelemetry auto-instrumentation for Kubernetes Java applications</a>. In that first part I walk through setting up and installing the <a href="https://github.com/open-telemetry/opentelemetry-operator/">OpenTelemetry Operator for Kubernetes</a>, and configuring that for auto-instrumentation of a Java application using the <a href="https://github.com/open-telemetry/opentelemetry-java-instrumentation/">OpenTelemetry Java agent</a>. </p>
<p>In this second part, I show how to install <em>any</em> Java agent via the OpenTelemetry operator, using the Elastic Java agents as examples.</p>
<h2 id="installationandconfigurationrecap">Installation and configuration recap</h2>
<p>Part 1 of this series, <a href="https://www.elastic.co/observability-labs/blog/using-the-otel-operator-for-injecting-java-agents">Zero config OpenTelemetry auto-instrumentation for Kubernetes Java applications</a>, details the installation and configuration of the OpenTelemetry operator and an Instrumentation resource. Here is an outline of the steps as a reminder:</p>
<ol>
<li>Install cert-manager, eg <code>kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.4/cert-manager.yaml</code></li>
<li>Install the operator, eg <code>kubectl apply -f https://github.com/open-telemetry/opentelemetry-operator/releases/latest/download/opentelemetry-operator.yaml</code></li>
<li>Create an Instrumentation resource</li>
<li>Add an annotation to either the deployment or the namespace</li>
<li>Deploy the application as normal</li>
</ol>
<p>In that first part, steps 3, 4 &amp; 5 were implemented for the <a href="https://github.com/open-telemetry/opentelemetry-java-instrumentation/">OpenTelemetry Java agent</a>. In this blog I’ll implement them for other agents, using the Elastic APM agents as examples. I assume that steps 1 &amp; 2 outlined above have already been done, ie that the operator is now installed. I will continue using the <code>banana</code> namespace for the examples, so ensure that namespace exists (<code>kubectl create namespace banana</code>). As per part 1, if you use any of the example instrumentation definitions below, you’ll need to substitute <code>my.apm.server.url</code> and <code>my-apm-secret-token</code> with the values appropriate for your collector.</p>
<h2 id="usingtheelasticdistributionforopentelemetryjava">Using the Elastic Distribution for OpenTelemetry Java</h2>
<p>From version 0.4.0, the <a href="https://github.com/elastic/elastic-otel-java">Elastic Distribution for OpenTelemetry Java</a> includes the agent jar at the path <code>/javaagent.jar</code> in the docker image - which is essentially all that is needed for a docker image to be usable by the OpenTelemetry operator for auto-instrumentation. This means the Instrumentation resource is straightforward to define, and as it’s a distribution of the OpenTelemetry Java agent, all the OpenTelemetry environment can apply:</p>
<pre><code>apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
  name: elastic-otel
  namespace: banana
spec:
  exporter:
    endpoint: https://my.apm.server.url
  propagators:
    - tracecontext
    - baggage
    - b3
  sampler:
    type: parentbased_traceidratio
    argument: "1.0"
  java:
    image: docker.elastic.co/observability/elastic-otel-javaagent:1.10.0
    env:
      - name: OTEL_EXPORTER_OTLP_HEADERS
        value: "Authorization=Bearer my-apm-secret-token"
      - name: ELASTIC_OTEL_INFERRED_SPANS_ENABLED
        value: "true"
      - name: ELASTIC_OTEL_SPAN_STACK_TRACE_MIN_DURATION
        value: "50"
</code></pre>
<p>I’ve included environment for switching on several features in the agent, including</p>
<ol>
<li>ELASTIC_APM_PROFILING_INFERRED_SPANS_ENABLED to switch on the inferred spans implementation feature described in <a href="https://www.elastic.co/observability-labs/blog/tracing-data-inferred-spans-opentelemetry">this blog</a></li>
<li>Span stack traces are automatically captured if the span takes more than ELASTIC_OTEL_SPAN_STACK_TRACE_MIN_DURATION (default would be 5ms)</li>
</ol>
<p>Adding in the annotation …</p>
<pre><code>metadata:
  annotations:
    instrumentation.opentelemetry.io/inject-java: "elastic-otel"
</code></pre>
<p>… to the pod yaml gets the application traced, and displayed in the Elastic APM UI, including the inferred child spans and stack traces</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1cf450efadd3a797/6a7f1c0296b5a66b7787b8c1/elastic-apm-ui-with-stack-trace.png" alt="Elastic APM UI showing methodB traced with stack traces and inferred spans" /></p>
<p>The additions from the features mentioned above are circled in red - inferred spans (for methodC and methodD) bottom left, and the stack trace top right. (Note that the pod included the <code>OTEL_INSTRUMENTATION_METHODS_INCLUDE</code> environment variable set to <code>"test.Testing[methodB]"</code> so that traces from methodB are shown; for pod configuration see the "Trying it" section in <a href="https://www.elastic.co/observability-labs/blog/using-the-otel-operator-for-injecting-java-agents">part 1</a>)</p>
<h2 id="usingtheelasticapmjavaagent">Using the Elastic APM Java agent</h2>
<p>From version 1.50.0, the <a href="https://github.com/elastic/apm-agent-java">Elastic APM Java agent</a> includes the agent jar at the path /javaagent.jar in the docker image - which is essentially all that is needed for a docker image to be usable by the OpenTelemetry operator for auto-instrumentation. This means the Instrumentation resource is straightforward to define:</p>
<pre><code>apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
  name: elastic-apm
  namespace: banana
spec:
  java:
    image: docker.elastic.co/observability/apm-agent-java:1.55.4
    env:
      - name: ELASTIC_APM_SERVER_URL
        value: "https://my.apm.server.url"
      - name: ELASTIC_APM_SECRET_TOKEN
        value: "my-apm-secret-token"
      - name: ELASTIC_APM_LOG_LEVEL
        value: "INFO"
      - name: ELASTIC_APM_PROFILING_INFERRED_SPANS_ENABLED
        value: "true"
      - name: ELASTIC_APM_LOG_SENDING
        value: "true"
</code></pre>
<p>I’ve included environment for switching on several features in the agent, including</p>
<ul>
<li>ELASTIC_APM_LOG_LEVEL set to the default value (INFO) which could easily be switched to DEBUG</li>
<li>ELASTIC_APM_PROFILING_INFERRED_SPANS_ENABLED to switch on the inferred spans implementation equivalent to the feature described in <a href="https://www.elastic.co/observability-labs/blog/tracing-data-inferred-spans-opentelemetry">this blog</a></li>
<li>ELASTIC_APM_LOG_SENDING which switches on sending logs to the APM UI, the logs are automatically correlated with transactions (for all common logging frameworks)</li>
</ul>
<p>Adding in the annotation …</p>
<pre><code>metadata:
  annotations:
     instrumentation.opentelemetry.io/inject-java: "elastic-apm"
</code></pre>
<p>… to the pod yaml gets the application traced, and displayed in the Elastic APM UI, including the inferred child spans</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt425d331c27b53881/6a7f1c0596b5a6621887b8c5/elastic-apm-ui-with-inferred-spans.png" alt="Elastic APM UI showing methodB traced with inferred spans" /></p>
<p>(Note that the pod included the <code>ELASTIC_APM_TRACE_METHODS</code> environment variable set to <code>"test.Testing#methodB"</code> so that traces from methodB are shown; for pod configuration see the "Trying it" section in <a href="https://www.elastic.co/observability-labs/blog/using-the-otel-operator-for-injecting-java-agents">part 1</a>)</p>
<h2 id="usinganextensionwiththeopentelemetryjavaagent">Using an extension with the OpenTelemetry Java agent</h2>
<p>Setting up an Instrumentation resource for the OpenTelemetry Java agent is straightforward and was done in <a href="https://www.elastic.co/observability-labs/blog/using-the-otel-operator-for-injecting-java-agents">part 1</a> of this two part series - and you can see from the above examples it’s just a matter of deciding on the docker image URL you want to use. However if you want to include an <em>extension</em> in your deployment, this is a little more complex, but also supported by the operator. Basically the extensions you want to include with the agent need to be in docker images - or you have to build an image which includes the extensions that are not already in images. Then you declare the images and the directories the extensions are in, in the Instrumentation resource. As an example, I’ll show an Instrumentation which uses version 2.5.0 of the <a href="https://github.com/open-telemetry/opentelemetry-java-instrumentation/">OpenTelemetry Java agent</a> together with the <a href="https://github.com/elastic/elastic-otel-java/tree/main/inferred-spans">inferred spans extension</a> from the <a href="https://github.com/elastic/elastic-otel-java">Elastic OpenTelemetry Java distribution</a>. The distro image includes the extension at path <code>/extensions/elastic-otel-agentextension.jar</code>. The Instrumentation resource allows either directories or file paths to be specified, here I’ll list the directory:</p>
<pre><code>apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
  name: otel-plus-extension-instrumentation
  namespace: banana
spec:
  exporter:
    endpoint: https://my.apm.server.url
  propagators:
    - tracecontext
    - baggage
    - b3
  sampler:
    type: parentbased_traceidratio
    argument: "1.0"
  java:
    image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-java:2.5.0
    extensions:
      - image: "docker.elastic.co/observability/elastic-otel-javaagent:1.10.0"
        dir: "/extensions"
    env:
      - name: OTEL_EXPORTER_OTLP_HEADERS
        value: "Authorization=Bearer my-apm-secret-token"
      - name: ELASTIC_OTEL_INFERRED_SPANS_ENABLED
        value: "true"
</code></pre>
<p>Note that you can have multiple <code>image … dir</code> pairs, ie include multiple extensions from different images. Note also if you are testing this specific configuration that the inferred spans extension included here will be contributed to the OpenTelemetry contrib repo at some point after this blog is published, after which the extension may no longer be present in a later version of the referred image (since it will be available from the <a href="https://github.com/open-telemetry/opentelemetry-java-contrib/">contrib repo</a> instead).</p>
<h2 id="nextsteps">Next steps</h2>
<p>Here I’ve shown how to use any agent with the <a href="https://github.com/open-telemetry/opentelemetry-operator/">OpenTelemetry Operator for Kubernetes</a>, and configure that for your system. In particular the examples have showcased how to use the Elastic Java agents to auto-instrument Java applications running in your Kubernetes clusters, along with how to enable features, using Instrumentation resources. And you can set it up for either zero config for deployments, or for just one annotation which is generally a more flexible mechanism (you can have multiple Instrumentation resource definitions, and the deployment can select the appropriate one for its application).</p>
<p><em>The release and timing of any features or functionality described in this post remain at Elastic's sole discretion. Any features or functionality not currently available may not be delivered on time or at all.</em></p>]]></content:encoded>
    <link>https://www.elastic.co/observability-labs/blog/using-the-otel-operator-for-injecting-elastic-agents</link>
    <guid isPermaLink="false">using-the-otel-operator-for-injecting-elastic-agents</guid>
    <category><![CDATA[OpenTelemetry]]></category>
    <category><![CDATA[APM]]></category>
    <category><![CDATA[Kubernetes]]></category>
    <category><![CDATA[Infrastructure Monitoring]]></category>
    <dc:creator><![CDATA[Jack Shirazi]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt55dfb115f9341105/6a7f1c08ea068d4de1f0a2f9/blog-header-720x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Tue, 16 Jul 2024 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Zero config OpenTelemetry auto-instrumentation for Kubernetes Java applications]]></title>
    <description><![CDATA[Walking through how to install and enable the OpenTelemetry Operator for Kubernetes to auto-instrument Java applications, with no configuration changes needed for deployments]]></description>
    <content:encoded><![CDATA[<p>The <a href="https://github.com/open-telemetry/opentelemetry-java-instrumentation/">OpenTelemetry Java agent</a> has a number of <a href="https://opentelemetry.io/docs/languages/java/automatic/#setup">ways to install</a> the agent into a Java application. If you are running your Java applications in Kubernetes pods, there is a separate mechanism (which under the hood uses JAVA_TOOL_OPTIONS and other environment variables) to auto-instrument Java applications. This auto-instrumentation can be achieved with zero configuration of the applications and pods!</p>
<p>The mechanism to achieve zero-config auto-instrumentation of Java applications in Kubernetes is via the <a href="https://github.com/open-telemetry/opentelemetry-operator/">OpenTelemetry Operator for Kubernetes</a>. This operator has many capabilities and the full documentation (and of course source) is available in the project itself. In this blog, I'll walk through installing, setting up and running zero-config auto-instrumentation of Java applications in Kubernetes using the OpenTelemetry Operator.</p>
<h2 id="installingtheopentelemetryoperatoraidinstallingtheopentelemetryoperatora">Installing the OpenTelemetry Operator<a id="installing-the-opentelemetry-operator"></a></h2>
<p>At the time of writing this blog, the OpenTelemetry Operator needs the certification manager to be installed, after which the operator can be installed. Installing from the web is straightforward. First install the <code>cert-manager</code> (the version to be installed will be specified in the <a href="https://github.com/open-telemetry/opentelemetry-operator/">OpenTelemetry Operator for Kubernetes</a> documentation):</p>
<pre><code>kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.4/cert-manager.yaml
</code></pre>
<p>Then when the cert managers are ready (<code>kubectl get pods -n cert-manager</code>)  …</p>
<pre><code>NAMESPACE&amp;nbsp; &amp;nbsp; &amp;nbsp; NAME &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; READY
cert-manager &amp;nbsp; cert-manager-67c98b89c8-rnr5s&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 1/1
cert-manager &amp;nbsp; cert-manager-cainjector-5c5695d979-q9hxz &amp;nbsp; &amp;nbsp; 1/1
cert-manager &amp;nbsp; cert-manager-webhook-7f9f8648b9-8gxgs&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 1/1
</code></pre>
<p>… you can install the OpenTelemetry Operator:</p>
<pre><code>kubectl apply -f https://github.com/open-telemetry/opentelemetry-operator/releases/latest/download/opentelemetry-operator.yaml
</code></pre>
<p>You can, of course, use a specific version of the operator instead of the <code>latest</code>. But here I’ve used the <code>latest</code> version.</p>
<h2 id="aninstrumentationresourceaidaninstrumentationresourcea">An Instrumentation resource<a id="an-instrumentation-resource"></a></h2>
<p>Now you need to add just one further Kubernetes resource to enable auto-instrumentation: an <code>Instrumentation</code> resource. I am going to use the <code>banana</code> namespace for my examples, so I have first created that namespace (<code>kubectl create namespace banana</code>). The auto-instrumentation is specified and configured by these Instrumentation resources. Here is a basic one which will allow every Java pod in the <code>banana</code> namespace to be auto-instrumented with version 2.5.0 of the <a href="https://github.com/open-telemetry/opentelemetry-java-instrumentation/">OpenTelemetry Java agent</a>:</p>
<pre><code>apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
  name: banana-instr
  namespace: banana
spec:
  exporter:
    endpoint: "https://my.endpoint"
  propagators:
    - tracecontext
    - baggage
    - b3
  sampler:
    type: parentbased_traceidratio
    argument: "1.0"
  java:
    image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-java:2.5.0
    env:
      - name: OTEL_EXPORTER_OTLP_HEADERS
        value: "Authorization=Bearer MyAuth"
</code></pre>
<p>Creating this resource (eg with <code>kubectl apply -f banana-instr.yaml</code>, assuming the above yaml was saved in file <code>banana-instr.yaml</code>) makes the <code>banana-instr</code> Instrumentation resource available for use. (Note you will need to change <code>my.endpoint</code> and <code>MyAuth</code> to values appropriate for your collector.) You can use this instrumentation immediately by adding an annotation to any deployment in the <code>banana</code> namespace:</p>
<pre><code>metadata:
&amp;nbsp;&amp;nbsp;annotations:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;instrumentation.opentelemetry.io/inject-java: "true"
</code></pre>
<p>The <code>banana-instr</code> Instrumentation resource is not yet set to be applied by <em>default</em> to all pods in the banana namespace. Currently it's zero-config as far as the <em>application</em> is concerned, but it requires an annotation added to a <em>pod or deployment</em>. To make it fully zero-config for <em>all pods</em> in the <code>banana</code> namespace, we need to add that annotation to the namespace itself, ie editing the namespace (<code>kubectl edit namespace banana</code>) so it would then have contents similar to</p>
<pre><code>apiVersion: v1
kind: Namespace
metadata:
&amp;nbsp;&amp;nbsp;name: banana
&amp;nbsp;&amp;nbsp;annotations:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;instrumentation.opentelemetry.io/inject-java: "banana-instr"
...
</code></pre>
<p>Now we have a namespace that is going to auto-instrument <em>every</em> Java application deployed in the <code>banana</code> namespace with the 2.5.0 <a href="https://github.com/open-telemetry/opentelemetry-java-instrumentation/">OpenTelemetry Java agent</a>!</p>
<h2 id="tryingitaidtryingita">Trying it<a id="trying-it"></a></h2>
<p>There is a simple example Java application at <a href="http://docker.elastic.co/demos/apm/k8s-webhook-test">docker.elastic.co/demos/apm/k8s-webhook-test</a> which just repeatedly calls the chain <code>main-&gt;methodA-&gt;methodB-&gt;methodC-&gt;methodD</code> with some sleeps in the calls. Running this (<code>kubectl apply -f banana-app.yaml</code>) using a very basic pod definition:</p>
<pre><code>apiVersion: v1
kind: Pod
metadata:
  name: banana-app
  namespace: banana
  labels:
    app: banana-app
spec:
  containers:
    - image: docker.elastic.co/demos/apm/k8s-webhook-test
      imagePullPolicy: Always
      name: banana-app
      env: 
      - name: OTEL_INSTRUMENTATION_METHODS_INCLUDE
        value: "test.Testing[methodB]"
</code></pre>
<p>results in the app being auto-instrumented with no configuration changes! The resulting app shows up in any APM UI, such as Elastic APM</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5339364ee45875ef/6a7f1c0d3ce8e2a2e5cf57d0/elastic-apm-ui-transaction.png" alt="Elastic APM UI showing methodB traced" /></p>
<p>As you can see, for this example I also added this env var to the pod yaml, <code>OTEL_INSTRUMENTATION_METHODS_INCLUDE="test.Testing[methodB]"</code> so that there were traces showing from methodB.</p>
<h2 id="thetechnologybehindtheautoinstrumentationaidthetechnologybehindtheautoinstrumentationa">The technology behind the auto-instrumentation<a id="the-technology-behind-the-auto-instrumentation"></a></h2>
<p>To use the auto-instrumentation there is no specific need to understand the underlying mechanisms, but for those of you interested, here’s a quick outline. </p>
<ol>
<li>The <a href="https://github.com/open-telemetry/opentelemetry-operator/">OpenTelemetry Operator for Kubernetes</a> installs a <a href="https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/">mutating webhook</a>, a standard Kubernetes component.</li>
<li>When deploying, Kubernetes first sends all definitions to the mutating webhook.</li>
<li>If the mutating webhook sees that the conditions for auto-instrumentation should be applied (ie </li>
<li>there is an Instrumentation resource for that namespace and</li>
<li>the correct annotation for that Instrumentation is applied to the definition in some way, either from the definition itself or from the namespace),</li>
<li>then the mutating webhook “mutates” the definition to include the environment defined by the Instrumentation resource.</li>
<li>The environment includes the explicit values defined in the env, as well as some implicit OpenTelemetry values (see the <a href="https://github.com/open-telemetry/opentelemetry-operator/">OpenTelemetry Operator for Kubernetes</a> documentation for full details).</li>
<li>And most importantly, the operator</li>
<li>pulls the image defined in the Instrumentation resource,</li>
<li>extracts the file at the path <code>/javaagent.jar</code> from that image (using shell command <code>cp</code>)</li>
<li>inserts it into the pod at path <code>/otel-auto-instrumentation-java/javaagent.jar</code></li>
<li>and adds the environment variable <code>JAVA_TOOL_OPTIONS=-javaagent:/otel-auto-instrumentation-java/javaagent.jar</code>.</li>
<li>The JVM automatically picks up that JAVA_TOOL_OPTIONS environment variable on startup and applies it to the JVM command-line.</li>
</ol>
<h2 id="nextstepsaidnextstepsa">Next steps<a id="next-steps"></a></h2>
<p>This walkthrough can be repeated in any Kubernetes cluster to demonstrate and experiment with auto-instrumentation (you will need to create the banana namespace first). In part 2 of this two part series, <a href="https://www.elastic.co/observability-labs/blog/using-the-otel-operator-for-injecting-elastic-agents">Using a custom agent with the OpenTelemetry Operator for Kubernetes</a>, I show how to install any Java agent via the OpenTelemetry operator, using the Elastic Java agents as examples.</p>]]></content:encoded>
    <link>https://www.elastic.co/observability-labs/blog/using-the-otel-operator-for-injecting-java-agents</link>
    <guid isPermaLink="false">using-the-otel-operator-for-injecting-java-agents</guid>
    <category><![CDATA[OpenTelemetry]]></category>
    <category><![CDATA[APM]]></category>
    <category><![CDATA[Kubernetes]]></category>
    <category><![CDATA[Infrastructure Monitoring]]></category>
    <dc:creator><![CDATA[Jack Shirazi]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt53c963d5c03388fb/6a7f1c101967ea3597330ba4/blog-header.png" length="0" type="image/png"/>
    <pubDate>Thu, 11 Jul 2024 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[How to easily add application monitoring in Kubernetes pods]]></title>
    <description><![CDATA[This blog walks through installing the Elastic APM K8s Attacher and shows how to configure your system for both common and non-standard deployments of Elastic APM agents.]]></description>
    <content:encoded><![CDATA[<p>The <a href="https://www.elastic.co/guide/en/apm/attacher/current/index.html">Elastic® APM K8s Attacher</a> allows auto-installation of Elastic APM application agents (e.g., the Elastic APM Java agent) into applications running in your Kubernetes clusters. The mechanism uses a <a href="https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/">mutating webhook</a>, which is a standard Kubernetes component, but you don’t need to know all the details to use the Attacher. Essentially, you can install the Attacher, add one annotation to any Kubernetes deployment that has an application you want monitored, and that’s it!</p>
<p>In this blog, we’ll walk through a full example from scratch using a Java application. Apart from the Java code and using a JVM for the application, everything else works the same for the other languages supported by the Attacher.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>This walkthrough assumes that the following are already installed on the system: JDK 17, Docker, Kubernetes, and Helm.</p>
<h2 id="theexampleapplication">The example application</h2>
<p>While the application (shown below) is a Java application, it would be easily implemented in any language, as it is just a simple loop that every 2 seconds calls the method chain methodA-&gt;methodB-&gt;methodC-&gt;methodD, with methodC sleeping for 10 milliseconds and methodD sleeping for 200 milliseconds. The choice of application is just to be able to clearly display in the Elastic APM UI that the application is being monitored.</p>
<p>The Java application in full is shown here:</p>
<pre><code>package test;

public class Testing implements Runnable {

  public static void main(String[] args) {
    new Thread(new Testing()).start();
  }

  public void run()
  {
    while(true) {
      try {Thread.sleep(2000);} catch (InterruptedException e) {}
      methodA();
    }
  }

  public void methodA() {methodB();}

  public void methodB() {methodC();}

  public void methodC() {
    System.out.println("methodC executed");
    try {Thread.sleep(10);} catch (InterruptedException e) {}
    methodD();
  }

  public void methodD() {
    System.out.println("methodD executed");
    try {Thread.sleep(200);} catch (InterruptedException e) {}
  }
}
</code></pre>
<p>We created a Docker image containing that simple Java application for you that can be pulled from the following Docker repository:</p>
<pre><code>docker.elastic.co/demos/apm/k8s-webhook-test
</code></pre>
<h2 id="deploythepod">Deploy the pod</h2>
<p>First we need a deployment config. We’ll call the config file webhook-test.yaml, and the contents are pretty minimal — just pull the image and run that as a pod &amp; container called webhook-test in the default namespace:</p>
<pre><code>apiVersion: v1
kind: Pod
metadata:
  name: webhook-test
  labels:
    app: webhook-test
spec:
  containers:
    - image: docker.elastic.co/demos/apm/k8s-webhook-test
      imagePullPolicy: Always
      name: webhook-test
</code></pre>
<p>This can be deployed normally using kubectl:</p>
<pre><code>kubectl apply -f webhook-test.yaml
</code></pre>
<p>The result is exactly as expected:</p>
<pre><code>$ kubectl get pods
NAME           READY   STATUS    RESTARTS   AGE
webhook-test   1/1     Running   0          10s

$ kubectl logs webhook-test
methodC executed
methodD executed
methodC executed
methodD executed
</code></pre>
<p>So far, this is just setting up a standard Kubernetes application with no APM monitoring. Now we get to the interesting bit: adding in auto-instrumentation.</p>
<h2 id="installelasticapmk8sattacher">Install Elastic APM K8s Attacher</h2>
<p>The first step is to install the <a href="https://www.elastic.co/guide/en/apm/attacher/current/index.html">Elastic APM K8s Attacher</a>. This only needs to be done once for the cluster — once installed, it is always available. Before installation, we will define where the monitored data will go. As you will see later, we can decide or change this any time. For now, we’ll specify our own Elastic APM server, which is at https://myserver.somecloud:443 — we also have a secret token for authorization to that Elastic APM server, which has value MY_SECRET_TOKEN. (If you want to set up a quick test Elastic APM server, you can do so at <a href="https://cloud.elastic.co/">https://cloud.elastic.co/</a>).</p>
<p>There are two additional environment variables set for the application that are not generally needed but will help when we see the resulting UI content toward the end of the walkthrough (when the agent is auto-installed, these two variables tell the agent what name to give this application in the UI and what method to trace). Now we just need to define the custom yaml file to hold these. On installation, the custom yaml will be merged into the yaml for the Attacher:</p>
<pre><code>apm:
  secret_token: MY_SECRET_TOKEN
  namespaces:
    - default
webhookConfig:
  agents:
    java:
      environment:
        ELASTIC_APM_SERVER_URL: "https://myserver.somecloud:443"
        ELASTIC_APM_TRACE_METHODS: "test.Testing#methodB"
        ELASTIC_APM_SERVICE_NAME: "webhook-test"
</code></pre>
<p>That custom.yaml file is all we need to install the attacher (note we’ve only specified the default namespace for agent auto-installation for now — this can be easily changed, as you’ll see later). Next we’ll add the Elastic charts to helm — this only needs to be done once, then all Elastic charts are available to helm. This is the usual helm add repo command, specifically:</p>
<pre><code>helm repo add elastic https://helm.elastic.co
</code></pre>
<p>Now the Elastic charts are available for installation (helm search repo would show you all the available charts). We’re going to use “elastic-webhook” as the name to install into, resulting in the following installation command:</p>
<pre><code>helm install elastic-webhook elastic/apm-attacher --namespace=elastic-apm --create-namespace --values custom.yaml
</code></pre>
<p>And that’s it, we now have the Elastic APM K8s Attacher installed and set to send data to the APM server defined in the custom.yaml file! (You can confirm installation with a helm list -A if you need.)</p>
<h2 id="autoinstallthejavaagent">Auto-install the Java agent</h2>
<p>The Elastic APM K8s Attacher is installed, but it doesn’t auto-install the APM application agents into every pod — that could lead to problems! Instead the Attacher is deliberately limited to auto-install agents into deployments defined a) by the namespaces listed in the custom.yaml, and b) to those deployments in those namespaces that have a specific annotation “co.elastic.apm/attach.”</p>
<p>So for now, restarting the webhook-test pod we created above won’t have any different effect on the pod, as it isn’t yet set to be monitored. What we need to do is add the annotation. Specifically, we need to add the annotation using the default agent configuration that was installed with the Attacher called “java” for the Java agent (we’ll see later how that agent configuration is altered — the default configuration installs the latest agent version and leaves everything else default for that version). So adding that annotation in to webhook-test yaml gives us the new yaml file contents (the additional config is shown labelled (1)):</p>
<pre><code>apiVersion: v1
kind: Pod
metadata:
  name: webhook-test
  annotations: #(1)
    co.elastic.apm/attach: java #(1)
  labels:
    app: webhook-test
spec:
  containers:
    - image: docker.elastic.co/demos/apm/k8s-webhook-test
      imagePullPolicy: Always
      name: webhook-test
</code></pre>
<p>Applying this change gives us the application now monitored:</p>
<pre><code>$ kubectl delete -f webhook-test.yaml
pod "webhook-test" deleted
$ kubectl apply -f webhook-test.yaml
pod/webhook-test created
$ kubectl logs webhook-test
… StartupInfo - Starting Elastic APM 1.45.0 …
</code></pre>
<p>And since the agent is now feeding data to our APM server, we can now see it in the UI:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltca8638b16b1aa112/6a85cb3b2d64d52d74081d44/webhook-test-k8s-blog.png" alt="webhook-test" /></p>
<p>Note that the agent identifies Testing.methodB method as a trace root because of the ELASTIC_APM_TRACE_METHODS environment variable set to test.Testing#methodB in the custom.yaml — this tells the agent to specifically trace that method. The time taken by that method will be available in the UI for each invocation, but we don’t see the sub-methods . . . currently. In the next section, we’ll see how easy it is to customize the Attacher, and in doing so we’ll see more detail about the method chain being executed in the application.</p>
<h2 id="customizingtheagents">Customizing the agents</h2>
<p>In your systems, you’ll likely have development, testing, and production environments. You’ll want to specify the version of the agent to use rather than just pull the latest version whatever that is, you’ll want to have debug on for some applications or instances, and you’ll want to have specific options set to specific values. This sounds like a lot of effort, but the attacher lets you enable these kinds of changes in a very simple way. In this section, we’ll add a configuration that specifies all these changes and we can see just how easy it is to configure and enable it.</p>
<p>We start at the custom.yaml file we defined above. This is the file that gets merged into the Attacher. Adding a new configuration with all the items listed in the last paragraph is easy — though first we need to decide a name for our new configuration. We’ll call it “java-interesting” here. The new custom.yaml in full is (the first part is just the same as before, the new config is simply appended):</p>
<pre><code>apm:
  secret_token: MY_SECRET_TOKEN
  namespaces:
    - default
webhookConfig:
  agents:
    java:
      environment:
        ELASTIC_APM_SERVER_URL: "https://myserver.somecloud:443"
        ELASTIC_APM_TRACE_METHODS: "test.Testing#methodB"
        ELASTIC_APM_SERVICE_NAME: "webhook-test"
    java-interesting:
      image: docker.elastic.co/observability/apm-agent-java:1.55.4
      artifact: "/usr/agent/elastic-apm-agent.jar"
      environment:
        ELASTIC_APM_SERVER_URL: "https://myserver.somecloud:443"
        ELASTIC_APM_TRACE_METHODS: "test.Testing#methodB"
        ELASTIC_APM_SERVICE_NAME: "webhook-test"
        ELASTIC_APM_ENVIRONMENT: "testing"
        ELASTIC_APM_LOG_LEVEL: "debug"
        ELASTIC_APM_PROFILING_INFERRED_SPANS_ENABLED: "true"
        JAVA_TOOL_OPTIONS: "-javaagent:/elastic/apm/agent/elastic-apm-agent.jar"
</code></pre>
<p>Breaking the additional config down, we have:</p>
<ul>
<li><p>The name of the new config java-interesting</p></li>
<li><p>The APM Java agent image docker.elastic.co/observability/apm-agent-java</p></li>
<li><p>With a specific version 1.43.0 instead of latest</p></li>
<li><p>We need to specify the agent jar location (the attacher puts it here)</p></li>
<li><p>artifact: "/usr/agent/elastic-apm-agent.jar"</p></li>
<li><p>And then the environment variables</p></li>
<li><p>ELASTIC_APM_SERVER_URL as before</p></li>
<li><p>ELASTIC_APM_ENVIRONMENT set to testing, useful when looking in the UI</p></li>
<li><p>ELASTIC_APM_LOG_LEVEL set to debug for more detailed agent output</p></li>
<li><p>ELASTIC_APM_PROFILING_INFERRED_SPANS_ENABLED turning this on (setting to true) will give us additional interesting information about the method chain being executed in the application</p></li>
<li><p>And lastly we need to set JAVA_TOOL_OPTIONS to the enable starting the agent "-javaagent:/elastic/apm/agent/elastic-apm-agent.jar" — this is fundamentally how the attacher auto-attaches the Java agent</p></li>
</ul>
<p>More configurations and details about configuration options are <a href="https://www.elastic.co/guide/en/apm/agent/java/current/configuration.html">here for the Java agent</a>, and <a href="https://www.elastic.co/guide/en/apm/agent/index.html">other language agents</a> are also available.</p>
<h2 id="theapplicationtracedwiththenewconfiguration">The application traced with the new configuration</h2>
<p>And finally we just need to upgrade the attacher with the changed custom.yaml:</p>
<pre><code>helm upgrade elastic-webhook elastic/apm-attacher --namespace=elastic-apm --create-namespace --values custom.yaml
</code></pre>
<p>This is the same command as the original install, but now using upgrade. That’s it — add config to the custom.yaml and upgrade the attacher, and it’s done! Simple.</p>
<p>Of course we still need to use the new config on an app. In this case, we’ll edit the existing webhook-test.yaml file, replacing java with java-interesting, so the annotation line is now:</p>
<pre><code>co.elastic.apm/attach: java-interesting
</code></pre>
<p>Applying the new pod config and restarting the pod, you can see the logs now hold debug output:</p>
<pre><code>$ kubectl delete -f webhook-test.yaml
pod "webhook-test" deleted
$ kubectl apply -f webhook-test.yaml
pod/webhook-test created
$ kubectl logs webhook-test
… StartupInfo - Starting Elastic APM 1.44.0 …
… DEBUG co.elastic.apm.agent. …
… DEBUG co.elastic.apm.agent. …
</code></pre>
<p>More interesting is the UI. Now that inferred spans is on, the full method chain is visible.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf182dab36de35372/6a85cb3d6826668f5b1eac03/trace-sample-k8s-blog.png" alt="trace sample" /></p>
<p>This gives the details for methodB (it takes 211 milliseconds because it calls methodC - 10ms - which calls methodD - 200ms). The times for methodC and methodD are inferred rather than recorded, (inferred rather than traced — if you needed accurate times you would instead add the methods to trace_methods and have them traced too).</p>
<h2 id="noteontheeckoperator">Note on the ECK operator</h2>
<p>The <a href="https://www.elastic.co/guide/en/cloud-on-k8s/master/k8s-overview.html">Elastic Cloud on Kubernetes operator</a> allows you to install and manage a number of other Elastic components on Kubernetes. At the time of publication of this blog, the <a href="https://www.elastic.co/guide/en/apm/attacher/current/index.html">Elastic APM K8s Attacher</a> is a separate component, and there is no conflict between these management mechanisms — they apply to different components and are independent of each other.</p>
<h2 id="tryityourself">Try it yourself!</h2>
<p>This walkthrough is easily repeated on your system, and you can make it more useful by replacing the example application with your own and the Docker registry with the one you use.</p>
<p><a href="https://www.elastic.co/observability/kubernetes-monitoring">Learn more about real-time monitoring with Kubernetes and Elastic Observability</a>.</p>
<p><em>The release and timing of any features or functionality described in this post remain at Elastic's sole discretion. Any features or functionality not currently available may not be delivered on time or at all.</em></p>]]></content:encoded>
    <link>https://www.elastic.co/observability-labs/blog/application-monitoring-kubernetes-pods</link>
    <guid isPermaLink="false">application-monitoring-kubernetes-pods</guid>
    <category><![CDATA[Kubernetes]]></category>
    <category><![CDATA[APM]]></category>
    <dc:creator><![CDATA[Jack Shirazi,Sylvain Juge,Alexander Wert]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbececa85f67fdcd1/6a85cb40eaf24581f5a49f65/139689_-_Blog_Header_Banner_V1.jpg" length="0" type="image/jpeg"/>
    <pubDate>Wed, 17 Jan 2024 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Elastic's contribution: Invokedynamic in the OpenTelemetry Java agent]]></title>
    <description><![CDATA[The instrumentation approach in OpenTelemetry's Java Agent comes with some limitations with respect to maintenance and testability. Elastic contributes an invokedynamic-based instrumentation approach that helps overcoming these limitations.]]></description>
    <content:encoded><![CDATA[<p>As the second largest and active Cloud Native Computing Foundation (CNCF) project, <a href="https://opentelemetry.io/">OpenTelemetry</a> is well on its way to becoming the ubiquitous, unified standard and framework for observability. OpenTelemetry owes this success to its comprehensive and feature-rich toolset that allows users to retrieve valuable observability data from their applications with low effort. The OpenTelemetry Java agent is one of the most mature and feature-rich components in OpenTelemetry’s ecosystem. It provides automatic instrumentation for JVM-based applications and comes with a broad coverage of auto-instrumentation modules for popular Java-frameworks and libraries.</p>
<p>The original instrumentation approach used in the OpenTelemetry Java agent left the maintenance and development of auto-instrumentation modules subject to some restrictions. As part of <a href="https://www.elastic.co/blog/transforming-observability-ai-assistant-otel-standardization-continuous-profiling-log-analytics">our reinforced commitment to OpenTelemetry</a>, Elastic® helps evolve and improve OpenTelemetry projects and components. <a href="https://www.elastic.co/blog/ecs-elastic-common-schema-otel-opentelemetry-announcement">Elastic’s contribution of the Elastic Common Schema</a> to OpenTelemetry was an important step for the open-source community. As another step in our commitment to OpenTelemetry, Elastic started contributing to the OpenTelemetry Java agent.</p>
<h2 id="elasticsinvokedynamicbasedinstrumentationapproach">Elastic’s invokedynamic-based instrumentation approach</h2>
<p>To overcome the above-mentioned limitations in developing and maintaining auto-instrumentation modules in the OpenTelemetry Java agent, Elastic started contributing its <a href="https://www.elastic.co/blog/embracing-invokedynamic-to-tame-class-loaders-in-java-agents"><strong>invokedynamic</strong></a><a href="https://www.elastic.co/blog/embracing-invokedynamic-to-tame-class-loaders-in-java-agents">-based instrumentation approach</a> to the OpenTelemetry Java agent in July 2023.</p>
<p>To explain the improvement, you should know that in Java, a common approach to do auto-instrumentation of applications is through utilizing Java agents that do bytecode instrumentation at runtime. <a href="https://bytebuddy.net/#/">Byte Buddy</a> is a popular and widespread utility that helps with bytecode instrumentation without the need to deal with Java’s bytecode directly. Instrumentation logic that collects observability data from the target application’s code lives in so-called <em>advice methods</em>. Byte Buddy provides different ways of hooking these advice methods into the target application’s methods:</p>
<ul>
<li><em>Advice inlining:</em> The advice method’s code is being copied into the instrumented target method.</li>
<li><em>Static advice dispatching:</em> The instrumented target method invokes static advice methods that need to be visible by the instrumented code.</li>
<li><em>Advice dispatching with</em>  <strong>invokedynamic</strong> __:_ The instrumented target method uses the JVM’s <strong>invokedynamic</strong> bytecode instruction to call advice methods that are isolated from the instrumented code.</li>
</ul>
<p>These different approaches are described in great detail in our related blog post on <a href="https://www.elastic.co/blog/embracing-invokedynamic-to-tame-class-loaders-in-java-agents">Elastic’s Java APM agent using invokedynamic</a>. In a nutshell, both approaches, <em>advice inlining</em> and <em>dispatching to static advice methods</em> come with some limitations with respect to writing and maintaining the advice code. So far, the OpenTelemetry Java agent has used <em>advice inlining</em> for its bytecode instrumentation. The resulting limitations on developing instrumentations are <a href="https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/v1.30.0/docs/contributing/writing-instrumentation-module.md#use-advice-classes-to-write-code-that-will-get-injected-to-the-instrumented-library-classes">documented in corresponding developer guidelines</a>. Among other things, the limitation of not being able to debug advice code is a painful restriction when developing and maintaining instrumentation code.</p>
<p>Elastic’s APM Java agent has been using the <strong>invokedynamic</strong> approach with its benefits for years — field-proven by thousands of customers. To help improve the OpenTelemetry Java agent, Elastic started contributing the <strong>invokedynamic</strong> approach with the goal to simplify and improve the development and maintainability of auto-instrumentation modules. The contribution proposal and the implementation outline is documented in more detail in <a href="https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/8999">this GitHub issue</a>.</p>
<p>With the new approach in place, Elastic will help migrate existing instrumentations so the OTel Java community can benefit from the <strong>invokedynamic</strong> -based instrumentation approach.</p>
<blockquote>
  <p>Elastic supports OTel natively, and has numerous capabilities to help you analyze your application with OTel. </p>
  <ul>
  <li><a href="https://www.elastic.co/blog/opentelemetry-observability">Native OpenTelemetry support in Elastic Observability</a></li>
  <li><a href="https://www.elastic.co/blog/best-practices-instrumenting-opentelemetry">Best Practices for instrumenting OpenTelemetry</a></li>
  <li><a href="https://www.elastic.co/blog/opentelemetry-observability">Independence with OpenTelemetry on Elastic</a></li>
  </ul>
  <p>Instrumenting with OpenTelemetry:</p>
  <ul>
  <li><a href="https://www.elastic.co/blog/getting-started-opentelemetry-instrumentation-sample-app">Elastiflix application</a>, a guide to instrument different languages with OpenTelemetry (this is the application the team built to highlight <em>all</em> the languages below)</li>
  <li>Python: <a href="https://www.elastic.co/blog/auto-instrumentation-of-python-applications-opentelemetry">Auto-instrumentation</a>, <a href="https://www.elastic.co/blog/manual-instrumentation-of-python-applications-opentelemetry">Manual instrumentation</a></li>
  <li>Java: <a href="https://www.elastic.co/blog/auto-instrumentation-of-java-applications-opentelemetry">Auto-instrumentation</a>, <a href="https://www.elastic.co/blog/manual-instrumentation-of-java-applications-opentelemetry">Manual instrumentation </a></li>
  <li>Node.js: <a href="https://www.elastic.co/blog/auto-instrument-nodejs-applications-opentelemetry">Auto-instrumentation</a>, <a href="https://www.elastic.co/blog/manual-instrumentation-of-nodejs-applications-opentelemetry">Manual instrumentation</a></li>
  <li>.NET: <a href="https://www.elastic.co/blog/auto-instrumentation-of-net-applications-opentelemetry">Auto-instrumentation</a>, <a href="https://www.elastic.co/blog/manual-instrumentation-of-net-applications-opentelemetry">Manual instrumentation</a><br />
  Go: <a href="https://elastic.co/blog/manual-instrumentation-of-go-applications-opentelemetry">Manual instrumentation</a></li>
  </ul>
</blockquote>
<p><em>The release and timing of any features or functionality described in this post remain at Elastic's sole discretion. Any features or functionality not currently available may not be delivered on time or at all.</em></p>]]></content:encoded>
    <link>https://www.elastic.co/observability-labs/blog/invokedynamic-opentelemetry-java-agent</link>
    <guid isPermaLink="false">invokedynamic-opentelemetry-java-agent</guid>
    <category><![CDATA[OpenTelemetry]]></category>
    <dc:creator><![CDATA[Alexander Wert,Jack Shirazi,Jonas Kunz,Sylvain Juge]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4923c41bb46647d7/6a85c99b18249cfe1d18f79f/24-crystals.jpeg" length="0" type="image/jpeg"/>
    <pubDate>Thu, 19 Oct 2023 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>