Once you have instrumented your Android application with the Android SDK, you can also use the APIs exposed by the SDK to customize the data for your app that appears in the Controller UI. 

Because the agent stores data about events in a local buffer before reporting the information, you are recommended to use the APIs with discretion.

Collect Additional Types of Data

The Instrumentation class has additional methods to allow you to extend the kinds of application data you can collect and aggregate using Mobile RUM. There are six basic kinds of extensions that you can create:

Type of DataDescriptionSpecificationsWhere Data is Displayed
Info pointsHow often a method is invoked, and how long it takes to run.
  • Data is numeric
  • Names must consist of
    alphanumeric characters and/or spaces
Custom timersAny arbitrary sequence of events within your code timed,
even spanning multiple methods.
  • Data is numeric
  • Metric names must consist of
    alphanumeric characters and/or spaces
Custom metricsAny integer-based data you wish to collect.
  • Data is numeric
  • Metric names must consist of
    alphanumeric characters and/or spaces
User dataAny string key/value pair you think might be useful.
  • Data can be any type
  • Metric names have no restrictions
BreadcrumbsThe context for a crash.
  • Data can be any data type
  • Metric names have no restrictions
User interactionsCapture when users press buttons, click on lists, and select text.
  • Data can be any data type
  • Metric names have no restrictions

When you have set up info points, custom timers, custom metrics, and/or user data, the Mobile Agent packages that data in a mobile beacon. Normally, the beacon is transmitted when the instrumented app sends an HTTP request or when the app is restarted following a crash, but if custom data has been collected and neither of those events has occurred for at least 5 minutes, the custom data is sent on at that time.

Info Points

Information points allow you to track how your own code is running. You can see how often a method is invoked, how long it takes to run, and if an exception is thrown. The simplest way to set up an information point is to use the @InfoPoint annotation. For example:

@InfoPoint
 public void infoPointMethod(String arg1, int arg2, long value) {
   System.out.println("Executing infoPointMethod!");
 }
CODE

You can also do this manually, using the CallTracker interface. For example, to collect information on your downloadImage method, you could use code similar to this:

private void downloadImage(URL url) {
     CallTracker tracker =
          Instrumentation.beginCall("com.example.android.awesomeapp.ImageDownloader", "downloadImage")
              .withArguments(url);
     try {
          //download image.
          tracker.reportCallEnded()
     } catch(Exception e) {
         //handle exception thrown
         tracker.reportCallEndedWithException(e);
     }
 }
CODE

This information appears in the Custom Data view of the Controller UI.

Custom Timers

Custom timers allow you to time any arbitrary sequence of events within your code, even spanning multiple methods, by using startTimer and stopTimer.

public class MyActivity extends Activity {
   @Override
   protected void onStart(){
       Instrumentation.startTimer("Time Spent on MyActivity");
       //your code here.
   }

   @Override
   protected void onStop(){
       Instrumentation.stopTimer("Time Spent on MyActivity");
       //your code here.
   }
 }
JAVA

 The methods startTimer(String) and stopTime(String) can be called from different threads. Calling startTimer again with the same name value resets a named timer.

This information appears in the Custom Data view of the Controller UI.

Custom Metrics

Any integer-based data can be passed to the agent. The first parameter to the reportMetric call is the name you want the metric to appear under in the Controller UI. The metric name should only contain alphanumeric characters and spaces. Illegal characters are replaced by their ASCII hex value.

For example, to track the number of times your users click the checkout button in your UI, you could use code similar to this.

findViewById(R.id.checkout_button).setOnClickListener(new View.OnClickListener(){
      @Override
      public void onClick(View view){
          //run your checkout routine.
          Instrumentation.reportMetric("Checkout Count", 1);
      }
 });
JAVA

This information appears in the Custom Data view of the Controller UI.

User Data

You can set any string key/value pair you think might be useful. The first parameter to the setUserData call is the key you want to use, which must be unique across your application. The second is the value you want to be assigned to the key.

For example: 

void onUserLoggedIn(String userid) {
    Instrumentation.setUserData("User ID", userid); 
    ...
}
JAVA

