Custom instrumentation of the Tealeaf iOS SDK
Customer instrumentation involves many events, including error, exception, location and custom events. Each event type has a method for instrumenting the SDK.
sharedInstance
Returns the shared instance of TLFCustomEvent
. You should use this instance when logging custom events.
+ (TLFCustomEvent *)sharedInstance
Returns a shared instance of TLFCustomEvent
Declared in TLFCustomEvent.h
Error events
Logs an error as described in an NSError
instance.
logNSErrorEvent:message:[file:line:level:]
Logs an error as described in an NSError
instance.
- (BOOL)logNSErrorEvent:(NSError _)error message:(NSString _)message [file:(const] char *)file line:(unsigned int)line level:(kTLFMonitoringLevelType)level;
- (BOOL)logNSErrorEvent:(NSError _)error message:(NSString _)message level:(kTLFMonitoringLevelType)level;
Parameter | Description |
---|---|
error | The NSError returned by the SDK or your own method. |
message | An associated message for your own. |
filename | The original file where the error occurred. The source code file name, usually from the FILE preprocessor macro (optional). |
line | The source code line number, usually from the LINE preprocessor macro (optional). |
level | The monitoring level of the event. The minimum logging level at which this error is logged. |
return | Whether the event was successfully logged or not. |
Declared in TLFCustomEvent.h
. kTLFMonitoringLevelType
is declared in TLFPublicDefinitions.h
This example shows the expected JSON:
{
"exception": {
"unhandled": false,
"data": {
"message": "Custom Message"
},
"name": "(null)",
"stackTrace": "",
"description": "An Error Occured,"
},
"fromWeb": false,
"count": 4,
"screenviewOffset": 23,
"offset": 39,
"type": 6,
"line": 1,
"fileName": "/path/to/file/AppDelegate.m"
}
Exception events
Use this method to log exceptions.
logNSExceptionEvent
Requests that the framework logs an exception trapped by your own exception handler. These methods do not use the Cocoa SDK, which is not exception-safe. Sets the Unhandled flag to false.
This example shows how to call the method:
- (BOOL)logNSExceptionEvent:(NSException *)exception;
- (BOOL)logNSExceptionEvent:(NSException *)exception
dataDictionary:(NSDictionary *)dataDictionary;
- (BOOL)logNSExceptionEvent:(NSException *)exception
dataDictionary:(NSDictionary *)dataDictionary
isUnhandled:(BOOL)unhandled;
Parameter | Description |
---|---|
exception | The caught NSexception instance. This value is whether the event was successfully logged. Values are true or false . |
dataDictionary | This value is additional data about the exception. |
unhandled | Indicates whether the exception was caught by an exception handler. |
Logging exceptions in Swift
NSException
codes are not supported for logging exceptions in Swift. Use the following code snippet to log exceptions in Swift.
enum MyError: ErrorType {
case RuntimeError(String)
case OutofIndex(String)
}
func throwError(message: String) throws {
throw MyError.RuntimeError(message)
}
func throwException(message: String) throws {
let info: [Int: String] = [1: "any"]
let exceptionInfo: [String: NSException] = [
"ExceptionObject": NSException(
name:
"TheException", reason: "WantToThrowNSException", userInfo: info)
]
throw NSError(domain: "exception", code: 10, userInfo: exceptionInfo)
}
@IBAction func generateUnhandledException(sender: UIButton) {
/* catching NSError with embedded NSException */
do {
try throwException("exceptionexception")
} catch let err as NSError {
let ex = err.userInfo["ExceptionObject"] as! NSException
TLFCustomEvent.sharedInstance().logNSExceptionEvent(
ex, dataDictionary: info,
isUnhandled:
true)
TLFCustomEvent.sharedInstance().logNSErrorEvent(
err, message: "error",
level:
kTLFMonitoringLevelType.TLFMonitoringLevel1)
} catch let ex as NSException {
TLFCustomEvent.sharedInstance().logNSExceptionEvent(
ex, dataDictionary: info,
isUnhandled:
true)
} catch {
print("unhandled")
}
}
Kill Switch events
Set device ID
[[TLFApplicationHelper sharedInstance] setDeviceId:@"CustomID"];
- (BOOL)setDeviceId:(NSString*)value;
This sets the Device ID.
Parameter | Description |
---|---|
@param | The string that represents the new Device ID. |
@return | Indicates whether the Device ID was set. |
Get string representation of device ID
[[TLFApplicationHelper sharedInstance] getDeviceId];
- (NSString*)getDeviceId;
This returns a string representation of the Device ID.
Parameter | Descripiton |
---|---|
@return | A string representation of the Device ID. |
Geolocation
Use this method to have the framework log a geographic location at a specific point in your application.
Requests that the framework logs a geographic location. This is an example of how to use this API:
CLLocationDegrees myLatitude=37.7888024;
CLLocationDegrees myLongitude=-122.40031809;
CLLocation *myLocation = [[CLLocation alloc] initWithLatitude:myLatitude longitude:myLongitude];
[[TLFCustomEvent sharedInstance] logLocation:myLocation];
Parameter | Description |
---|---|
location | A CLLocation Object containing a location of interest. |
GPS location events
To avoid making unnecessary location updates, and to protect the privacy of your application's users by ensuring that location is reported only when the application has some other reason to request it, location events are not logged automatically. To log location updates, you use logLocationUpdateEventWithLatitude.
logLocationUpdateEventWithLatitude:longitude:level
This method is meant to be called inside your handler for locationManager:didUpdateToLocation:fromLocation:
. Your application must include the Core Location framework (CoreLocation.framework
).
#import "CoreLocation/CoreLocation.h"
#import "TLFCustomEvent.h"
...
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
CLLocationCoordinate2D c = newLocation.coordinate;
... [[TLFCustomEvent sharedInstance]
logLocationUpdateEventWithLatitude:c.latitude
longitude:longitude];
}
- (void)logLocationUpdateEventWithLatitude:(double)latitude
longitude:(double)longitude
level:(kTLFMonitoringLevelType)level
Parameter | Description |
---|---|
latitude | The latitude to log. |
longitude | The longitude to log. |
level | The minimum logging level for locations. |
Declared in TLFCustomEvent.h
. kTLFMonitoringLevelType
is declared in TLFPublicDefinitions.h
.
Custom events
You can log a specified event with or without also logging an associated value or dictionary.
logEvent:values:level
Logs a named event and associated dictionary. The dictionary is converted to its JSON representation.
Note:
To be convertible to a JSON representation, the values of the dictionary must be
NSDictionary
,NSArray
,NSString
,NSNumber
orSNull
objects.
- (void)logEvent:(NSString _)eventName values:(NSDictionary _)values;
- (void)logEvent:(NSString _)eventName
values:(NSDictionary _)values
level:(kTLFMonitoringLevelType)level;
Parameter | Description |
---|---|
eventName | The name of the event. Must not contain equal signs or square brackets. |
values | More data items that are associated with the event. |
level | The minimum logging level for this event logged (optional, default is 1). |
Declared in TLFCustomEvent.h
. kTLFMonitoringLevelType
is declared in TLFPublicDefinitions.h
.
Log screen layout for iOS mobile app session replay
You can replay a mobile app session in cxImpact Browser Based Replay as you would an HTML web session instead of viewing the mobile app session as a series of screen captures.
The screen layouts of the native mobile app sessions are captured in Tealeaf JSON format. The screen layouts are then sent back to replay server. The replay server uses a template engine, which interprets the JSON into HTML format. You can then replay the screen lay out from the native mobile app session as HTML pages in cxImpact Browser Based Replay.
There are several advantages to using JSON data to replay mobile app session over screen captures.
- Reduce bandwidth. Screen captures for each screenview generate relatively large image data. It not only consumes large amounts of wireless and cellular bandwidth, but it also consumes more memory inside the device. It also impacts the app performance.
- Mask sensitive information. You cannot mask sensitive information in a screen capture. When using JSON data to replay mobile app sessions, you can mask
EditTexts
by addingView IDs
to theMaskIdList
attribute in TealeafBasicConfig.properties. - Draw user interactions (UI events) onto the HTML pages that are created from the JSON data.
Replay logging can be automatic, manual, or a combination of the two. To enable automatic layout logging find LogViewLayoutOnScreenTransition
in TealeafBasicConfig and set it to YES
. This will automatically log a view controller when the view controller's viewDidAppear:(BOOL)animated
method is called.
Note:
If the
viewController
overrode theviewDidAppear
,method[super viewDidAppear:animated]
must be called.
Correct
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// Custom code
}
Incorrect
- (void)viewDidAppear:(BOOL)animated {
// Custom code
}
Several methods are included for manual logging of screen layout.
The following is the most basic manual logging method. The following method logs the layout of the viewController passed into it.
- (BOOL)logScreenLayoutWithViewController:(UIViewController *)viewController
The following method performs the same action as the first method, but you can pass in a specific name for the screen layout that is logged. This is helpful when you log a view controller that can perform several different functions.
- (BOOL)logScreenLayoutWithViewController:(UIViewController *)viewController
andName:(NSString *)name
The following method performs the same action as the first method, but after the specified delay. This is helpful for logging after certain events, such as reloading the data in a table. The delay is measured in seconds.
- (BOOL)logScreenLayoutWithViewController:(UIViewController *)viewController
andDelay:(CGFloat)delay;
The following method performs the same function as the previous method, but it allows you to pass in a name for the layout.
- (BOOL)logScreenLayoutWithViewController:(UIViewController *)viewController
andDelay:(CGFloat)delay
andName:(NSString *)name
In addition to logging the main view controller passed in, this method allows you to pass in an array of other views to be logged at the same time. This is useful in instances where there are elements on screen that are not part of the same view hierarchy, such as an overlay attached directly to the application's window or an alert view.
- (BOOL)logScreenLayoutWithViewController:(UIViewController *)viewController
andRelatedViews:(NSArray *)views
The following method performs the same action as the previous method, but it allows you to pass in a name for the layout.
- (BOOL)logScreenLayoutWithViewController:(UIViewController *)viewController
andRelatedViews:(NSArray *)views
andName:(NSString *)name
Where and when to call manual logging
With automatic logging enabled, view controllers are logged during the viewDidAppear stage of the view lifecycle. If the view that is logged is loading remote data, this is not adequate. In this case, the ideal time to call the logging method is when the remote data is done loading and displaying.
- (void)RESTRequestCompleted:(RESTRequest *)request
responseData:(NSDictionary *)responseData
response:(NSHTTPURLResponse *)response {
[self updateUI:[responseData objectForKey:[self productKeyKey]]];
[self hideActivityIndicator];
[[TLFCustomEvent sharedInstance] logScreenLayoutWithViewController:self];
}
In some cases, you need to delay triggering logging to give time for UI animations to complete or a UITableView reloadData call to complete. The Custom Event provides a method to accomplish this.
- (void)RESTRequestCompleted:(RESTRequest *)request
responseData:(NSDictionary *)responseData
response:(NSHTTPURLResponse *)response {
items = [responseData objectForKey:[self itemsKey]];
[self.itemsTable reloadData];
[self hideActivityIndicator];
[[TLFCustomEvent sharedInstance] logScreenLayoutWithViewController:self
andDelay:0.1];
}
After certain UIEvents, it may be beneficial to trigger logging, such as upon selection of an item on table view that stretches beyond one screen.
- (NSIndexPath *)tableView:(UITableView *)tableView
willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[[TLFCustomEvent sharedInstance] logScreenLayoutWithViewController:self];
return indexPath;
}
A manual logging call is required to capture an alert view.
- (IBAction)btnSubmitFormClick:(id)sender {
UIAlertView *alert =
[[UIAlertView alloc] initWithTitle:@"Thank You!"
message:@"We will be in touch with you soon."
delegate:self
cancelButtonTitle:@"Ok"
otherButtonTitles:nil];
[alert show];
[[TLFCustomEvent sharedInstance]
logScreenLayoutWithViewController:self
andRelatedViews:@[ alert ]];
}
You should also log the screen layout after the alert dialog is dismissed.
- (void)alertView:(UIAlertView *)alertView
clickedButtonAtIndex:(NSInteger)buttonIndex {
[[TLFCustomEvent sharedInstance] logScreenLayoutWithViewController:self];
}
Tealeaf screen layout logging only logs the views and controls that are on screen when the logging call is made. When UITableView
contains more rows than can be view on a screen at once, call the screen layout logging when an item is selected. This ensures that the event matches the row selected. Use the following code in your UITableViewDelegate
to make this change.
- (NSIndexPath *)tableView:(UITableView *)tableView
willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[[TLFCustomEvent sharedInstance] logScreenLayoutWithViewController:self];
return indexPath;
}
Disabling auto-instrumentation to include advanced custom instrumentation
By default, the iOS SDK automatically instruments your application by using a template of selected items that are based on the configured logging level.
As needed, you can configure the iOS SDK for custom instrumentation. A predefined set of events and objects are instrumented in the application, and the rest can be instrumented through custom methods.
Note:
Before you begin, complete the initial configuration tasks that are associated with instrumentation.
- Optionally, you can disable auto-instrumentation and use manual instrumentation.
- In your implementation file, import
TLFCustomEvent.h
. - You can use any of the available custom instrumentation APIs to meet your application requirements.
Manual instrumentation
You turn off the auto-instrumentation feature in the TealeafBasicConfig.plist file. When you do so, no method swizzling occurs, the application state is not monitored, and screen changes or any other events are not automatically tracked.
To disable auto-instrumentation, in the TealeafBasicConfig.plist file, which is in the TLFResources.bundle, set DisableAutoInstrumentation
flag to YES
.
Note:
Disabling auto-instrumentation is not recommended because of the large configuration effort, high chance of errors, and possibility of incomplete coverage. If you choose to disable auto-instrumentation, you are responsible for implementing theses changes.
Required actions
When you use the iOS SDK with auto-instrumentation turned OFF
, you must configure a set of actions to occur that auto-instrumentation would otherwise do. The list of required actions follows.
- View Controller changes must be logged by using the API
logAppContext
from theTLFCustomEvent
class. - HTTP Connection updates must be logged by using the API
logConnection
from theTLFCustomEvent
class. There are threelogConnection
APIs: one each for initialization, successful response, and failure. - Button click events must be logged by using API
logClickEvent
from theTLFCustomEvent
. UITableViewCell
tap events must be logged by using the APIlogValueChangeEvent
from theTLFCustomEvent
class.- Text change events for
UITextField
,UITextView
, andUILabel
must be logged by using the APIlogTextChangeEvent
from theTLFCustomEvent
class. - To sessionize all
NSURLMutableRequest
objects, you use the APIsessionizeRequest
from theTLFApplicationHelper
class. - To track all requests that are made by
UIWebView
from theUIWebViewDelegate
shouldStartLoadWithRequest
, you use the APIisTealeafHybridBridgeRequest
from theTLFApplicationHelper
class. - To inject the Acoustic Tealeaf hybrid bridge into the JavaScript for all web page loads from
UIWebViewDelegate
webViewDidFinishLoad
, you use the APIInjectTealeafHybridBridgeOnWebViewDidFinishLoad
from theTLFApplicationHelper
class.
TLFCustomEvent class
Use the following information to manually track various events with the TLFCustomEvent
class.
- (BOOL)logAppContext:(NSString_)logicalPageName
applicationContext:(NSString_)applicationContext
referrer:(NSString\*)referrer
A custom event which in conjunction can have a dictionary of keys and values.
- (BOOL)logEvent:(NSString_)eventName values:(NSDictionary_)values;
Use this API to log failures that occur when a connection is attempted; typically from NSURLConnectionDelegate
didFailWithError
or when sendSynchronousRequest
returns an error. The first parameter is the connection object, and the second parameter is the error that you received.
- (BOOL)logConnection:(NSURLConnection_)connection error:(NSError_)error
Use this API to log successful connections; typically from NSURLConnectionDelegate
didReceiveResponse
or when sendSynchronousRequest
returns success. The first parameter is the connection object. The second parameter is the response that you received, and the third is the connection's response type in milliseconds.
- (BOOL)logConnection:(NSURLConnection_)connection
response:(NSURLResponse_)response
responseTimeInMilliseconds:(long long)responseTime;
Use this API to log connection initialization; typically before or after a NSURLConnection
initWithRequest
call. The first parameter is connection object, and the second parameter is the request object.
- (BOOL)logConnection:(NSURLConnection_)connection
request:(NSURLRequest_)request;
Use this API to log failures that occur when a connection is attempted; typically from NSURLConnectionDelegate
didFailWithError
or when sendSynchronousRequest
returns an error. The first parameter is the connection object, and the second parameter is the error that you received.
- (BOOL)logNSURLSession:(NSObject_)urlSession error:(NSError_)error;
Use this API to log successful connections; typically from NSURLConnectionDelegate
didReceiveResponse
or when sendSynchronousRequest
returns success. The first parameter is the connection object. The second parameter is the response that you received, and the third is the connection's response type in milliseconds.
- (BOOL)logNSURLSession:(NSObject_)urlSession
response:(NSURLResponse_)response
responseTimeInMilliseconds:(long long)responseTime;
Use this API to log connection initialization; typically before or after a call NSURLConnection
initWithRequest
. The first parameter is connection object, and the second parameter is the request object.
- (BOOL)logNSURLSession:(NSObject_)urlSession request:(NSURLRequest_)request;
Use this API to log button click events. Call this from your button click event handlers. The first parameter view is the UIButton
object on which the click event happened. The second parameter is optional, and is for future use. You can pass Nil
for now.
- (BOOL)logClickEvent:(UIView_)view data:(NSDictionary_)data;
Use this API to log UITableViewCell
tap events. Call this from your UITableViewDelegate
didSelectRowAtIndexPath
. The first parameter view is the UITableViewCell
object on which the tap event happened The second parameter is optional, and is for future use. You can pass Nil
for now.
- (BOOL)logValueChangeEvent:(UIView_)view data:(NSDictionary_)data;
Use this API to log text change events for UITextField
, UITextView
, and UILabel
. Call this from your application wherever contents of these three controls changed. If you add the UITextViewTextDidEndEditingNotification
observer, you can call it from there. The first parameter view is the object of any of UITextField
, UITextView
, and UILabel
whose text was edited. The second parameter is optional, and is for future use. You can passNil
for now.
- (BOOL)logTextChangeEvent:(UIView_)view data:(NSDictionary_)data;
Use this API to indicate form completion on view.
- (BOOL)logFormCompletion:(BOOL)submitted;
Use this API to log the image as passed in, inside a new type 10 layout message. During replay, the image is displayed under Dynamic Update
or as a screenview when the API is called. If the API is called when the screen has already transitioned, the image is shown as Dynamic Update
in the replay navlist in Tealeaf SaaS and Tealeaf OnPrem version 10.x. In Tealeaf OnPrem (prior to 10.x) or if the screen has not transitioned, the image displays as a new screenview.
The API returns true
if image is successfully logged; else returns false
. If image is nil, API returns false
.
- All APIs are blocking calls. They are all optional and can be called based on your application's design and state machine.
- All the APIs return
YES
if data is logged, andNO
in case of failure. The console debug log shows the reason for failure.
- (BOOL)logScreenLayoutWithImage:(UIImage \*)image;
TLFApplicationHelper class
- (BOOL)sessionizeRequest:(NSMutableURLRequest*)request;
Use this API so that the Acoustic Tealeaf iOS SDK can add various Headers and Cookies that can be used to tie all the application session hits together on the server. Call this API as soon as you create the NSMutableURLRequest
object, and before you start the HTTP connection. The first parameter is the object of NSMutableURLRequest
that the Acoustic Tealeaf SDK updates.
- (BOOL)isTealeafHybridBridgeRequest:(NSURLRequest_)request
webView:(UIWebView_)webView;
Start this API from UIWebViewDelegate
shouldStartLoadWithRequest
. The first parameter is object of NSURLRequest
, and the second is object of the current UIWebView
. The API determines whether the request is specific to and meant for the Acoustic Tealeaf iOS SDK from the Acoustic Tealeaf JavaScript SDK. If it is, the API consumes the data that is sent by the Acoustic Tealeaf JavaScript SDK. If not, handle the request inside your shouldStartLoadWithRequest
. For example, if this API returns YES
, ignore the request and return NO
from shouldStartLoadWithRequest
. It was not an actual page navigation request from your HTML or JavaScript. If this API returns NO
, handle the request as it came from your own HTML page or JavaScript.
- (BOOL)InjectTealeafHybridBridgeOnWebViewDidFinishLoad:(UIWebView *)webView;
Use this API to inject Acoustic Tealeaf specific JavaScript into your web page. The JavaScript injection helps transfer data from the Acoustic Tealeaf JavaScript UI Capture SDK to the Acoustic Tealeaf Native iOS SDK. The first parameter is the object of UIWebView
in which the current web page is loaded. Call it every time a new page is loaded into the UIWebView
. Place it in UIWebViewDelegate
webViewDidFinishLoad
.
Base instrumentation
The objects and events to populate the following sections are automatically instrumented, even if you enable custom instrumentation.
Environmental Data: This data set is automatically captured during initialization.
Note:
User Actions and Behaviors are not captured when auto-instrumentation is disabled. These events must be manually instrumented.
Custom instrumentation APIs
The iOS SDK logs many events automatically, but you can also use it to log errors, exceptions, and custom events.
To log custom events, you can use the TLFCustomEvent
class. This singleton class offers different methods to log custom events.
For convenience, Acoustic Tealeaf provides standard events for location tracking and wireless carrier recording.
Example
[[TLFCustomEvent sharedInstance] logEvent:@"PurchaseConfirmed"];
API - log event
You use the logEvent API to log a simple custom event quickly.
[[TLFCustomEvent sharedInstance] logEvent:@"EventName1"];
- (void)logEvent:(NSString*)eventName;
API - log event and dictionary of values
You use the logEvent API to log a custom event and a dictionary of values that are related to that event.
[[TLFCustomEvent sharedInstance] logEvent:@"EventName3" values:dictionary];
- (void)logEvent:(NSString_)eventName values:(NSDictionary_)values;
API - log event, dictionary of values, and set monitoring level
You use the logEvent API to log a custom event, a dictionary of values, and set a specific TLFMonitoringLevel.
[[TLFCustomEvent sharedInstance] logEvent:@"EventName6" values:
dictionary level:2];
- (void)logEvent:(NSString_)eventName
values:(NSDictionary_)values
level:(kTLFMonitoringLevelType)level;
Updated about 2 months ago