OneAgent SDK for Android

OneAgent SDK for Android can be used to report additional details about the mobile user sessions of your app. OneAgent SDK for Android enables you to create custom user actions, measure web requests, report errors, and tag specific users. This topic explains how to enable these capabilities.

OneAgent SDK is automatically added by the DESK Android Gradle plugin. Alternatively, you can add the OneAgent SDK when you want to use standalone manual instrumentation for your Android application project.

Note: All technical information is available at JavaDoc for OneAgent SDK.

Start OneAgent

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

public class YourApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        DESK.startup(this, new DESKConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconUrl>")
            ... // additional configuration
            .buildConfiguration());
    }
}

If your app supports Direct Boot, ensure that DESK.startup is never called from a Direct Boot aware component. You should also see Adjust OneAgent communication to ensure that OneAgent is able to transmit the data to the cluster.

Configure OneAgent

Use the DESKConfigurationBuilder class to customize all advanced OneAgent settings with different API methods.

new DESKConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconURL>")
    .withUserOptIn(true)
    .withCrashReporting(true)
    .buildConfiguration();

Note:
If you use a combination of manual and auto-instrumentation, the auto-instrumentation injects a DESK.startup call into the Application.onCreate method. In this case, you will lose your manual configuration because the DESK.startup call from the auto-instrumentation is called before your DESK.startup call.

The autoStart.enabled property allows you to deactivate the auto-start feature from the auto-instrumentation. You can then define a manual DESK.startup call in the Application.onCreate method. In this case, you can override the values preconfigured from the auto-instrumentor.

User action monitoring

With user action monitoring you can define and report your own custom user actions. These user actions can be enriched with the following monitoring operations:

Manually created user actions are different from user actions created with the DESK Android Gradle plugin. OneAgent not only adds additional events (such as web requests) to your user action, it will also not automatically close your user actions after a specific time period.

Create custom user actions

You can define your own custom user actions. First, you have to create them. Then you can enhance them with additional information, and finally, you must close them. OneAgent discards all action-related monitoring data when the action isn't closed.

You must call enterAction to start each action and leaveAction to close each action. Timing is measured automatically.

// start user action
DTXAction action = DESK.enterAction("exampleName");

// ...do some work here...

// end the action after the search completed
action.leaveAction();

Child actions

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

Child actions are generated using the method DESK.enterAction(String, DTXAction).

// start parent user action
DTXAction parentAction = DESK.enterAction("parent_user_action_name");

// ...do some work here...

// start child user action
DTXAction childAction = DESK.enterAction("child_user_action_name", parentAction);

// ...do some work here...

// end the child action
childAction.leaveAction();

// ...do some work here...

// end the parent action
parentAction.leaveAction();

User action 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 user action
  2. reports a custom metric
  3. reports a handled exception
  4. monitors a web request
  5. creates a child action
public boolean search(String query) {
    // [1a] start outer/parent action
    DTXAction searchAction = DESK.enterAction("search");

    // [2] report your own metric
    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 outer action
        searchAction.leaveAction();
        return false;
    }

    // [4.1] Generate a new unique tag associated with the user action "search"
    String uniqueRequestTag = searchAction.getRequestTag();
    // [4.2] Generate a WebRequestTiming object based on the unique tag
    WebRequestTiming timing = DESK.getWebRequestTiming(uniqueRequestTag);

    Request request = new Request.Builder()
            .url(url)
            // [4.3] Place the DESK HTTP header on your web request
            .addHeader(DESK.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 was obtained
        timing.stopWebRequestTiming(url, response.code(), response.message());

        // [5a] start inner action
        DTXAction parseAction = DESK.enterAction("parse result", searchAction);

        parseResult(body);

        // [5b] end inner 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 outer action
        searchAction.leaveAction();
    }
}

Custom value reporting

Report event

The report event feature allows you to report the time point of a specific event. The reported event must be part of a user action.

action.reportEvent("event_name");

Report value

The report value feature allows you to report your own metrics. These metrics must be part of a user action. The OneAgent SDK allows you to report

// report int
action.reportValue("int_metrics_key", 5);
// report double
action.reportValue("double_metrics_key", 5.6);
// report string
action.reportValue("string_metrics_key", "exampleValue");

