<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Elastic Observability Labs - Articles by Alexander Wert</title>
        <link>https://www.elastic.co/observability-labs</link>
        <description>Trusted security news &amp; research from the team at Elastic.</description>
        <lastBuildDate>Fri, 06 Mar 2026 16:24:31 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Elastic Observability Labs - Articles by Alexander Wert</title>
            <url>https://www.elastic.co/observability-labs/assets/observability-labs-thumbnail.png</url>
            <link>https://www.elastic.co/observability-labs</link>
        </image>
        <copyright>© 2026. Elasticsearch B.V. All Rights Reserved</copyright>
        <item>
            <title><![CDATA[Collecting JMX metrics with OpenTelemetry]]></title>
            <link>https://www.elastic.co/observability-labs/blog/collecting-jmx-metrics-opentelemetry</link>
            <guid isPermaLink="false">collecting-jmx-metrics-opentelemetry</guid>
            <pubDate>Thu, 05 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Learn how to collect Tomcat JMX metrics with OpenTelemetry using the Java agent or jmx-scraper, then extend coverage with custom YAML rules and validate output.]]></description>
            <content:encoded><![CDATA[<p>Java Management Extensions (JMX) is the JVM's built-in management interface, exposing runtime and component metrics such as memory, threads, and request pools. It is useful for collecting operational telemetry from Java services without changing application code.</p>
<p>Collecting JMX metrics with OpenTelemetry can be done in two main ways depending on your environment, requirements and constraints:</p>
<ul>
<li>from inside the JVM with the <a href="https://github.com/open-telemetry/opentelemetry-java-instrumentation">OpenTelemetry Instrumentation Java</a> agent (or <a href="https://www.elastic.co/docs/reference/opentelemetry/edot-sdks/java">EDOT Java</a>)</li>
<li>from outside the JVM with the <a href="https://github.com/open-telemetry/opentelemetry-java-contrib/tree/main/jmx-scraper">jmx-scraper</a>.</li>
</ul>
<p>Thorough this article, we will use the term &quot;Java agent&quot; to refer to the <a href="https://github.com/open-telemetry/opentelemetry-java-instrumentation">OpenTelemetry Java instrumentation</a> agent, this
also applies to the Elastic own distribution (<a href="https://www.elastic.co/docs/reference/opentelemetry/edot-sdks/java">EDOT Java</a>) which is based on it and provides the same features.</p>
<p>This walkthrough uses a <a href="https://tomcat.apache.org/">Tomcat</a> server as the target and shows how to validate which metrics are emitted with the logging exporter.</p>
<p>The configuration examples in this article use Java system properties that must be passed using <code>-D</code> flags in the JVM startup command, equivalent environment variables can also be used for configuration.</p>
<h2>Prerequisites</h2>
<ul>
<li>A local <a href="https://tomcat.apache.org/">Tomcat</a> install (or any JVM app you can start with custom JVM flags)</li>
<li>Java 8+ on the host, the Tomcat version used might require a more recent version though.</li>
<li>An OpenTelemetry Collector endpoint if you want to ship metrics beyond local logging</li>
</ul>
<h2>Choosing between the Java agent and jmx-scraper</h2>
<p><img src="https://www.elastic.co/observability-labs/assets/images/collecting-jmx-metrics-opentelemetry/collection_options.png" alt="Java agent vs jmx-scraper" /></p>
<p>Use the Java agent (or EDOT Java) when you can modify JVM startup flags and want in-process collection with full context from the running application: this allows to capture traces, logs and metrics with a single tool deployment.</p>
<p>Use jmx-scraper when you cannot install an agent on the JVM or prefer out-of-process collection from a separate host. This requires the JVM and the network to be configured for remote JMX access and also dealing with authentication and credentials.</p>
<p>Both approaches rely on the same JMX metric mappings and can use the logging exporter for validation and then use OTLP to send metrics to the collector / an OTLP endpoint.</p>
<h2>Option 1: Collect JMX metrics inside the JVM with the Java agent</h2>
<p>OpenTelemetry Java instrumentation ships with a curated set of JMX metric mappings. For Tomcat, you just need to enable the Java agent and set <code>otel.jmx.target.system=tomcat</code>.</p>
<h3>Step 1 - Download the OpenTelemetry Java agent</h3>
<p>The agent is downloaded in <code>/opt/otel</code> but you can choose any location on the host.
Make sure the path is consistent with the <code>-javaagent</code> flag in the next step.</p>
<pre><code class="language-bash">mkdir -p /opt/otel
curl -L -o /opt/otel/opentelemetry-javaagent.jar \
  https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar
</code></pre>
<h3>Step 2 - Configure Tomcat with <code>bin/setenv.sh</code></h3>
<p>Create or update <code>bin/setenv.sh</code> so Tomcat launches with the agent and JMX target system enabled.</p>
<pre><code class="language-bash">#!/bin/bash
export CATALINA_OPTS=&quot;$CATALINA_OPTS \
  -javaagent:/opt/otel/opentelemetry-javaagent.jar \
  -Dotel.service.name=tomcat-demo \
  -Dotel.metrics.exporter=otlp,logging \
  -Dotel.jmx.target.system=tomcat&quot;
</code></pre>
<p>This will configure the agent to log metrics (using the <code>logging</code> exporter) in addition to sending them to the Collector.</p>
<h3>Step 3 - Validate the emitted metrics</h3>
<p>Start Tomcat and watch stdout.</p>
<pre><code class="language-bash">./bin/catalina.sh run
</code></pre>
<p>By defaults metrics are sampled and emitted every minute, so you might have to wait a bit for the metrics to be logged.
If needed, you can use <code>otel.metric.export.interval</code> configuration to increase or reduce the frequency.</p>
<p>You should see logging exporter output with JVM and Tomcat metrics. Look for lines containing the <code>LoggingMetricExporter</code> class name.</p>
<pre><code class="language-text">INFO io.opentelemetry.exporter.logging.LoggingMetricExporter - MetricData{name=tomcat.threadpool.currentThreadsBusy, ...}
INFO io.opentelemetry.exporter.logging.LoggingMetricExporter - MetricData{name=jvm.memory.used, ...}
</code></pre>
<h3>Step 4 - Send metrics to a Collector</h3>
<p>Once metric capture is validated, you should be ready to send metrics to a collector.</p>
<p>You will have to:</p>
<ul>
<li>remove the <code>logging</code> exporter as it's no longer necessary for production</li>
<li>configure the OTLP endpoint (<code>otel.exporter.otlp.endpoint</code>) and headers (<code>otel.exporter.otlp.headers</code>) if needed</li>
</ul>
<p>The <code>bin/setenv.sh</code> file should be modified to look like this:</p>
<pre><code class="language-bash">#!/bin/bash
export CATALINA_OPTS=&quot;$CATALINA_OPTS \
  -javaagent:/opt/otel/opentelemetry-javaagent.jar \
  -Dotel.service.name=tomcat-demo \
  -Dotel.jmx.target.system=tomcat \
  -Dotel.exporter.otlp.endpoint=https://your-collector:4317 \
  -Dotel.exporter.otlp.headers=Authorization=Bearer &lt;your-token&gt;&quot;
</code></pre>
<p>When using the Java agent, the JVM metrics are automatically captured by the <a href="https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/runtime-telemetry"><code>runtime-telemetry</code></a> module, it is thus not necessary to include <code>jvm</code> in the <code>otel.jmx.target.system</code> configuration option.</p>
<h2>Option 2: Collect JMX metrics from outside the JVM with jmx-scraper</h2>
<p>When you cannot install an agent in the JVM or if only metrics are required, jmx-scraper lets you query JMX remotely and export metrics to an OTLP endpoint.</p>
<h3>Step 1 - Enable remote JMX on Tomcat</h3>
<p>Add JMX remote options to <code>bin/setenv.sh</code> and create access/password files.</p>
<blockquote>
<p><strong>Warning:</strong> This uses trivial credentials and disables SSL. Do not use this configuration in production.</p>
</blockquote>
<pre><code class="language-bash">mkdir -p /opt/jmx
cat &lt;&lt;EOF &gt; ${CATALINA_HOME}/jmxremote.access
monitorRole readonly
EOF

cat &lt;&lt;EOF &gt; ${CATALINA_HOME}/jmxremote.password
monitorRole monitorPass
EOF

chmod 600 ${CATALINA_HOME}/jmxremote.password

export CATALINA_OPTS=&quot;$CATALINA_OPTS \
  -Dcom.sun.management.jmxremote \
  -Dcom.sun.management.jmxremote.port=9010 \
  -Dcom.sun.management.jmxremote.rmi.port=9010 \
  -Dcom.sun.management.jmxremote.authenticate=true \
  -Dcom.sun.management.jmxremote.ssl=false \
  -Dcom.sun.management.jmxremote.access.file=${CATALINA_HOME}/jmxremote.access \
  -Dcom.sun.management.jmxremote.password.file=${CATALINA_HOME}/jmxremote.password \
  -Djava.rmi.server.hostname=127.0.0.1&quot;
</code></pre>
<h3>Step 2 - Download jmx-scraper</h3>
<p>The jmx-scraper is downloaded in <code>/opt/otel</code> but you can choose any location on the host.</p>
<pre><code class="language-bash">mkdir -p /opt/otel
curl -L -o /opt/otel/opentelemetry-jmx-scraper.jar \
  https://github.com/open-telemetry/opentelemetry-java-contrib/releases/latest/download/opentelemetry-jmx-scraper.jar
</code></pre>
<h3>Step 3 - Check the JMX connection</h3>
<p>Run jmx-scraper with credentials from previous step to confirm it can reach Tomcat. If the credentials are wrong, you will see authentication errors.</p>
<pre><code class="language-bash">java -jar /opt/otel/opentelemetry-jmx-scraper.jar \
  -Dotel.jmx.service.url=service:jmx:rmi:///jndi/rmi://localhost:9010/jmxrmi
  -Dotel.jmx.username=monitorRole \
  -Dotel.jmx.password=monitorPass \
  -Dotel.jmx.target.system=tomcat \
  -test
</code></pre>
<p>You should get in the standard output:</p>
<ul>
<li><code>JMX connection test OK</code> if the connection and authentication is successful</li>
<li><code>JMX connection test ERROR</code> otherwise</li>
</ul>
<h3>Step 4 - Validate the emitted metrics</h3>
<p>Using the logging exporter allows to inspect metrics and attributes before sending them to a collector.</p>
<p>In order to capture both Tomcat and JVM metrics, it is required to set <code>otel.jmx.target.system</code> to <code>tomcat,jvm</code>.</p>
<pre><code class="language-bash">java -jar /opt/otel/opentelemetry-jmx-scraper.jar \
  -Dotel.jmx.service.url=service:jmx:rmi:///jndi/rmi://localhost:9010/jmxrmi
  -Dotel.jmx.username=monitorRole \
  -Dotel.jmx.password=monitorPass \
  -Dotel.jmx.target.system=tomcat,jvm \
  -Dotel.metrics.exporter=logging
</code></pre>
<h3>Step 5 - Send metrics to a Collector</h3>
<p>After validation, to send metrics to an OTLP endpoint, you will have to:</p>
<ul>
<li>remove the <code>-Dotel.metrics.exporter</code> to restore the <code>otlp</code> default value.</li>
<li>configure the OTLP endpoint (<code>otel.exporter.otlp.endpoint</code>) and headers (<code>otel.exporter.otlp.headers</code>) if needed</li>
</ul>
<pre><code class="language-bash">java -jar /opt/otel/opentelemetry-jmx-scraper.jar \
  -Dotel.jmx.service.url=service:jmx:rmi:///jndi/rmi://localhost:9010/jmxrmi
  -Dotel.jmx.username=monitorRole \
  -Dotel.jmx.password=monitorPass \
  -Dotel.jmx.target.system=tomcat,jvm \
  -Dotel.exporter.otlp.endpoint=https://your-collector:4317
  -Dotel.exporter.otlp.headers=&quot;Authorization=Bearer &lt;your-token&gt;&quot;
</code></pre>
<h2>Customizing the JMX Metrics Collection</h2>
<p>Once the built-in Tomcat and JVM mappings are flowing, you can add custom rules with <code>otel.jmx.config</code>. Create a YAML file and pass its path alongside <code>otel.jmx.target.system</code>.</p>
<p>For example, the following <code>custom.yaml</code> file allows to capture the <code>custom.jvm.thread.count</code> metric from the <code>java.lang:type=Threading</code> MBean:</p>
<pre><code class="language-yaml">---
rules:
  - bean: &quot;java.lang:type=Threading&quot;
    mapping:
      ThreadCount:
        metric: custom.jvm.thread.count
        type: gauge
        unit: &quot;{thread}&quot;
        desc: Current number of live threads.
</code></pre>
<p>For complete reference on the configuration format and syntax, refer to <a href="https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/jmx-metrics">jmx-metrics</a> module in Opentelemetry Java instrumentation.</p>
<p>This custom configuration can be used both with jmx-scraper and Java agent, both support the <code>otel.jmx.config</code> configuration option, for example with jmx-scraper:</p>
<pre><code class="language-bash">java -jar /opt/otel/opentelemetry-jmx-scraper.jar \
  -Dotel.jmx.service.url=service:jmx:rmi:///jndi/rmi://localhost:9010/jmxrmi
  -Dotel.jmx.username=monitorRole \
  -Dotel.jmx.password=monitorPass \
  -Dotel.jmx.target.system=tomcat,jvm \
  otel.jmx.config=/opt/otel/jmx/custom.yaml
</code></pre>
<p>You can pass multiple custom files as a comma-separated list to <code>otel.jmx.config</code> when you need to organize metrics by team or component.</p>
<h2>Using the JMX Metrics in Kibana</h2>
<p>Once you have collected the JMX metrics using one of the approaches described in this article, you can start using them in Kibana.
You can build custom dashboards and visualizations to explore and analyze the metrics, create custom alerts on top of them or build MCP tools and AI Agents to use them in your agentic workflows.</p>
<p>Here is an example of how you can use the JMX metrics in Kibana through ES|QL:</p>
<pre><code class="language-esql">TS metrics*
| WHERE telemetry.sdk.language == &quot;java&quot;
| WHERE service.name == ?instance
| STATS
    request_rate = SUM(RATE(tomcat.request.count))
  BY Time = BUCKET(@timestamp, 100, ?_tstart, ?_tend)
</code></pre>
<p>You can use the native metric and dimension names of the JMX metrics to build your queries.
With the <code>TS</code> command you get first-class support for time series aggregation functions and dimensions on your metrics.
This kind of queries constitute the building blocks for your dashboards, alerts, workflows and AI agent tools.</p>
<p>Here is an example of a dashboard that visualizes the typical JMX metrics for Apache Tomcat:</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/collecting-jmx-metrics-opentelemetry/tomcat_jmx_dashboard.png" alt="Tomcat Dashboard" /></p>
<h2>Conclusion</h2>
<p>In this article, we have seen how to collect JMX metrics with OpenTelemetry using the Java agent or jmx-scraper.
We have also seen how to use the JMX metrics in Kibana through ES|QL to build custom dashboards, alerts, workflows and AI agent tools.</p>
<p>This is just the beginning of what you can do with the JMX metrics and Elastic Observability.
Try it out yourself and explore the full potential of your JMX metrics when combined with powerful features provided by the Elastic Observability platform.</p>]]></content:encoded>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/collecting-jmx-metrics-opentelemetry/jmx_header_image.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Introducing Elastic Distribution of OpenTelemetry Collector]]></title>
            <link>https://www.elastic.co/observability-labs/blog/elastic-distribution-opentelemetry-collector</link>
            <guid isPermaLink="false">elastic-distribution-opentelemetry-collector</guid>
            <pubDate>Fri, 09 Aug 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[We are thrilled to announce the technical preview of the Elastic Distribution of OpenTelemetry Collector. This new offering underscores Elastic dedication to this important framework and highlights our ongoing contributions to make OpenTelemetry the best vendor agnostic data collection framework.]]></description>
            <content:encoded><![CDATA[<p>OpenTelemetry is an open-source framework that ensures vendor-agnostic data collection, providing a standardized approach for the collection, processing, and ingestion of observability data. Elastic is fully committed to this principle, aiming to make observability truly vendor-agnostic and eliminating the need for users to reinstrument their observability when switching platforms.</p>
<p>Over the past year, Elastic has made several notable contributions to the OpenTelemetry ecosystem. We <a href="https://opentelemetry.io/blog/2023/ecs-otel-semconv-convergence/">donated our Elastic Common Schema (ECS)</a> to OpenTelemetry, successfully <a href="https://opentelemetry.io/blog/2024/elastic-contributes-continuous-profiling-agent/">integrated the eBPF-based profiling agent</a>, and have consistently been one of the top contributing companies across the OpenTelemetry project. Additionally, Elastic has significantly improved upstream logging capabilities within OpenTelemetry with enhancements to key areas such as <a href="https://opentelemetry.io/blog/2024/otel-collector-container-log-parser/">container logging</a>, further enhancing the framework’s robustness.</p>
<p>These efforts demonstrate our strategic focus on enhancing and expanding the capabilities of OpenTelemetry for the broader observability community and reinforce the vendor-agnostic benefits of using OpenTelemetry.</p>
<p>Today, we are thrilled to announce the technical preview of the Elastic Distribution of OpenTelemetry Collector. This new offering underscores Elastic’s dedication to this important framework and highlights our ongoing contributions to make OpenTelemetry the best vendor agnostic data collection framework.</p>
<h2>Elastic Agent as an OpenTelemetry Collector&lt;a id=&quot;elastic-agent-as-an-opentelemetry-collector&quot;&gt;&lt;/a&gt;</h2>
<p>Technically, the Elastic Distribution of OpenTelemetry Collector represents an evolution of the Elastic Agent. In its latest version, the Elastic Agent can operate in an OpenTelemetry mode. This mode invokes a module within the Elastic Agent which is essentially a distribution of the OpenTelemetry collector. It is crafted using a selection of upstream components from the contrib distribution.</p>
<p>The Elastic OpenTelemetry Collector also includes configuration for this set of <a href="https://github.com/elastic/elastic-agent/tree/main/internal/pkg/otel#components">upstream OpenTelemetry Collector components</a>, providing out-of-the-box functionality with Elastic Observability. This integration allows users to seamlessly utilize Elastic’s advanced observability features with minimal setup.</p>
<p>The technical preview version of the Elastic OpenTelemetry Collector has been tailored with out-of-the-box configurations for the below use cases, we will keep working to add more as we progress: :</p>
<ul>
<li>
<p><strong><em>Collect and ship logs</em></strong>: Use the Elastic OpenTelemetry Collector to gather log data from various sources and ship it directly to Elastic where it can be analyzed in Kibana Discover, and Elastic Observability’s Explorer (also in Tech Preview in 8.15).</p>
</li>
<li>
<p><strong><em>Assess host health</em></strong>: Leverage the OpenTelemetry host metrics and Kubernetes receivers to monitor to evaluate the performance of hosts and pods. This data can then be visualized and analyzed in Elastic’s Infrastructure Observability UIs, providing deep insights into host performance and health. Details of how this is configured in the OTel collector is outlined in this <a href="https://www.elastic.co/observability-labs/blog/infrastructure-monitoring-with-opentelemetry-in-elastic-observability">blog</a>.</p>
</li>
<li>
<p><strong>Kubernetes container logs</strong>: Additionally, users of the Elastic OpenTelemetry Collector benefit from out-of-the-box Kubernetes container and application logs enriched with Kubernetes metadata by leveraging the powerful <a href="https://opentelemetry.io/blog/2024/otel-collector-container-log-parser/">container log parser</a> Elastic recently contributed to OTel. This OpenTelemetry-based enrichment enhances the context and value of the collected logs, providing deeper insights and more effective troubleshooting capabilities.</p>
</li>
</ul>
<p>While the Elastic OpenTelemetry Collector comes pre-built and preconfigured for the sake of easier onboarding and getting started experience, Elastic is committed to the vision of vendor-neutral collection of data. Thus, we strive to contribute any Elastic specific features back to the upstream OpenTelemetry components, to advance and help grow the OpenTelemetry landscape and capabilities.</p>
<p>Stay tuned for upcoming announcements sharing our plans to combine the best of Elastic Agent and OpenTelemetry Collector.</p>
<h2>Get started the Elastic Distribution of OpenTelemetry Collector&lt;a id=&quot;get-started-the-elastic-distribution-for-opentelemetry-collector&quot;&gt;&lt;/a&gt;</h2>
<p>To get started with a guided onboarding flow for the Elastic Distribution of the OpenTelemetry Collector for Kubernetes, Linux, and Mac environments, visit the<a href="https://github.com/elastic/opentelemetry/blob/main/docs/guided-onboarding.md"> guided onboarding documentation</a>.</p>
<p>For more advanced manual configuration, follow the<a href="https://github.com/elastic/opentelemetry/blob/main/docs/manual-configuration.md"> manual configuration instructions</a>.</p>
<p>Once the Elastic Distribution of the OpenTelemetry Collector is set up and running, you’ll be able to analyze your systems within various features of the Elastic Observability solution.</p>
<p>Analyze the performance and health of your infrastructure, through corresponding metrics and logs collected through OpenTelemetry Collector receivers, such as the host metrics receiver and different Kubernetes receivers.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/elastic-distribution-opentelemetry-collector/hosts.png" alt="OTel Monitoring Hosts" /></p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/elastic-distribution-opentelemetry-collector/otel-daemonset-green-logs.png" alt="OTel Logs" /></p>
<p>With Elastic OpenTelemetry Collector, container and application logs are enriched with Kubernetes metadata out-of-the-box making filtering, grouping and logs analysis easier and more efficient.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/elastic-distribution-opentelemetry-collector/explorer.png" alt="OTel Discover" /></p>
<p>The Elastic Distribution of the OpenTelemetry Collector allows for tracing just like any other collector distribution made of upstream components. Explore and analyze the performance and runtime behavior of your applications and services through RED metric, service maps and distributed traces collected from OpenTelemetry SDKs.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/elastic-distribution-opentelemetry-collector/apm.png" alt="OTel APM" /></p>
<p>The above capabilities and features packed with the Elastic OpenTelemetry Collector can be achieved in a similar way with a custom build of the upstream OpenTelemetry Collector packing the right set of upstream components. To do just that follow our <a href="https://www.elastic.co/docs/reference/opentelemetry/edot-collector/customization">guidance here</a>.</p>
<h2>Outlook&lt;a id=&quot;outlook&quot;&gt;&lt;/a&gt;</h2>
<p>The launch of the technical preview of the Elastic Distribution of OpenTelemetry Collector is another step on Elastic’s journey towards OpenTelemetry based observability. On that journey we are committed to a vendor-agnostic approach to data collection and therefore prioritize upstream contribution to OpenTelemetry over Elastic-specific data collection features.</p>
<p>Stay tuned to see more of Elastic’s contributions to OpenTelemetry and observe Elastic’s journey towards fully OpenTelemetry-based observability.</p>
<p>Additional resources for OpenTelemetry with Elastic:</p>
<ul>
<li>
<p>Elastic Distributions recently introduced:</p>
<ul>
<li>
<p><a href="https://www.elastic.co/observability-labs/blog/elastic-distribution-opentelemetry-java-agent">Elastic Distribution of OpenTelemetry's Java SDK</a>.</p>
</li>
<li>
<p><a href="https://www.elastic.co/observability-labs/blog/elastic-opentelemetry-distribution-python">Elastic Distribution of OpenTelemetry's Python SDK</a></p>
</li>
<li>
<p><a href="https://www.elastic.co/observability-labs/blog/elastic-opentelemetry-distribution-node-js">Elastic Distribution of OpenTelemetry's NodeJS SDK</a></p>
</li>
<li>
<p><a href="https://www.elastic.co/observability-labs/blog/elastic-opentelemetry-distribution-dotnet-applications">Elastic Distribution of OpenTelemetry's .NET SDK</a></p>
</li>
<li>
<p><a href="https://www.elastic.co/observability-labs/blog/apm-ios-android-native-apps">Elastic Distribution of OpenTelemetry of iOS and Android</a></p>
</li>
</ul>
</li>
<li>
<p>Other Elastic OpenTelemetry resources:</p>
<ul>
<li>
<p><a href="https://www.elastic.co/blog/opentelemetry-observability">Independence with OpenTelemetry on Elastic</a></p>
</li>
<li>
<p><a href="https://www.elastic.co/blog/implementing-kubernetes-observability-security-opentelemetry">Modern observability and security on Kubernetes with Elastic and OpenTelemetry</a></p>
</li>
<li>
<p><a href="https://www.elastic.co/blog/3-models-logging-opentelemetry-elastic">3 models for logging with OpenTelemetry and Elastic</a></p>
</li>
</ul>
</li>
<li>
<p>Instrumentation resources:</p>
<ul>
<li>
<p>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></p>
</li>
<li>
<p>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></p>
</li>
<li>
<p>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></p>
</li>
<li>
<p>.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></p>
</li>
</ul>
</li>
</ul>
]]></content:encoded>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/elastic-distribution-opentelemetry-collector/otel-collector-announcement.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Announcing GA of Elastic distribution of the OpenTelemetry Java Agent]]></title>
            <link>https://www.elastic.co/observability-labs/blog/elastic-distribution-opentelemetry-java-agent</link>
            <guid isPermaLink="false">elastic-distribution-opentelemetry-java-agent</guid>
            <pubDate>Thu, 12 Sep 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Elastic announces general availability of the Elastic distribution of the OpenTelemetry (OTel) Java Agent, a fully OTel-compatible agent with a rich set of useful additional features.]]></description>
            <content:encoded><![CDATA[<p>As Elastic continues its commitment to OpenTelemetry (OTel), we are excited to announce general availability of the <a href="https://github.com/elastic/elastic-otel-java">Elastic Distribution of OpenTelemetry Java (EDOT Java)</a>. EDOT Java is a fully compatible drop-in replacement for the OTel Java agent that comes with a set of built-in, useful extensions for powerful additional features and improved usability with Elastic Observability. Use EDOT Java to start the OpenTelemetry SDK with your Java application, and automatically capture tracing data, performance metrics, and logs. Traces, metrics, and logs can be sent to any OpenTelemetry Protocol (OTLP) collector you choose.</p>
<p>With EDOT Java you have access to all the features of the OpenTelemetry Java agent plus:</p>
<ul>
<li>Access to SDK improvements and bug fixes contributed by the Elastic team before the changes are available upstream in OpenTelemetry repositories.</li>
<li>Access to optional features that can enhance OpenTelemetry data that is being sent to Elastic (for example, inferred spans and span stacktrace).</li>
</ul>
<p>In this blog post, we will explore the rationale behind our unique distribution, detailing the powerful additional features it brings to the table. We will provide an overview of how these enhancements can be utilized with our distribution, the standard OTel SDK, or the vanilla OTel Java agent. Stay tuned as we conclude with a look ahead at our future plans and what you can expect from Elastic contributions to OTel Java moving forward.</p>
<h2>Elastic Distribution of OpenTelemetry Java (EDOT Java)</h2>
<p>Until now, Elastic users looking to monitor their Java services through automatic instrumentation had two options: the proprietary Elastic APM Java agent or the vanilla OTel Java agent. While both agents offer robust capabilities and have reached a high level of maturity, each has its distinct advantages and limitations. The OTel Java agent provides extensive instrumentation across a broad spectrum of frameworks and libraries, is highly extensible, and natively emits OTel data. Conversely, the Elastic APM Java agent includes several powerful features absent in the OTel Java agent.</p>
<p>Elastic’s distribution of the OTel Java agent aims to bring together the best aspects of the proprietary Elastic Java agent and the OpenTelemetry Java agent. This distribution enhances the vanilla OTel Java agent with a set of additional features realized through extensions, while still being a fully compatible drop-in replacement.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/elastic-distribution-opentelemetry-java-agent/1.png" alt="Elastic distribution of the OpenTelemetry Java agent" /></p>
<p>Elastic’s commitment to OpenTelemetry not only focuses on standardizing data collection around OTel but also includes improving OTel components and integrating Elastic's data collection features into OTel. In this vein, our ultimate goal is to contribute as many features from Elastic’s distribution back to the upstream OTel Java agent; our distribution is designed in such a way that the additional features, realized as extensions, work directly with the OTel SDK. This means they can be used independent of Elastic’s distro — either with the Otel Java SDK or with the vanilla OTel Java agent. We’ll discuss these usage patterns further in the sections below.</p>
<h2>Features included</h2>
<p>The Elastic distribution of the OpenTelemetry Java agent includes a suite of extensions that deliver the features outlined below.</p>
<h3>Inferred spans</h3>
<p>In a <a href="https://www.elastic.co/observability-labs/blog/tracing-data-inferred-spans-opentelemetry">recent blog post</a>, we introduced inferred spans, a powerful feature designed to enhance distributed traces with additional profiling-based spans.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/elastic-distribution-opentelemetry-java-agent/2.png" alt="Inferred spans" /></p>
<p>Inferred spans (blue spans labeled “internal” in the above image) offer valuable insights into sources of latency within the code that might remain uncaptured by purely instrumentation-based traces. In other words, they fill in the gaps between instrumentation-based traces. The Elastic distribution of the OTel Java agent includes the inferred spans feature. It can be enabled by setting the following environment variable.</p>
<pre><code class="language-bash">ELASTIC_OTEL_INFERRED_SPANS_ENABLED=true
</code></pre>
<h3>Correlation with profiling</h3>
<p>With <a href="https://opentelemetry.io/blog/2024/profiling/">OpenTelemetry embracing profiling</a> and <a href="https://www.elastic.co/blog/elastic-donation-proposal-to-contribute-profiling-agent-to-opentelemetry">Elastic's proposal to donate its eBPF-based, continuous profiling agent</a>, a new frontier opens up in correlating distributed traces with continuous profiling data. This integration offers unprecedented code-level insights into latency issues and CO2 emission footprints, all within a clearly defined service, transaction, and trace context. To get started, follow <a href="https://www.elastic.co/observability-labs/blog/universal-profiling-with-java-apm-services-traces">this guide</a> to setup universal profiling and the OpenTelemetry integration. In order to get more background information on the feature, check out <a href="https://www.elastic.co/blog/continuous-profiling-distributed-tracing-correlation">this blog article</a>, where we explore how these technologies converge to enhance observability and environmental consciousness in software development.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/elastic-distribution-opentelemetry-java-agent/3.png" alt="Correlation with profiling" /></p>
<p>Users of Elastic Universal Profiling can already leverage the Elastic distribution of the OTel Java agent to access this powerful integration. With Elastic's proposed donation of the profiling agent, we anticipate that this capability will soon be available to all OTel users who employ the OTel Java agent in conjunction with the new OTel eBPF profiling.</p>
<h3>Span stack traces</h3>
<p>In many cases, spans within a distributed trace are relatively coarse-grained, particularly when features like inferred spans are not used. Understanding precisely where in the code path a span originates can be incredibly valuable. To address this need, the Elastic distribution of the OTel Java agent includes the span stack traces feature. This functionality provides crucial insights by collecting corresponding stack traces for spans that exceed a configurable minimum duration, pinpointing exactly where a span is initiated in the code.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/elastic-distribution-opentelemetry-java-agent/4.png" alt="Span stack traces" /></p>
<p>This simple yet powerful feature significantly enhances problem troubleshooting, offering developers a clearer understanding of their application’s performance dynamics.</p>
<p>In the example above, it allows you to get the call stack of a gRPC call, which can help understanding which code paths triggered it.</p>
<h3>Auto-detection of service and cloud resources</h3>
<p>In today's expansive and diverse cloud environments, which often include multiple regions and cloud providers, having information on where your services are operating is incredibly valuable. Particularly in Java services, where the service name is frequently embedded within the deployment artifacts, the ability to automatically retrieve service and cloud resource information marks a substantial leap in usability.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/elastic-distribution-opentelemetry-java-agent/5.png" alt="Auto-detection of service and cloud resources" /></p>
<p>To address this need, the Elastic distribution of the OTel Java agent includes built-in auto detectors for service and cloud resources, specifically for AWS and GCP, sourced from <a href="https://github.com/open-telemetry/opentelemetry-java-contrib">the OpenTelemetry Java Contrib repository</a>. This feature, which is on by default, enhances observability and streamlines the management of services across various cloud platforms, making it a key asset for any cloud-based deployment.</p>
<h2>Ways to use the EDOT Java</h2>
<p>The Elastic distribution of the OTel Java agent is designed to meet our users exactly where they are, accommodating a variety of needs and strategic approaches. Whether you're looking to fully integrate new observability features or simply enhance existing setups, the Elastic distribution offers multiple technical pathways to leverage its capabilities. This flexibility ensures that users can tailor the agent's implementation to align perfectly with their specific operational requirements and goals.</p>
<h3>Using Elastic’s distribution directly</h3>
<p>The most straightforward path to harnessing the capabilities described above is by adopting the Elastic distribution of the OTel Java agent as a drop-in replacement for the standard OTel Java agent. Structurally, the Elastic distro functions as a wrapper around the OTel Java agent, maintaining full compatibility with all upstream configuration options and incorporating all its features. Additionally, it includes the advanced features described above that significantly augment its functionality. Users of the Elastic distribution will also benefit from the comprehensive technical support provided by Elastic, which will commence once the agent achieves general availability. To get started, simply <a href="https://mvnrepository.com/artifact/co.elastic.otel/elastic-otel-javaagent">download the agent Jar file</a> and attach it to your application:</p>
<pre><code class="language-bash">​​java -javaagent:/pathto/elastic-otel-javaagent.jar -jar myapp.jar
</code></pre>
<h3>Using Elastic’s extensions with the vanilla OTel Java agent</h3>
<p>If you prefer to continue using the vanilla OTel Java agent but wish to take advantage of the features described above, you have the flexibility to do so. We offer a separate agent extensions package specifically designed for this purpose. To integrate these enhancements, simply <a href="https://mvnrepository.com/artifact/co.elastic.otel/elastic-otel-agentextension">download and place the extensions jar file</a> into a designated directory and configure the OTel Java agent extensions directory:</p>
<pre><code class="language-bash">​​OTEL_JAVAAGENT_EXTENSIONS=/pathto/elastic-otel-agentextension.jar
java -javaagent:/pathto/otel-javaagent.jar -jar myapp.jar
</code></pre>
<h3>Using Elastic’s extensions manually with the OTel Java SDK</h3>
<p>If you build your instrumentations directly into your applications using the OTel API and rely on the OTel Java SDK instead of the automatic Java agent, you can still use the features we've discussed. Each feature is designed as a standalone component that can be integrated with the OTel Java SDK framework. To implement these features, simply refer to the specific descriptions for each one to learn how to configure the OTel Java SDK accordingly:</p>
<ul>
<li><a href="https://github.com/elastic/elastic-otel-java/tree/main/inferred-spans">Setting up the inferred spans feature with the SDK</a></li>
<li><a href="https://github.com/elastic/elastic-otel-java/tree/main/universal-profiling-integration">Setting up profiling correlation with the SDK</a></li>
<li><a href="https://github.com/open-telemetry/opentelemetry-java-contrib/tree/main/span-stacktrace">Setting up the span stack traces feature with the SDK</a></li>
<li>Setting up resource detectors with the SDK
<ul>
<li><a href="https://github.com/open-telemetry/opentelemetry-java-contrib/tree/main/resource-providers">Service resource detectors</a></li>
<li><a href="https://github.com/open-telemetry/opentelemetry-java-contrib/tree/main/aws-resources">AWS resource detector</a></li>
<li><a href="https://github.com/open-telemetry/opentelemetry-java-contrib/tree/main/gcp-resources">GCP resource detector</a></li>
</ul>
</li>
</ul>
<p>This approach ensures that you can tailor your observability tools to meet your specific needs without compromising on functionality.</p>
<h2>Future plans and contributions</h2>
<p>We are committed to OpenTelemetry, and our contributions to the OpenTelemetry Java project will continue without limit. Not only are we focused on general improvements within the OTel Java project, but we are also committed to ensuring that the features discussed in this blog post become official extensions to the OpenTelemetry Java SDK/Agent and are included in the OpenTelemetry Java Contrib repository. We have already contributed the <a href="https://github.com/open-telemetry/opentelemetry-java-contrib/tree/main/span-stacktrace">span stack trace feature</a> and initiated the contribution of the inferred spans feature, and we are eagerly anticipating the opportunity to add the profiling correlation feature following the successful integration of Elastic’s profiling agent.</p>
<p>Moreover, our efforts extend beyond the current enhancements; we are actively working to port more features from the Elastic APM Java agent to OpenTelemetry. A particularly ambitious yet thrilling endeavor is our project to enable dynamic configurability of the OpenTelemetry Java agent. This future enhancement will allow for the OpenTelemetry Agent Management Protocol (OpAMP) to be used to remotely and dynamically configure OTel Java agents, improving their adaptability and ease of use.</p>
<p>We encourage you to experience the new Elastic distribution of the OTel Java agent and share your feedback with us. Your insights are invaluable as we strive to enhance the capabilities and reach of OpenTelemetry, making it even more powerful and user-friendly.</p>
<p>Check out more information on Elastic Distributions of OpenTelemetry in <a href="https://github.com/elastic/opentelemetry?tab=readme-ov-file">github</a> and our latest <a href="https://www.elastic.co/observability-labs/blog/elastic-distributions-opentelemetry">EDOT Blog</a></p>
<p>Elastic provides the following components of EDOT:</p>
<ul>
<li>
<p><a href="https://www.elastic.co/observability-labs/blog/elastic-distribution-opentelemetry-collector">Elastic Distribution of OpenTelemetry (EDOT) Collector</a></p>
</li>
<li>
<p><a href="https://www.elastic.co/observability-labs/blog/elastic-distribution-opentelemetry-java-agent">Elastic Distribution of OpenTelemetry (EDOT) Java</a>.</p>
</li>
<li>
<p><a href="https://www.elastic.co/observability-labs/blog/elastic-opentelemetry-distribution-python">Elastic Distribution of OpenTelemetry (EDOT) Python</a></p>
</li>
<li>
<p><a href="https://www.elastic.co/observability-labs/blog/elastic-opentelemetry-distribution-node-js">Elastic Distribution of OpenTelemetry (EDOT) NodeJS</a></p>
</li>
<li>
<p><a href="https://www.elastic.co/observability-labs/blog/elastic-opentelemetry-distribution-dotnet-applications">Elastic Distribution of OpenTelemetry (EDOT) .NET</a></p>
</li>
<li>
<p><a href="https://www.elastic.co/observability-labs/blog/apm-ios-android-native-apps">Elastic Distribution of OpenTelemetry (EDOT)  iOS and Android</a></p>
</li>
</ul>
<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>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/elastic-distribution-opentelemetry-java-agent/observability-launch-series-3-java-auto.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Introducing Elastic Distributions of OpenTelemetry]]></title>
            <link>https://www.elastic.co/observability-labs/blog/elastic-distributions-opentelemetry</link>
            <guid isPermaLink="false">elastic-distributions-opentelemetry</guid>
            <pubDate>Thu, 15 Aug 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Elastic is proud to introduce Elastic Distributions of OpenTelemetry (EDOT), which contains Elastic’s versions of the OpenTelemetry Collector and several language SDKs like Python, Java, .NET, and NodeJS. These help provide enhanced features and enterprise-grade support for EDOT.]]></description>
            <content:encoded><![CDATA[<p>We are announcing the availability of Elastic Distributions of OpenTelemetry (EDOT). These Elastic distributions, currently in tech preview,  have been developed to enhance the capabilities of standard OpenTelemetry distributions and improve existing OpenTelemetry support from Elastic. </p>
<p>The Elastic Distributions of OpenTelemetry (EDOT) are composed of OpenTelemetry (OTel) project components, OTel Collector, and language SDKs,  which provide users with the necessary capabilities and out-of-the-box configurations, enabling quick and effortless infra and application monitoring.</p>
<p>While OTel components are feature-rich, enhancements through the community can take time. Additionally, support is left up to the community or individual users and organizations. Hence EDOT will bring the following to end users:</p>
<ul>
<li>
<p><strong>Deliver enhanced features earlier than OTel</strong>: By providing features unavailable in the “vanilla” OpenTelemetry components, we can quickly meet customers’ requirements while still providing an OpenTelemetry native and vendor-agnostic instrumentation for their applications. Elastic will continuously upstream these enhanced features.</p>
</li>
<li>
<p><strong>Enhanced OTel support</strong> - By maintaining Elastic distributions, we can better support customers with enhancements and fixes outside of the OTel release cycles. In addition, Elastic support can troubleshoot issues on the EDOT.</p>
</li>
</ul>
<p>EDOT currently includes the following tech preview components, which will  grow over time:</p>
<ul>
<li>
<p><a href="https://www.elastic.co/observability-labs/blog/elastic-distribution-opentelemetry-collector">Elastic Distribution of OpenTelemetry (EDOT) Collector</a></p>
</li>
<li>
<p><a href="https://www.elastic.co/observability-labs/blog/elastic-distribution-opentelemetry-java-agent">Elastic Distribution of OpenTelemetry (EDOT) Java</a>.</p>
</li>
<li>
<p><a href="https://www.elastic.co/observability-labs/blog/elastic-opentelemetry-distribution-python">Elastic Distribution of OpenTelemetry (EDOT) Python</a></p>
</li>
<li>
<p><a href="https://www.elastic.co/observability-labs/blog/elastic-opentelemetry-distribution-node-js">Elastic Distribution of OpenTelemetry (EDOT) NodeJS</a></p>
</li>
<li>
<p><a href="https://www.elastic.co/observability-labs/blog/elastic-opentelemetry-distribution-dotnet-applications">Elastic Distribution of OpenTelemetry (EDOT) .NET</a></p>
</li>
<li>
<p><a href="https://www.elastic.co/observability-labs/blog/apm-ios-android-native-apps">Elastic Distribution of OpenTelemetry (EDOT)  iOS and Android</a></p>
</li>
</ul>
<p>Details and documentation for all EDOT are available in our public <a href="https://github.com/elastic/opentelemetry">OpenTelemetry GitHub repository</a>. </p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/elastic-distributions-opentelemetry/edot-components.png" alt="EDOT Components" /></p>
<h2>Elastic Distribution of OpenTelemetry (EDOT) Collector&lt;a id=&quot;elastic-distribution-of-opentelemetry-edot-collector&quot;&gt;&lt;/a&gt;</h2>
<p>The EDOT Collector, recently released with the 8.15 release of Elastic Observability enhances Elastic’s existing OTel capabilities. The EDOT Collector can, in addition to service monitoring, forward application logs, infrastructure logs, and metrics using standard OpenTelemetry Collector receivers like file logs and host metrics receivers.</p>
<p>Additionally, users of the Elastic Distribution of the OpenTelemetry Collector benefit from container logs automatically enriched with Kubernetes metadata by leveraging the powerful <a href="https://opentelemetry.io/blog/2024/otel-collector-container-log-parser/">container log parser</a> that Elastic recently contributed. This OpenTelemetry-based enrichment enhances the context and value of the collected logs, providing deeper insights and more effective troubleshooting capabilities.</p>
<p>This new collector distribution ensures that exported data is fully compatible with the Elastic Platform, enhancing the overall observability experience. Elastic also ensures that Elastic-curated UIs can seamlessly handle both the Elastic Common Schema (ECS) and OpenTelemetry formats.</p>
<h2>Elastic Distributions for Language SDKs&lt;a id=&quot;elastic-distributions-for-language-sdks&quot;&gt;&lt;/a&gt;</h2>
<p><a href="https://www.elastic.co/guide/en/apm/agent/index.html">Elastic's APM agents</a> have capabilities yet to be available in the OTel SDKs. EDOT brings these capabilities into the OTel language SDKs while maintaining seamless integration with Elastic Observability. Elastic will release OTel versions of all its APM agents, and continue to add additional language SDKs mirroring OTel.</p>
<h2>Continued support for Native OTel components&lt;a id=&quot;continued-support-for-native-otel-components&quot;&gt;&lt;/a&gt;</h2>
<p>EDOT does not preclude users from using native components. Users are still able to use:</p>
<ul>
<li>
<p><strong>OpenTelemetry Vanilla Language SDKs:</strong> use standard OpenTelemetry code instrumentation for many popular programming languages sending OTLP traces to Elastic via APM server.</p>
</li>
<li>
<p><strong>Upstream Distribution of OpenTelemetry Collector (Contrib or Custom):</strong> Send traces using the OpenTelemetry Collector with OTLP receiver and OTLP exporter to Elastic via APM server.</p>
</li>
</ul>
<p>Elastic is committed to contributing EDOT features or components upstream into the OpenTelemetry community, fostering a collaborative environment, and enhancing the overall OpenTelemetry ecosystem.</p>
<h2>Extending our commitment to vendor-agnostic data collection&lt;a id=&quot;extending-our-commitment-to-vendor-agnostic-data-collection&quot;&gt;&lt;/a&gt;</h2>
<p>Elastic remains committed to supporting OpenTelemetry by being OTel first and building a vendor-agnostic framework. As OpenTelemetry constantly grows its support of SDKs and components,  Elastic will continue to refine and mirror EDOT to OpenTelemetry and push enhancements upstream. </p>
<p>Over the past year, Elastic has been active in OTel through its <a href="https://opentelemetry.io/blog/2023/ecs-otel-semconv-convergence/">donation of Elastic Common Schema (ECS)</a>, contributions to the native <a href="https://www.elastic.co/observability-labs/blog/elastic-distribution-opentelemetry-collector">OpenTelemetry Collector</a> and language SDKs, and a recent <a href="https://www.elastic.co/observability-labs/blog/elastic-profiling-agent-acceptance-opentelemetry">donation of its Universal Profiling agent</a> to OpenTelemetry. </p>
<p>EDOT  builds on our decision to fully adopt and recommend OpenTelemetry as the preferred solution for observing applications. With EDOT, Elastic customers can future-proof their investments and adopt OpenTelemetry, giving them vendor-neutral instrumentation with Elastic enterprise-grade support.</p>
<p>Our vision is that Elastic will work with the OpenTelemetry community to donate features through the standardization processes and contribute the code to implement those in the native OpenTelemetry components. In time, as OTel capabilities advance, and many of the Elastic-exclusive features transition into OpenTelemetry, we look forward to no longer having Elastic Distributions for OpenTelemetry.. In the meantime, we can deliver those capabilities via our OpenTelemetry distributions.</p>
]]></content:encoded>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/elastic-distributions-opentelemetry/edot-image.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[OpenTelemetry and Elastic: Working together to establish continuous profiling for the community]]></title>
            <link>https://www.elastic.co/observability-labs/blog/elastic-donation-proposal-to-contribute-profiling-agent-to-opentelemetry</link>
            <guid isPermaLink="false">elastic-donation-proposal-to-contribute-profiling-agent-to-opentelemetry</guid>
            <pubDate>Tue, 12 Mar 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[OpenTelemetry is embracing profiling. Elastic is donating its whole-system continuous profiling agent to OpenTelemetry to further this advancement, empowering OTel users to improve computational efficiency and reduce their carbon footprint.]]></description>
            <content:encoded><![CDATA[<p>Profiling is emerging as a core pillar of observability, aptly dubbed the fourth pillar, with the OpenTelemetry (OTel) project leading this essential development. This blog post dives into the recent advancements in profiling within OTel and how Elastic® is actively contributing toward it.</p>
<p>At Elastic, we’re big believers in and contributors to the OpenTelemetry project. The project’s benefits of flexibility, performance, and vendor agnosticism have been making their rounds; we’ve seen a groundswell of customer interest.</p>
<p>To this end, after donating our <a href="https://www.elastic.co/blog/ecs-elastic-common-schema-otel-opentelemetry-faq"><strong>Elastic Common Schema</strong></a> and our <a href="https://www.elastic.co/blog/elastic-invokedynamic-opentelemetry-java-agent">invokedynamic based java agent approach</a>, we recently <a href="https://github.com/open-telemetry/community/issues/1918">announced our intent to donate our continuous profiling agent</a> — a whole-system, always-on, continuous profiling solution that eliminates the need for run-time/bytecode instrumentation, recompilation, on-host debug symbols, or service restarts.</p>
<p>Profiling helps organizations run efficient services by minimizing computational wastage, thereby reducing operational costs. Leveraging <a href="https://ebpf.io/">eBPF</a>, the Elastic profiling agent provides unprecedented visibility into the runtime behavior of all applications: it builds stacktraces that go from the kernel, through userspace native code, all the way into code running in higher level runtimes, enabling you to identify performance regressions, reduce wasteful computations, and debug complex issues faster.</p>
<h2>Enabling profiling in OpenTelemetry: A step toward unified observability</h2>
<p>Elastic actively participates in the OTel community, particularly within the Profiling Special Interest Group (SIG). This group has been instrumental in defining the OTel <a href="https://github.com/open-telemetry/oteps/blob/main/text/profiles/0239-profiles-data-model.md">Profiling Data Model</a>, a crucial step toward standardizing profiling data.</p>
<p>The recent merger of the <a href="https://github.com/open-telemetry/oteps/pull/239">OpenTelemetry Enhancement Proposal (OTEP) introducing profiling support to the OpenTelemetry Protocol (OTLP)</a> marks a significant milestone. With the standardization of profiles as a core observability pillar alongside metrics, tracing, and logs, OTel offers a comprehensive suite of observability tools, empowering users to gain a holistic view of their applications' health and performance.</p>
<p>In line with this advancement, we are donating our whole-system, eBPF-based continuous profiling agent to OTel. In parallel, we are implementing the experimental OTel Profiling signal in the profiling agent, to ensure and demonstrate OTel protocol compatibility in the agent and prepare it for a fully OTel-based collection of profiling signals and correlate it to logs, metrics, and traces.</p>
<h2>Why is Elastic donating the eBPF-based profiling agent to OpenTelemetry?</h2>
<p>Computational efficiency has always been a critical concern for software professionals. However, in an era where every line of code affects both the bottom line and the environment, there's an additional reason to focus on it. Elastic is committed to helping the OpenTelemetry community enhance computational efficiency because efficient software not only reduces the cost of goods sold (COGS) but also reduces carbon footprint.</p>
<p>We have seen firsthand — both internally and from our customers' testimonials — how profiling insights aid in enhancing software efficiency. This results in an improved customer experience, lower resource consumption, and reduced cloud costs.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/elastic-donation-proposal-to-contribute-profiling-agent-to-opentelemetry/1-flamegraph.png" alt="A differential flamegraph showing regression in release comparison" /></p>
<p>Moreover, adopting a whole-system profiling strategy, such as <a href="https://www.elastic.co/blog/whole-system-visibility-elastic-universal-profiling">Elastic Universal Profiling</a>, differs significantly from traditional instrumentation profilers that focus solely on runtime. Elastic Universal Profiling provides whole-system visibility, profiling not only your own code but also third-party libraries, kernel operations, and other code you don't own. This comprehensive approach facilitates rapid optimizations by identifying non-optimal common libraries and uncovering &quot;unknown unknowns&quot; that consume CPU cycles. Often, a tipping point is reached when the resource consumption of libraries or certain daemon processes exceeds that of the applications themselves. Without system-wide profiling, along with the capabilities to slice data per service and aggregate total usage, pinpointing these resource-intensive components becomes a formidable challenge.</p>
<p>At Elastic, we have a customer with an extensive cloud footprint who plans to negotiate with their cloud provider to reclaim money for the significant compute resource consumed by the cloud provider's in-VM agents. These examples highlight the importance of whole-system profiling and the benefits that the OpenTelemetry community will gain if the donation proposal is accepted.</p>
<p>Specifically, OTel users will gain access to a lightweight, battle-tested production-grade continuous profiling agent with the following features:</p>
<ul>
<li>
<p>Very low CPU and memory overhead (1% CPU and 250MB memory are our upper limits in testing, and the agent typically manages to stay way below that)</p>
</li>
<li>
<p>Support for native C/C++ executables without the need for DWARF debug information by leveraging .eh_frame data, as described in “<a href="https://www.elastic.co/blog/universal-profiling-frame-pointers-symbols-ebpf">How Universal Profiling unwinds stacks without frame pointers and symbols</a>”</p>
</li>
<li>
<p>Support profiling of system libraries without frame pointers and without debug symbols on the host</p>
</li>
<li>
<p>Support for mixed stacktraces between runtimes — stacktraces go from Kernel space through unmodified system libraries all the way into high-level languages</p>
</li>
<li>
<p>Support for native code (C/C++, Rust, Zig, Go, etc. without debug symbols on host)</p>
</li>
<li>
<p>Support for a broad set of High-level languages (Hotspot JVM, Python, Ruby, PHP, Node.JS, V8, Perl), .NET is in preparation</p>
</li>
<li>
<p><strong>100% non-intrusive:</strong> there's no need to load agents or libraries into the processes that are being profiled</p>
</li>
<li>
<p>No need for any reconfiguration, instrumentation, or restarts of HLL interpreters and VMs: the agent supports unwinding each of the supported languages in the default configuration</p>
</li>
<li>
<p>Support for x86 and Arm64 CPU architectures</p>
</li>
<li>
<p>Support for native inline frames, which provide insights into compiler optimizations and offer a higher precision of function call chains</p>
</li>
<li>
<p>Support for <a href="https://www.elastic.co/guide/en/observability/current/profiling-probabilistic-profiling.html">Probabilistic Profiling</a> to reduce data storage costs</p>
</li>
<li>
<p>. . . and more</p>
</li>
</ul>
<p>Elastic's commitment to enhancing computational efficiency and our belief in the OpenTelemetry vision underscores our dedication to advancing the observability ecosystem –– by donating the profiling agent. Elastic is not only contributing technology but also dedicating a team of specialized profiling domain experts to co-maintain and advance the profiling capabilities within OpenTelemetry.</p>
<h2>How does this donation benefit the OTel community?</h2>
<p>Metrics, logs, and traces offer invaluable insights into system health. But what if you could unlock an even deeper level of visibility? Here's why profiling is a perfect complement to your OTel toolkit:</p>
<h3>1. Deep system visibility: Beyond the surface</h3>
<p>Think of whole-system profiling as an MRI scan for your fleet. It goes deeper into the internals of your system, revealing hidden performance issues lurking beneath the surface. You can identify &quot;unknown unknowns&quot; — inefficiencies you wouldn't have noticed otherwise — and gain a comprehensive understanding of how your system functions at its core.</p>
<h3>2. Cross-signal correlation: Answering &quot;why&quot; with confidence</h3>
<p>The Elastic Universal Profiling agent supports trace correlation with the OTel Java agent/SDK (with Go support coming soon!). This correlation enables OTel users to view profiling data by services or service endpoints, allowing for a more context-aware and targeted root cause analysis. This powerful combination allows you to pinpoint the exact cause of resource consumption at the trace level. No more guessing why specific functions hog CPU or why certain events occur. You can finally answer the critical &quot;why&quot; questions with precision, enabling targeted optimization efforts.</p>
<h3>3. Cost and sustainability optimization: Beyond performance</h3>
<p>Our approach to profiling goes beyond just performance gains. By correlating whole-system profiling data with tracing, we can help you measure the environmental impact and cloud cost associated with specific services and functionalities within your application. This empowers you to make data-driven decisions that optimize both performance and resource utilization, leading to a more sustainable and cost-effective operation.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/elastic-donation-proposal-to-contribute-profiling-agent-to-opentelemetry/2-universal-profiling.png" alt="A differential function insight, showing the performance, cost, and CO2 impact of a change" /></p>
<h2>Elastic's commitment to OpenTelemetry</h2>
<p>Elastic currently supports a growing list of Cloud Native Computing Foundation (CNCF) projects <a href="https://www.elastic.co/blog/kubernetes-k8s-observability-elasticsearch-cncf">such as Kubernetes (K8S), Prometheus, Fluentd, Fluent Bit, and Istio</a>. <a href="https://www.elastic.co/observability/application-performance-monitoring">Elastic’s application performance monitoring (APM)</a> also natively supports OTel, ensuring all APM capabilities are available with either Elastic or OTel agents or a combination of the two. In addition to the ECS contribution and ongoing collaboration with OTel SemConv, Elastic <a href="https://www.elastic.co/observability/opentelemetry">has continued to make contributions to other OTel projects</a>, including language SDKs (such as OTel Swift, OTel Go, OTel Ruby, and others), and participates in several <a href="https://github.com/open-telemetry/community#special-interest-groups">special interest groups (SIGs)</a> to establish OTel as a standard for observability and security.</p>
<p>We are excited about our <a href="https://opentelemetry.io/blog/2023/ecs-otel-semconv-convergence/">strengthening relationship with OTel</a> and the opportunity to donate our profiling agent in a way that benefits both the Elastic community and the broader OTel community.Learn more about <a href="https://www.elastic.co/observability/opentelemetry">Elastic’s OpenTelemetry support</a> or contribute to the <a href="https://github.com/open-telemetry/community/issues/1918">donation proposal or just join the conversation</a>.</p>
<p>Stay tuned for further updates as the profiling part of OTel continues to evolve.</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>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/elastic-donation-proposal-to-contribute-profiling-agent-to-opentelemetry/ecs-otel-announcement-1.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Elastic's contribution: Invokedynamic in the OpenTelemetry Java agent]]></title>
            <link>https://www.elastic.co/observability-labs/blog/invokedynamic-opentelemetry-java-agent</link>
            <guid isPermaLink="false">invokedynamic-opentelemetry-java-agent</guid>
            <pubDate>Thu, 19 Oct 2023 00:00:00 GMT</pubDate>
            <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>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>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/invokedynamic-opentelemetry-java-agent/24-crystals.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Elastic contributes its Universal Profiling agent to OpenTelemetry]]></title>
            <link>https://www.elastic.co/observability-labs/blog/elastic-profiling-agent-acceptance-opentelemetry</link>
            <guid isPermaLink="false">elastic-profiling-agent-acceptance-opentelemetry</guid>
            <pubDate>Thu, 06 Jun 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Elastic is advancing the adoption of OpenTelemetry with the contribution of its universal profiling agent. Elastic is committed to ensuring a vendor-agnostic ingestion and collection of observability and security telemetry through OpenTelemetry.]]></description>
            <content:encoded><![CDATA[<p>Following great collaboration between Elastic and OpenTelemetry's profiling community, which included a thorough review process, the OpenTelemetry community has accepted Elastic's donation of our continuous profiling agent. This marks a significant milestone in helping establish profiling as the fourth telemetry signal in OpenTelemetry. Elastic’s eBPF-based continuous profiling agent observes code across different programming languages and runtimes, third-party libraries, kernel operations, and system resources with low CPU and memory overhead in production. SREs can now benefit from these capabilities: quickly identifying performance bottlenecks, maximizing resource utilization, reducing carbon footprint, and optimizing cloud spend.
Over the past year, we have been instrumental in <a href="https://opentelemetry.io/blog/2023/ecs-otel-semconv-convergence/">enhancing OpenTelemetry's Semantic Conventions</a> with the donation of Elastic Common Schema (ECS), contributing to the OpenTelemetry Collector and language SDKs, and have been working with OpenTelemetry’s Profiling Special Interest Group (SIG) to lay the foundation necessary to make profiling stable.</p>
<p>With today’s acceptance, we are officially contributing our continuous profiler technology to OpenTelemetry. We will also dedicate a team of profiling domain experts to co-maintain and advance the profiling capabilities within OTel.</p>
<p>We want to thank the OpenTelemetry community for the great and constructive cooperation on the donation proposal. We look forward to jointly establishing continuous profiling as an integral part of OpenTelemetry.</p>
<h2>What is continuous profiling?</h2>
<p>Profiling is a technique used to understand the behavior of a software application by collecting information about its execution. This includes tracking the duration of function calls, memory usage, CPU usage, and other system resources.</p>
<p>However, traditional profiling solutions have significant drawbacks limiting adoption in production environments:</p>
<ul>
<li>Significant cost and performance overhead due to code instrumentation</li>
<li>Disruptive service restarts</li>
<li>Inability to get visibility into third-party libraries</li>
</ul>
<p>Unlike traditional profiling, which is often done only in a specific development phase or under controlled test conditions, continuous profiling runs in the background with minimal overhead. This provides real-time, actionable insights without replicating issues in separate environments. SREs, DevOps, and developers can see how code affects performance and cost, making code and infrastructure improvements easier.</p>
<h2>Contribution of production-grade features</h2>
<p>Elastic Universal Profiling is a whole-system, always-on, continuous profiling solution that eliminates the need for code instrumentation, recompilation, on-host debug symbols or service restarts. Leveraging eBPF, Elastic Universal Profiling profiles every line of code running on a machine, including application code, kernel, and third-party libraries. The solution measures code efficiency in three dimensions, CPU utilization, CO2, and cloud cost, to help organizations manage efficient services by minimizing computational waste.</p>
<p>The Elastic profiling agent facilitates identifying non-optimal code paths, uncovering &quot;unknown unknowns&quot;, and provides comprehensive visibility into the runtime behavior of all applications. Elastic’s continuous profiling agent supports various runtimes and languages, such as C/C++, Rust, Zig, Go, Java, Python, Ruby, PHP, Node.js, V8, Perl, and .NET.</p>
<p>Additionally, organizations can meet sustainability objectives by minimizing computational wastage, ensuring seamless alignment with their strategic <a href="https://en.wikipedia.org/wiki/Environmental,_social,_and_corporate_governance">ESG</a> goals.</p>
<h2>Benefits to OpenTelemetry</h2>
<p>This contribution not only boosts the standardization of continuous profiling for observability but also accelerates the practical adoption of profiling as the fourth key signal in OTel. Customers get a vendor-agnostic way of collecting profiling data and enabling correlation with existing signals, like tracing, metrics, and logs, opening <a href="https://www.elastic.co/blog/continuous-profiling-distributed-tracing-correlation">new potential for observability insights and a more efficient troubleshooting experience</a>. </p>
<p>OTel-based continuous profiling unlocks the following possibilities for users:</p>
<ul>
<li>Improved customer experience: delivering consistent service quality and performance through continuous profiling ensures customers have an application that performs optimally, remains responsive, and is reliable.</li>
</ul>
<ul>
<li>Maximize gross margins: Businesses can optimize their cloud spend and improve profitability by reducing the computational resources needed to run applications. Whole system continuous profiling identifies the most expensive functions (down to the lines of code) across diverse environments that may span multiple cloud providers. In the cloud context, every CPU cycle saved translates to money saved. </li>
</ul>
<ul>
<li>Minimize environmental impact: energy consumption associated with computing is a growing concern (source: <a href="https://energy.mit.edu/news/energy-efficient-computing/">MIT Energy Initiative</a> ). More efficient code translates to lower energy consumption, reducing carbon (CO2) footprint. </li>
</ul>
<ul>
<li>Accelerate engineering workflows: continuous profiling provides detailed insights to help troubleshoot complex issues faster, guide development, and improve overall code quality.</li>
</ul>
<ul>
<li>Improved vendor neutrality and increased efficiency: an OTel eBPF-based profiling agent removes the need to use proprietary APM agents and offers a more efficient way to collect profiling telemetry.</li>
</ul>
<p>With these benefits, customers can now manage the overall application’s efficiency on the cloud while ensuring their engineering teams optimize it.</p>
<h2>What comes next?</h2>
<p>While the acceptance of Elastic’s donation of the profiling agent marks a significant milestone in the evolution of OTel’s eBPF-based continuous profiling capabilities, it represents the beginning of a broader journey. Moving forward, we will continue collaborating closely with the OTel Profiling and Collector SIGs to ensure seamless integration of the profiling agent within the broader OTel ecosystem. During this phase, users can test early preview versions of the OTel profiling integration by following the directions in the <a href="https://github.com/elastic/otel-profiling-agent/">otel-profiling-agent</a> repository.</p>
<p>Elastic remains deeply committed to OTel’s vision of enabling cross-signal correlation. We plan to further contribute to the community by sharing our innovative research and implementations, specifically those facilitating the correlation between profiling data and distributed traces, across several OTel language SDKs and the profiling agent.</p>
<p>We are excited about our <a href="https://opentelemetry.io/blog/2023/ecs-otel-semconv-convergence/">growing relationship with OTel</a> and the opportunity to donate our profiling agent in a way that benefits both the Elastic community and the broader OTel community. Learn more about <a href="https://www.elastic.co/observability/opentelemetry">Elastic’s OpenTelemetry support</a> and learn how to contribute to the ongoing profiling work in the community.</p>
<h2>Additional Resources</h2>
<p>Additional details on Elastic’s Universal Profiling can be found in the <a href="https://www.elastic.co/observability-labs/blog/elastic-profiling-agent-acceptance-opentelemetry-faq">FAQ</a>.</p>
<p>For insights into observability, visit Observability labs where OTel specific articles are also available.</p>
]]></content:encoded>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/elastic-profiling-agent-acceptance-opentelemetry/profiling-acceptance.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Elastic's collaboration with OpenTelemetry on improving the filelog receiver]]></title>
            <link>https://www.elastic.co/observability-labs/blog/elastics-collaboration-opentelemetry-filelog-receiver</link>
            <guid isPermaLink="false">elastics-collaboration-opentelemetry-filelog-receiver</guid>
            <pubDate>Mon, 17 Jun 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Elastic is committed to help OpenTelemetry advance it's logging capabilities. Learn about our collaboration with the OpenTelemetry community on improving the capabilities and quality aspects of the OpenTelemetry Collector's filelog receiver.]]></description>
            <content:encoded><![CDATA[<p>As the newest generally available signal in OpenTelemetry (OTel), logging support currently lags behind tracing and metrics in terms of feature scope and maturity.
At Elastic, we bring years of extensive experience with logging use cases and the challenges they present.
Committed to advancing OpenTelemetry's logging capabilities, we have focused on enhancing its logging functionalities.</p>
<p>Over the past few months, we have dealt with the capabilities of the <a href="https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/v0.102.0/receiver/filelogreceiver/README.md">filelog receiver</a>
in the <a href="https://opentelemetry.io/docs/collector/">OpenTelemetry Collector</a>, leveraging our expertise as the <a href="https://www.elastic.co/beats/filebeat">Filebeat's</a> maintainers to help refine and expand its potential.
Our goal is to contribute meaningfully to the evolution of OpenTelemetry's logging features, ensuring they meet the high standards required for robust observability.</p>
<p>Specifically, we focused on verifying that the receiver is well covered for cases and aspects that have been a pain for us in the past with Filebeat
— such as fail-over handling, self-telemetry, test coverage, documentation and usability.
Based on our exploration, we started insightful conversations with the OTel project's maintainers, sharing our thoughts and any suggestions that could be useful from our experience.
Moreover, we've started putting up PRs to add documentation, make enhancements, improve tests, fix bugs, and even implement completely new features.</p>
<p>In this blog post we'll provide a sneak preview of the work that we've done so far in collaboration with the OpenTelemetry community and what's coming next as we continue to explore ways to improve the OpenTelemetry Collector for log collection.</p>
<h2>Enhancing the filelog receiver's telemetry</h2>
<p>Observability tools are software components like any other and, thus, need to be monitored as any other software to be able to debug problems and tune relevant settings.
In particular, users of the filelog receiver will want to know how it's performing.
It's important that the filelog receiver emits sufficient telemetry data for common troubleshooting and optimization use cases.
This includes sufficient logging and observable metrics providing insights into the filelog receiver's internal state.</p>
<p>While the filelog receiver already provided a good set of self-telemetry data, we identified some areas of improvement.
In particular, we contributed functionality to emit self-telemetry <a href="https://github.com/open-telemetry/opentelemetry-collector-contrib/pull/33237">logs on crucial events</a> like when log files are discovered, moved or truncated.
Another contribution includes <a href="https://github.com/open-telemetry/opentelemetry-collector-contrib/pull/31544">observable metrics about filelog’s receiver internal state</a> about how many files are opened and being harvested.
You can find more information on the <a href="https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/31256">respective tracking issue</a>.</p>
<h2>Improving the Kubernetes container logs parsing</h2>
<p>The filelog receiver has been able to parse Kubernetes container logs for some time now.
However, properly parsing logs from Kubernetes Pods required a fair bit of configuration to deal with different runtime formats and to extract important meta information, such as <code>k8s.pod.name</code>, <code>k8s.container.name</code>, etc.
With this in mind we proposed to abstract these complex set of configuration into a simpler implementation specific container parser and contributed this new feature to the filelog receiver.
With that new feature, setting up logs collection for Kubernetes is by magnitudes easier - with only eight lines of configuration vs. ~ 80 lines of configuration before.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/elastics-collaboration-opentelemetry-filelog-receiver/container-parser-config-example.png" alt="1 - Usability improvement for parsing Kubernetes container logs" /></p>
<p>You can learn more about the details of the new <a href="https://opentelemetry.io/blog/2024/otel-collector-container-log-parser">container logs parser in the corresponding OpenTelemetry blog post</a>.</p>
<h3>Evaluating test coverage</h3>
<p>Logs collection from files can run into different unexpected scenarios such as restarts, overload and error scenarios.
To ensure reliable and consistent collection of logs, it's important to ensure tests cover these kind of scenarios.
Based on our experience with testing Filebeat, we evaluated the existing filelog receiver tests with respect to those scenarios.
While most of the use cases and scenarios were well-tested already, we identified a few scenarios to improve tests for to ensure reliable logs collection.<br />
At the creation time of this blog posts we were working on contributing additional tests to address the identified test coverage gaps.
You can learn more about it in <a href="https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/32001">this GitHub issue</a>.</p>
<h3>Persistence evaluation</h3>
<p>Another important aspect for log collection that we often hear from Elastic's log users are the failover handling capabilities and the delivery guarantees for logs.
Some logging use cases, for example audit logging, have strict delivery guarantee requirements.
Hence, it's important that the filelog receiver provides functionality to reliably handle situations, such as temporary unavailability of the logging backend or unexpected restarts of the OTel Collector.</p>
<p>Overall, the filelog receiver already has corresponding functionality to deal with such situations.
However, user documentation on how to setup reliable logs collection with tangible examples was an area with potential for improvement.</p>
<p>In this regard, beyond verifying the persistence and offset tracking capabilities we worked on improving respective documentation
<a href="https://github.com/open-telemetry/opentelemetry-collector-contrib/pull/31886">1</a> <a href="https://github.com/open-telemetry/opentelemetry-collector-contrib/pull/30914">2</a>
and also are collaborating on a <a href="https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/31074">community reported issue</a> to ensure delivery guarantees for logs.</p>
<h3>Helping users help themselves</h3>
<p>Elastic has a long and varied history of supporting customers who use our products for log ingestion.
Drawing from this experience, we've proposed a couple of documentation improvements to the OpenTelemetry Collector to help logging users get out of some tricky situations.</p>
<p><strong>Documenting the structure of the tracking file</strong></p>
<p>For every log file the filelog receiver ingests, it needs to track how far into the file it has already read, so it knows where to start reading from when new contents are added to the file.
By default, the filelog receiver doesn't persist this tracking information to disk, but it can be configured to do so.
We felt it would be useful to <a href="https://github.com/open-telemetry/opentelemetry-collector-contrib/pull/32180">document the structure of this tracking file</a>. When ingestion stops unexpectedly,
peeking into this tracking file can often provide clues as to where the problem may lie.</p>
<p><strong>Challenges with symlink target changes</strong></p>
<p>The filelog receiver periodically refreshes its memory of the files it's supposed to be ingesting.
The interval at which these refreshes happen is controlled by the <code>poll_interval</code> setting.
In certain setups log files being ingested by the filelog receiver are symlinks pointing to actual files.
Moreover, these symlinks can be updated to point to newer files over time.
If the symlink target changes twice before the filelog receiver has had a chance to refresh its memory, it will miss the first change and therefore not ingest the corresponding target file.
We've <a href="https://github.com/open-telemetry/opentelemetry-collector-contrib/pull/32217">documented this edge case</a>, suggesting the users with such setups should make sure they set <code>poll_interval</code> to a sufficiently low value.</p>
<h3>Planning ahead for the receiver's GA </h3>
<p>Last but not least, we have raised the topic of making the filelog receiver a generally available (GA) component.
For users it's important to be able to rely on the stability of used functionality, hence, not being required to deal with the risk of breaking changes through minor version updates.
In this regard, for the filelog receiver we have kicked off a first plan with the maintainers to mark any issue that is a blocker for stability with a <code>required_for_ga</code>
<a href="https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Arelease%3Arequired-for-ga+label%3Areceiver/filelog">label</a>.
Once the OpenTelemetry collector goes to version <code>v1.0.0</code> we will be able to also work towards the specific receiver’s GA.</p>
<h2>Conclusion</h2>
<p>Overall, OTel's filelog receiver component is in a good shape and provides important functionality for most log collection use cases.
Where there are still minor gaps or need for improvement with the filelog receiver, we are gladly to contribute our expertise and experience from Filebeat use cases.
The above is just the beginning of our effort to help advancing the OpenTelemetry Collector, and specifically for log collection, get closer to a stable version.
Moreover, we are happy to help the filelog receiver maintainers with general maintenance of the component, hence, dealing with community issues and PRs, jointly working on the component's roadmap, etc.</p>
<p>We'd like to thank the OTel Collector group and, in particular, <a href="https://github.com/djaglowski">Daniel Jaglowski</a> for the great and constructive collaboration on the filelog receiver, so far!</p>
<p>Stay tuned to <a href="https://www.elastic.co/observability/opentelemetry">learn more about our future contributions and involvement in OpenTelemetry</a>.</p>
]]></content:encoded>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/elastics-collaboration-opentelemetry-filelog-receiver/otel-filelog-receiver.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Bridging the Gap: End-to-End Observability from Cloud Native to Mainframe]]></title>
            <link>https://www.elastic.co/observability-labs/blog/end-to-end-o11y-from-cloud-native-to-mainframe</link>
            <guid isPermaLink="false">end-to-end-o11y-from-cloud-native-to-mainframe</guid>
            <pubDate>Sun, 01 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Achieving end-to-end observability in hybrid enterprise environments, where modern cloud-native applications interact with critical, yet often opaque, IBM mainframe systems is a challenge. By utilizing IBM Z Observability Connect, which enables OTel output, with Elastic Observability is a solution, transforming your mainframe black box into a fully observable component in your deployment]]></description>
            <content:encoded><![CDATA[<h2>Introduction:</h2>
<p>OpenTelemetry is emerging as the standard for modern observability. As a highly active project within the Cloud Native Computing Foundation (CNCF)—second only to Kubernetes—it has become the monitoring solution of choice for cloud-native applications. OpenTelemetry provides a unified method for collecting traces, metrics, and logs across Kubernetes, microservices, and infrastructure.</p>
<p>However, for many enterprises—especially in banking, insurance, healthcare, and government—the reality is more complex than just “cloud native.” Although most organizations have deployed mobile apps and adopted microservices architectures, much of their critical core processing still relies on IBM mainframe applications. These systems process credit card swipes, financial transactions, patient records, and premium calculations.</p>
<p>This creates a dilemma: while the modern distributed systems of the hybrid environment are well-observed, the critical backend remains a black box.</p>
<h2>The “Broken Trace”</h2>
<p>A common challenge we see with customers involves a request that originates from a modern mobile application. The request hits microservices running on Kubernetes, initiates a service call to the mainframe, and suddenly, visibility stops.</p>
<p>When latency spikes or a transaction fails, Site Reliability Engineers (SREs) are left guessing. Is it the network? The API gateway? Or underlying mainframe applications like CICS? Without a unified, end-to-end view of the services involved—from the frontend Node.js microservices to the backend CICS service—mean time to resolution (MTTR) becomes “mean time to innocence,” with teams simply proving it wasn't their microservice rather than fixing root causes.</p>
<p>We need a unified view where a trace flows seamlessly from a cloud-native frontend (like React) all the way into mainframe transactions.</p>
<h2>IBM Z Observability Connect</h2>
<p>With the recent release of <a href="https://www.ibm.com/docs/en/zapmc/7.1.0?topic=z-observability-connect-overview">Z Observability Connect</a>, IBM has introduced OpenTelemetry-native instrumentation into mainframe applications. This creates a bridge between modern cloud-native services and mainframe transactions.</p>
<p>This means the mainframe is no longer a special case; it acts just like any other microservice in a mesh. It functions as an OpenTelemetry data producer, emitting traces, metrics, and logs to OpenTelemetry-compliant backends like Elastic.</p>
<h2>The Architecture</h2>
<p>The architecture is straightforward:</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/end-to-end-o11y-from-cloud-native-to-mainframe/architecture.png" alt="architecture" /></p>
<ul>
<li><strong>The Collector</strong>: <a href="https://docs.google.com/document/d/1-0gDjeM6s63AaQio1j0Cb2Pfodkr6KfSw1-q847Gzes/edit?tab=t.0#heading=h.xa5hqxwq5lps">IBM Z Observability Connect</a> runs on z/OS. It collects logs, metrics, or traces and converts them into the OTLP (OpenTelemetry Protocol) format.</li>
<li><strong>The Processor</strong>: The <a href="https://www.elastic.co/docs/reference/opentelemetry/motlp">Elastic Cloud Managed OTLP Endpoint</a> acts as a gateway collector, providing fully hosted, scalable, and reliable native OTLP ingestion.</li>
<li><strong>The Consumer</strong>: <a href="https://www.elastic.co/docs/solutions/observability/apm">Elastic APM</a> enables OpenTelemetry-native application performance monitoring, making it easy to pinpoint and fix performance problems quickly.</li>
</ul>
<h2>Putting it all together in Kubernetes</h2>
<p>We deploy an OpenTelemetry Collector within our Kubernetes cluster. This collector acts as a specialized gateway. It is configured to receive OTLP traffic directly from IBM Z Observability Connect on the mainframe and forward it securely to our observability backend, Elastic APM, by using the <code>otlp/elastic</code> exporter.</p>
<p>Here is the configuration for the OpenTelemetry Collector. Note the <code>exporters</code> section, which handles the authentication and batched transmission to Elastic:</p>
<pre><code>exporters:
  # Exporter to print the first 5 logs/metrics and then every 1000th
  debug:
    verbosity: detailed
    sampling_initial: 5
    sampling_thereafter: 1000

  # Exporter to send logs and metrics to Elasticsearch Managed OTLP Input
  otlp/elastic:
    endpoint: ${env:ELASTIC_OTLP_ENDPOINT}
    headers:
      Authorization: ApiKey ${env:ELASTIC_API_KEY}
    sending_queue:
      enabled: true
      sizer: bytes
      queue_size: 50000000 # 50MB uncompressed
      block_on_overflow: true
    batch:
      flush_timeout: 1s
      min_size: 1_000_000 # 1MB uncompressed
      max_size: 4_000_000 # 4MB uncompressed

service:
  extensions: [pprof, zpages, health_check]
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlp/elastic, debug]
</code></pre>
<p><em>Note: We strongly recommend using environment variables for your endpoints and API keys to keep your manifest secure.</em></p>
<h2>Why the OTel specification matters</h2>
<p><a href="https://www.elastic.co/docs/reference/opentelemetry/motlp">Elastic’s managed OTLP endpoint</a> and observability solution is built with native OTel support and adheres to the OTel specification and semantic conventions. Once we wired everything up and the data started to flow, we noticed that some of the traces in Elastic APM were not being represented correctly.</p>
<p>Most observability solutions derive the so-called RED metrics (rate, error, and duration) for the most important spans in a trace—i.e., incoming and outgoing spans of each individual service. This allows for an efficient indication of a service’s performance without the need to comb through all of the tracing data to show something as simple as the latency of a service’s endpoint or the error rate on outgoing requests.</p>
<p>For an efficient calculation of such derived metrics for incoming spans on a service, the <a href="https://github.com/open-telemetry/opentelemetry-specification/blob/main/oteps/0182-otlp-remote-parent.md">OTel community</a> introduced the <code>SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK</code> and <code>SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK</code> flags on the span entities within the OTLP protocol. These flags provide an unambiguous indication of whether an individual span is an entry span and, thus, allow observability backends to efficiently calculate metrics for entry-level spans.</p>
<p>If these flags are set incorrectly for an entry span, the span cannot be recognized as an entry span, and metrics are not derived properly—leading to a broken experience. This is what we initially experienced with the ingested OTel data from the IBM mainframe instrumentation.</p>
<p>In a proprietary world, this might have been a dead end or a months-long troubleshooting exercise. However, since OpenTelemetry is an open standard, we were able to debug the issue rapidly and share our findings with IBM engineers, who quickly developed a fix.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/end-to-end-o11y-from-cloud-native-to-mainframe/service_map.png" alt="service_map" /></p>
<h2>Streamline observability</h2>
<p>We now have end-to-end visibility that spans from modern mobile or web applications deep into the IBM mainframe. This unlocks significant value:</p>
<ul>
<li><strong>Unified Service Maps</strong>: You can visually see the dependency between the cloud-native cart service and the backend inventory system on z/OS.</li>
<li><strong>Single Pane of Glass</strong>: SREs no longer need to switch between modern observability tools and separate mainframe monitoring tools to view service health.</li>
<li><strong>Operational Efficiency</strong>: By eliminating the “blind spot” in the trace, you reduce the time spent on coordinating between cloud and mainframe teams, making issue resolution faster.</li>
</ul>
<h2>Conclusion</h2>
<p>If you are running hybrid workloads, it is time to stop treating your mainframe as a black box. With IBM Z Observability Connect, the Elastic Managed OTLP Endpoint, and Elastic APM, your entire stack can finally speak a single language: OpenTelemetry.</p>
]]></content:encoded>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/end-to-end-o11y-from-cloud-native-to-mainframe/end-to-end-o11y.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[How to easily add application monitoring in Kubernetes pods]]></title>
            <link>https://www.elastic.co/observability-labs/blog/application-monitoring-kubernetes-pods</link>
            <guid isPermaLink="false">application-monitoring-kubernetes-pods</guid>
            <pubDate>Wed, 17 Jan 2024 00:00:00 GMT</pubDate>
            <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>Prerequisites</h2>