This information is available in Network Request Analyze and is added to any crash snapshots that may be taken. Keys and values are limited to 2048 characters each.

You can also set user data with values of other types (Long, Boolean, Double, Date) using the following methods:

Breadcrumbs

Breadcrumbs allow you to situate a crash in the context of your user's experience. Set a breadcrumb when something interesting happens. If your application crashes at some point in the future, the breadcrumb will be displayed along with the crash report.

There are two ways of leaving breadcrumbs:

Using this method means that breadcrumbs are reported in crash reports only.

public static void leaveBreadcrumb(java.lang.String breadcrumb)
JAVA
Using this method lets you fine tune where the breadcrumbs are reported, either only in crash reports or in crash reports and sessions.
public static void leaveBreadcrumb(java.lang.String breadcrumb, int mode)
JAVA

Where mode is either:

  • CRASHES_ONLY
  • CRASHES_AND_SESSIONS

If the  breadcrumb is over 2048 characters, it is truncated.  If it is empty, no breadcrumb is recorded. Each crash report displays the most recent 99 breadcrumbs.


Add a Crash Reporting Callback

You may want to make crash report information that Mobile RUM collects available to other parts of your code, for example, to Google Analytics, if you are using it. To enable passing on summary crash information, you can set up a crash report runtime callback. To get a callback when the Android Agent detects and then reports a crash, you need to implement the following interface in your code:

public interface CrashReportCallback {
    void onCrashesReported(Collection<CrashReportSummary> summaries);
}
JAVA

We send a Collection instead of an individual callback because there could be more than one crash, even though there typically is only one. 

The method onCrashesReported is invoked during the next initialization of the agent after a crash has occurred.

This callback is invoked on your app's UI thread, so any work should be done on a separate work thread.

Each CrashReportSummary has the following properties:

public class CrashReportSummary {
    public final String crashId;
    public final String exceptionClass;
    public final String exceptionMessage;
}
JAVA

If you are sending the information to another analytics tool, such as Google Analytics, it is best to include all three properties: exceptionClass and exceptionMessage are useful for quick identification of the crash, but for more detailed information, crashId can be used to look up the crash in the AppDynamics Controller UI.

For example, to print the crash information to Android's logger, you could implement a CrashReportCallback class like this:

public static class MyCrashReportCallback implements CrashReportCallback {
    @Override
    public void onCrashesReported(Collection<CrashReportSummary> summaries) {
        for (CrashReportSummary crash : summaries) {
            Log.e("MyApp", "Crash Detected: " + crash.exceptionClass + " : " + crash.exceptionMessage + " (" + crash.crashId + ")");
        }
    }
}
JAVA

You set your callback as using the AgentConfiguration object:

final AgentConfiguration config = AgentConfiguration.builder()
        .withAppKey(appKey)
        .withContext(context)
        .withCrashCallback(new MyCrashReportCallback())
        .build();
JAVA

Your callback is invoked after a crash, during the next initialization, on the main thread. For more information, see the latest JavaDocs for the complete Android SDK API.

Report Errors and Exceptions

You can report exceptions using the method reportError from the Instrumentation class. Reported exceptions will appear in session details.

You can also set one of the severity levels below for an issue. With the severity level, you can filter errors in the Code Issues Dashboard or Code Issues Analyze.

  • ErrorSeverityLevel.INFO
  • ErrorSeverityLevel.WARNING
  • ErrorSeverityLevel.CRITICAL

The example below uses the API to report possible exceptions and sets the severity level to ErrorSeverityLevel.CRITICAL (critical) when writing to a file.

private void writeToFile(String filePath, String data) {
    try {
        OutputStream outputStream = new FileOutputStream(filePath);
        Writer outputStreamWriter = new OutputStreamWriter(outputStream);
        outputStreamWriter.write(data);
        outputStreamWriter.close();
    } catch (IOException e) {
        Log.e("Exception", "File write failed: " + e.toString());
        Instrumentation.reportError(e, ErrorSeverityLevel.CRITICAL);
    } 
}
JAVA

Configure Hybrid Support