Report errors

The reporting error feature is different from the reporting value feature in that it is specifically identified as an error type event. The OneAgent SDK allows you to report:

// report error code
action.reportError("error_code_key", -1);
// report exception
action.reportError("exception_key", exception);

You can also report errors as stand-alone error events via the class DESK:

// report error code
DESK.reportError("error_code_key", -1);
// report exception
DESK.reportError("exception_key", exception);

Web request monitoring

To track web requests, add the x-desk 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.

Perform the following steps to successfully monitor a web request:

Generate a new unique tag.

Generate a WebRequestTiming object based on the tag.

Place the DESK HTTP header on your web request.

Start web request timing before the HTTP request is sent.

Stop web request timing.

The HTTP response is received and the response body is obtained.

A connection exception occurs.

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

Web requests can either be:

Note: For monitoring standalone web 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 the user action

The following sample shows how a synchronous OkHttp web request could be monitored:

URL url = new URL("https://www.example.com");

// First, create a user action
DTXAction webAction = DESK.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 = DESK.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 DESK HTTP header on your web request
        .addHeader(DESK.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, leave the action
    webAction.leaveAction();
}

Standalone web request

The following sample shows how a synchronous OkHttp web request can be monitored:

URL url = new URL("https://www.example.com");

// [1] Generate a new unique tag
String uniqueRequestTag = DESK.getRequestTag();
// [2] Generate a WebRequestTiming object based on the unique tag
WebRequestTiming timing = DESK.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 DESK HTTP header on your web request
        .addHeader(DESK.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
}

HttpURLConnection

For monitoring HttpURLConnection web requests, OneAgent SDK contains an additional API method: DESK.getWebRequestTiming(HttpURLConnection). 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.

URL url = new URL("https://www.example.com");
HttpURLConnection conn = null;
WebRequestTiming timing = null;

// First, create an action
DTXAction webAction = DESK.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 = DESK.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, leave the action
    webAction.leaveAction();
}

Other samples

Crash reporting

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

Disable crash reporting

You can also deactivate crash reporting with the withCrashReporting method:

new DESKConfigurationBuilder("<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 manually tag an individual user via the DESK API.

DESK.identifyUser("john.doe@example.com");

Data privacy

The OneAgent SDK enables you to dynamically adjust data-privacy settings so that you can build your apps in compliance with GDPR data-privacy regulations. To activate this feature, enable the userOptIn flag via the DSL from the DESK Android Gradle plugin or use the ConfigurationBuilder.withUserOptIn method.

The privacy API methods allow you to dynamically activate/deactivate crash reporting and to change the data-collection level based on the individual preferences of your end users. Each end user can select from three data-privacy levels:

  • off: OneAgent won't capture any monitoring data.
  • performance: OneAgent will only capture anonymous performance data. Monitoring data that can be used to identify individual users, such as user tags and custom values, won't be captured.
  • user behavior: OneAgent will capture both performance and user data. In this mode, OneAgent recognizes and reports on users who re-visit in future sessions.

When OneAgent starts for the first time, OneAgent deactivates crash reporting and sets the data-collection level to off. You should change the privacy settings, based on each user's individual preference when your app starts for the first time. OneAgent doesn't provide a privacy settings dialog or any similar UI component. You must integrate a privacy dialog into your app. We recommend that you display the privacy dialog before your app is displayed and then apply the user's privacy preference. You should also allow your users to change their privacy settings in the future.

OneAgent persists the privacy setting and automatically applies it when the app is restarted. Each time the user changes the data-collection level, a new session with the new privacy settings will be generated by OneAgent. Don't wrap this API method with a user action. Otherwise, OneAgent won't be able to attach the user action to the correct session.

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

You can retrieve the privacy settings with the DESK.getDataCollectionLevel() and DESK.isCrashReportingOptedIn() methods. But you can't use the privacy API methods before OneAgent is started. Otherwise, OneAgent will throw an exception.

Hybrid apps that use the RUM JavaScript tag inside a WebView

For hybrid applications that use the RUM JavaScript tag, 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.

You can activate the hybrid app monitoring feature with the withHybridMonitoring method. All used domains, hosts, and IP addresses must be specified via the withMonitoredDomains method. Domains and sub-domains must start with a dot.

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