<p>This walkthrough assumes that the following are already installed on the system: JDK 17, Docker, Kubernetes, and Helm.</p>
<h2>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 class="language-java">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(&quot;methodC executed&quot;);
    try {Thread.sleep(10);} catch (InterruptedException e) {}
    methodD();
  }

  public void methodD() {
    System.out.println(&quot;methodD executed&quot;);
    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 class="language-bash">docker.elastic.co/demos/apm/k8s-webhook-test
</code></pre>
<h2>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 class="language-yaml">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 class="language-yaml">kubectl apply -f webhook-test.yaml
</code></pre>
<p>The result is exactly as expected:</p>
<pre><code class="language-bash">$ 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>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 <a href="https://myserver.somecloud:443">https://myserver.somecloud:443</a> — 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 class="language-yaml">apm:
  secret_token: MY_SECRET_TOKEN
  namespaces:
    - default
webhookConfig:
  agents:
    java:
      environment:
        ELASTIC_APM_SERVER_URL: &quot;https://myserver.somecloud:443&quot;
        ELASTIC_APM_TRACE_METHODS: &quot;test.Testing#methodB&quot;
        ELASTIC_APM_SERVICE_NAME: &quot;webhook-test&quot;
</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 class="language-bash">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 class="language-bash">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>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 class="language-yaml">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 class="language-bash">$ kubectl delete -f webhook-test.yaml
pod &quot;webhook-test&quot; 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://www.elastic.co/observability-labs/assets/images/application-monitoring-kubernetes-pods/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>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 class="language-yaml">apm:
  secret_token: MY_SECRET_TOKEN
  namespaces:
    - default
webhookConfig:
  agents:
    java:
      environment:
        ELASTIC_APM_SERVER_URL: &quot;https://myserver.somecloud:443&quot;
        ELASTIC_APM_TRACE_METHODS: &quot;test.Testing#methodB&quot;
        ELASTIC_APM_SERVICE_NAME: &quot;webhook-test&quot;
    java-interesting:
      image: docker.elastic.co/observability/apm-agent-java:1.55.4
      artifact: &quot;/usr/agent/elastic-apm-agent.jar&quot;
      environment:
        ELASTIC_APM_SERVER_URL: &quot;https://myserver.somecloud:443&quot;
        ELASTIC_APM_TRACE_METHODS: &quot;test.Testing#methodB&quot;
        ELASTIC_APM_SERVICE_NAME: &quot;webhook-test&quot;
        ELASTIC_APM_ENVIRONMENT: &quot;testing&quot;
        ELASTIC_APM_LOG_LEVEL: &quot;debug&quot;
        ELASTIC_APM_PROFILING_INFERRED_SPANS_ENABLED: &quot;true&quot;
        JAVA_TOOL_OPTIONS: &quot;-javaagent:/elastic/apm/agent/elastic-apm-agent.jar&quot;
</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>
<ul>
<li>With a specific version 1.43.0 instead of latest</li>
</ul>
</li>
<li>
<p>We need to specify the agent jar location (the attacher puts it here)</p>
<ul>
<li>artifact: &quot;/usr/agent/elastic-apm-agent.jar&quot;</li>
</ul>
</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 &quot;-javaagent:/elastic/apm/agent/elastic-apm-agent.jar&quot; — 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>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 class="language-bash">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 class="language-yaml">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 class="language-bash">$ kubectl delete -f webhook-test.yaml
pod &quot;webhook-test&quot; 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://www.elastic.co/observability-labs/assets/images/application-monitoring-kubernetes-pods/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>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>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>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/application-monitoring-kubernetes-pods/139689_-_Blog_Header_Banner_V1.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Dynamic workload discovery on Kubernetes now supported with EDOT Collector]]></title>
            <link>https://www.elastic.co/observability-labs/blog/k8s-discovery-with-EDOT-collector</link>
            <guid isPermaLink="false">k8s-discovery-with-EDOT-collector</guid>
            <pubDate>Tue, 01 Apr 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Discover how Elastic's OpenTelemetry Collector leverages Kubernetes pod annotations providing dynamic workload discovery and improves automated metric and log collection for Kubernetes clusters.]]></description>
            <content:encoded><![CDATA[<p>At Elastic, Kubernetes is one of the most significant observability use cases we focus on.
We want to provide the best onboarding experience and lifecycle management based on real-world GitOps best practices.</p>
<p>OpenTelemetry recently <a href="https://opentelemetry.io/blog/2025/otel-collector-k8s-discovery/">published a blog</a> on how to do <code>Autodiscovery based on Kubernetes Pods' annotations</code> with the OpenTelemetry Collector.</p>
<p>In this blog post, we will talk about how to use this Kubernetes-related feature of the OpenTelemetry Collector,
which is already available with the Elastic Distribution of the OpenTelemetry (EDOT) Collector.</p>
<p>In addition to this feature, at Elastic, we heavily invest in making OpenTelemetry the best, standardized ingest solution for Observability.
You might already have seen us focusing on:</p>
<ul>
<li>
<p><a href="https://www.elastic.co/blog/ecs-elastic-common-schema-otel-opentelemetry-announcement">Semantic Conventions standardization</a></p>
</li>
<li>
<p>significant <a href="https://www.elastic.co/observability-labs/blog/elastics-collaboration-opentelemetry-filelog-receiver">log collection improvements</a></p>
</li>
<li>
<p>various other topics around <a href="https://www.elastic.co/observability-labs/blog/auto-instrumentation-go-applications-opentelemetry">instrumentation</a></p>
</li>
<li>
<p><a href="https://www.elastic.co/observability-labs/blog/elastic-donation-proposal-to-contribute-profiling-agent-to-opentelemetry">profiling</a></p>
</li>
</ul>
<p>Let's walk you through a hands-on journey using the EDOT Collector covering various use cases you might encounter in the real world, highlighting the capabilities of this powerful feature.</p>
<h2>Configuring EDOT Collector</h2>
<p>The Collector’s configuration is not our main focus here, since based on the nature of this feature it is minimal,
letting workloads define how they should be monitored.</p>
<p>To illustrate the point, here is the Collector configuration snippet that enables the feature for both logs and metrics:</p>
<pre><code class="language-yaml">receivers:
    receiver_creator/metrics:
      watch_observers: [k8s_observer]
      discovery:
        enabled: true
      receivers:

    receiver_creator/logs:
      watch_observers: [k8s_observer]
      discovery:
        enabled: true
      receivers:
</code></pre>
<p>You can include the above in the EDOT’s Collector configuration, specifically the
<a href="https://github.com/elastic/elastic-agent/blob/v9.0.0-rc1/deploy/helm/edot-collector/kube-stack/values.yaml#L339">receivers’ section</a>.</p>
<p>Since logs collection in our examples will happen from the discovery feature make sure that the static filelog receiver
<a href="https://github.com/elastic/elastic-agent/blob/v9.0.0-rc1/deploy/helm/edot-collector/kube-stack/values.yaml#L348">configuration block</a> is removed
and its <a href="https://github.com/elastic/elastic-agent/blob/v9.0.0-rc1/deploy/helm/edot-collector/kube-stack/values.yaml#L193"><code>preset</code></a>
is disabled (i.e. set to <code>false</code>) to avoid having log duplication.</p>
<p>Make sure that the receiver creator is properly added in the pipelines for
<a href="https://github.com/elastic/elastic-agent/blob/v9.0.0-rc1/deploy/helm/edot-collector/kube-stack/values.yaml#L471">logs</a>
(in addition to removing the <code>filelog</code> receiver completely)
and <a href="https://github.com/elastic/elastic-agent/blob/v9.0.0-rc1/deploy/helm/edot-collector/kube-stack/values.yaml#L484">metrics</a>
respectively.</p>
<p>Ensure that <a href="https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/v0.122.0/extension/observer/k8sobserver/README.md"><code>k8sobserver</code></a>
is enabled as part of the extensions:</p>
<pre><code class="language-yaml">extensions:
  k8s_observer:
    observe_nodes: true
    observe_services: true
    observe_ingresses: true

// ...

service:
  extensions: [k8s_observer]
</code></pre>
<p>Last but not least, ensure the log files' volume is mounted properly:</p>
<pre><code class="language-yaml">volumeMounts:
 - name: varlogpods
   mountPath: /var/log/pods
   readOnly: true

volumes:
  - name: varlogpods
    hostPath:
      path: /var/log/pods
</code></pre>
<p>Once the configuration is ready follow the <a href="https://www.elastic.co/docs/reference/opentelemetry/quickstart/">Kubernetes quickstart guides on how to deploy the EDOT Collector</a>.
Make sure to replace the <code>values.yaml</code> file linked in the quickstart guide with the file that includes the above-described modifications.</p>
<h3>Collecting Metrics from Moving Targets Based on Their Annotations</h3>
<p>In this example, we have a Deployment with a Pod spec that consists of two different containers.
One container runs a Redis server, while the other runs an NGINX server. Consequently, we want to provide
different hints for each of these target containers.</p>
<p>The annotation-based discovery feature supports this, allowing us to specify metrics annotations
per exposed container port.</p>
<p>Here is how the complete spec file looks:</p>
<pre><code class="language-yaml">apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-conf
data:
  nginx.conf: |
    user  nginx;
    worker_processes  1;
    error_log  /dev/stderr warn;
    pid        /var/run/nginx.pid;
    events {
      worker_connections  1024;
    }
    http {
      include       /etc/nginx/mime.types;
      default_type  application/octet-stream;

      log_format  main  '$remote_addr - $remote_user [$time_local] &quot;$request&quot; '
                        '$status $body_bytes_sent &quot;$http_referer&quot; '
                        '&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;';
      access_log  /dev/stdout main;
      server {
          listen 80;
          server_name localhost;

          location /nginx_status {
              stub_status on;
          }
      }
      include /etc/nginx/conf.d/*;
    }
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-deployment
  labels:
    app: redis
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
      annotations:
        # redis container port hints
        io.opentelemetry.discovery.metrics.6379/enabled: &quot;true&quot;
        io.opentelemetry.discovery.metrics.6379/scraper: redis
        io.opentelemetry.discovery.metrics.6379/config: |
          collection_interval: &quot;20s&quot;
          timeout: &quot;10s&quot;

        # nginx container port hints
        io.opentelemetry.discovery.metrics.80/enabled: &quot;true&quot;
        io.opentelemetry.discovery.metrics.80/scraper: nginx
        io.opentelemetry.discovery.metrics.80/config: |
          endpoint: &quot;http://`endpoint`/nginx_status&quot;
          collection_interval: &quot;30s&quot;
          timeout: &quot;20s&quot;
    spec:
      volumes:
      - name: nginx-conf
        configMap:
          name: nginx-conf
          items:
            - key: nginx.conf
              path: nginx.conf
      containers:
        - name: webserver
          image: nginx:latest
          ports:
            - containerPort: 80
              name: webserver
          volumeMounts:
            - mountPath: /etc/nginx/nginx.conf
              readOnly: true
              subPath: nginx.conf
              name: nginx-conf
        - image: redis
          imagePullPolicy: IfNotPresent
          name: redis
          ports:
            - name: redis
              containerPort: 6379
              protocol: TCP
</code></pre>
<p>When this workload is deployed, the Collector will automatically discover it and identify the specific annotations.
After this, two different receivers will be started, each one responsible for each of the target containers.</p>
<h3>Collecting Logs from Multiple Target Containers</h3>
<p>The annotation-based discovery feature also supports log collection based on the provided annotations.
In the example below, we again have a Deployment with a Pod consisting of two different containers,
where we want to apply different log collection configurations.
We can specify annotations that are scoped to individual container names:</p>
<pre><code class="language-yaml">apiVersion: apps/v1
kind: Deployment
metadata:
  name: busybox-logs-deployment
  labels:
    app: busybox
spec:
  replicas: 1
  selector:
    matchLabels:
      app: busybox
  template:
    metadata:
      labels:
        app: busybox
      annotations:
        io.opentelemetry.discovery.logs.lazybox/enabled: &quot;true&quot;
        io.opentelemetry.discovery.logs.lazybox/config: |
          operators:
            - id: container-parser
              type: container
            - id: some
              type: add
              field: attributes.tag
              value: hints-lazybox
        io.opentelemetry.discovery.logs.busybox/enabled: &quot;true&quot;
        io.opentelemetry.discovery.logs.busybox/config: |
          operators:
            - id: container-parser
              type: container
            - id: some
              type: add
              field: attributes.tag
              value: hints-busybox
    spec:
      containers:
        - name: busybox
          image: busybox
          args:
            - /bin/sh
            - -c
            - while true; do echo &quot;otel logs from busybox at $(date +%H:%M:%S)&quot; &amp;&amp; sleep 5s; done
        - name: lazybox
          image: busybox
          args:
            - /bin/sh
            - -c
            - while true; do echo &quot;otel logs from lazybox at $(date +%H:%M:%S)&quot; &amp;&amp; sleep 25s; done
</code></pre>
<p>The above configuration enables two different filelog receiver instances, each applying a unique parsing configuration.
This is handy when we know how to parse specific technology logs, such as Apache server access logs.</p>
<h3>Combining Both Metrics and Logs Collection</h3>
<p>In our third example, we illustrate how to define both metrics and log annotations on the same workload.
This allows us to collect both signals from the discovered workload.
Below is a Deployment with a Pod consisting of a Redis server and a BusyBox container that performs dummy log writing.
We can target annotations to the port and container levels to collect metrics from the Redis server using
the Redis receiver, and logs from the BusyBox using the filelog receiver. Here’s how:</p>
<pre><code class="language-yaml">apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-deployment
  labels:
    app: redis
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
      annotations:
        io.opentelemetry.discovery.metrics.6379/enabled: &quot;true&quot;
        io.opentelemetry.discovery.metrics.6379/scraper: redis
        io.opentelemetry.discovery.metrics.6379/config: |
          collection_interval: &quot;20s&quot;
          timeout: &quot;10s&quot;

        io.opentelemetry.discovery.logs.busybox/enabled: &quot;true&quot;
        io.opentelemetry.discovery.logs.busybox/config: |
          operators:
            - id: container-parser
              type: container
            - id: some
              type: add
              field: attributes.tag
              value: hints
    spec:
      containers:
        - image: redis
          imagePullPolicy: IfNotPresent
          name: redis
          ports:
            - name: redis
              containerPort: 6379
              protocol: TCP
        - name: busybox
          image: busybox
          args:
            - /bin/sh
            - -c
            - while true; do echo &quot;otel logs at $(date +%H:%M:%S)&quot; &amp;&amp; sleep 15s; done
</code></pre>
<h3>Explore and analyse data coming from dynamic targets in Elastic</h3>
<p>Once the target Pods are discovered and the Collector has started collecting telemetry data from them,
we can then explore this data in Elastic. In Discover we can search for Redis and NGINX metrics as well as
logs collected from the Busybox container. Here is how it looks like:</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/k8s-discovery-with-EDOT-collector/discoverlogs.png" alt="Logs Discovery" />
<img src="https://www.elastic.co/observability-labs/assets/images/k8s-discovery-with-EDOT-collector/discovermetrics.png" alt="Metrics Discovery" /></p>
<h2>Summary</h2>
<p>The examples above showcase how users of our OpenTelemetry Collector can take advantage of this new feature
— one we played a major role in developing.</p>
<p>For this, we leveraged our years of experience with similar features already supported in
<a href="https://www.elastic.co/guide/en/beats/metricbeat/current/configuration-autodiscover-hints.html">Metricbeat</a>,
<a href="https://www.elastic.co/guide/en/beats/filebeat/current/configuration-autodiscover-hints.html">Filebeat</a>, and
<a href="https://www.elastic.co/guide/en/fleet/current/hints-annotations-autodiscovery.html">Elastic-Agent</a>.
This makes us extremely happy and confident, as it closes the feature gap between Elastic's specific
monitoring agents and the OpenTelemetry Collector — making it even better.</p>
<p>Interested in learning more? Visit the
<a href="https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/receiver/receivercreator/README.md#generate-receiver-configurations-from-provided-hints">documentation</a>
and give it a try by following our <a href="https://www.elastic.co/docs/reference/opentelemetry/quickstart/">EDOT quickstart guide</a>.</p>
]]></content:encoded>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/k8s-discovery-with-EDOT-collector/k8s-discovery-new.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Monitoring Android applications with Elastic APM]]></title>
            <link>https://www.elastic.co/observability-labs/blog/monitoring-android-applications-apm</link>
            <guid isPermaLink="false">monitoring-android-applications-apm</guid>
            <pubDate>Tue, 21 Mar 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Elastic has launched its APM agent for Android applications, allowing developers to track key aspects of applications to help troubleshoot issues and performance flaws with mobile applications, corresponding backend services, and their interactions.]]></description>
            <content:encoded><![CDATA[<blockquote>
<p><strong>WARNING</strong>: This article shows information about the Android agent that is no longer accurate for versions <code>1.x</code>. Please refer to <a href="https://www.elastic.co/docs/reference/apm/agents/android">its documentation</a> to learn about its new APIs.</p>
</blockquote>
<p>People are handling more and more matters on their smartphones through mobile apps both privately and professionally. With thousands or even millions of users, ensuring great <a href="https://www.elastic.co/observability/application-performance-monitoring">monitor application performance</a> and reliability is a key challenge for providers and operators of mobile apps and related backend services. Understanding the behavior of mobile apps, the occurrences and types of crashes, the <a href="https://www.elastic.co/blog/apm-correlations-elastic-observability-root-cause-transactions">root causes of slow response times</a>, and the real user impact of backend issues is key to managing the performance of mobile apps and associated backend services.</p>
<p>Elastic has launched its application performance monitoring (<a href="https://www.elastic.co/observability/application-performance-monitoring">APM</a>) agent for Android applications, allowing developers to keep track of key aspects of their applications, from crashes and HTTP requests to screen rendering times and end-to-end distributed tracing. All of this helps troubleshoot issues and performance flaws with mobile applications, corresponding backend services, and their interaction. The Elastic APM Android Agent automatically instruments your application and its dependencies so that you can simply “plug-and-play” the agent into your application without having to worry about changing your codebase much.</p>
<p>The Elastic APM Android Agent has been developed from scratch on top of OpenTelemetry, an open standard and framework for observability. Developers will be able to take full advantage of its capabilities, as well as the support provided by a huge and active community. If you’re familiar with OpenTelemetry and your application is already instrumented with OpenTelemetry, then you can simply reuse it all when switching to the Elastic APM Android Agent. But no worries if that’s not the case — the agent is configured to handle common traceable scenarios automatically without having to deep dive into the specifics of the OpenTelemetry API.</p>
<p>[Related article: <a href="https://www.elastic.co/blog/adding-free-and-open-elastic-apm-as-part-of-your-elastic-observability-deployment">Adding free and open Elastic APM as part of your Elastic Observability deployment</a>]</p>
<h2>How it works</h2>
<p>The Elastic APM Android Agent is a combination of an SDK plus a Gradle plugin. The SDK contains utilities that will let you initialize and configure the agent’s behavior, as well as prepare and initialize the OpenTelemetry SDK. You can use the SDK for programmatic configuration and initialization of the agent, in particular for advanced and special use cases.</p>
<p>In most cases, a programmatic configuration and initialization won’t be necessary. Instead, you can use the provided Gradle plugin to configure the agent and automatically instrument your app. The Gradle plugin uses Byte Buddy and the official Android Gradle plugin API under the hood to automatically inject instrumentation code into your app through compile-time transformation of your application’s and its dependencies’ classes.</p>
<p>Compiling your app with the Elastic Android APM Agent Gradle Plugin configured and enabled will make your Android app report tracing data, metrics, and different events and logs at runtime.</p>
<h2>Using the Elastic APM Agent in an Android app</h2>
<p>By means of a <a href="https://github.com/elastic/sample-app-android-apm">simple demo application</a>, we’re going through the steps mentioned in the “<a href="https://www.elastic.co/guide/en/apm/agent/android/current/setup.html">Set up the Agent</a>” guide to set up the Elastic Android APM Agent.</p>
<h3>Prerequisites</h3>
<p>For this example, you will need the following:</p>
<ul>
<li>An Elastic Stack with APM enabled (We recommend using Elastic’s Cloud offering. <a href="https://www.elastic.co/cloud/elasticsearch-service/signup?baymax=docs-body&amp;elektra=docs">Try it for free</a>.)</li>
<li>Java 11+</li>
<li><a href="https://developer.android.com/studio?gclid=Cj0KCQiAic6eBhCoARIsANlox87QsDnyjpKObQSivZz6DHMLTiL76CmqZGXTEqf4L7h3jQO7ljm8B14aAo4xEALw_wcB&amp;gclsrc=aw.ds">Android Studio</a></li>
<li><a href="https://developer.android.com/studio/run/emulator">Android Emulator, AVD device</a></li>
</ul>
<p>You’ll also need a way to push the app’s <a href="https://opentelemetry.io/docs/concepts/signals/">signals</a> into Elastic. Therefore, you will need Elastic APM’s <a href="https://www.elastic.co/guide/en/apm/guide/current/secret-token.html#create-secret-token">secret token</a> that you’ll configure into our sample app later.</p>
<h3>Test project for our example</h3>
<p>To showcase an end-to-end scenario including distributed tracing, in this example, we’ll instrument a <a href="https://github.com/elastic/sample-app-android-apm">simple weather application</a> that comprises two Android UI fragments and a simple local backend service based on Spring Boot.</p>
<p>The first fragment will have a dropdown list with some city names and also a button that takes you to the second one, where you’ll see the selected city’s current temperature. If you pick a non-European city on the first screen, you’ll get an error from the (local) backend when you head to the second screen. This is to demonstrate how network and backend errors are captured and correlated in Elastic APM.</p>
<h3>Applying the Elastic APM Agent plugin</h3>
<p>In the following, we will explain <a href="https://www.elastic.co/guide/en/apm/agent/android/current/setup.html">all the steps required to set up the Elastic APM Android Agent</a> from scratch for an Android application. In case you want to skip these instructions and see the agent in action right away, use the main branch of that repo and apply only Step (3.b) before continuing with the next Section (“Setting up the local backend service”).</p>
<ol>
<li>Clone the <a href="https://github.com/elastic/sample-app-android-apm">sample app</a> repo and open it in Android Studio.</li>
<li>Switch to the uninstrumented repo branch to start from a blank, uninstrumented Android application. You can run this command to switch to the uninstrumented branch:</li>
</ol>
<pre><code class="language-bash">git checkout uninstrumented
</code></pre>
<ol start="3">
<li>Follow the Elastic APM Android Agent’s <a href="https://www.elastic.co/guide/en/apm/agent/android/current/setup.html">setup guide</a>:</li>
</ol>
<p>Add the co.elastic.apm.android plugin to the app/build.gradle file (please make sure to use the latest version available of the plugin, which you can find <a href="https://plugins.gradle.org/plugin/co.elastic.apm.android">here</a>).</p>
<p>Configure the agent’s connection to the Elastic APM backend by providing the ‘serverUrl’ and ‘secretToken’ in the ‘elasticAPM’ section of the app/build.gradle file.</p>
<pre><code class="language-java">// Android app's build.gradle file
plugins {
    //...
    id &quot;co.elastic.apm.android&quot; version &quot;[latest_version]&quot;
}

//...

elasticApm {
    // Minimal configuration
    serverUrl = &quot;https://your.elastic.apm.endpoint&quot;

    // Optional
    serviceName = &quot;weather-sample-app&quot;
    serviceVersion = &quot;0.0.1&quot;
    secretToken = &quot;your Elastic APM secret token&quot;
}
</code></pre>
<ol start="4">
<li>The only actual code change required is a one-liner to initialize the Elastic APM Android Agent in the Application.onCreate method. The application class for this sample app is located at app/src/main/java/co/elastic/apm/android/sample/MyApp.kt.</li>
</ol>
<pre><code class="language-kotlin">
package co.elastic.apm.android.sample

import android.app.Application
import co.elastic.apm.android.sdk.ElasticApmAgent

class MyApp : Application() {

    override fun onCreate() {
        super.onCreate()
        ElasticApmAgent.initialize(this)
    }
}
</code></pre>
<p>Bear in mind that for this example, we’re not changing the agent’s default configuration — if you want more information about how to do so, take a look at the agent’s <a href="https://www.elastic.co/guide/en/apm/agent/android/current/configuration.html#_runtime_configuration">runtime configuration guide</a>.</p>
<p>Before launching our Android Weather App, we need to configure and start the local weather-backend service as described in the next section.</p>
<h3>Setting up the local backend service</h3>
<p>One of the key features the agent provides is distributed tracing, which allows you to see the full end-to-end story of an HTTP transaction, starting from our mobile app and traversing instrumented backend services used by the app. Elastic APM will show you the full picture as one distributed trace, which comes in very handy for troubleshooting issues, especially the ones related to high latency and backend errors.</p>
<p>As part of our sample app, we’re going to launch a simple local backend service that will handle our app’s HTTP requests. The backend service is instrumented with the <a href="https://www.elastic.co/guide/en/apm/agent/java/current/index.html">Elastic APM Java agent</a> to collect and send its own APM data over to Elastic APM, allowing it to correlate the mobile interactions with the processing of the backend requests.</p>
<p>In order to configure the local server, we need to set our Elastic APM endpoint and secret token (the same used for our Android app in the previous step) into the backend/src/main/resources/elasticapm.properties file:</p>
<pre><code class="language-bash">service_name=weather-backend
application_packages=co.elastic.apm.android.sample
server_url=YOUR_ELASTIC_APM_URL
secret_token=YOUR_ELASTIC_APM_SECRET_TOKEN
</code></pre>
<h3>Launching the demo</h3>
<p>Our sample app will get automatic instrumentation for the agent’s currently <a href="https://www.elastic.co/guide/en/apm/agent/android/current/supported-technologies.html">supported frameworks</a>, which means that we’ll get to see screen rendering spans as well as OkHttp requests out of the box. For frameworks not currently supported, you could apply manual instrumentation to enrich your APM data (see “Manual Instrumentation” below).</p>
<p>We are ready to launch the demo. (The demo is meant to be executed on a local environment using an emulator for Android.) Therefore, we need to:</p>
<ol>
<li>Launch the backend service using this command in a terminal located in the root directory of our sample project: ./gradlew bootRun (or gradlew.bat bootRun if you’re on Windows). Alternatively, you can start the backend service from Android Studio.</li>
<li>Launch the weather sample app in an Android emulator (from Android Studio).</li>
</ol>
<p>Once everything is running, we need to navigate around in the app to generate some load that we would like to observe in Elastic APM. So, select a city, click <strong>Next</strong> and repeat it multiple times. Please, also make sure to select <strong>New York</strong> at least once. You will see that the weather forecast won’t work for New York as the city. Below, we will use Elastic APM to find out what’s going wrong when selecting New York.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/monitoring-android-applications-apm/blog-elastic-android-apm-city-selection.png" alt="apm android city selection" /></p>
<h2>First glance at the APM results</h2>
<p>Let’s open Kibana and navigate to the Observability solution.</p>
<p>Under the Services navigation item, you should see a list of two services: our Android app <strong>weather-sample-app</strong> and the corresponding backend service <strong>weather-backend</strong>. Click on the <strong>Service map</strong> tab to see a visualization of the dependencies between those services and any external services.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/monitoring-android-applications-apm/blog-elastic-apm-android-services.png" alt="apm android services" /></p>
<p>Click on the <strong>weather-sample-app</strong> to dive into the dashboard for the Android app. The service view for mobile applications is in technical preview at the publishing of this blog post, but you can already see insightful information about the app on that screen. You see information like the amount of active sessions in the selected time frame, number of HTTP requests emitted by the weather-sample-app, geographical distribution of the requests as well as breakdowns on device models, OS versions, network connection types, and app versions. (Information on crashes and app load times are under development.)</p>
<p>For the purpose of demonstration, we kept this demo simple, so the data is less diversified and also rather limited. However, this kind of data is particularly useful when you are monitoring a mobile app with higher usage numbers and higher diversification on device models, OS versions, etc. Troubleshooting problems and performance issues becomes way easier when you can use these properties to filter and group your APM data. You can use the quick filters at the top to do so and see how the metrics adopt depending on your selection.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/monitoring-android-applications-apm/blog-elastic-apm-android-weather-sample-app.png" alt="apm android weather sample app" /></p>
<p>Now, let’s see how individual user interactions are processed, including downstream calls into the backend service. Under the Transactions tab (at the top), we see the different end-to-end transaction groups, including the two transactions for the FirstFragment and the SecondFragment.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/monitoring-android-applications-apm/blog-elastic-apm-android-latency-distribution.png" alt="apm android latency distribution" /></p>
<p>Let’s deep dive into the SecondFragment - View appearing transaction, to see the metrics (e.g., latency, throughput) for this transaction group and also the invocation waterfall view for the individual user interactions. As we can see in the following screenshot, after view creation, the fragment performs an HTTP GET request to 10.0.2.2, which takes ~130 milliseconds. In the same waterfall, we see that the HTTP call is processed by the weather-backend service, which itself conducts an HTTP call to api.open-meteo.com.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/monitoring-android-applications-apm/blog-elastic-apm-android-trace-samples.png" alt="apm android trace samples" /></p>
<p>Now, when looking at the waterfall view for a request where New York was selected as the city, we see an error happening on the backend service that explains why the forecast didn’t work for New York. By clicking on the red <strong>View related error</strong> badge, you will get details on the error and the actual root cause of the problem.</p>
<p>The exception message on the weather-backend states that “This service can only retrieve geo locations for European cities!” That’s the problem with selecting New York as the city.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/monitoring-android-applications-apm/blog-elastic-apm-android-weather-backend.png" alt="apm android weather backend" /></p>
<h2>Manual instrumentation</h2>
<p>As previously mentioned, the Elastic APM Android Agent does a bunch of automatic instrumentation on your behalf for the <a href="https://www.elastic.co/guide/en/apm/agent/android/current/supported-technologies.html">supported frameworks</a>; however, in some cases, you might want to get extra instrumentation depending on your app’s use cases. For those cases, you’ve gotten covered by the OpenTelemetry API, which is what the Elastic APM Android Agent is based on. The OpenTelemetry Java SDK contains tools to create custom spans, metrics, and logs, and since it’s the base of the Elastic APM Android Agent, it’s available for you to use without having to add any extra dependencies into your project and without having to configure anything to connect your custom signals to your own Elastic environment either, as the agent does that for you.</p>
<p>The way to start would be by getting OpenTelemetry’s instance like so:</p>
<pre><code class="language-java">OpenTelemetry openTelemetry = GlobalOpenTelemetry.get();
</code></pre>
<p>And then you can follow the instructions from the <a href="https://opentelemetry.io/docs/instrumentation/java/manual/#acquiring-a-tracer">OpenTelemetry Java documentation</a> in order to create your custom signals. See the following example for the creation of a custom span:</p>
<pre><code class="language-java">OpenTelemetry openTelemetry = GlobalOpenTelemetry.get();
Tracer tracer = openTelemetry.getTracer(&quot;instrumentation-library-name&quot;, &quot;1.0.0&quot;);
Span span = tracer.spanBuilder(&quot;my span&quot;).startSpan();

// Make the span the current span
try (Scope ss = span.makeCurrent()) {
  // In this scope, the span is the current/active span
} finally {
    span.end();
}
</code></pre>
<h2>Conclusion</h2>
<p>In this blog post, we demonstrated how you can use the Elastic APM Android Agent to achieve end-to-end observability into your Android-based mobile applications. Setting up the agent is a matter of a few minutes and the provided insights allow you to analyze your app’s performance and its dependencies on backend services. With the Elastic APM Android Agent in place, you can leverage Elastic’s rich APM feature as well as the various possibilities to customize your analysis workflows through custom instrumentation and custom dashboards.</p>
<p>Are you curious? Then try it yourself. Sign up for a <a href="https://www.elastic.co/cloud/elasticsearch-service/signup">free trial on the Elastic Cloud</a>, enrich your Android app with the Elastic APM Android agent as described in this blog, and explore the data in <a href="https://www.elastic.co/observability">Elastic’s Observability solution</a>.</p>
]]></content:encoded>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/monitoring-android-applications-apm/illustration-indusrty-technology-social-1680x980.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[OpenTelemetry Data Quality Insights with the Instrumentation Score and Elastic]]></title>
            <link>https://www.elastic.co/observability-labs/blog/otel-instrumentation-score</link>
            <guid isPermaLink="false">otel-instrumentation-score</guid>
            <pubDate>Thu, 06 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[This post explores the Instrumentation Score for OpenTelemetry data quality, sharing practical insights, key learnings, and a hands-on look at implementing this approach with Elastic's powerful observability features.]]></description>
            <content:encoded><![CDATA[<p>OpenTelemetry adoption is rapidly increasing and more companies rely on OpenTelemetry to collect observability data.
While OpenTelemetry offers clear specifications and semantic conventions to guide telemetry data collection, it also introduces significant flexibility.
With high flexibility comes high responsibility — many things can go wrong with OTel-based data collection, easily resulting in mediocre or low-quality telemetry.
Poor data quality can hinder backend analysis, confuse users, and degrade system performance.
To unlock actionable insights from OpenTelemetry data, maintaining high data quality is essential.
The <a href="https://instrumentation-score.com/">Instrumentation Score</a> initiative addresses this challenge by providing a standardized way to measure OpenTelemetry data quality.
Although the specification and tooling are still evolving, the underlying concepts are already compelling.
In this blog post, I’ll share my experience experimenting with the Instrumentation Score concept and demonstrate how to use the Elastic Stack — utlizing ES|QL, Kibana Task Manager, and Dashboards — to build a POC for data quality analysis based on this approach within Elastic Observability.</p>
<h2>Instrumentation Score - The Power of Rule-based Data Quality Analysis</h2>
<p>When you first hear the term &quot;Instrumentation Score&quot;, your initial reaction might be: &quot;OK, there's a <em>single</em>, percentage-like metric that tells me my instrumentation (i.e. OTel data) has a score of 60 out of 100.
So what? How does it help me?&quot;</p>
<p>However, the Instrumentation Score is much more than just a single number.
Its power lies in the individual rules from which the score is calculated.
The rule definitions' <code>rationale</code>, <code>impact level</code>, and <code>criteria</code> provide an evaluation framework that enables you to drill down into data quality issues and identify specific areas for improvement.
Also, the Instrumentation Score specification does not mandate specific tools and implementation details for calculating the score and rule evaluations.</p>
<p>As I explored the Instrumentation Score concepts, I developed the following mental model for deriving actionable insights.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/otel-instrumentation-score/inst-score-drill-down.png" alt="Instrumentation Score Drill-down" /></p>
<h5>The Score</h5>
<p>The score itself is an indicator of the quality of your telemetry data. The lower the number, the more room for improvement with your data quality.
In general, if a score falls below 75, you should consider fixing your instrumentation and data collection.</p>
<h5>Breakdown by Instrumentation Score Rules</h5>
<p>Exploring the evaluation results of individual Instrumentation Score <em>rules</em> will give you insights into <em>what</em> is wrong with your data quality.
In addition, the rules' rationales explain <em>why</em> the violation of a rule is problematic.</p>
<p>As an example, let's take the <a href="https://github.com/instrumentation-score/spec/blob/main/rules/SPA-002.md"><code>SPA-002 rule</code></a>:</p>
<blockquote>
<p><strong>Description</strong>:</p>
<p>Traces do not contain orphan spans.</p>
<p><strong>Rationale</strong>:</p>
<p>Orphaned spans indicate potential issues in tracing instrumentation or data integrity. This can lead to incomplete or misleading trace data, hindering effective troubleshooting and performance analysis.</p>
</blockquote>
<p>If your data violates the <code>SPA-002</code> rule, you know <em>what</em> is wrong (i.e. you have broken traces), and the rationale explains why that is an issue (i.e. degraded analysis capabilities).</p>
<h5>Breakdown by Services</h5>
<p>When you have a large system with hundreds or maybe even thousands of entities (such as services, Kubernetes pods, etc.), a binary signal on all of the data — such as &quot;has a certain rule been passed or not&quot; — is not really actionable.
Is the data from all services violating a certain rule, or just a small subset of services?</p>
<p>Breaking down rule evaluation by services (and potentially other entity types) may help you to identify <em>where</em> there are issues with data quality.
For example, let's assume only one service — the <code>cart-service</code> — (out of your fifty services) is affected by the violation of rule <code>SPA-002</code>.
With that information, you can focus on fixing the instrumentation for the <code>cart-service</code> instead of having to check all fifty services.</p>
<p>Once you know which services (or other entities) violate which Instrumentation Score rules, you're very close to actionable insights.
However, there are two more things that I found to be extremely useful for data quality analysis when I was experimenting with the Instrumentation Score evaluation: (1) a quantitative indication of the extent, and (2) concrete examples of rule violation occurrences in your data.</p>
<h5>Quantifying the Rule Violation Extent</h5>
<p>The Instrumentation Score spec already defines an impact level (e.g. <code>NORMAL</code>, <code>IMPORTANT</code>, <code>CRITICAL</code>) per rule.
However, this only covers the &quot;importance&quot; of the rule itself, not the extent of a rule violation.
For example, if a single trace (out of a million traces) on your service has an orphan span, technically speaking the rule <code>SPA-002</code> is violated.
But is it really a relevant issue if only one out of a million traces is affected? Probably not. It definitely would be if half of your traces were broken.</p>
<p>Hence, having a quantitative indication of the extent of a rule violation per service — e.g. &quot;40% of your traces violate <code>SPA-002</code>&quot; — would provide additional information on how severe a rule violation actually is.</p>
<h5>Tangible Examples</h5>
<p>Finally, nothing is as meaningful and self-explanatory as tangible, concrete examples from your own data.
If the telemetry data of your <code>cart-service</code> violates <code>SPA-002</code> (i.e., has traces with orphan spans), wouldn't you want to see a concrete trace from that service that demonstrates the rule violation?
Analyzing concrete examples may give you hints about the root cause of broken traces — or, more generally, why your data violates Instrumentation Score rules.</p>
<h2>Instrumentation Score with Elastic</h2>
<p>The Instrumentation Score spec does not prescribe tool usage or implementation details for the calculation of the score and evaluation of the rules.
This allows for integrating the Instrumentation Score concept with whatever backend your OpenTelemetry data is being sent to.</p>
<p>With the goal of building a POC for an end-to-end integration of the Instrumentation Score with Elastic Observability, I combined the powerful capabilities of ES|QL with Kibana's task manager and dashboarding features.</p>
<p>Each Instrumentation Score rule can be formulated as an ES|QL query that covers the steps described above:</p>
<ul>
<li>rule passed or not</li>
<li>breakdown by services</li>
<li>calculation of the extent</li>
<li>sampling of an example occurrence</li>
</ul>
<p>Here is an example query for the <code>LOG-002</code> rule that checks the validity of the <code>severity_number</code> field:</p>
<pre><code class="language-esql">FROM logs-*.otel-* METADATA _id
| WHERE data_stream.type == &quot;logs&quot;
    AND @timestamp &gt; NOW() - 1h
| EVAL no_sev = severity_number IS NULL OR severity_number == 0
| STATS 
    logs_wo_severity = COUNT(*) WHERE no_sev,
    example = SAMPLE(_id, 1) WHERE no_sev,
    total = COUNT(*)
      BY service.name
| EVAL rule_passed = (logs_wo_severity == 0),
    extent = CASE(total != 0, logs_wo_severity / total, 0.0)
| KEEP rule_passed, service.name, example, extent
</code></pre>
<p>These rule evaluation queries are wrapped in a Kibana <code>instrumentation-score</code> plugin that utilizes the task manager for regular execution.
The <code>instrumentation-score</code> plugin then takes the results from all the evaluation queries for the different rules and calculates the final instrumentation score value (overall and broken down by service) following the <a href="https://github.com/instrumentation-score/spec/blob/main/specification.md#score-calculation-formula">Instrumentation Score spec's calculation formula</a>.
The resulting instrumentation score values, as well as the rule evaluation results (with the examples and extent) are then stored in separate Elasticsearch indices for consumption.</p>
<p>With the results stored in dedicated Elasticsearch indices, we can build Dashboards to visualize the Instrumentation Score insights and allow users to troubleshoot their data quality issues.</p>
<p>In this POC I implement subet of instrumentation score rules to prove out the approach.</p>
<p>The Instrumentation Score concept accommodates extension with your own custom rules.
I did that in my POC as well to test some quality rules that are not yet formalized as rules in the Instrumentation Score spec,
but are important for Elastic Observability to provide the maximum value from the OTel data.</p>
<h2>Applying the Instrumentation Score on the OpenTelemetry Demo</h2>
<p>The <a href="https://github.com/open-telemetry/opentelemetry-demo">OpenTelemetry Demo</a> is the most-used environment to play around with and showcase OpenTelemetry capabilities.
Initially, I thought the demo would be the worst environment to test my Instrumentation Score implementation.
After all, it's the showcase environment for OpenTelemetry, and I expected it to have an Instrumentation Score close to 100.
Surprisingly, that wasn't the case.</p>
<p>Let's start with the overview.</p>
<h3>The Overview</h3>
<p><img src="https://www.elastic.co/observability-labs/assets/images/otel-instrumentation-score/dashboard-overview.png" alt="Dashboard Overview" /></p>
<p>This dashboard shows an overview of the Instrumentation Score results for the OpenTelemetry Demo environment.
The first thing you might notice is the very low overall score <code>35</code> (top-left corner).
The table in the bottom-left corner shows a breakdown of the score by services.
Somewhat surprisingly, all the service scores are higher than the overall score.
How is that possible?</p>
<p>The main reason is that Instrumentation Score rules have, by definition, a binary result — passed or not.
So it can happen that each service fails a single but distinct rule. Hence, the service score is not perfect but also not too bad.
But, from the overall perspective, many rules have failed (each by a different service), hence, leading to a very low overall score.</p>
<p>In the table on the right, we see the results for the individual rules with their description, impact level, and example occurrences.
We see that 7 out of 11 implemented rules have failed. Let's pick our favorite example from earlier — <code>SPA-002</code> (in row 5), the orphan spans rule.</p>
<p>With the dashboard indicating that the rule <code>SPA-002</code> has failed, we know that there are orphan spans somewhere in our OTel traces. But where exactly?</p>
<p>For further analysis, we have two ways to drill down: (1) into a specific rule to see which services violate a specific rule, or (2) into a specific service to see which rules are violated by that service.</p>
<h3>Rule Drilldown</h3>
<p>The following dashboard shows a detailed view into the rule evaluation results for individual rules.
In this case we selected rule <code>SPA-002</code> at the top.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/otel-instrumentation-score/dashboard-rule-spa-002.png" alt="Dashboard Overview" /></p>
<p>In addition to the rule's meta information, such as its description, rationale, and criteria, we see some statistics on the right.
For example, we see that 2 services have failed that rule, 16 passed, and for 19 services this rule is not applicable (e.g., because those don't have tracing data).
In the table below, we see which two services are impacted by this rule violation: the <code>frontend</code> and <code>frontend-proxy</code> services.
For each service, we also see the <em>extent</em>. In the case of the <code>frontend</code> service, around 20% of traces have orphan spans.
This information is crucial as it gives an indication of how severe the rule violation actually is.
If it had been under 1%, this problem might have been negligible, but with one trace out of five being broken, it definitely needs to be fixed.
Also, for each of the services, we have an example <code>span.id</code> for which no spans could be found but that are referenced in the <code>parent.id</code> by other spans.
This allows us to perform further analyses (e.g., by investigating the referring spans in Kibana's Discover) on concrete example cases.</p>
<p>With that view, we now know that the <code>frontend</code> service has a good amount of broken traces.
But is that service also violating other rules? And, if yes, which?</p>
<h3>Service Drilldown</h3>
<p>To answer the above question we can switch to the <code>Per Service</code> Dashboard.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/otel-instrumentation-score/dashboard-service-frontend.png" alt="Dashboard Overview" /></p>
<p>In this dashboard, we see similar information as on the overview dashboard, however, filtered on a single selected service (e.g., <code>frontend</code> service in this example).
In the table, we see that the <code>frontend</code> service violates three rules. We already know about <code>SPA-002</code> from the previous section.
In addition, the violation of the custom rule <code>SPA-C-001</code> shows that around 99% of transaction span names have high cardinality.
In Elastic Observability, <code>transactions</code> refer to service-local root spans (i.e., entry points into services).
In the example value, we see directly why the <code>span.name</code>s (here referred to as <code>transaction.name</code>s) have high cardinality.
The span name contains unique identifiers (here the session ID) as part of the URL that the span name is constructed from in the instrumentation.
As the <a href="https://www.elastic.co/docs/reference/edot-collector">EDOT Collector</a> derives metrics for transaction-type spans, we also can observe a violation of the <code>MET-001</code> which requires bound cardinality on metric dimensions.</p>
<p>As you can see, with the Instrumentation Score concept and a few different breakdown views, we were able to pinpoint data quality issues and identify which services and instrumentations need improvement to fix the issues.</p>
<h2>Learnings and Observations</h2>
<p>My experimentation with the Instrumentation Score was very insightful and showed me the power of this concept — though it's still in its early phase.
It is particularly insightful if the implementation and calculation include breakdowns by meaningful entities, such as services, K8s pods, hosts, etc.
With such a breakdown, you can narrow down data quality issues to a manageable scope, instead of having to sift through huge amounts of data and entities.</p>
<p>Furthermore, I realized that having some notion of problem extent (per rule and service), as well as concrete examples, helps make the problem more tangible.</p>
<p>Thinking further about the idea of rule violation <code>extent</code>, there might even be a way to incorporate that into the score formula itself.
In my humble opinion, this would make the score significantly more comparable and indicative of the actual impact.
I <a href="https://github.com/instrumentation-score/spec/issues/43">proposed this idea in an issue</a> on the Instrumentation Score project.</p>
<h2>Conclusion</h2>
<p>The Instrumentation Score is a powerful approach to ensuring a high level of data quality with OpenTelemetry.</p>
<p>Thank you to the maintainers — Antoine Toulme, Daniel Gomez Blanco, Juraci Paixão Kröhling, and Michele Mancioppi — for bringing this great project to life, and to all the contributors for their participation!</p>
<p>With proper implementation of the rules and score calculation, users can easily get actionable insights into what they need to fix in their instrumentation and data collection.
The Instrumentation Score rules are in an early stage and are steadily improved and extended.
I'm looking forward to what the community will build in the scope of this project in the future, and I hope to intensify my contributions as well.</p>]]></content:encoded>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/otel-instrumentation-score/otel-instrumentation-grade.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Revealing unknowns in your tracing data with inferred spans in OpenTelemetry]]></title>
            <link>https://www.elastic.co/observability-labs/blog/tracing-data-inferred-spans-opentelemetry</link>
            <guid isPermaLink="false">tracing-data-inferred-spans-opentelemetry</guid>
            <pubDate>Mon, 22 Apr 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Distributed tracing is essential in understanding complex systems, but it can miss latency issue details. By combining profiling techniques with distributed tracing, Elastic provides the inferred spans feature as an extension for the OTel Java SDK.]]></description>
            <content:encoded><![CDATA[<p>In the complex world of microservices and distributed systems, achieving transparency and understanding the intricacies and inefficiencies of service interactions and request flows has become a paramount challenge. Distributed tracing is essential in understanding distributed systems. But distributed tracing, whether manually applied or auto-instrumented, is usually rather coarse-grained. Hence, distributed tracing covers only a limited fraction of the system and can easily miss parts of the system that are the most useful to trace.</p>
<p>Addressing this gap, Elastic developed the concept of inferred spans as a powerful enhancement to traditional instrumentation-based tracing as an extension for the OpenTelemetry Java SDK/Agent. We are in the process of contributing this back to OpenTelemetry, until then our <a href="https://github.com/elastic/elastic-otel-java/tree/main/inferred-spans">extension</a> can be seamlessly used with the existing OpenTelelemetry Java SDK (as described below).</p>
<p>Inferred spans are designed to augment the visibility provided by instrumentation-based traces, shedding light on latency sources within the application or libraries that were previously uninstrumented. This feature significantly expands the utility of distributed tracing, allowing for a more comprehensive understanding of system behavior and facilitating a deeper dive into performance optimization.</p>
<h2>What is inferred spans?</h2>
<p>Inferred spans is an observability technique that combines distributed tracing with profiling techniques to illuminate the darker, unobserved corners of your application — areas where standard instrumentation techniques fall short. The inferred spans feature interweaves information derived from profiling stacktraces with instrumentation-based tracing data, allowing for the generation of new spans based on the insights drawn from profiling data.</p>
<p>This feature proves invaluable when dealing with custom code or third-party libraries that significantly contribute to the request latency but lack built-in or external instrumentation support. Often, identifying or crafting specific instrumentation for these segments can range from challenging to outright unfeasible. Moreover, certain scenarios exist where implementing instrumentation is impractical due to the potential for substantial performance overhead. For instance, instrumenting application locking mechanisms, despite their critical role, is not viable because of their ubiquitous nature and the significant latency overhead the instrumentation can introduce to application requests. Still, ideally, such latency issues would be visible within your distributed traces.</p>
<p>Inferred spans ensures a deeper visibility into your application’s performance dynamics including the above-mentioned scenarios.</p>
<h2>Inferred spans in action</h2>
<p>To demonstrate the inferred spans feature we will use the Java implementation of the <a href="https://github.com/elastic/observability-examples/tree/main/Elastiflix/java-favorite">Elastiflix demo application</a>. Elasticflix has an endpoint called favorites that does some Redis calls and also includes an artificial delay. First, we use the plain OpenTelemetry Java Agent to instrument our application:</p>
<pre><code class="language-java">java -javaagent:/path/to/otel-javaagent-&lt;version&gt;.jar \
-Dotel.service.name=my-service-name \
-Dotel.exporter.otlp.endpoint=https://&lt;our-elastic-apm-endpoint&gt; \
&quot;-Dotel.exporter.otlp.headers=Authorization=Bearer SECRETTOKENHERE&quot; \
-jar my-service-name.jar
</code></pre>
<p>With the OpenTelemetry Java Agent we get out-of-the-box instrumentation for HTTP entry points and calls to Redis for our Elastiflix application. The resulting traces contain spans for the POST /favorites entrypoint, as well as a few short spans for the calls to Redis.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/tracing-data-inferred-spans-opentelemetry/image2.png" alt="POST /favorites entrypoint" /></p>
<p>As you can see in the trace above, it’s not clear where most of the time is spent within the POST /favorites request.</p>
<p>Let’s see how inferred spans can shed light into these areas. You can use the inferred spans feature either manually with your OpenTelemetry SDK (see section below), package it as a drop-in extension for the upstream OpenTelemetry Java agent, or just use <a href="https://github.com/elastic/elastic-otel-java/tree/main">Elastic’s distribution of the OpenTelemetry Java agent</a> that comes with the inferred spans feature.</p>
<p>For convenience, we just download the <a href="https://mvnrepository.com/artifact/co.elastic.otel/elastic-otel-javaagent/0.0.1">agent jar</a> of the Elastic distribution and extend the configuration to enable the inferred spans feature:</p>
<pre><code class="language-java">java -javaagent:/path/to/elastic-otel-javaagent-&lt;version&gt;.jar \
-Dotel.service.name=my-service-name \
-Dotel.exporter.otlp.endpoint=https://XX.apm.europe-west3.gcp.cloud.es.io:443 \
&quot;-Dotel.exporter.otlp.headers=Authorization=Bearer SECRETTOKENHERE&quot; \
-Delastic.otel.inferred.spans.enabled=true \
-jar my-service-name.jar
</code></pre>
<p>The only non-standard option here is elastic.otel.inferred.spans.enabled: The inferred spans Feature is currently opt-in and therefore needs to be enabled explicitly. Running the same application with the inferred spans feature enabled yields more comprehensive traces:</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/tracing-data-inferred-spans-opentelemetry/image1.png" alt="more comprehensive traces" /></p>
<p>The inferred-spans (colored blue in the above screenshot) follow the naming pattern Class#method. With that, the inferred spans feature helps us pinpoint the exact methods that contribute the most to the overall latency of the request. Note that the parent-child relationship between the HTTP entry span, the Redis spans, and the inferred spans is reconstructed correctly, resulting in a fully functional trace structure.</p>
<p>Examining the handleDelay method within the Elastiflix application reveals the use of a straightforward sleep statement. Although the sleep method is not CPU-bound, the full duration of this delay is captured as inferred spans. This stems from employing the async-profiler's wall clock time profiling, as opposed to solely relying on CPU profiling. The ability of the inferred spans feature to reflect actual latency, including for I/O operations and other non-CPU-bound tasks, represents a significant advancement. It allows for diagnosing and resolving performance issues that extend beyond CPU limitations, offering a more nuanced view of system behavior.</p>
<h2>Using inferred spans with your own OpenTelemetry SDK</h2>
<p>OpenTelemetry is a highly extensible framework: Elastic embraces this extensibility by also publishing most extensions shipped with our OpenTelemetry Java Distro as standalone-extensions to the <a href="https://github.com/open-telemetry/opentelemetry-java">OpenTelemetry Java SDK</a>.</p>
<p>As a result, if you do not want to use our distro (e.g., because you don’t need or want bytecode instrumentation in your project), you can still use our extensions, such as the extension for the inferred spans feature. All you need to do is set up the <a href="https://opentelemetry.io/docs/languages/java/instrumentation/#initialize-the-sdk">OpenTelemetry SDK in your code</a> and add the inferred spans extension as a dependency:</p>
<pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;co.elastic.otel&lt;/groupId&gt;
    &lt;artifactId&gt;inferred-spans&lt;/artifactId&gt;
    &lt;version&gt;{latest version}&lt;/version&gt;
&lt;/dependency&gt;
</code></pre>
<p>During your SDK setup, you’ll have to initialize and register the extension:</p>
<pre><code class="language-java">InferredSpansProcessor inferredSpans = InferredSpansProcessor.builder()
  .samplingInterval(Duration.ofMillis(10)) //the builder offers all config options
  .build();
SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
  .addSpanProcessor(inferredSpans)
.addSpanProcessor(BatchSpanProcessor.builder(OtlpGrpcSpanExporter.builder()
    .setEndpoint(&quot;https://&lt;your-elastic-apm-endpoint&gt;&quot;)
    .addHeader(&quot;Authorization&quot;, &quot;Bearer &lt;secrettoken&gt;&quot;)
    .build()).build())
  .build();
inferredSpans.setTracerProvider(tracerProvider);
</code></pre>
<p>The inferred spans extension seamlessly integrates with the <a href="https://opentelemetry.io/docs/languages/java/instrumentation/#automatic-configuration">OpenTelemetry SDK Autoconfiguration mechanism</a>. By incorporating the OpenTelemetry SDK and its extensions as dependencies within your application code — rather than through an external agent — you gain the flexibility to configure them using the same environment variables or JVM properties. Once the inferred spans extension is included in your classpath, activating it for autoconfigured SDKs becomes straightforward. Simply enable it using the elastic.otel.inferred.spans.enabled property, as previously described, to leverage the full capabilities of this feature with minimal setup.</p>
<h2>How does inferred spans work?</h2>
<p>The inferred spans feature leverages the capabilities of collecting wall clock time profiling data of the widely-used <a href="https://github.com/async-profiler/async-profiler">async-profiler</a>, a low-overhead, popular production-time profiler in the Java ecosystem. It then transforms the profiling data into actionable spans as part of the distributed traces. But what mechanism allows for this transformation?</p>
<p>Essentially, the inferred spans extension engages with the lifecycle of span events, specifically when a span is either activated or deactivated across any thread via the <a href="https://opentelemetry.io/docs/specs/otel/context/">OpenTelemetry context</a>. Upon the activation of the initial span within a transaction, the extension commences a session of wall-clock profiling via the async-profiler, set to a predetermined duration. Concurrently, it logs the details of all span activations and deactivations, capturing their respective timestamps and the threads on which they occurred.</p>
<p>Following the completion of the profiling session, the extension processes the profiling data alongside the log of span events. By correlating the data, it reconstructs the inferred spans. It's important to note that, in certain complex scenarios, the correlation may assign an incorrect name to a span. To mitigate this and aid in accurate identification, the extension enriches the inferred spans with stacktrace segments under the code.stacktrace attribute, offering users clarity and insight into the precise methods implicated.</p>
<h2>Inferred spans vs. correlation of traces with profiling data</h2>
<p>In the wake of OpenTelemetry's recent <a href="https://opentelemetry.io/blog/2024/profiling/">announcement of the profiling signal</a>, coupled with <a href="https://www.elastic.co/blog/elastic-donation-proposal-to-contribute-profiling-agent-to-opentelemetry">Elastic's commitment to donating the Universal Profiling Agent</a> to OpenTelemetry, you might be wondering about how the inferred spans feature differentiates from merely correlating profiling data with distributed traces using span IDs and trace IDs. Rather than viewing these as competing functionalities, it's more accurate to consider them complementary.</p>
<p>The inferred spans feature and the correlation of tracing with profiling data both employ similar methodologies — melding tracing information with profiling data. However, they each shine in distinct areas. Inferred spans excels at identifying long-running methods that could escape notice with traditional CPU profiling, which is more adept at pinpointing CPU bottlenecks. A unique advantage of inferred spans is its ability to account for I/O time, capturing delays caused by operations like disk access that wouldn't typically be visible in CPU profiling flamegraphs.</p>
<p>However, the inferred spans feature has its limitations, notably in detecting latency issues arising from &quot;death by a thousand cuts&quot; — where a method, although not time-consuming per invocation, significantly impacts total latency due to being called numerous times across a request. While individual calls might not be captured as inferred spans due to their brevity, CPU-bound methods contributing to latency are unveiled through CPU profiling, as flamegraphs display the aggregate CPU time consumed by these methods.</p>
<p>An additional strength of the inferred spans feature lies in its data structure, offering a simplified tracing model that outlines typical parent-child relationships, execution order, and good latency estimates. This structure is achieved by integrating tracing data with span activation/deactivation events and profiling data, facilitating straightforward navigation and troubleshooting of latency issues within individual traces.</p>
<p>Correlating distributed tracing data with profiling data comes with a different set of advantages. Learn more about it in our related blog post, <a href="https://www.elastic.co/blog/continuous-profiling-distributed-tracing-correlation">Beyond the trace: Pinpointing performance culprits with continuous profiling and distributed tracing correlation</a>.</p>
<h2>What about the performance overhead?</h2>
<p>As mentioned before, the inferred spans functionality is based on the widely used async-profiler, known for its minimal impact on performance. However, the efficiency of profiling operations is not without its caveats, largely influenced by the specific configurations employed. A pivotal factor in this balancing act is the sampling interval — the longer the interval between samples, the lower the incurred overhead, albeit at the expense of potentially overlooking shorter methods that could be critical to the inferred spans feature discovery process.</p>
<p>Adjusting the probability-based trace sampling presents another way for optimization, directly influencing the overhead. For instance, setting trace sampling to 50% effectively halves the profiling load, making the inferred spans feature even more resource-efficient on average per request. This nuanced approach to tuning ensures that the inferred spans feature can be leveraged in real-world, production environments with a manageable performance footprint. When properly configured, this feature offers a potent, low-overhead solution for enhancing observability and diagnostic capabilities within production applications.</p>
<h2>What’s next for inferred spans and OpenTelemetry?</h2>
<p>This blog post outlined and introduced the inferred spans feature available as an extension for the OpenTelemetry Java SDK and built into the newly introduced Elastic OpenTelemetry Java Distro. Inferred spans allows users to troubleshoot latency issues in areas of code that are not explicitly instrumented while utilizing traditional tracing data.</p>
<p>The feature is currently merely a port of the existing feature from the proprietary Elastic APM Agent. With Elastic embracing OpenTelemetry, we plan on contributing this extension to the upstream OpenTelemetry project. For that, we also plan on migrating the extension to the latest async-profiler 3.x release. <a href="https://github.com/elastic/elastic-otel-java/tree/main/inferred-spans">Try out inferred spans for yourself</a> and see how it can help you diagnose performance problems in your applications.</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>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/tracing-data-inferred-spans-opentelemetry/148360-Blog-header-image--Revealing-Unknowns-in-your-Tracing-Data-with-Inferred-Spans-in-OpenTelemetry_V1.jpg" length="0" type="image/jpg"/>
        </item>
    </channel>
</rss>