By default, the Android Agent instruments Android WebViews. The Android Agent is able to do this by injecting the JavaScript Agent into WebViews. See Hybrid Application Support for an overview and an explanation of how it works. 

Runtime Configuration for Hybrid Support

The code example below disables the injection of the JavaScript Agent. If the client receives a false for this flag, then the JavaScript Agent will be disabled. Thus, WebViews will not be instrumented, and Ajax requests will not be monitored.

Instrumentation.start(
	AgentConfiguration.builder()
		.withAppKey(getString(R.string.app_key))
		.withContext(applicationContext)
		.withJSAgentInjectionEnabled(false)
		.build())
JAVA

The injection occurs during the creation of a new WKWebView. So, if a WKWebView is created when this flag is set to false, that particular WKWebView won't be instrumented even if the flag is subsequently set to true.

The collection and reporting of Ajax calls are disabled by default. To enable the injection and the collection and reporting of Ajax calls, pass true to the method jsAgentEnabled in the instrumentation configuration as shown below.


Instrumentation.start(
	AgentConfiguration.builder()
	.withAppKey(getString(R.string.app_key))
	.withContext(applicationContext)
	.withJSAgentAjaxEnabled(true)
	.build())
JAVA

Programmatically Control Sessions

By default, a mobile session ends after a period of user inactivity. For example, when a user opens your application, the session begins and only ends after the user stops using the app for a set period of time. When the user begins to use the application again, a new session begins. 

Instead of having a period of inactivity to define the duration of a session, however, you can use the following API to programmatically control when sessions begin and end:

void startNextSession()
JAVA

When you call the method startNextSession from the Instrumentation class, the current session ends and a new session begins. The API enables you to define and frame your sessions so that they align more closely with business goals and expected user flows. For example, you could use the API to define a session that tracks a purchase of a product or registers a new user. 

Excessive use of this API will cause sessions to be throttled (excessive use is >10 calls per minute per Android Agent, but is subject to change). When not using the API, sessions will fall back to the default of ending after a period of user inactivity.

Example of a Programmatically Controlled Session

In the code example below, the current session ends and a new one begins when the check out is made.

public void checkoutCart(){
    if (currentCartItems!=null && currentCartItems.size()>0){
	    CheckoutTask checkoutReq = new CheckoutTask();
		checkoutReq.execute(getEndpoint() + "cart/co");
		currentCartItemsMap.clear();
		convertItemsMaptoList();
        Instrumentation.startNextSession();
	} else {
	    displayToast("There are no items in the cart");
	}
}
JAVA

Start and End Session Frames

You can use the SessionFrame API to create session frames that will appear in the session activity. Session frames provide context for what the user is doing during a session. With the API, you can improve the names of user screens and chronicle user flows within a business context. 

Use Cases

The following are common use cases for using the SessionFrame API:

  • One Activity performs multiple functions and you want more granular tracking of the individual functions.
  • A user flow spans multiple activities or user interactions. For example, you could use the API to create the session frames "Login", "Product Selection", and "Purchase" to chronicle the user flow for purchases.
  • You want to capture dynamic information based on user interactions to name session frames, such as an order ID.

SessionFrame API

The table below lists the three methods you can use with session frames.

ClassMethodDescription
Instrumentation
static SessionFrame startSessionFrame(String sessionFrameName)
JAVA

Use this to start and name your session frame.

Naming session frames enable you to easily identify and track the frames in the Sessions Dialog.

SessionFrame
static void updateName(String updatedSessionFrameName)
JAVA

Use this to start and name your session frame.

Naming session frames enable you to easily identify and track the frames in the Sessions Dialog.

SessionFrame
static void end()
JAVA
End the session frame. You call this method from the SessionFrame object returned from startSessionFrame.

Session Frame Example

In the following example, the ShoppingCartActivity class uses the SessionFrame API to track user activity during the checkout process. 

public class ShoppingCartActivity extends Activity {

  SessionFrame checkoutSessionFrame;

