• Home
  • How to use Dynatrace
  • RUM
  • Setup and configuration
  • Mobile apps
  • Android
  • SDK
  • Instrumentation via OneAgent SDK for Android

Instrumentation via OneAgent SDK for Android

Use the OneAgent SDK for Android to report additional details about the user sessions in your mobile app. The OneAgent SDK for Android allows you to create custom actions, report errors, tag specific users, and more. The sections below explain how to enable these capabilities.

You can use the OneAgent SDK in Java and Kotlin.

Start OneAgent

If you've disabled auto-start with the autoStart.enabled property or you're using standalone manual instrumentation instead of auto-instrumentation, start OneAgent manually in the Application.onCreate method. Use the Dynatrace.startup(Application, Configuration) API method.

java
public class YourApplication extends Application { @Override public void onCreate() { super.onCreate(); // provide the application context as parameter Dynatrace.startup(this, new DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconUrl>") ... // additional configuration .buildConfiguration()); } }
kotlin
class YourApplication : Application() { override fun onCreate() { super.onCreate() // provide the application context as parameter Dynatrace.startup(this, DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconUrl>") ... // additional configuration .buildConfiguration()) } }

If you need to start OneAgent at a later stage, use the Dynatrace.startup(Activity, Configuration) API method. You have to provide the active Activity as a parameter so that OneAgent can immediately monitor it.

java
Dynatrace.startup(yourActiveActivity, new DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconUrl>") ... // additional configuration .buildConfiguration());
kotlin
Dynatrace.startup(yourActiveActivity, DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconUrl>") ... // additional configuration .buildConfiguration())
Start OneAgent in OneAgent SDK for Android versions 8.229 and earlier

If you've disabled auto-start with the autoStart.enabled property or you're using standalone manual instrumentation instead of auto-instrumentation, start OneAgent manually in the Application.onCreate method.

java
public class YourApplication extends Application { @Override public void onCreate() { super.onCreate(); Dynatrace.startup(this, new DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconUrl>") ... // additional configuration .buildConfiguration()); } }
kotlin
class YourApplication : Application() { override fun onCreate() { super.onCreate() Dynatrace.startup(this, DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconUrl>") ... // additional configuration .buildConfiguration()) } }

If your app supports Direct Boot, ensure that Dynatrace.startup is never called from a Direct Boot aware component. Also see Adjust communication with OneAgent SDK for Android to make sure that OneAgent can transmit data to the Dynatrace Cluster.

Configure OneAgent

Use the DynatraceConfigurationBuilder class to customize OneAgent settings.

java
new DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconURL>") .withUserOptIn(true) .withCrashReporting(true) .buildConfiguration();
kotlin
DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconURL>") .withUserOptIn(true) .withCrashReporting(true) .buildConfiguration()

If you use a combination of manual and auto-instrumentation, the auto-instrumentation injects a Dynatrace.startup call into the Application.onCreate method. In this case, the injected Dynatrace.startup call is called before your manual Dynatrace.startup call, so your manual configuration is ignored.

Use the autoStart.enabled property to deactivate the auto-start feature from the auto-instrumentation. You can then define a manual Dynatrace.startup call. In this case, you can override the values pre-configured from the auto-instrumentation.

User action monitoring

With user action monitoring, you can define and report custom actions. You can then enrich these custom actions using the following monitoring operations:

  • Create a child action
  • Report an event
  • Report a value
  • Report an error
  • Attach a web request to the user action

Custom actions are different from the user actions created with the Dynatrace Android Gradle plugin. OneAgent does not automatically add additional events, such as web requests, to custom actions or close custom actions. However, when OneAgent shuts down or has to start a new session, it closes all open custom actions.

Create custom actions

You can create custom actions and enhance them with additional information. If custom actions are not closed explicitly, OneAgent closes them and sends them to the Dynatrace Cluster.

Call enterAction to start a custom action and leaveAction to close a custom action. Timing is measured automatically.

java
// start a custom action DTXAction action = Dynatrace.enterAction("Tap on Search"); // ...do some work here... // end a custom action action.leaveAction();
kotlin
// start a custom action val action = Dynatrace.enterAction("Tap on Search") // ...do some work here... // end a custom action action.leaveAction()

For a mobile custom action or a mobile autogenerated user action, the maximum name length is 250 characters.

Create child actions

Child actions are similar to parent actions. When the parent action is closed, OneAgent automatically closes all child actions of the parent action.

Generate child actions using the Dynatrace.enterAction(String, DTXAction) method.

java
// start a parent custom action DTXAction parentAction = Dynatrace.enterAction("Tap on Search"); // ...do some work here... // start a child action DTXAction childAction = Dynatrace.enterAction("Tap on Confirm", parentAction); // ...do some work here... // end a child action childAction.leaveAction(); // ...do some work here... // end a parent custom action parentAction.leaveAction();
kotlin
// start a parent custom action val parentAction = Dynatrace.enterAction("Tap on Search") // ...do some work here... // start a child action val childAction = Dynatrace.enterAction("Tap on Confirm", parentAction) // ...do some work here... // end a child action childAction.leaveAction() // ...do some work here... // end a parent custom action parentAction.leaveAction()

For a mobile custom action or a mobile autogenerated user action, the maximum name length is 250 characters.

Cancel custom actions

OneAgent SDK for Android version 8.231+

If you need to cancel an already created but not yet completed custom action, use the DTXAction#cancel() API call.

Canceling an action discards all data associated with it: all reported values are discarded and all child actions are canceled. Also, note that you cannot cancel a completed action.

java
// create a custom action DTXAction action = Dynatrace.enterAction("Tap on Purchase"); try { // ...do some work here... performWork(); // close the custom action. All associated data is stored and sent to Dynatrace action.leaveAction(); } catch(Exception e) { // cancel the custom action. All associated data is discarded. action.cancel(); }
kotlin
// create a custom action val action = Dynatrace.enterAction("Tap on Purchase") try { // ...do some work here... performWork() // close the custom action. All associated data is stored and sent to Dynatrace action.leaveAction() } catch (e: Exception) { // cancel the custom action. All associated data is discarded. action.cancel() }

Determine custom action state

OneAgent SDK for Android version 8.231+

Sometimes it's helpful to know whether a custom action is still open and can be used to report data.

To check the state of a custom action, use the DTXAction#isFinished() method.

A custom action is finished when the action is:

  • Completed via DTXAction#leaveAction(), or
  • Canceled via DTXAction#cancel(), or
  • Terminated by OneAgent (for example, when OneAgent shuts down)

Note that you shouldn't interact with a finished custom action.

Custom action code sample

The following code snippet shows a sample instrumentation of the fictional method search, which makes a web request to an instrumented server and parses the received result. The following instrumentation actions are part of the code snippet:

  1. Creates a custom action
  2. Reports a value
  3. Reports a error
  4. Monitors a web request
  5. Creates a child action
java
public boolean search(String query) { // [1a] start a parent custom action DTXAction searchAction = Dynatrace.enterAction("Tap on Search"); // [2] report a value searchAction.reportValue("query", query); URL url; try { url = new URL("https://www.example.com/?query=" + query); } catch (MalformedURLException e) { // [3] report an error searchAction.reportError("invalid url", e); // [1b] end a parent custom action searchAction.leaveAction(); return false; } // [4.1] Generate a new unique tag associated with the custom action "Tap on Search" String uniqueRequestTag = searchAction.getRequestTag(); // [4.2] Generate a WebRequestTiming object based on the unique tag WebRequestTiming timing = Dynatrace.getWebRequestTiming(uniqueRequestTag); Request request = new Request.Builder() .url(url) // [4.3] Place the Dynatrace HTTP header on your web request .addHeader(Dynatrace.getRequestTagHeader(), uniqueRequestTag) .build(); // [4.4] Start web request timing before the HTTP request is sent timing.startWebRequestTiming(); try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) { // [4.5] Stop web request timing when a connection exception occurs timing.stopWebRequestTiming(url, response.code(), response.message()); return false; } String body = response.body().string(); // [4.5] Stop web request timing when the HTTP response is received and the response body is obtained timing.stopWebRequestTiming(url, response.code(), response.message()); // [5a] start a child action DTXAction parseAction = Dynatrace.enterAction("Parse result", searchAction); parseResult(body); // [5b] end a child action parseAction.leaveAction(); return true; } catch (IOException e) { // [4.5] Stop web request timing when a connection exception occurs timing.stopWebRequestTiming(url, -1, e.toString()); return false; } finally { // [1b] end a parent custom action searchAction.leaveAction(); } }
kotlin
fun search(query: String): Boolean { // [1a] start a parent custom action val searchAction = Dynatrace.enterAction("Tap on Search") // [2] report a value searchAction.reportValue("query", query) var url: URL? = null try { url = URL("https://www.example.com/?query=$query") } catch (e: MalformedURLException) { // [3] report an error searchAction.reportError("invalid url", e) // [1b] end a parent custom action searchAction.leaveAction() return false } // [4.1] Generate a new unique tag associated with the custom action "Tap on Search" val uniqueRequestTag = searchAction.requestTag // [4.2] Generate a WebRequestTiming object based on the unique tag val timing = Dynatrace.getWebRequestTiming(uniqueRequestTag) val request = Request.Builder() .url(url) // [4.3] Place the Dynatrace HTTP header on your web request .addHeader(Dynatrace.getRequestTagHeader(), uniqueRequestTag) .build() try { // [4.4] Start web request timing before the HTTP request is sent timing.startWebRequestTiming() client.newCall(request).execute().use { response -> if (!response.isSuccessful) { // [4.5] Stop web request timing when a connection exception occurs timing.stopWebRequestTiming(url, response.code, response.message) return false } val body = response.body!!.string() // [4.5] Stop web request timing when the HTTP response is received and the response body was obtained timing.stopWebRequestTiming(url, response.code, response.message) // [5a] start a child action val parseAction = Dynatrace.enterAction("Parse result", searchAction) parseResult(body) // [5b] end a child action parseAction.leaveAction() } return true } catch (e: IOException) { // [4.5] Stop web request timing when a connection exception occurs timing.stopWebRequestTiming(url, -1, e.toString()) return false } finally { // [1b] end a parent custom action searchAction.leaveAction() } }

Custom value reporting

Using the OneAgent SDK for Android, you can report events, values, and errors.

Report an event

With reportEvent, you can report a specific event. The reported event must be part of a user action.

java
action.reportEvent("event_name");
kotlin
action.reportEvent("event_name")

Report a value

The reportValue method allows you to report your own metrics. These metrics must be part of a user action.

The OneAgent SDK allows you to report metrics with the following value types:

  • int
  • long
  • double
  • string

Metrics with type long are supported for OneAgent SDK versions 8.197+.

java
// report int action.reportValue("int_metrics_name", 5); // report long action.reportValue("long_metrics_name", 5L); // report double action.reportValue("double_metrics_name", 5.6); // report string action.reportValue("string_metrics_name", "exampleValue");
kotlin
// report int action.reportValue("int_metrics_name", 5) // report long action.reportValue("long_metrics_name", 5L) // report double action.reportValue("double_metrics_name", 5.6) // report string action.reportValue("string_metrics_name", "exampleValue")

Report an error

The reportError method is different from the reportValue method, as it is specifically identified as an error type event.

The OneAgent SDK allows you to report the following:

  • Error codes. Use the reportError(String, int) method.
  • Handled exceptions. Use the reportError(String, Throwable) method.

There are two options for reporting an error event. You can report an error as part of a user action or as a standalone error, which is generated as a global event that is not tied to a specific user action.

Error within a user action

java
// report an error code action.reportError("error_code_name", -1); // report an exception action.reportError("exception_name", exception);
kotlin
// report an error code action.reportError("error_code_name", -1) // report an exception action.reportError("exception_name", exception)

Standalone error

You can report standalone error events via the Dynatrace class.

java
// report an error code Dynatrace.reportError("error_code_name", -1); // report an exception Dynatrace.reportError("exception_name", exception);
kotlin
// report an error code Dynatrace.reportError("error_code_name", -1) // report an exception Dynatrace.reportError("exception_name", exception)

Lifecycle monitoring

OneAgent SDK for Android version 8.223+

With lifecycle monitoring, OneAgent collects the following data:

  • Activity display: Measures the timespan from Activity.onCreate(Bundle) to Activity.onPostResume() and reports the time of each activity lifecycle state that is entered.
  • Activity redisplay: Measures the time it takes to redisplay a previously created activity and reports the time of each activity lifecycle state that is entered until the activity is visible again.

Activity lifecycle monitoring is turned on by default, but you can disable it with the withActivityMonitoring method.

java
new DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconURL>") .withActivityMonitoring(false) .buildConfiguration();
kotlin
DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconURL>") .withActivityMonitoring(false) .buildConfiguration()

Web request monitoring

To track web requests, add the x-dynatrace HTTP header with a unique value to the web request. The tag correlates the server-side monitoring data to the corresponding mobile web request. Additionally, the timing values from the mobile side must be measured.

To monitor a web request

  1. Generate a new unique tag.
  2. Generate a WebRequestTiming object based on the tag.
  3. Place the Dynatrace HTTP header on your web request.
  4. Start web request timing before the HTTP request is sent.
  5. Stop web request timing.
    • The HTTP response is received, and the response body is obtained.
    • A connection exception occurs.

Do not manually and auto-instrument the same web requests. This behavior can lead to incorrect monitoring data.

There are two types of web requests:

  • Requests attached to a user action
  • Standalone requests. For these requests, OneAgent automatically tries to find an appropriate user action. If it finds one, the web request is attached to the user action. The web request is only reported as a standalone web request when no appropriate user action is found.

Attach a web request to a user action

To attach a web request to a user action, generate a unique tag with the DTXAction.getRequestTag() method.

The following sample shows how to attach a synchronous OkHttp web request to the "Search request" user action.

java
URL url = new URL("https://www.example.com"); // First, create a custom action DTXAction webAction = Dynatrace.enterAction("Search request"); // [1] Generate a new unique tag associated with the user action String uniqueRequestTag = webAction.getRequestTag(); // [2] Generate a WebRequestTiming object based on the unique tag WebRequestTiming timing = Dynatrace.getWebRequestTiming(uniqueRequestTag); // Define your OkHttp request. This varies greatly depending on your implementation Request request = new Request.Builder() .url(url) // Define your headers for the OkHttp request .addHeader(yourKey1, yourValue1) .addHeader(yourKey2, yourValue2) // [3] Place the Dynatrace HTTP header on your web request .addHeader(Dynatrace.getRequestTagHeader(), uniqueRequestTag) .build(); // [4] Start web request timing before the HTTP request is sent timing.startWebRequestTiming(); try (Response response = client.newCall(request).execute()) { if (response.isSuccessful()) { // handle response String body = response.body().string(); } // [5.1] Stop web request timing when the HTTP response is received and the response body was obtained timing.stopWebRequestTiming(url, response.code(), response.message()); } catch (IOException e) { // [5.2] Stop web request timing when a connection exception occurs timing.stopWebRequestTiming(url, -1, e.toString()); // user-defined exception handling } finally { // Lastly, end the custom action webAction.leaveAction(); }
kotlin
val url = URL("https://www.example.com") // First, create a custom action val webAction = Dynatrace.enterAction("Search request") // [1] Generate a new unique tag associated with the user action val uniqueRequestTag = webAction.requestTag // [2] Generate a WebRequestTiming object based on the unique tag val timing = Dynatrace.getWebRequestTiming(uniqueRequestTag) // Define your OkHttp request. This varies greatly depending on your implementation val request = Request.Builder() .url(url) // Define your headers for the OkHttp request .addHeader(yourKey1, yourValue1) .addHeader(yourKey2, yourValue2) // [3] Place the Dynatrace HTTP header on your web request .addHeader(Dynatrace.getRequestTagHeader(), uniqueRequestTag) .build() try { // [4] Start web request timing before the HTTP request is sent timing.startWebRequestTiming() client.newCall(request).execute().use { response -> if (response.isSuccessful) { // handle response val body = response.body!!.string() } // [5.1] Stop web request timing when the HTTP response is received and the response body was obtained timing.stopWebRequestTiming(url, response.code, response.message) } } catch (e: IOException) { // [5.2] Stop web request timing when a connection exception occurs timing.stopWebRequestTiming(url, -1, e.toString()) // user-defined exception handling } finally { // Lastly, end the custom action webAction.leaveAction() }
Attach an asynchronous OkHttp web request to a user action
java
final URL url = new URL("https://www.example.com"); // First, create a custom action final DTXAction webAction = Dynatrace.enterAction("Search request"); // [1] Generate a new unique tag associated with the user action String uniqueRequestTag = webAction.getRequestTag(); // [2] Generate a WebRequestTiming object based on the unique tag final WebRequestTiming timing = Dynatrace.getWebRequestTiming(uniqueRequestTag); // Define your OkHttp request. This varies greatly depending on your implementation Request request = new Request.Builder() .url(url) // Define your headers for the OkHttp request .addHeader(yourKey1, yourValue1) .addHeader(yourKey2, yourValue2) // [3] Place the Dynatrace HTTP header on your web request .addHeader(Dynatrace.getRequestTagHeader(), uniqueRequestTag) .build(); // [4] Call startWebRequestTiming to begin the timing, and then handle the response body from the OkHttp call timing.startWebRequestTiming(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { // [5.2] Stop web request timing when a connection exception occurs timing.stopWebRequestTiming(url, -1, e.toString()); // user-defined exception handling // [8] Lastly, end the custom action webAction.leaveAction(); } @Override public void onResponse(Call call, Response response) throws IOException { try (ResponseBody responseBody = response.body()) { if (response.isSuccessful()) { // handle response String body = response.body().string(); } // [5.1] Stop web request timing when the HTTP response is received and the response body was obtained timing.stopWebRequestTiming(url, response.code(), response.message()); // Lastly, end the custom action webAction.leaveAction(); } } });
kotlin
val url = URL("https://www.example.com") // First, create a custom action val webAction = Dynatrace.enterAction("Search request") // [1] Generate a new unique tag associated with the user action val uniqueRequestTag = webAction.requestTag // [2] Generate a WebRequestTiming object based on the unique tag val timing = Dynatrace.getWebRequestTiming(uniqueRequestTag) // Define your OkHttp request. This varies greatly depending on your implementation val request = Request.Builder() .url(url) // Define your headers for the OkHttp request .addHeader(yourKey1, yourValue1) .addHeader(yourKey2, yourValue2) // [3] Place the Dynatrace HTTP header on your web request .addHeader(Dynatrace.getRequestTagHeader(), uniqueRequestTag) .build() // [4] Call startWebRequestTiming to begin the timing, and then handle the response body from the OkHttp call timing.startWebRequestTiming() client.newCall(request).enqueue(object : Callback { override fun onFailure(call: Call, e: IOException) { // [5.2] Stop web request timing when a connection exception occurs timing.stopWebRequestTiming(url, -1, e.toString()) // user-defined exception handling // [8] Lastly, end the custom action webAction.leaveAction() } @Throws(IOException::class) override fun onResponse(call: Call, response: Response) { response.use { if (response.isSuccessful) { // handle response val body = response.body!!.string() } // [5.1] Stop web request timing when the HTTP response is received and the response body was obtained timing.stopWebRequestTiming(url, response.code, response.message) // Lastly, end the custom action webAction.leaveAction() } } })

Monitor a standalone web request

To monitor a web request as a standalone request, generate a unique tag with the Dynatrace.getRequestTag() method.

The following sample shows how to monitor a synchronous OkHttp web request.

java
URL url = new URL("https://www.example.com"); // [1] Generate a new unique tag String uniqueRequestTag = Dynatrace.getRequestTag(); // [2] Generate a WebRequestTiming object based on the unique tag WebRequestTiming timing = Dynatrace.getWebRequestTiming(uniqueRequestTag); // Define your OkHttp request. This varies greatly depending on your implementation Request request = new Request.Builder() .url(url) // Define your headers for the OkHttp request .addHeader(yourKey1, yourValue1) .addHeader(yourKey2, yourValue2) // [3] Place the Dynatrace HTTP header on your web request .addHeader(Dynatrace.getRequestTagHeader(), uniqueRequestTag) .build(); // [4] Start web request timing before the HTTP request is sent timing.startWebRequestTiming(); try (Response response = client.newCall(request).execute()) { if (response.isSuccessful()) { // handle response String body = response.body().string(); } // [5.1] Stop web request timing when the HTTP response is received and the response body was obtained timing.stopWebRequestTiming(url, response.code(), response.message()); } catch (IOException e) { // [5.2] Stop web request timing when a connection exception occurs timing.stopWebRequestTiming(url, -1, e.toString()); // user-defined exception handling }
kotlin
val url = URL("https://www.example.com") // [1] Generate a new unique tag val uniqueRequestTag = Dynatrace.getRequestTag() // [2] Generate a WebRequestTiming object based on the unique tag val timing = Dynatrace.getWebRequestTiming(uniqueRequestTag) // Define your OkHttp request. This varies greatly depending on your implementation val request = Request.Builder() .url(url) // Define your headers for the OkHttp request .addHeader(yourKey1, yourValue1) .addHeader(yourKey2, yourValue2) // [3] Place the Dynatrace HTTP header on your web request .addHeader(Dynatrace.getRequestTagHeader(), uniqueRequestTag) .build() try { // [4] Start web request timing before the HTTP request is sent timing.startWebRequestTiming() client.newCall(request).execute().use { response -> if (response.isSuccessful) { // handle response val body = response.body!!.string() } // [5.1] Stop web request timing when the HTTP response is received and the response body was obtained timing.stopWebRequestTiming(url, response.code, response.message) } } catch (e: IOException) { // [5.2] Stop web request timing when a connection exception occurs timing.stopWebRequestTiming(url, -1, e.toString()) // user-defined exception handling }

Monitor HttpURLConnection requests

For monitoring HttpURLConnection web requests, the OneAgent SDK for Android has an additional Dynatrace.getWebRequestTiming(HttpURLConnection) API method. It automatically generates a unique tag and places it on the HttpURLConnection connection. You can also use the WebRequestTiming.stopWebRequestTiming() method because OneAgent can automatically determine the status code and message from the specified HttpURLConnection.

java
URL url = new URL("https://www.example.com"); HttpURLConnection conn = null; WebRequestTiming timing = null; // First, create a custom action DTXAction webAction = Dynatrace.enterAction("Search request"); try { conn = (HttpURLConnection) url.openConnection(); // [1], [2], [3] Once the connection object is obtained, tag it automatically and receive a WebRequestTiming instance timing = Dynatrace.getWebRequestTiming(conn); // [4] Stop web request timing when the HTTP response is received and the response body was obtained timing.startWebRequestTiming(); InputStream stream = new BufferedInputStream(conn.getInputStream()); readStream(stream); // [5.1] Stop web request timing when the HTTP response is received and the response body was obtained timing.stopWebRequestTiming(); } catch (Exception e) { if(timing != null) { // [5.2] Stop web request timing when a connection exception occurs timing.stopWebRequestTiming(url, -1, e.toString()); } // user-defined exception handling } finally { if (conn != null) { conn.disconnect(); } // Lastly, end the custom action webAction.leaveAction(); }
kotlin
val url = URL("https://www.example.com") var conn: HttpURLConnection? = null var timing: WebRequestTiming? = null // First, create a custom action val webAction = Dynatrace.enterAction("Search request") try { conn = url.openConnection() as HttpURLConnection // [1], [2], [3] Once the connection object is obtained, tag it automatically and receive a WebRequestTiming instance timing = Dynatrace.getWebRequestTiming(conn) // [4] Stop web request timing when the HTTP response is received and the response body was obtained timing.startWebRequestTiming() val stream = BufferedInputStream(conn.getInputStream()) readStream(stream) // [5.1] Stop web request timing when the HTTP response is received and the response body was obtained timing.stopWebRequestTiming() } catch (e: Exception) { timing?.stopWebRequestTiming(url, -1, e.toString()) // user-defined exception handling } finally { conn?.disconnect() // Lastly, end the custom action webAction.leaveAction() }

Monitor WebSocket connections

OneAgent SDK for Android version 8.239+

OneAgent for Android does not support auto-instrumentation of WebSocket requests. If you need to monitor a WebSocket request (starts with ws:// or wss://), check the code samples below.

  • Use the stopWebRequestTiming(URI requestUri, int respCode, String respPhrase) API method to manually instrument WebSocket requests.
  • Make sure to pass along the original URI. Do not retrieve the URI from the OkHttp object because this doesn't return the original URI.
  • This approach is only suitable for WebSocket connections that are open for up to about 9 minutes. Longer connections may not be reported.
java
final URI uri = URI.create("wss://websocket.example.com"); // First, create a custom action DTXAction webSocketAction = Dynatrace.enterAction("WebSocket"); // Generate a WebRequestTiming object based on the unique request tag WebRequestTiming timing = Dynatrace.getWebRequestTiming(webSocketAction.getRequestTag()); // Define your OkHttp request. This varies greatly depending on your implementation Request request = new Request.Builder() .url(uri.toString()) .build(); // Start web request timing when you are about to open a WebSocket connection timing.startWebRequestTiming(); WebSocket webSocket = client.newWebSocket(request, new WebSocketListener() { @Override public void onClosing(@NonNull WebSocket webSocket, int code, @NonNull String reason) { // Stop web request timing when the webSocket connection closes // Don't retrieve the URI from the OkHttp object because it always replaces wss:// with https:// timing.stopWebRequestTiming(uri, code, reason); // end the action webSocketAction.leaveAction(); } @Override public void onFailure(@NonNull WebSocket webSocket, @NonNull Throwable t, @Nullable Response response) { // Stop web request timing when the webSocket connection fails and customize the return code and message // Don't retrieve the URI from the OkHttp object because it always replaces wss:// with https:// timing.stopWebRequestTiming(uri, 1011, "ERROR"); // end the action webSocketAction.leaveAction(); } });
kotlin
val uri = URI.create("wss://websocket.example.com") // First, create a custom action val webSocketAction = Dynatrace.enterAction("WebSocket") // Generate a WebRequestTiming object based on the unique request tag val webRequestTiming = Dynatrace.getWebRequestTiming(webSocketAction.requestTag) // Define your OkHttp request. This varies greatly depending on your implementation val request = Request.Builder() .url(uri.toString()) .build() // Start web request timing when you are about to open a WebSocket connection webRequestTiming.startWebRequestTiming() val webSocket = client.newWebSocket(request, object : WebSocketListener() { override fun onClosing(webSocket: WebSocket, code: Int, reason: String) { // Stop web request timing when the webSocket connection closes // Don't retrieve the URI from the OkHttp object because it always replaces wss:// with https:// webRequestTiming.stopWebRequestTiming(uri, code, reason) // end the action webSocketAction.leaveAction() } override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { // Stop web request timing when the webSocket connection fails // Don't retrieve the URI from the OkHttp object because it always replaces wss:// with https:// webRequestTiming.stopWebRequestTiming(uri, 1011, "ERROR") // end the action webSocketAction.leaveAction() } })

Crash reporting

OneAgent captures all unhandled exceptions and errors and sends the crash report to the server immediately. The Android crash report includes the occurrence time and the full stack trace of the exception.

You can deactivate crash reporting using the withCrashReporting method:

java
new DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconURL>") .withCrashReporting(false) .buildConfiguration();
kotlin
DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconURL>") .withCrashReporting(false) .buildConfiguration()

Tag specific users

You can tag each user of your mobile apps with a unique user name. This enables you to search and filter specific user sessions and analyze individual user behavior over time.

The following steps explain how to tag an individual user via the Dynatrace API.

java
Dynatrace.identifyUser("john.doe@example.com");
kotlin
Dynatrace.identifyUser("john.doe@example.com")

The user tag value is not stored and must be renewed every session.

Configure data privacy

With the user opt-in mode for mobile apps, you can dynamically adjust data privacy settings and build your apps in compliance with data protection laws and regulations.

To activate the user opt-in mode, enable the userOptIn flag via the DSL from the Dynatrace Android Gradle plugin or use the ConfigurationBuilder.withUserOptIn method.

With the Dynatrace.applyUserPrivacyOptions method, you can adjust privacy settings based on the user's decision.

java
Dynatrace.applyUserPrivacyOptions(UserPrivacyOptions.builder() .withDataCollectionLevel(DataCollectionLevel.USER_BEHAVIOR) .withCrashReportingOptedIn(true) .build() );
kotlin
Dynatrace.applyUserPrivacyOptions(UserPrivacyOptions.builder() .withDataCollectionLevel(DataCollectionLevel.USER_BEHAVIOR) .withCrashReportingOptedIn(true) .build() )

OneAgent persists the privacy settings and automatically applies them when the app is restarted. Additionally, OneAgent generates a new session whenever the privacy settings are changed via the Dynatrace.applyUserPrivacyOptions method.

You can also retrieve the privacy settings with the Dynatrace.getUserPrivacyOptions method. However, you should use this method after OneAgent starts.

Data privacy in OneAgent SDK for Android versions 8.189 and earlier

With the Dynatrace.setCrashReportingOptedIn(boolean) method, you can activate or deactivate crash reporting. The data collection level can be changed with the Dynatrace.setDataCollectionLevel(DataCollectionLevel) method.

You can retrieve the privacy settings with the Dynatrace.getDataCollectionLevel() and Dynatrace.isCrashReportingOptedIn() methods. Use the privacy API methods after OneAgent starts.

Configure hybrid apps

For hybrid applications that use the RUM JavaScript inside WebView (Android) or WKWebView (iOS), cookies must be set for each instrumented domain or server that the application communicates with. When the hybrid app monitoring feature is enabled, OneAgent generates these cookies for every specified domain and stores them in CookieManager.

Enable hybrid app monitoring

You can activate the hybrid app monitoring feature with the withHybridMonitoring method. Specify all used domains, hosts, and IP addresses via the withMonitoredDomains or the withMonitoredHttpsDomains method. Start domains and sub-domains with a dot (.).

withMonitoredDomains method

java
new DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconURL>") .withHybridMonitoring(true) .withMonitoredDomains("<domain1>", "<domain2>") .buildConfiguration();
kotlin
DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconURL>") .withHybridMonitoring(true) .withMonitoredDomains("<domain1>", "<domain2>") .buildConfiguration()

withMonitoredHttpsDomains method

OneAgent SDK for Android version 8.237+

Dynatrace allows you to add the Secure cookie attribute for all cookies that are set by Dynatrace. This ensures that the browser sends these cookies only over secure connections.

java
new DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconURL>") .withHybridMonitoring(true) .withMonitoredHttpsDomains("https://<domain1>", "https://<domain2>") .buildConfiguration();
kotlin
DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconURL>") .withHybridMonitoring(true) .withMonitoredHttpsDomains("https://<domain1>", "https://<domain2>") .buildConfiguration()

Instrument WebView

OneAgent SDK for Android version 8.191+

To enable communication between the RUM JavaScript and OneAgent for Android, instrument all WebView objects before the URL is loaded with WebView.loadUrl(String). Instrument the Dynatrace.instrumentWebView method for every WebView that contains the RUM JavaScript. Without this, the monitoring data may not be associated with the same session.

java
WebView myWebView = (WebView) findViewById(R.id.webview); Dynatrace.instrumentWebView(myWebView); myWebView.loadUrl("http://www.example.com");
kotlin
val myWebView: WebView = findViewById(R.id.webview) Dynatrace.instrumentWebView(myWebView) myWebView.loadUrl("http://www.example.com")

Due to security reasons, this API call is ignored on devices with API versions 15 and 16.

Preserve Dynatrace cookies

OneAgent SDK for Android version 8.191+

For hybrid apps, it is important to ensure that the Dynatrace cookies are not deleted. Without these cookies, Dynatrace cannot combine the monitoring data from the RUM JavaScript and OneAgent for Android into a single session.

When you delete cookies via CookieManager#removeAllCookies(ValueCallback) or CookieManager#removeSessionCookies(ValueCallback), you should also call the restoreCookies method to restore the Dynatrace cookies.

java
CookieManager.getInstance().removeAllCookies(null); Dynatrace.restoreCookies();
kotlin
CookieManager.getInstance().removeAllCookies(null) Dynatrace.restoreCookies()

Enable load balancing

OneAgent allows you to enable client-side load balancing that helps avoid unbalanced load on the server when multiple OneAgents simultaneously establish a connection to ActiveGate.

java
new DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconURL>") .withStartupLoadBalancing(true) .buildConfiguration();
kotlin
DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconURL>") .withStartupLoadBalancing(true) .buildConfiguration()