<?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 Cesar Munoz</title>
        <link>https://www.elastic.co/observability-labs</link>
        <description>Trusted security news &amp; research from the team at Elastic.</description>
        <lastBuildDate>Mon, 17 Aug 2026 17:42:30 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 Cesar Munoz</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[Elastic APM for iOS and Android Native apps]]></title>
            <link>https://www.elastic.co/observability-labs/blog/apm-ios-android-native-apps</link>
            <guid isPermaLink="false">apm-ios-android-native-apps</guid>
            <pubDate>Thu, 08 Feb 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[This blog provides an overview of the key capabilities included in the Elastic APM solution for iOS and Android native apps, as well as a walkthrough of the configuration details and troubleshooting workflow for a few error scenarios.]]></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>Elastic® APM for iOS and Android native apps is generally available in the stack release v8.12. The Elastic <a href="https://github.com/elastic/apm-agent-ios">iOS</a> and <a href="https://github.com/elastic/apm-agent-android">Android</a> APM agents are open-source and have been developed on-top, i.e., as a distribution of the OpenTelemetry Swift and Android SDK/API, respectively.</p>
<h2>Overview of the Mobile APM solution</h2>
<p>The OpenTelemetry SDK/API for iOS and Android supports capabilities such as auto-instrumentation of HTTP requests, API for manual instrumentation, data model based on the OpenTelemetry semantic conventions, and buffering support. Additionally, the Elastic APM agent distributions also support an easier initialization process and novel features such as remote config and user session based sampling. The Elastic <a href="https://github.com/elastic/apm-agent-ios">iOS</a> and <a href="https://github.com/elastic/apm-agent-android">Android</a> APM agents being <em>distributions</em> are maintained per Elastic’s standard support T&amp;Cs.</p>
<p>There are curated or pre-built dashboards provided in Kibana® for monitoring, data analysis, and for troubleshooting purposes. The <strong>Service Overview</strong> view shown below provides relevant frontend KPIs such as crash rate, http requests, average app load time, and more, including the comparison view.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/apm-ios-android-native-apps/1.png" alt="1 - comparison view" /></p>
<p>Further, the geographic distribution of user traffic is available on a map at a country and regional level. The service overview dashboard also shows trends of metrics such as throughput, latency, failed transaction rate, and distribution of traffic by device make-model, network connection type, and app version.</p>
<p>The <strong>Transactions</strong> view shown below highlights the performance of the different transaction groups, including the distributed trace end-to-end of individual transactions with links to associated spans, errors and crashes. Further, users can see at a glance the distribution of traffic by device make and model, app version, and OS version.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/apm-ios-android-native-apps/2.png" alt="2- opbeans android" /></p>
<p>Tabular views such as the one highlighted below located at the bottom of <strong>Transactions</strong> tab makes it relatively easy to see how the device make and model, App version, etc., impacts latency and crash rate.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/apm-ios-android-native-apps/3.png" alt="3 - latency and crash rate" /></p>
<p>The <strong>Errors &amp; Crashes</strong> view shown below can be used to analyze the different error and crash groups. The unsymbolicated (iOS) or obfuscated (Android) stacktrace of the individual error or crash instance is also available in this view.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/apm-ios-android-native-apps/4.png" alt="4 - opbeans swift" /></p>
<p>The <strong>Service Map</strong> view shown below provides a visualization of the end-to-end service interdependencies, including any third-party APIs, proxy servers, and databases.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/apm-ios-android-native-apps/5.png" alt="5 - flowchart" /></p>
<p>The comprehensive pre-built dashboards for observing the mobile frontend in Kibana provide visibility into the sources of errors, crashes, and bottlenecks to ease troubleshooting of issues in the production environment. The underlying Elasticsearch® Platform also supports the ability to query raw data, build custom metrics and custom dashboards, alerting, SLOs, and anomaly detection. Altogether the platform provides a comprehensive set of tools to expedite root cause analysis and remediation, thereby facilitating a high velocity of innovation.</p>
<h2>Walkthrough of the debugging workflow for some error scenarios</h2>
<p>Next, we will provide a walkthrough of the configuration details and the troubleshooting workflow for a couple of error scenarios in iOS and Android native apps.</p>
<h3>Scenario 1</h3>
<p>In this example, we will debug a crash in an asynchronous method using Apple’s crash report <strong>symbolication</strong> as well as <strong>breadcrumbs</strong> to deduce the cause of the crash.</p>
<p><strong>Symbolication</strong><br />
In this scenario, users notice a spike in the crash occurrences of a particular crash group in the Errors &amp; Crashes tab and decide to investigate further. A new crash comes in on the Crashes tab, and the developer follows these steps to symbolicate the crash report locally.</p>
<ol>
<li>Copy the crash via the UI and paste it into a file with the following name format &lt;AppBinaryName&gt;_&lt;DateTime&gt;. For example, “opbeans-swift_2024-01-18-114211.ips`.</li>
</ol>
<p><img src="https://www.elastic.co/observability-labs/assets/images/apm-ios-android-native-apps/6.png" alt="6 - Symbolication" /></p>
<ol start="2">
<li>Apple provides <a href="https://developer.apple.com/documentation/xcode/adding-identifiable-symbol-names-to-a-crash-report">detailed instructions</a> on how to symbolicate this file locally either automatically through Xcode or manually using the command line.</li>
</ol>
<p><strong>Breadcrumbs</strong><br />
The second frame of the first thread shows that the crash is occuring in a Worker instance.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/apm-ios-android-native-apps/7.png" alt="7 - Breadcrumbs" /></p>
<p>This instance is actually used in many places, and due to the asynchronous nature of this function, it’s not possible to determine immediately where this call is coming from. Nevertheless, we can utilize features of the Open Telemetry SDK to add more context to these crashes and then put the pieces together to find the site of the crash.</p>
<p>By adding “breadcrumbs” around this Worker instance, it is possible to track down which calls to the Worker are actually associated with this crash.</p>
<p><strong>Example:</strong><br />
Create a logger provider in the Worker class as a public variable for ease of access, as shown below:</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/apm-ios-android-native-apps/8.png" alt="8 - example code" /></p>
<p>Create breadcrumbs everywhere the Worker.doWork() function is called:</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/apm-ios-android-native-apps/9.png" alt="9 - Create breadcrumbs everywhere the Worker.doWork() function" /></p>
<p>Each of these breadcrumbs will use the same event <strong>name</strong> “worker_breadcrumb” so they can be consistently queried, and the differentiation will be done using the “ <strong>source</strong> ” attribute.</p>
<p>In this example, the Worker.doWork() function is being called from a CustomerRow struct (a table row which does work ‘onTapGesture’). If you were to call this method from multiple places in a CustomerRow struct, you may also add additional differentiations to the “ <strong>source</strong> ” attribute value, such as the associated function (e.g., “CustomerRow#onTapGesture”).</p>
<p>Now that the app is reporting these breadcrumbs, we can use Discover to <strong>query</strong> for them, as shown below:</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/apm-ios-android-native-apps/10.png" alt="10 - Discover to query" /></p>
<p>_ <strong>Note:</strong> _ <em>Event</em> _ <strong>names</strong> _ <em>sent by the agent are translated to event</em> _ <strong>action</strong> _ <em>in Elastic Common Schema (ECS), so ensure the query uses this field.</em></p>
<ol>
<li>
<p>You can add a filter: <code>event.action: “worker_breadcrumb”</code> and it shows all events generated from this new breadcrumb.</p>
</li>
<li>
<p>You can also see the various sources: ProductRow, CustomerRow, CartRow, etc.</p>
</li>
<li>
<p>If you add <strong>error.type : crash</strong> to the query, you can see crashes alongside the breadcrumbs:</p>
</li>
</ol>
<p><img src="https://www.elastic.co/observability-labs/assets/images/apm-ios-android-native-apps/11.png" alt="11 - crashes along side the breadcrumbs" /></p>
<p>A crash and a breadcrumb next to each other in the timeline may come from completely different devices, so we need another differentiator. For each crash, we have metadata that contains the <strong>session.id</strong> associated with the crash, viewable from the Metadata tab. We can query using this <strong>session.id</strong> to ensure that the only data we are looking at in Discover is from a single user session (i.e., a single device) that resulted in the crash.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/apm-ios-android-native-apps/12.png" alt="12. - session.id" /></p>
<p>In Discover, we can now see the session event flow, on a single device, concerning the crash via the breadcrumbs, as shown below:</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/apm-ios-android-native-apps/13.png" alt="13 - session event flow" /></p>
<p>It looks like the last breadcrumb before the crash was from the “CustomerRow” breadcrumb. Now this gives the app developer a good place to start their root cause analysis or investigation.</p>
<h3>Scenario 2</h3>
<p>_ <strong>Note:</strong> _ <em>This scenario requires the Elastic Android agent version “0.14.0” or higher.</em></p>
<p>An Android sample app has a form composed of two screens that are created using two fragments (<code>FirstPage</code> and <code>SecondPage</code>). In the first screen, the app makes a backend API call to get a key that identifies the form submission. This key is stored in memory in the app and must be available on the last screen where the form is sent; the key must be sent along with the form's data.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/apm-ios-android-native-apps/14.jpg" alt="14 - form submission" /></p>
<p><strong>The problem</strong><br />
We start to see a spike in crash occurrences in Kibana (null pointer exception) in the Errors &amp; Crashes tab that always seem to happen on the last screen of the form, when the users click on the &quot;FINISH&quot; button. Nevertheless, <strong>this is not always reproducible</strong> , so the root cause isn't clear just by looking at the crash’s stacktrace alone. Here’s what it looks like:</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/apm-ios-android-native-apps/15.png" alt="15 - stack trace" /></p>
<p>When we take a look at the code referenced in the stacktrace, this is what we can see:</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/apm-ios-android-native-apps/16.png" alt="16 - When we take a look at the code referenced in the stacktrace, this is what we can see:" /></p>
<p>This is the line where the crash happens, so it seems like the variable “formId” (which is a static String located in “FirstPage”) was null by the time this code was executed, causing a null pointer exception to be raised. This variable is set within the “FirstPage” fragment after the backend request is done to retrieve the id. The only way to get to the “SecondPage” is by passing through the “FirstPage.” So, the stacktrace alone doesn’t help much as the pages have to be opened in order, and the first one will always set the “formId” variable. Therefore, it doesn’t seem likely that the formId could be null in “SecondPage.”</p>
<p><strong>Finding the root cause</strong><br />
Apart from taking a look at the crash’s stacktrace, it could also be useful to take a look at complementary data that would help put the pieces together and get a broader picture of what other things happened while our app was running when the crash happened. For this case, we know that the form ID must come from our backend service, so we could start by ruling out that there was an error with the backend call. We do this by checking the traces from the creation of our FirstPage fragment where the form ID request is executed, in the Transaction details view:</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/apm-ios-android-native-apps/17.png" alt="17 - trace sample" /></p>
<p>The “Created” spans represent the time it took to create the first fragment. The topmost one shows the Activity creation, followed by the NavHostFragment, followed by “FirstScreen.” Not long after its creation, we see that a GET HTTP request to our backend is made to retrieve our form ID and, according to the traces, the GET request was successful. We can therefore rule out that there is an issue with the backend communication for this problem.</p>
<p>Another option could be looking at the logs sent throughout the <a href="https://opentelemetry.io/docs/specs/semconv/general/session/">session</a> in our app where the crash occurred (we could also take a look at all the logs coming from our app but they would be too many to analyze this one issue). To do so, we first copy one of the spans’ “session.id” values (any span would work since the same session ID will be available in all the data that was sent from our app during the time that the crash occurred) available in the span details flyout.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/apm-ios-android-native-apps/18.png" alt="18 - red box highlighted" /></p>
<p>_ <strong>Note:</strong> _ <em>The same session ID can also be found in the crash metadata.</em></p>
<p>Now that we have identified our session, we can open up the Logs Explorer view and take a look at all of our app’s logs within that same session, as shown below:</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/apm-ios-android-native-apps/19.png" alt="19 - app's logs" /></p>
<p>By looking at the logs, and adding a few fields to show the app’s lifecycle status and the error types, we see the log events that are <a href="https://github.com/elastic/apm/blob/main/specs/agents/mobile/events.md">automatically collected</a> from our app. We can see the crash event at the top of the list as the latest one. We can also see our app’s lifecycle events, and if we keep scrolling through, we’ll get to some lifecycle events that are going to help find our root cause:</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/apm-ios-android-native-apps/20.png" alt="20 - root cause" /></p>
<p>We can see there are a couple of lifecycle events that tell us that the app was restarted during the session. This is an important hint because it means that the Android OS killed our app at some point, which is common when an app stays in the background for a while. With this information, we could try to reproduce the issue by forcing the OS to kill our app in the background and then see how it behaves when reopened from the recently opened apps menu.</p>
<p>After giving it a try, we could reproduce the issue and we found that the static “formId” variable was lost when the app was restarted, causing it to be null when the SecondPage fragment requested it. We can now research best practices of passing arguments to Fragments so we can change our code to prevent relying on static fields and instead store and share values between screens, thus preventing this crash from happening again.</p>
<p><strong>Bonus:</strong> For this scenario, it was enough for us to rely on the events that are sent automatically by the APM Agent; however, if those aren’t enough for other cases, we can always send custom events in the places where we want to track the state changes of our app via the OpenTelemetry event API, as shown in the the code snippet below:</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/apm-ios-android-native-apps/21.png" alt="21 - black code box" /></p>
<h2>Make the most of your Elastic APM Experience</h2>
<p>In this post, we reviewed Elastic’s new Mobile APM solution available in 8.12. The new solution uses Elastic’s new <a href="https://github.com/elastic/apm-agent-ios">iOS</a> and <a href="https://github.com/elastic/apm-agent-android">Android</a> APM agents that are open-source and have been developed on-top, i.e., as a distribution of the OpenTelemetry Swift and Android SDK/API, respectively.</p>
<p>We also reviewed configuration details and the troubleshooting workflow for two error scenarios in iOS and Android native apps.</p>
<ul>
<li>
<p><strong>iOS scenario:</strong> Debug a crash in an asynchronous method using Apple’s crash report <strong>symbolication</strong> as well as <strong>breadcrumbs</strong> to deduce the cause of the crash.</p>
</li>
<li>
<p><strong>Android scenario:</strong> Analyze why users get a null pointer exception on the last screen when they click on the “FINISH” button of a form. Analyzing this is not always clear by looking at the crash’s stack trace and isn’t easily reproducible.</p>
</li>
</ul>
<p>In both instances, we found the root cause of the crash using distributed traces from the mobile device as well as correlated logs. Hopefully this blog provided a review of how Elastic can help manage and monitor Mobile native apps.</p>
<p>Elastic invites SREs and developers to experience our Mobile APM solution firsthand and unlock new horizons in their data tasks. Try it today at <a href="https://ela.st/free-trial">https://ela.st/free-trial</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/apm-ios-android-native-apps/141949-elastic-blogheaderimage.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Android application monitoring with OpenTelemetry: distributed tracing from tap to backend]]></title>
            <link>https://www.elastic.co/observability-labs/blog/distributed-tracing-android-mobile-apm-opentelemetry</link>
            <guid isPermaLink="false">distributed-tracing-android-mobile-apm-opentelemetry</guid>
            <pubDate>Wed, 12 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[EDOT Android adds mobile APM to your Android app with one Gradle dependency: crash reporting, session tracking and distributed tracing visible in Kibana.]]></description>
            <content:encoded><![CDATA[<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 performance and reliability is a key challenge for mobile app teams and the backend services they depend on. Understanding real user impact, crash patterns, and the root causes of slow response times is fundamental to managing mobile app quality.</p>
<p>The challenge deepens when something goes wrong. A crash on the device, a slow screen, or an error response might originate in the Android app itself, in a backend service, or somewhere in the network path between them. Debugging these problems without a connected, E2E view from the mobile client to the backend is time-consuming and frustrating. And without a standard instrumentation format, mobile teams often end up maintaining separate tooling that doesn't integrate with what the backend and infrastructure teams already use.</p>
<p><a href="https://opentelemetry.io/">OpenTelemetry</a> offers a way out: a unified, open-standard instrumentation model that works across platforms and languages, backed by a large community. The Elastic Distribution of OpenTelemetry Android, or EDOT Android, is an APM agent for native Android applications built on top of OpenTelemetry. It gives Android teams a practical path to observe mobile app behavior in Elastic, providing them with distributed tracing, crash reporting, session tracking, disk buffering, and automatic instrumentation, with as little code as possible while staying grounded in open standards.</p>
<p>To see what it all looks like, we will instrument a demo Android weather application end to end. You will run Elasticsearch, Kibana, and the Elastic Agent locally. The Elastic Agent provides the OTLP endpoint that receives telemetry from the Android app and backend. You will then generate distributed traces, custom spans, logs, and Android crashes from the app, and explore the results in Kibana using the Android OpenTelemetry dashboards.</p>
<p>This article focuses on a hands-on experiment to explore the E2E experience of observing Android apps with Elastic, using the EDOT Android agent. For more specific details on the EDOT Android agent, such as a list of supported features and a setup guide for your own Android project, take a look at <a href="https://www.elastic.co/docs/reference/opentelemetry/edot-sdks/android">EDOT Android docs</a>.</p>
<h2>Setting up EDOT Android with Elasticsearch and Kibana</h2>
<p>We will use the <a href="https://github.com/elastic/android-agent-demo">EDOT Android demo application</a>. The demo is intentionally small but covers the main workflows you need when evaluating mobile observability with Elastic.</p>
<p>The demo has two main components: an <strong>Android app</strong>, and a <strong>Spring Boot backend</strong>. Additionally, you'll need an <strong>Elastic Stack</strong> environment up and running; we'll explain more about how to get one later in this guide.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/distributed-tracing-android-mobile-apm-opentelemetry/blog-demo-project-components.png" alt="Demo app components" /></p>
<h3>Prerequisites</h3>
<ul>
<li>Java 17 or higher.</li>
<li><a href="https://www.docker.com/">Docker</a>.</li>
<li><a href="https://developer.android.com/studio">Android Studio</a>.</li>
<li>An <a href="https://developer.android.com/studio/run/emulator">Android emulator</a>.</li>
<li>On Windows, use <a href="https://learn.microsoft.com/en-us/windows/wsl/install">Windows Subsystem for Linux (WSL)</a> to run the demo scripts.</li>
</ul>
<h3>Step 1: Clone the demo app's repository</h3>
<p>We'll start by cloning the <a href="https://github.com/elastic/android-agent-demo">EDOT Android demo application</a>:</p>
<pre><code class="language-shell">git clone git@github.com:elastic/android-agent-demo.git
</code></pre>
<h3>Step 2: Start the Elastic Stack</h3>
<p>The demo uses <a href="https://github.com/elastic/start-local/">start-local</a> to run Elasticsearch, Kibana, and the <a href="https://www.elastic.co/docs/reference/fleet/elastic-agent-as-otel-collector">Elastic Agent</a> with a single command. In this setup, the Elastic Agent provides the OTLP endpoint that receives telemetry from the application and backend. Run this from the directory where you want the local Elastic files to be created:</p>
<pre><code class="language-bash">curl -fsSL https://elastic.co/start-local | sh -s -- --edot
</code></pre>
<p>For more information on this step, take a look at the <a href="https://github.com/elastic/android-agent-demo#step-1-setting-up-elasticsearch-kibana-and-the-elastic-agent">demo app's instructions</a>.</p>
<h3>Step 3: Start the local backend</h3>
<p>The demo backend is a Spring Boot service instrumented with the <a href="https://github.com/elastic/elastic-otel-java/">EDOT Java agent</a>. It handles the app's weather requests and calls the <a href="https://open-meteo.com/">Open-Meteo</a> public API for weather data.</p>
<pre><code class="language-bash">./backend-manager start
</code></pre>
<p>For more information on managing the backend service, take a look at the <a href="https://github.com/elastic/android-agent-demo#step-2-launching-the-backend-service">demo app's instructions</a>.</p>
<h3>Step 4: Launch the Android application</h3>
<p>Use <a href="https://developer.android.com/studio/intro">Android Studio</a> to open up the <a href="https://github.com/elastic/android-agent-demo">EDOT Android demo application</a> repo and run the application in your emulator. More info on how to run Android apps from Android Studio <a href="https://developer.android.com/studio/run">here</a>.</p>
<h2>Generating distributed traces, errors and crashes from an Android app</h2>
<p>The Android app has two screens: a city selector and a weather display screen that shows the current weather for the selected city on the previous screen. It includes two intentional failure paths: the first one is reached by selecting <strong>New York</strong>, which causes the backend to reject the request (the demo backend only supports European cities), and tapping the floating crash button intentionally crashes the app so you can review crash reporting in Kibana after relaunch. We'll take a look at those use cases in more detail below.</p>
<h3>Tracing a successful request end to end</h3>
<p><img src="https://www.elastic.co/observability-labs/assets/images/distributed-tracing-android-mobile-apm-opentelemetry/blog-android-app-selecting-paris.png" alt="Selecting Paris" /></p>
<p>In the EDOT Android demo app, selecting &quot;Paris&quot; as the city triggers a successful backend request on the second screen, for which a span will be automatically generated using EDOT Android's <a href="https://www.elastic.co/docs/reference/opentelemetry/edot-sdks/android/automatic-instrumentation#okhttp">OkHttp auto-instrumentation</a>, which supports all OkHttp-generated HTTP requests and tools using it, such as Retrofit. Aside from the Android HTTP span, the successful city request continues e2e and creates a backend HTTP client span to Open-Meteo.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/distributed-tracing-android-mobile-apm-opentelemetry/blog-trace-waterfall-view.png" alt="Trace waterfall" /></p>
<h3>How backend errors appear in the Android distributed trace</h3>
<p><img src="https://www.elastic.co/observability-labs/assets/images/distributed-tracing-android-mobile-apm-opentelemetry/blog-android-app-selecting-new-york.png" alt="Selecting New York" /></p>
<p>The demo backend only supports European cities, so selecting &quot;New York&quot; causes it to fail, which in turn automatically creates an error associated with our Android app's HTTP span. This is done automatically. We'll see later how to find and inspect these issues from Kibana.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/distributed-tracing-android-mobile-apm-opentelemetry/blog-error-trace-waterfall-view.png" alt="Error trace waterfall" /></p>
<h3>How EDOT Android captures and reports app crashes</h3>
<p><img src="https://www.elastic.co/observability-labs/assets/images/distributed-tracing-android-mobile-apm-opentelemetry/blog-android-app-selecting-crash.png" alt="Application crash" /></p>
<p>The crash button creates a crash event that appears in Kibana after the app is reopened. This event contains session information that will help us narrow down its root cause from Kibana, as we'll see later.</p>
<p>Note: EDOT Android automatically attaches Android session context to spans and logs. That means that any span or log created before the crash can be reviewed together with the crash event and nearby spans from the same session, giving you a complete picture of what the user was doing. This even applies to <a href="https://www.elastic.co/docs/reference/opentelemetry/edot-sdks/android/manual-instrumentation">manually created spans and logs</a>.</p>
<h2>Visualizing Android application monitoring data in Kibana</h2>
<p>To see the whole story from our Android app in a single place, we'll install Kibana's <a href="https://www.elastic.co/docs/reference/integrations/otel_android_dashboards">Android OpenTelemetry Assets</a> package by following the steps below.</p>
<ol>
<li>In Kibana, search for &quot;Android OpenTelemetry Assets&quot; in the <a href="https://www.elastic.co/docs/explore-analyze/find-and-organize/find-apps-and-objects">global search field</a>.</li>
<li>Open it and click <strong>Install</strong> to add the Android dashboards to your Kibana instance.</li>
</ol>
<p><img src="https://www.elastic.co/observability-labs/assets/images/distributed-tracing-android-mobile-apm-opentelemetry/blog-content-pack-search.png" alt="Searching content pack" /></p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/distributed-tracing-android-mobile-apm-opentelemetry/blog-content-pack-install.png" alt="Installing content pack" /></p>
<h3>Exploring Android application monitoring dashboards in Kibana</h3>
<p>Once the content package is installed, open the [Android OTel] Application Overview dashboard:</p>
<ol>
<li>In Kibana, search for Dashboards in the <a href="https://www.elastic.co/docs/explore-analyze/find-and-organize/find-apps-and-objects">global search field</a> or in Kibana's menu.</li>
<li>In Dashboards, search for Android OTel and open the &quot;[Android OTel] Application Overview&quot; dashboard.</li>
<li>Select your application from the Applications panel at the top of the dashboard.</li>
</ol>
<p><img src="https://www.elastic.co/observability-labs/assets/images/distributed-tracing-android-mobile-apm-opentelemetry/blog-dashboard-list.png" alt="Dashboard list" /></p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/distributed-tracing-android-mobile-apm-opentelemetry/blog-dashboard-android-overview.png" alt="Android overview dashboard" /></p>
<p>The dashboard provides a set of metric panels for an overview of your app's health, performance, and RUM, as well as a set of panels that can be further explored either in Discover or the Exception dashboard, as explained below.</p>
<h2>How to inspect the distributed tracing waterfall in Kibana</h2>
<p>From the Application Overview dashboard, go to one of the span tables (either <strong>All spans</strong> or <strong>Failed spans</strong>) and click its <strong>Explore in Discover</strong> button.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/distributed-tracing-android-mobile-apm-opentelemetry/blog-dashboard-android-overview-explore-spans.png" alt="Explore spans" /></p>
<p>In Discover, click the expand icon on the left side of any span row to open its details panel. The trace waterfall UI appears inside, showing the full span hierarchy and timing for that trace. You can expand the waterfall to full screen and drill down from there.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/distributed-tracing-android-mobile-apm-opentelemetry/blog-discover-span-dialog-open.png" alt="Discover open span dialog" /></p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/distributed-tracing-android-mobile-apm-opentelemetry/blog-discover-span-dialog-view.png" alt="Discover span dialog" /></p>
<h3>Analyzing failed spans and backend errors in Kibana</h3>
<p>While you can find all kinds of spans in the dashboard's <strong>All spans</strong> panel, you can narrow them down to failed ones only by exploring the <strong>Failed spans</strong> panel instead.</p>
<p>For the New York path, find a failed span and expand it. The trace waterfall highlights the backend error, and the exception details show the intentional backend rule that only supports European cities.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/distributed-tracing-android-mobile-apm-opentelemetry/blog-dashboard-android-overview-explore-failed-spans.png" alt="Explore failed spans" /></p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/distributed-tracing-android-mobile-apm-opentelemetry/blog-discover-failed-span-dialog-open.png" alt="Discover failed span dialog open" /></p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/distributed-tracing-android-mobile-apm-opentelemetry/blog-discover-failed-span-dialog.png" alt="Discover failed span dialog" /></p>
<h2>Reviewing crash details and stacktraces in the exception dashboard</h2>
<p>Crash reporting is provided by the <a href="https://www.elastic.co/docs/reference/opentelemetry/edot-sdks/android/automatic-instrumentation#crash-reporting">crash automatic instrumentation plugin</a>. When an unhandled exception crashes the app, EDOT Android stores the crash event on disk. The event is exported the next time the app starts. Disk buffering ensures the crash event is not lost even if the network was unavailable at the time of the crash.</p>
<p>In the Application Overview dashboard, scroll to the <strong>Crashes</strong> section. You will see crash groups listed by a computed stacktrace group ID. Select a group and click <strong>View crash details</strong> to open the Exception Details dashboard.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/distributed-tracing-android-mobile-apm-opentelemetry/blog-dashboard-android-overview-crash-list.png" alt="Crash list" /></p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/distributed-tracing-android-mobile-apm-opentelemetry/blog-dashboard-android-overview-crash-view-details.png" alt="View crash details" /></p>
<p>The Exception Details dashboard shows a set of metrics to better understand the impact of the selected crash, as well as its full stacktrace. Crash events are grouped based on their stacktrace, which helps ensure that the same crash is counted and aggregated in this dashboard to better understand a single crash's impact on your application.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/distributed-tracing-android-mobile-apm-opentelemetry/blog-dashboard-android-exceptions.png" alt="Exception dashboard view" /></p>
<p>For this demo, the stacktrace points to the intentional crash in <code>MainActivity</code>. The nearby session events should also include the custom <code>Crash button click</code> log created just before the crash, which helps explain how the crash was triggered. We'll take a look at how to inspect a session to get an idea of the user's journey within your application that led them to a crash.</p>
<h2>Using sessions to understand user flow in EDOT Android</h2>
<p>Mobile troubleshooting often starts with a single bad outcome (a crash, an error, a slow UX), but the useful question is what happened before that outcome. EDOT Android helps answer that by attaching <code>session.id</code> to every span and log emitted by the application, even for manually created ones.</p>
<p>A session is meant to cover a single user interaction with your application. A new one is created when there is no previous active session or when the previous session has expired. Sessions expire after 30 minutes of inactivity. If the app stays active, a session can last up to 4 hours.</p>
<p>This lets you query all the telemetry from a single session and review it in order. After finding a crash group, drill into one affected session from the <strong>Top affected sessions</strong> panel and review the event timeline. You can see the custom logs, app startup spans, HTTP request spans, and crash data together in one investigation path.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/distributed-tracing-android-mobile-apm-opentelemetry/blog-dashboard-android-exceptions-view-session-details.png" alt="Exception dashboard view session details" /></p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/distributed-tracing-android-mobile-apm-opentelemetry/blog-dashboard-android-overview-with-session-filter.png" alt="Overview dashboard with session filter" /></p>
<p>The <strong>Event timeline</strong> panel on the Application Overview dashboard is also useful here: select a session from the dashboard's top filters, and the timeline shows the full sequence of spans and logs in that session chronologically.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/distributed-tracing-android-mobile-apm-opentelemetry/blog-dashboard-android-overview-event-timeline.png" alt="Event timeline with session filter" /></p>
<h2>What EDOT Android adds as a mobile APM for production apps</h2>
<p>The demo uses a local stack and simple code, but the same agent features apply to production apps.</p>
<p><strong>Disk buffering</strong> stores telemetry locally before export. This reduces data loss when the device has poor connectivity or the app is temporarily offline.</p>
<p><strong>Automatic instrumentation</strong> creates telemetry for supported targets without adding code around every call. Today that includes OkHttp, crash reporting, and an adapter for <a href="https://github.com/open-telemetry/opentelemetry-android">OpenTelemetry Android</a> instrumentation.</p>
<p><strong>Manual instrumentation</strong> lets you add spans, logs, and metrics for app-specific workflows. This is useful for screen loading times, checkout flows, login steps, feature usage, or any area where framework-level telemetry alone is not enough.</p>
<p><strong>Central configuration</strong> can remotely adjust selected EDOT Android behavior through Kibana when the OpAMP endpoint is configured. At the time of writing, central configuration for EDOT Android is in preview and supports settings such as recording and session sample rate.</p>
<p><strong>Distributed tracing</strong> connects Android app requests to backend service spans so you can trace the full path of any user action, from the tap on the screen to the database query on the server. EDOT Android ensures that your application's telemetry timestamps are in sync with the <a href="https://en.wikipedia.org/wiki/Coordinated_Universal_Time">coordinated universal time</a>. This ensures a proper trace waterfall hierarchy later on in Kibana, where different components are properly coordinated in time.</p>
<h2>Clean up the demo</h2>
<p>When you are finished, stop the backend in case you're planning to restart it later, or uninstall it otherwise:</p>
<pre><code class="language-bash">./backend-manager stop
# ./backend-manager uninstall
</code></pre>
<p>Then stop or uninstall the local Elastic Stack:</p>
<pre><code class="language-bash">cd elastic-start-local
./stop.sh
# ./uninstall.sh
</code></pre>
<h2>Getting started with EDOT Android in your own app</h2>
<p>EDOT Android gives native Android teams an OpenTelemetry-based path for mobile APM in Elastic. With a small Gradle setup and one early initialization call, you get automatic HTTP spans, crash reporting, session tracking, and direct access to the OpenTelemetry SDK for custom telemetry, and you can see it all tied together in Kibana's Android dashboards.</p>
<p>Observability is a crucial part of modern mobile development. Crashes, slow screens, and backend errors all impact real users, and the sooner you can identify root causes across the full request path, from the device to the database, the better. The demo app is a good first step because it exercises the complete workflow without requiring a production deployment. After that, the same setup model applies to your own app with production endpoints, API key authentication, and custom spans and logs tailored to your use cases.</p>
<p>Developer resources:</p>
<ul>
<li><a href="https://github.com/elastic/android-agent-demo">EDOT Android demo application</a></li>
<li><a href="https://www.elastic.co/docs/reference/opentelemetry/edot-sdks/android">EDOT Android documentation</a></li>
<li><a href="https://www.elastic.co/docs/reference/opentelemetry/edot-sdks/android/getting-started">EDOT Android getting started guide</a></li>
<li><a href="https://www.elastic.co/docs/reference/opentelemetry/edot-sdks/android/automatic-instrumentation">EDOT Android automatic instrumentation</a></li>
<li><a href="https://www.elastic.co/docs/reference/opentelemetry/edot-sdks/android/manual-instrumentation">EDOT Android manual instrumentation</a></li>
<li><a href="https://www.elastic.co/docs/reference/opentelemetry/edot-sdks/android/configuration">EDOT Android configuration</a></li>
<li><a href="https://www.elastic.co/docs/troubleshoot/ingest/opentelemetry/edot-sdks/android">EDOT Android troubleshooting</a></li>
<li><a href="https://www.elastic.co/docs/reference/integrations/otel_android_dashboards">Android OpenTelemetry Assets dashboard docs</a></li>
</ul>
<p>Don't have an Elastic Cloud account yet? <a href="https://cloud.elastic.co/registration">Sign up for Elastic Cloud</a> and try out mobile observability with EDOT Android as described in this guide. We'd love to hear about your experience gaining visibility into your Android application stack with Elastic.</p>
]]></content:encoded>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/distributed-tracing-android-mobile-apm-opentelemetry/header-image.png" length="0" type="image/png"/>
        </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>
    </channel>
</rss>