PDFs


This page applies to an earlier version of the AppDynamics App IQ Platform.
For documentation on the latest version, see the 4.4 Documentation.


On this page:

Related pages:

Your Rating:
Results:
PatheticBadOKGoodOutstanding!
23 rates

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

See the latest iOS SDK documentation or the previous versions listed below:

The ADEumInstrumentation class contains the methods that are of interest.

Extend the Mobile Agent

You can use methods available in the ADEUMInstrumentation class to collect five additional types of data:

When you have set up additional data types, 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 five 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, and how long it takes to run, by using beginCall and endCall, something like this:

- (void)myMethod
    {
        id tracker = [ADEumInstrumentation beginCall:self selector:_cmd];

        // Implementation of method here ...

        [ADEumInstrumentation endCall:tracker];
    }

If an exception is thrown, it is also reported. This information appears in the Custom Data view in 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. For example, to track the time a user spends viewing a screen, the instrumentation could look like this:

     - (void)viewDidAppear:(BOOL)animated {
        [super viewDidAppear:animated];
        [ADEumInstrumentation startTimerWithName:@"View Lifetime"];
    }
    - (void)viewDidDisappear:(BOOL)animated {
        [super viewDidDisappear:animated];
        [ADEumInstrumentation stopTimerWithName:@"View Lifetime"];
    }

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

Calling startTimerWithName again with the same name value resets a named timer.

Custom Metrics

Any integer-based data can be passed to the agent. The first parameter to the report.MetricWithName call is the name you want the metric to appear under in the Controller UI. Reporting a metric called "My custom metric", for example, would look something like this:

[ADEumInstrumentation reportMetricWithName:@"My custom metric" value:<VALUE HERE>];

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 assigned to the key.

For example: 

- (void) onUserLoggedIn:(NSString *)userid { 
    [ADEumInstrumentation setUserData:@"User ID" value:userid];
    ...
 }

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.

+ (void)leaveBreadcrumb:(NSString *)breadcrumb
Using this method lets you fine tune where the breadcrumbs are reported, either only in crash reports or in crash reports and sessions.
+ (void)leaveBreadcrumb:(NSString *)breadcrumb mode:(ADEumBreadcrumbVisibility)mode

Where mode is either:

  • ADEumBreadcrumbVisibilityCrashesOnly
  • ADEumBreadcrumbVisibilityCrashesAndSessions

If the breadcrumb is over 2048 characters, it is truncated. If it is empty or nil, 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 you to pass on summary crash information, you can set up a crash report runtime callback. To get a callback when the iOS Agent detects and then reports a crash, you need to implement the following protocol in your code:

@protocol ADEumCrashReportCallback <NSObject>
  
- (void)onCrashesReported:(NSArray<ADEumCrashReportSummary *> *)crashReportSummaries;
  
@end

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

Each ADEumCrashReportSummary passed in has the following properties:

@interface ADEumCrashReportSummary : NSObject
 
/** Uniquely defines the crash, can be used as key to find full crash report. */
@property (nonatomic, readonly) NSString *crashId;
 
/** The exception name, may be `nil` if no `NSException` occured. */
@property (nonatomic, readonly) NSString * ADEUM_NULLABLE exceptionName;
 
/** The exception reason, may be `nil` if no `NSException` occured. */
@property (nonatomic, readonly) NSString * ADEUM_NULLABLE exceptionReason;
 
/** The Mach exception signal name */
@property (nonatomic, readonly) NSString *signalName;
 
/** The Mach exception signal code */
@property (nonatomic, readonly) NSString *signalCode;
 
@end

If you are sending the information to another analytics tool, such as Google Analytics, it is best to include all five properties: 

  • exceptionName and exceptionReason are optional and useful for a quick identification of what the crash is. These are only present if the crash cause occurred within an exception reporting runtime, such as Objective-C.
  • signalName and signalCode are useful for quick identification of the crash. These are from the system and are independent of the runtime.
  • For additional information, crashId can be used to look up the crash in the AppDynamics Controller UI.

For example, to print the crash information to iOS's logger, you could implement an ADEumCrashReportCallback class like this:

// assumes the containing object has "adopted" the protocol
- (void)onCrashesReported:(NSArray<ADEumCrashReportSummary *> *)summaries {
    for (ADEumCrashReportSummary *summary in summaries) {
        NSLog(@"Crash ID: %@", summary.crashId);
        NSLog(@"Signal: %@ (%@)", summary.signalName, summary.signalCode);
        NSLog(@"Exception Name:\n%@", summary.exceptionName);
        NSLog(@"Exception Reason:\n%@", summary.exceptionReason);
    }
}