  public void onCheckoutCartButtonClicked() {
    // The user starts the checkout by clicking the checkout button.
    // This may be after they have updated the quantities of items in the cart, etc.
    checkoutSessionFrame = Instrumentation.startSessionFrame("Checkout");
  }

  public void onConfirmOrderButtonClicked() {
    // Once they have confirmed payment info and shipping information, and they
    // are clicking the "Confirm" button to start the backend process of checking out,
    // we may know more information about the order itself, such as an order ID.
    checkoutSessionFrame.updateName("Checkout: Order ID " + orderId);
  }

  public void onProcessOrderCompleted() {
    // Once the order is processed, the user is done "checking out", so we end the session frame.
    checkoutSessionFrame.end();
    checkoutSessionFrame = null;
  }

  public void onCheckoutCanceled() {
    // If the user cancels or returns to the cart, you'll want to end the session frame also, or else it will be
    // left open and appear to have never ended.
    checkoutSessionFrame.end();
    checkoutSessionFrame = null;
  }
}
JAVA

Use a Custom HTTP Library

The Android Agent automatically detects network requests when the underlying implementation is handled by any one of the supported network libraries. To have the Android Agent detect requests from a custom library, add request tracking code to your application manually, using the HttpRequestTracker interface.  

Supported Network Libraries

The libraries below cover the great majority of Android network requests. In some cases, however, mobile applications use custom HTTP libraries.  

  • HttpURLConnection
  • HttpsURLConnection
  • HttpClient classes
  • OkHttp
  • OkHttp3
  • ch.boye.httpclientandroidlib

To set headers to allow correlation with server-side processing, use the ServerCorrelationHeaders class.  

Add Request Tracking

To add request tracking manually, you use an HttpRequestTracker object to tell the agent when the request begins and when it ends and to report fields of the response to the agent.

Tracking a request

To begin tracking an HTTP request, use an instance of the following interface.

You must initialize the agent using the Instrumentation.start method before using this interface.

public interface HttpRequestTracker {
    public Exception getException();
    public HttpRequestTracker withException(Exception e);
 
    public String getError();
    public HttpRequestTracker withError(String error);
 
    public int getResponseCode();
    public HttpRequestTracker withResponseCode(int responseCode);
 
    public Map<String, List<String>> getResponseHeaderFields();
    public HttpRequestTracker withResponseHeaderFields(Map<String, List<String>> responseHeaderFields);
 
   /**
    * Stops tracking an HTTP request.
    *
    * Immediately after receiving a response or an error, set the appropriate fields and call this method to
    * report the outcome of the HTTP request. You should not continue to use this object after calling this
    * method -- if you need to track another request, obtain a new instance.
    */
    public void reportDone();
}
JAVA

Example:

Given a request snippet like this:

public byte[] sendRequest(URL url) throws HttpException {
    try {
        // implementation omitted
        return responseBody;
    } catch (UnderlyingException e) {
        throw new HttpException(e);
    }
}
JAVA

Adding the tracker could look something like this:

public byte[] sendRequest(URL url) throws HttpException {
    HttpRequestTracker tracker = Instrumentation.beginHttpRequest(url);
    try {
        // implementation omitted
        tracker.withResponseCode(theResponseCode)
               .withResponseHeaderFields(theResponseHeaderFields)
               .reportDone();
        return responseBody;
    } catch (UnderlyingException e) {
        tracker.withException(e)
               .reportDone();
        throw new HttpException(e);
    }
}
JAVA

Enable Server-Side Correlation

To enable correlation between your request and server-side processing, add specific headers to outgoing requests that the server-side agent can detect.

This is done automatically for standard HTTP libraries.

public class ServerCorreleationHeaders {
    public static Map<String, List<String>> generate();
}
JAVA

You must:

  1. Call the generate method and set the generated headers before sending a request to the backend.
  2. Report back the response headers, using data from the withResponseHeaderFields field.

Override the Request/Response Content-Length

You can generally obtain the content lengths of the network request and response by passing the headers with HttpRequestTracker.withRequestHeaderFields() and HttpRequestTracker.withResponseHeaderFields().

