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.
You should start OneAgent manually in the following cases:
Use the Dynatrace.startup(Application, Configuration)
API method, and start OneAgent manually in the Application.onCreate
method.
public class YourApplication extends Application {@Overridepublic void onCreate() {super.onCreate();// provide the application context as parameterDynatrace.startup(this, new DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconUrl>")... // additional configuration.buildConfiguration());}}
If you need to start OneAgent at a later stage, use the Dynatrace.startup(Activity, Configuration)
API method. Provide an active Activity
as a parameter so that OneAgent can immediately monitor it.
Dynatrace.startup(yourActiveActivity, new DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconUrl>")... // additional configuration.buildConfiguration());
To get the correct application identification keys (applicationId
and beaconUrl
), access the mobile instrumentation wizard for your application.
If your application supports Direct Boot, never call the Dynatrace.startup
API method from a Direct Boot aware component. Also, check Adjust communication with OneAgent SDK for Android to make sure that OneAgent can transmit data to Dynatrace.
Use the DynatraceConfigurationBuilder class to customize OneAgent settings.
new 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.
With user action monitoring, you can define and report custom actions. You can then enrich these custom actions using the following monitoring operations:
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.
When the user opt-in mode is enabled for your application, it might affect user tagging and reporting of custom events, user actions, values, and errors. The exact data types not reported to Dynatrace depend on the data collection level set by a particular user. For details, refer to Data collection levels.
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.
// start a custom actionDTXAction action = Dynatrace.enterAction("Tap on Search");// ...do some work here...// end a custom actionaction.leaveAction();
For a mobile custom action or a mobile autogenerated user action, the maximum name length is 250 characters.
The maximum duration of a mobile custom action is 9 minutes.
If a custom action takes longer than 9 minutes and is not closed, such an action is discarded and not reported to Dynatrace.
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.
// start a parent custom actionDTXAction parentAction = Dynatrace.enterAction("Tap on Search");// ...do some work here...// start a child actionDTXAction childAction = Dynatrace.enterAction("Tap on Confirm", parentAction);// ...do some work here...// end a child actionchildAction.leaveAction();// ...do some work here...// end a parent custom actionparentAction.leaveAction();
For a mobile custom action or a mobile autogenerated user action, the maximum name length is 250 characters.
There's no limit on the number of child actions attached to a parent action. However, note that you can have only nine levels of child actions—you can create one parent action and nine levels of child actions (when child action A is added to a parent action, child action B is added to child action A, child action C is added to child action B, and so on). Also, refer to User session structure for individual user.
Child actions are not displayed on the user session details page, but you can view them on the waterfall analysis page for a parent action to which these child actions are attached. Even though the child action nesting is not fully preserved in the waterfall analysis view and all child actions are displayed as child actions of level 1, you can still grasp the action nesting from the timings.
OneAgent 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.
// create a custom actionDTXAction action = Dynatrace.enterAction("Tap on Purchase");try {// ...do some work here...performWork();// close the custom action. All associated data is stored and sent to Dynatraceaction.leaveAction();}catch(Exception e) {// cancel the custom action. All associated data is discarded.action.cancel();}
OneAgent 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:
DTXAction#leaveAction()
, orDTXAction#cancel()
, orNote that you shouldn't interact with a finished custom action.
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:
public boolean search(String query) {// [1a] start a parent custom actionDTXAction searchAction = Dynatrace.enterAction("Tap on Search");// [2] report a valuesearchAction.reportValue("query", query);URL url;try {url = new URL("https://www.example.com/?query=" + query);} catch (MalformedURLException e) {// [3] report an errorsearchAction.reportError("invalid url", e);// [1b] end a parent custom actionsearchAction.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 tagWebRequestTiming 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 senttiming.startWebRequestTiming();try (Response response = client.newCall(request).execute()) {if (!response.isSuccessful()) {// [4.5] Stop web request timing when a connection exception occurstiming.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 obtainedtiming.stopWebRequestTiming(url, response.code(), response.message());// [5a] start a child actionDTXAction parseAction = Dynatrace.enterAction("Parse result", searchAction);parseResult(body);// [5b] end a child actionparseAction.leaveAction();return true;} catch (IOException e) {// [4.5] Stop web request timing when a connection exception occurstiming.stopWebRequestTiming(url, -1, e.toString());return false;}finally {// [1b] end a parent custom actionsearchAction.leaveAction();}}
Using the OneAgent SDK for Android, you can report events, values, and errors. Reported events, values, and errors that are part of a user action are then displayed in the user action waterfall analysis. Reported errors (both standalone and "attached" to a user action) are also displayed on the user session details page and multidimensional User action analysis page.
When the user opt-in mode is enabled for your application, it might affect user tagging and reporting of custom events, user actions, values, and errors. The exact data types not reported to Dynatrace depend on the data collection level set by a particular user. For details, refer to Data collection levels.
With reportEvent
, you can report a specific event. The reported event must be part of a user action.
action.reportEvent("event_name");
The reportValue
method allows you to report key-value pairs of metadata that you can later view in the Dynatrace web UI and convert into user action and user session properties. The reported values must be part of a user action.
You can report values of the following data types:
// report intaction.reportValue("int_value_name", 5);// report longaction.reportValue("long_value_name", 5L);// report doubleaction.reportValue("double_value_name", 5.6);// report stringaction.reportValue("string_value_name", "exampleValue");
To view the reported values in the Dynatrace web UI, go to the details of the user action that should contain that metadata and scroll down to the Reported values section.
To add action and session properties based on the reported values and then use these properties to create powerful queries, segmentations, and aggregations, see Define user action and user session properties for mobile applications.
The reportError
method is different from the reportValue
method in that it's specifically identified as an error type event.
The OneAgent SDK allows you to report the following:
reportError(String, int)
method.reportError(String, Throwable)
method.There are two options for reporting an error. 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.
// report an error codeaction.reportError("error_code_name", -1);// report an exceptionaction.reportError("exception_name", exception);
You can report standalone errors via the Dynatrace
class.
// report an error codeDynatrace.reportError("error_code_name", -1);// report an exceptionDynatrace.reportError("exception_name", exception);
To track lifecycle events, we use the official Android ActivityLifecycleCallbacks
interface. For activities, Dynatrace reports the time of each entered lifecycle state until the activity is visible; if available, the timestamps of lifecycle callbacks are displayed in the user action waterfall analysis and are marked as a Lifecycle event.
With lifecycle monitoring, OneAgent collects data on the following lifecycle events for the Activity
class.
The timespan used for measuring the lifecycle event duration depends on the lifecycle event type and the level of Android API. When Android API level 29+ is used, we can measure the duration of lifecycle events more accurately thanks to pre- and post-lifecycle callbacks.
onActivityPreCreated
– onActivityPostResumed
onActivityCreated
– onActivityResumed
onCreate
onStart
onResume
onActivityPreStarted
– onActivityPostResumed
onActivityStarted
– onActivityResumed
onStart
onResume
onActivityPreResumed
– onActivityPostResumed
onResume
Activity lifecycle monitoring is turned on by default, but you can disable it with the withActivityMonitoring
method.
new DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconURL>").withActivityMonitoring(false).buildConfiguration();
The Dynatrace Android Gradle plugin automatically instruments most web requests. However, you have to manually instrument requests in the following cases:
For HTTP(S) requests, never combine automatic and manual web request instrumentation. However, you can use automatic instrumentation for HTTP(S) requests and manual instrumentation for non-HTTP(S) requests.
To track web requests, add the x-dynatrace
HTTP header with a unique value to the web request. This is required to correlate 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
WebRequestTiming
object based on the tag.There are two types of web requests in terms of their hierarchy:
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.
Currently, you cannot view standalone requests in Session Segmentation.
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.
URL url = new URL("https://www.example.com");// First, create a custom actionDTXAction webAction = Dynatrace.enterAction("Search request");// [1] Generate a new unique tag associated with the user actionString uniqueRequestTag = webAction.getRequestTag();// [2] Generate a WebRequestTiming object based on the unique tagWebRequestTiming timing = Dynatrace.getWebRequestTiming(uniqueRequestTag);// Define your OkHttp request. This varies greatly depending on your implementationRequest 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 senttiming.startWebRequestTiming();try (Response response = client.newCall(request).execute()) {if (response.isSuccessful()) {// handle responseString body = response.body().string();}// [5.1] Stop web request timing when the HTTP response is received and the response body was obtainedtiming.stopWebRequestTiming(url, response.code(), response.message());} catch (IOException e) {// [5.2] Stop web request timing when a connection exception occurstiming.stopWebRequestTiming(url, -1, e.toString());// user-defined exception handling}finally {// Lastly, end the custom actionwebAction.leaveAction();}
final URL url = new URL("https://www.example.com");// First, create a custom actionfinal DTXAction webAction = Dynatrace.enterAction("Search request");// [1] Generate a new unique tag associated with the user actionString uniqueRequestTag = webAction.getRequestTag();// [2] Generate a WebRequestTiming object based on the unique tagfinal WebRequestTiming timing = Dynatrace.getWebRequestTiming(uniqueRequestTag);// Define your OkHttp request. This varies greatly depending on your implementationRequest 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 calltiming.startWebRequestTiming();client.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {// [5.2] Stop web request timing when a connection exception occurstiming.stopWebRequestTiming(url, -1, e.toString());// user-defined exception handling// [8] Lastly, end the custom actionwebAction.leaveAction();}@Overridepublic void onResponse(Call call, Response response) throws IOException {try (ResponseBody responseBody = response.body()) {if (response.isSuccessful()) {// handle responseString body = response.body().string();}// [5.1] Stop web request timing when the HTTP response is received and the response body was obtainedtiming.stopWebRequestTiming(url, response.code(), response.message());// Lastly, end the custom actionwebAction.leaveAction();}}});
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.
URL url = new URL("https://www.example.com");// [1] Generate a new unique tagString uniqueRequestTag = Dynatrace.getRequestTag();// [2] Generate a WebRequestTiming object based on the unique tagWebRequestTiming timing = Dynatrace.getWebRequestTiming(uniqueRequestTag);// Define your OkHttp request. This varies greatly depending on your implementationRequest 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 senttiming.startWebRequestTiming();try (Response response = client.newCall(request).execute()) {if (response.isSuccessful()) {// handle responseString body = response.body().string();}// [5.1] Stop web request timing when the HTTP response is received and the response body was obtainedtiming.stopWebRequestTiming(url, response.code(), response.message());} catch (IOException e) {// [5.2] Stop web request timing when a connection exception occurstiming.stopWebRequestTiming(url, -1, e.toString());// user-defined exception handling}
OneAgent for Android version 8.249+
Monitoring of WebSocket connections is available starting with OneAgent for Android version 8.239. Monitoring of all non-HTTP(S) requests is available starting with OneAgent for Android version 8.249.
OneAgent for Android does not support auto-instrumentation of non-HTTP(S) requests. If you need to report requests such as a WebSocket request (starts with ws://
or wss://
), check the code samples below.
stopWebRequestTiming(URI requestUri, int respCode, String respPhrase)
API method to manually instrument non-HTTP(S) requests.OkHttp
object because this doesn't return the original URI.final URI uri = URI.create("wss://websocket.example.com");// First, create a custom actionDTXAction webSocketAction = Dynatrace.enterAction("WebSocket");// Generate a WebRequestTiming object based on the unique request tagWebRequestTiming timing = Dynatrace.getWebRequestTiming(webSocketAction.getRequestTag());// Define your OkHttp request. This varies greatly depending on your implementationRequest request = new Request.Builder().url(uri.toString()).build();// Start web request timing when you are about to open a WebSocket connectiontiming.startWebRequestTiming();WebSocket webSocket = client.newWebSocket(request, new WebSocketListener() {@Overridepublic 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 actionwebSocketAction.leaveAction();}@Overridepublic 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 actionwebSocketAction.leaveAction();}});
OneAgent captures all uncaught exceptions. The crash report includes the occurrence time and the full stack trace of the exception.
In general, the crash details are sent immediately after the crash, so the user doesn’t have to relaunch the application. However, in some cases, the application should be reopened within 10 minutes so that the crash report is sent. Note that Dynatrace doesn't send crash reports that are older than 10 minutes (as such reports can no longer be correlated on the Dynatrace Cluster).
You can deactivate crash reporting using the withCrashReporting
method.
new DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconURL>").withCrashReporting(false).buildConfiguration();
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. For more details, see User tagging.
The following steps explain how to tag an individual user via the Dynatrace API.
Dynatrace.identifyUser("john.doe@example.com");
OneAgent for Android version 237+ Sessions split due to idle or duration timeout are re-tagged automatically.
When OneAgent ends a tagged session because the session duration has reached its set limit or due to the user's inactivity, the subsequent session is re-tagged automatically. You don't need to provide the user identification information again.
However, note that OneAgent does not re-tag the subsequent session in the following cases:
endVisit
See User sessions > Session end to learn when OneAgent ends a mobile user session.
When the user opt-in mode is enabled for your application, it might affect user tagging and reporting of custom events, user actions, values, and errors. The exact data types not reported to Dynatrace depend on the data collection level set by a particular user. For details, refer to Data collection levels.
You can force a session to end via the Dynatrace API. This also closes all open actions and starts a new session.
Dynatrace.endVisit();
With user opt-in mode, each user of your application can set their data privacy preferences and decide whether they want or don't want to share their information. When the opt-in mode is enabled, you need to ask each user for permission to capture their data; then, you store their data privacy preferences. For details, see User opt-in mode.
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 the data privacy preferences based on the decision of a particular user.
Dynatrace.applyUserPrivacyOptions(UserPrivacyOptions.builder()// set a data collection level (user allowed you to capture performance and personal data).withDataCollectionLevel(DataCollectionLevel.USER_BEHAVIOR)// allow crash reporting (user allowed you to collect information on crashes).withCrashReportingOptedIn(true)// allow Session Replay on crashes (user allowed you to record replays of crashes via Session Replay).withCrashReplayOptedIn(true).build());
The possible values for the data collection level are as follows:
OFF
PERFORMANCE
USER_BEHAVIOR
OneAgent persists the data privacy preferences and automatically applies them when the application is restarted. Additionally, OneAgent generates a new session whenever the data privacy preferences are changed.
You can also retrieve the data privacy preferences of a particular user with the Dynatrace.getUserPrivacyOptions
method. Use this method only after OneAgent starts.
For hybrid applications, the native mobile app is monitored via OneAgent, while the browser part is observed by the Dynatrace RUM JavaScript. For this reason, hybrid application monitoring requires some additional configuration. See Instrument hybrid apps for more information.
To activate the hybrid application monitoring feature, use the withHybridMonitoring
method.
For hybrid applications that use the RUM JavaScript inside WebView
, OneAgent must set cookies for each instrumented domain or server that your application communicates with. When the hybrid application monitoring feature is enabled, OneAgent generates these cookies for every specified domain and stores them in CookieManager
. Dynatrace uses these cookies to identify mobile and web sessions within your application and merge these sessions into the same "hybrid" session.
To specify your domains, hostnames, and IP addresses, use either the withMonitoredDomains
or the withMonitoredHttpsDomains
method. Start domains and sub-domains with a period (.
).
withMonitoredDomains
methodnew DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconURL>").withHybridMonitoring(true).withMonitoredDomains(".<domain1>", ".<domain2>").buildConfiguration();
withMonitoredHttpsDomains
methodOneAgent for Android version 8.237+
If you use the withMonitoredHttpsDomains
method, the Secure
cookie attribute is added for all cookies that Dynatrace sets. This ensures that the browser sends these cookies only over secure connections.
new DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconURL>").withHybridMonitoring(true).withMonitoredHttpsDomains("https://.<domain1>", "https://.<domain2>").buildConfiguration();
WebView
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 received from WebView
will not be associated with the same mobile session.
WebView myWebView = (WebView) findViewById(R.id.webview);Dynatrace.instrumentWebView(myWebView);myWebView.loadUrl("http://www.example.com");
OneAgent for Android version 8.271+
To set cookies for file domains (starting with file://
), Dynatrace uses setAcceptFileSchemeCookies
. However, this API is no longer recommended because of security issues; we plan to stop adding cookies to file scheme domains in a couple of months.
If you want to secure your application right now, set fileDomainCookies
to false
, and Dynatrace won't add cookies to file scheme domains.
new DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconURL>").withHybridMonitoring(true).fileDomainCookies(false).buildConfiguration();
For hybrid applications, it's important to ensure that the Dynatrace cookies are not deleted. Without these cookies, Dynatrace can't combine the monitoring data received from the RUM JavaScript and OneAgent 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.
CookieManager.getInstance().removeAllCookies(null);Dynatrace.restoreCookies();
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.
new DynatraceConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconURL>").withStartupLoadBalancing(true).buildConfiguration();