You set the object that implements the ADEumCrashReportCallback protocol during agent configuration:

ADEumAgentConfiguration *config = [ADEumAgentConfiguration new];
config.crashReportCallback = myCrashReportCallback;

Your callback is invoked, on the main/UI thread, if a crash from a previous run is detected and collected. See the latest iOS SDK documentation for more information.

Configure the Agent for Custom App Names

By default, AppDynamics automatically detects the name of your application. The application name is a string form of the bundle ID. Thus, if the bundle ID is com.example.appdynamics.HelloWorld, the application name will be "com.example.appdynamics.HelloWorld". 

There may be cases, however, where you deploy essentially the same app binary with different bundle IDs to various regional app stores. To make sure all the data belonging to one app is collected and displayed together, despite varying bundle IDs, you can set a common name by giving the apps a custom name. To do this, set the application name property in the ADEumAgentConfiguration instance that you use to set up ADEumInstrumentation. See the latest iOS SDK documentation for more information.

@property (nonatomic, strong) NSString *applicationName; 

Configure the Agent for Ignoring Some HTTP Requests

In some cases, HTTP requests using NSURL are used for internal purposes in an application and do not represent actual network requests. Metrics created based on these requests are not normally useful in tracking down issues, so preventing data on them from being collected can be useful. To ignore specific NSURL requests, set the excluded URL patterns property in the ADEumAgentConfiguration instance that you use to set up ADEumInstrumentation. Use the simplest regex possible. See the latest iOS SDK documentation for more information.

@property (nonatomic, strong) NSSet * excludedUrlPatterns;

Use the Agent with a Custom HTTP Library

The iOS Agent automatically detects network requests when the underlying implementation is handled by either by the NSURLConnection or the NSURLSession classes. This covers the great majority of iOS network requests. In some cases, however, mobile applications use custom HTTP libraries.  

  • To have the iOS Agent detect requests from a custom library, add request tracking code to your application manually, using the ADEumHTTPRequestTracker class.  
  • To set headers to allow correlation with server-side processing, use the ADEEumServerCorrelationHeaders class.  
  • To configure the agent to use your custom library to deliver its beacons over HTTP, use the ADEumCollectorChannel protocol and the ADEumAgentConfiguration class.

Add Request Tracking

To add request tracking manually, you tell the agent when the request begins and when it ends. You also set properties to tell the agent the status of the response.

Start and complete tracking a request

To begin tracking an HTTP request, call the following method immediately before sending the request.

 You must initialize the agent using one of the ADEumInstrumentation's initWithKey methods before using this method.

@interface ADEumHTTPRequestTracker : NSObject
... 
+ (ADEumHTTPRequestTracker *)requestTrackerWithURL:(NSURL *)url;

Where url is the URL being requested. This parameter must not be nil.

To complete tracking an HTTP request, immediately after receiving a response or an error, set the appropriate properties (see below) on the tracker object and call the following method to report the outcome of the request back to the agent. You should not continue to use this object after calling this method. To track another request, call requestTrackerWithURL again.

- (void)reportDone;

Properties to be set

The following properties should be set on the requestTrackerWithURL object to describe to the agent the results of the call.

@property (copy, nonatomic) NSError *error;

Indicates the failure to receive a response, if this occurred. If the request was successful, this should be nil.

@property (copy, nonatomic) NSNumber *statusCode;
Reports the HTTP status code of the response, if one was received.
  • If a response was received, this should be an integer.

  • If an error occurred and a response was not received, this should be nil.

@property (copy, nonatomic) NSDictionary *allHeaderFields;

Provides a dictionary representing the keys and values from the server’s response header. The format of this dictionary should be identical to the allHTTPHeadersFields property of NSURLRequest. The dictionary elements consist of key/value pairs, where the key is the header key name and the value is the header value.

If an error occurred and a response was not received, this should be nil.  

Example:

Given a request snippet like this:

- (NSData *)sendRequest:(NSURL *) url error:(NSError **)error { 
      // implementation omitted 
      NSData *result = nil; 
      if (errorOccurred) { 
          *error = theError; 
      } else { 
          result = responseBody; 
      } 
      return result; 
  }

Adding the tracker could look something like this:

- (NSData *)sendRequest:(NSURL *)url error:(NSError **)error { 
      ADEumHTTPRequestTracker *tracker = [ADEumHTTPRequestTracker requestTrackerWithURL:url]; 
      // implementation omitted 
      NSData *result = nil; 
      if (errorOccurred) { 
          *error = theError; tracker.error = theError; 
      } else { 
          tracker.statusCode = theStatusCode; 
          tracker.allHeaderFields = theResponseHeaders; 
          result = responseBody; 
      } 
      [tracker reportDone]; 
      return result; 
  }

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

and return the headers obtained from the server-side agent in the response to make them available to the iOS Agent.

This is done automatically for standard HTTP libraries.

@interface ADEumServerCorrelationHeaders : NSObject + (NSDictionary *)generate; @end

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 the allHeaderFields property shown above.

Configure Agent to Use Custom HTTP Library

The iOS 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 conforms to this protocol:

    /** * Protocol for customizing the connection between the agent SDK and the collector. */ 
    @protocol ADEumCollectorChannel <NSObject> 
     
    /** 
    * Sends a request synchronously and returns the response received, or an error. 
    * 
    * The semantics of this method are exactly equivalent to NSURLConnection's 
    * sendSynchronousRequest:returningResponse:error: method. 
    * 
    * @param request The URL request to load. 
    * @param response Out parameter for the URL response returned by the server. 
    * @param error Out parameter used if an error occurs while processing the request. May be NULL. 
    */ 
    - (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error; 
    @end
  2. Set the collectorChannel property in ADEumAgentConfiguration before initializing ADEumInstrumentation, passing in an instance of your class that implements ADEumCollectorChannel. See the latest iOS SDK documentation for more information.

    @property (nonatomic, strong) id<ADEumCollectorChannel> collectorChannel;

Enable User Interaction Capture Mode

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

The interaction capture mode is disabled by default for security and privacy reasons as user interactions may contain sensitive information.

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

  • press buttons
  • select table cells
  • select text fields
  • select text views

To enable user interaction capture mode, you assign the capture mode to the property interactionCaptureMode of the ADEumAgentConfiguration object. The instrumentation code example below configures the iOS Agent to capture all the supported types of user interactions. 

ADEumAgentConfiguration *config = [[ADEumAgentConfiguration alloc] initWithAppKey: @"<EUM_APP_KEY>"];
config.interactionCaptureMode = ADEumInteractionCaptureModeAll;
[ADEumInstrumentation initWithConfiguration:config];

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

ADEumAgentConfiguration *config = [[ADEumAgentConfiguration alloc] initWithAppKey: @"<EUM_APP_KEY>"];
config.interactionCaptureMode = ADEumInteractionCaptureModeButtonPressed;
[ADEumInstrumentation initWithConfiguration:config];

Manually Take Screenshots

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

Objective-C

[ADEumInstrumentation takeScreenshot];

Swift

ADEumInstrumentation.takeScreenshot();

Disable Screenshots

 You can disable screenshots from the Controller UI or with the iOS SDK. To disable screenshots with the iOS SDK, set the property screenshotsEnabled of the ADEumAgentConfiguration object to false as shown here.

Objective-C

ADEumAgentConfiguration *config = [[ADEumAgentConfiguration alloc] initWithAppKey: @"<EUM_APP_KEY>"];
config.screenshotsEnabled = false;
[ADEumInstrumentation initWithConfiguration:config];

Swift

let config = ADEumAgentConfiguration(appKey: "<EUM_APP_KEY>");
config.screenshotsEnabled = true;
ADEumInstrumentation.initWith(config);

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 protocol below. The callback method networkRequestCallback is synchronous, so it is recommended that you return from the function quickly.

- (BOOL)networkRequestCallback:(ADEumHTTPRequestTracker *)networkRequest

 Transforming URLs

The networkRequestCallback 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 ADEumHTTPRequestTracker object. (Modifying other properties of the ADEumHTTPRequestTracker object will be ignored.)
  3. Assign a valid URL to the url property. 
  4. Return YES (Objective-C) or true (Swift).

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

Objective-C

- (BOOL)networkRequestCallback:(ADEumHTTPRequestTracker *)networkRequest
{
    NSString *maskURL = @"http://networkrequest-mask.com";
    NSURL *url = [NSURL URLWithString:maskURL];
    networkRequest.url = url;
    return YES;
} 

Swift

func networkRequestCallback(networkRequest: ADEumHTTPRequestTracker) -> Bool {
    var maskURL = "http://networkrequest-mask.com"
    var url = NSURL(string: maskURL)!
    networkRequest.url = url
    return true
}
In general, however, you would want to identify and transform URLs that contain sensitive information as implied in the example below.

Objective-C

- (BOOL)networkRequestCallback:(ADEumHTTPRequestTracker *)networkRequest
{
    NSString *urlString = networkRequest.url.absoluteString;
    returnBeacon = true;
    NSString *maskURL = @"http://customer-account.com";
    if (!([urlString rangeOfString:@"accountInfo"].location == NSNotFound)) {
        networkRequest.url = [NSURL URLWithString:maskURL];
    }
    return returnBeacon;
}

Swift

func networkRequestCallback(networkRequest: ADEumHTTPRequestTracker) -> Bool {
    var urlString = networkRequest.url.absoluteString
    var returnBeacon = true
    var maskURL = "http://customer-account.com"
    if !((urlString as NSString).rangeOfString("accountInfo").location == NSNotFound) {
        networkRequest.url = NSURL(string: maskURL)!
    }
    return returnBeacon
}

Ignoring URLs

If the networkRequestCallback 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 by having the callback networkRequestCallback always return NO (Objective-C) or false (Swift):

Objective-C

- (BOOL)networkRequestCallback:(ADEumHTTPRequestTracker *)networkRequest
{
    return NO;
}

Swift

 func networkRequestCallback(networkRequest: ADEumHTTPRequestTracker) -> Bool {
    return false
}
In general, though, you would identify network requests that you didn't want to monitor and return NO (Objective-C) or false (Swift) to ignore the network request as implied by this example.

Objective-C

- (BOOL)networkRequestCallback:(ADEumHTTPRequestTracker *)networkRequest
{
    NSString *urlString = networkRequest.url.absoluteString;
    BOOL returnBeacon = YES;
    if (!([urlString rangeOfString:@"avatar"].location == NSNotFound)) {
        returnBeacon = NO;
    }
    return returnBeacon;
}

Swift

 func networkRequestCallback(networkRequest: ADEumHTTPRequestTracker) -> Bool {
    var urlString = networkRequest.url.absoluteString
    var returnBeacon = true
    if !((urlString as NSString).rangeOfString("avatar").location == NSNotFound) {
        returnBeacon = false
    }
    return returnBeacon
}

Register the Callback

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

Objective-C

ADEumAgentConfiguration *config = [[ADEumAgentConfiguration alloc] initWithAppKey: <#EUM_APP_KEY#>];
config.networkRequestCallback = self;
[ADEumInstrumentation initWithConfiguration:config];

Swift

let config = ADEumAgentConfiguration(appKey: <#EUM_APP_KEY#>)
config.networkRequestCallback = self
ADEumInstrumentation.initWith(config)

Enable Logging and Set Logging Level

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

  • ADEumLoggingLevelOff 

  • ADEumLoggingLevelAll 

  • ADEumLoggingLevelVerbose

  • ADEumLoggingLevelDebug 

  • ADEumLoggingLevelInfo 

  • ADEumLoggingLevelWarn 

  • ADEumLoggingLevelError 

Use verbose, all, and debug levels of logging only for troubleshooting and be sure to turn off for production.

Examples:

Objective C:

-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // appKey should be assigned your EUM app key
    ADEumAgentConfiguration *config = [[ADEumAgentConfiguration alloc] initWithAppKey:[Settings appKey]];
    config.loggingLevel = ADEumLoggingLevelAll;
    [ADEumInstrumentation initWithConfiguration:config];
    ...
}

Swift:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
{
    // appKey should be assigned your EUM app key
    let config = ADEumAgentConfiguration(appKey: appKey)
    config.loggingLevel = .all
    ADEumInstrumentation.initWithConfiguration(config)
    ...
    return true
}

iOS SDK Deprecations for 4.3

The following sections list the deprecations for the iOS SDK. 

enum ADEumBreadcrumbVisibility

The following members were deprecated in 4.2 and have been removed from the 4.3 iOS Agent:

  • CrashesOnly
  • CrashesAndSessions

class ADEumAgentConfiguration

The following property has been deprecated:

  • enableLogging

class ADEumInstrumenation

The following methods have been deprecated:

  • +setUserData:value:persist: The ability to persist user data has been deprecated.
  • +initWithKey:enableLogging: (Undocumented)
  • +initWithKey:collectorUrl:enableLogging: (Undocumented)

The last two methods have been deprecated even though they are undocumented because many developers used them for debugging.