If for some reason this does not work for your custom HTTP tracking—for example, the network library doesn't populate those fields until its being transmitted—then you can still report the request and response content lengths using HttpRequestTracker.withRequestContentLength(Long length) and HttpRequestTracker.withResponseContentLength(Long length).

For example, suppose you want to track a request that has a byte array of content. You could report the request content length by passing the size of the byte array as shown below.

byte[] requestContent;
HttpRequestTracker tracker;
tracker.withRequestContentLength(requestContent.size());
JAVA

Customize the Agent Configuration

To customize the behavior of the agent itself, you pass the AgentConfiguration object to the Instrumentation.start method. The AgentConfiguration object allows you to do these things:

  • Point to an on-premises EUM Server
  • Enable logging
  • Custom set the application name, useful if you deploy essentially the same app binary with different package names to different geographic areas. This ensures that all the data ends up being processed under the same name.
  • Ignore HTTP requests internal to your application that are not used for network requests
  • Configure the agent to use your custom HTTP library to send its beacons

The syntax looks like the following:

Instrumentation.start(AgentConfiguration.builder()
      .withAppKey("<EUM_APP_KEY>")
      .withContext(getApplicationContext())
      .withCollectorURL(collectorURL*) // The URL of the EUM Server(on-prem)
      .withCompileTimeInstrumentationCheck(true) // Set to false if you are using features of the SDK only, like custom HTTP support, but not to instrument your app.      
      .withLoggingEnabled(true)//set default INFO logging. Tagged "AppDynamics".
      .withApplicationName(applicationName)//set a custom app name
	  .withExcludedUrlPatterns(excludedUrlPatterns) // Set excluded url regex patterns for http tracking
      .withCollectorChannelFactory(collectorChannelFactory()) // The custom HTTP implementation to use
      .build());
JAVA

* The default URL of the EUM server is https://mobile.eum-appdynamics.com:443. For a list of URLs of EUM servers, see External Access Locations. 

See the latest JavaDocs for more information.

Configure the Agent to Use Custom HTTP Library

The Android Agent uses HTTP to deliver its beacons. To have the agent use your custom HTTP library for this purpose, do the following.

  1. Implement a class that extends the following abstract class:

    public abstract class CollectorChannel {
        private URL url;
        private int connectTimeout;
        private int readTimeout;
        private Map<String, List<String>> requestProperties = new HashMap<String, List<String>>();
        private String requestMethod;
     
        public void setURL(URL url) {
            this.url = url;
        }
     
        public URL getURL() {
            return url;
        }
     
        public void setConnectTimeout(int connectTimeout) {
            this.connectTimeout = connectTimeout;
        }
     
        public int getConnectTimeout() {
            return connectTimeout;
        }
     
        public void setReadTimeout(int readTimeout) {
            this.readTimeout = readTimeout;
        }
     
        public int getReadTimeout() {
            return readTimeout;
        }
     
        public void addRequestProperty(String property, String value) {
            if (!requestProperties.containsKey(property)) {
                requestProperties.put(property, new ArrayList<String>());
            }
            requestProperties.get(property).add(value);
        }
     
        public Map<String, List<String>> getRequestProperties() {
            return Collections.unmodifiableMap(requestProperties);
        }
     
        public void setRequestMethod(String requestMethod) {
            this.requestMethod = requestMethod;
        }
     
        public String getRequestMethod() {
            return requestMethod;
        }
     
        public abstract OutputStream getOutputStream() throws IOException;
     
        public abstract InputStream getInputStream() throws IOException;
     
        public abstract int getResponseCode() throws IOException;
     
        public abstract Map<String,List<String>> getHeaderFields() throws IOException;
    }
    CODE

    This interface is loosely based on HttpURLConnection.

  2. Implement a version of the CollectorChannelFactory interface, which looks like this:

    public interface CollectorChannelFactory {
    
        /**
         * Returns a new instance of CollectorChannel.
         *
         * If you want to supply a custom CollectorChannel, implement this interface, and return
         * an instance of your concrete implementation of CollectorChannel from this method.
         */
        public CollectorChannel newCollectorChannel();
    }
    JAVA

    The implementation of newCollectorChannel should return a new instance of your implementation of CollectorChannel.

  3. Pass the CollectorChannelFactory to the AgentConfiguration object.

Capture User Interactions

You can enable the Android Agent to track certain user interactions. Once user interactions have been captured, you can sort sessions by UI event and view the UI event in the timeline of the session waterfall. 

You can capture when users do one or all of the following:

  • press buttons
  • select a text field
  • click a list item

Security and Privacy Concerns

The interaction capture mode is disabled by default for security and privacy reasons as user interactions may contain sensitive information. Moreover, this potential security and privacy issue may be compounded if you enable both the capturing of UI interactions and screenshots. 

Enable User Interaction Capture Mode

To enable user interaction capture mode, pass the capture mode to the method withInteractionCaptureMode() from an AgentConfiguration object. The instrumentation code example below configures the Android Agent to capture all the supported types of user interactions.

Instrumentation.start(AgentConfiguration.builder()
      .withAppKey("<EUM_APP_KEY>")
      .withContext(getApplicationContext())
      .withInteractionCaptureMode(InteractionCaptureMode.All)
      .build());
JAVA

You can also configure the Android Agent to only capture one type of user interaction:

Instrumentation.start(AgentConfiguration.builder()
      .withAppKey("<EUM_APP_KEY>")
      .withContext(getApplicationContext())
      .withInteractionCaptureMode(InteractionCaptureMode.ButtonPressed)
      .build());
JAVA

Configure and Take Screenshots

Mobile screenshots are enabled by default in the Android Agent. You can configure the Controller UI to automatically take screenshots or use the Android SDK to manually take a screenshot as shown below:

Instrumentation.takeScreenshot(); 
JAVA

For example, you might want to take a screenshot after you load a UI element to view how it's displayed to customers:

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_spinner_with_toast);
   spinner = (Spinner) findViewById(R.id.spnOptions); 
   btnSpinnerVal = (Button) findViewById(R.id.btnSpinnerValue);
   loadSpinner();
   Instrumentation.takeScreenshot();
}
JAVA

Disable Screenshots

You can disable screenshots from the Controller UI or with the Android SDK. To disable screenshots with the Android SDK, use the method withScreenshotsEnabled(false) from the AgentConfiguration class as shown below.

Instrumentation.start(AgentConfiguration.builder()
     .withAppKey("<EUM_APP_KEY>")
     .withContext(getApplicationContext())
     .withScreenshotsEnabled(false)
     .build());
}
JAVA

Block/Unblock Screenshots

You can also use the Android SDK to block screenshots from being taken during the execution of code block. This just temporarily blocks screenshots from being taken until you unblock screenshots. This enables you to stop taking screenshots in situations where users are entering personal data, such as on login and account screens.

You use the methods Instrumentation.blockScreenshots() and Instrumentation.unblockScreenshots() to block and unblock screenshots. If screenshots are disabled through AgentConfiguration.Builder.withScreenshotsEnabled(true) or through the Controller UI, these methods have no effect. You can call Instrumentation.screenshotsBlocked() to check if screenshots are being blocked.

The following example demonstrates how you could use the API to block and unblock screenshots when displaying user information.

public class UserAccountActivity extends Activity {
  ...
  public void displayCustomerAccount() {
    // Check to see if screenshots are blocked
    if (! Instrumentation.screenshotsBlocked()) {
        // If screenshots aren't blocked, block them before showing customer details
        Instrumentation.blockScreenshots();    
    } 
    // Code to display customer details
    displayAccount(this.user);
    // After you're done, unblock screenshots
    Instrumentation.unblockScreenshots();
  }
  ...
}
CPP

Transform URLs for Network Requests

When your application makes network requests, you may not want to report URLs containing sensitive information to the EUM Server. You can instead transform the network request URL before reporting it or ignore it altogether. 

To do so:

  1. Implement a network request callback that modifies or ignores specific URLs. 
  2. Register the network request callback in the initialization code.

Implement the Network Request Callback

The callback that modifies or ignore specific URLs is an implementation of the interface below. The method onNetworkRequest is synchronous, so it is recommended that you return from the function quickly.

public interface com.appdynamics.eumagent.runtime.NetworkRequestCallback  {
    boolean onNetworkRequest(HttpRequestTracker httpRequestTracker);
}
JAVA

 Transforming URLs

The onNetworkRequest method, in general, should follow the steps below to transform URLs:

  1. Identify specific URLs using techniques such as regex or pattern matching.
  2. Modify the url property of the HttpRequestTracker object.
  3. Assign a valid URL to the url property. (Modifying other properties of the HttpRequestTracker object will be ignored.)
  4. Return true.

The first step is optional as you could choose to transform the URLs of all network requests. 

private static class myNetworkRequestCallback implements com.appdynamics.eumagent.runtime.NetworkRequestCallback  {
    @Override
    public boolean onNetworkRequest(HttpRequestTracker httpRequestTracker) {
        URL urlMask = new URL("http://networkrequest-mask.com");
        httpRequestTracker.withURL(urlMask);
        return true;
    }
}
JAVA

In general, however, you would want to identify and transform URLs that contain sensitive information as implied in the example below.

private static class myNetworkRequestCallback implements com.appdynamics.eumagent.runtime.NetworkRequestCallback  {
    @Override
    public boolean onNetworkRequest(HttpRequestTracker httpRequestTracker) {
        String urlString = httpRequestTracker.getURL().toString();
        try {
            URL url = new URL("http://customer-account.com");
            if (urlString.contains("accountInfo")) {
                // Change the URL for calls to Facebook
                httpRequestTracker.withURL(url);
                return true;
            } 
        } catch (MalformedURLException e) {
            return false;
        }
        return true;
    }
}
JAVA

Ignoring URLs

If the onNetworkRequest method returns false, the beacon is dropped. The general process for ignoring beacons is as follows:

  1. Identify specific URLs using techniques such as regex or pattern matching.

  2. Return false.

You could theoretically ignore all network requests with the following implementation of onNetworkRequest.

private static class myNetworkRequestCallback implements com.appdynamics.eumagent.runtime.NetworkRequestCallback  {
    @Override
    public boolean onNetworkRequest(HttpRequestTracker httpRequestTracker) {
        return false;
    }
}
JAVA

In general, you would identify network requests that you didn't want to monitor and return false to ignore the network request as implied by this example.

private static class myNetworkRequestCallback implements com.appdynamics.eumagent.runtime.NetworkRequestCallback  {
    @Override
    public boolean onNetworkRequest(HttpRequestTracker httpRequestTracker) {
        String urlString = httpRequestTracker.getURL().toString();
        try {
            URL url = new URL("http://socialnetworksite.com");
            if (urlString.contains("avatar")) {
                // Ignore calls for avatars
                return false;
            }
        } catch (MalformedURLException e) {
            return false;
        }
        return true;
    }
}
JAVA

Register the Network Request Callback

After implementing the callback, you register it in the initialization code as shown below. When the Android Agent is ready to create a network request beacon, it will first call the callback with an HttpRequestTracker object.

Instrumentation.start(AgentConfiguration.builder()
        .withContext(getApplicationContext())
        .withAppKey("<EUM_APP_KEY>")
        .withNetworkRequestCallback(new myNetworkRequestCallback())
        .build());
JAVA

Enable Logging and Set Logging Level

You use the method withLoggingLevel of the class AgentConfiguration to enable logging and set the logging level. You can set logging to one of the following levels:

  • LOGGING_LEVEL_NONE
  • LOGGING_LEVEL_INFO
  • LOGGING_LEVEL_VERBOSE

Use verbose logging only for troubleshooting and be sure to disable for production.

Example:

AgentConfiguration config = AgentConfiguration.builder()
config.withAppKey(appKey)
config.withContext(context)
 .withLoggingLevel(Instrumentation.LOGGING_LEVEL_VERBOSE)
        .build();
    Instrumentation.start(config);
JAVA

Android SDK Documentation

For the complete SDK API documentation, see the latest JavaDocs or the previous versions listed below: