macOS Application Integration¶
Guance User Access Monitoring can collect various macOS application Metrics data and analyze the performance of each macOS application endpoint in a visualized manner.
Prerequisites¶
Note
If the RUM Headless service has been activated, the prerequisites have been automatically configured, and you can directly integrate the application.
- Install DataKit;
- Configure RUM Collector
Application Integration¶
- Navigate to User Access Monitoring > Create > macOS;
- Input the application name;
- Input the application ID;
-
Choose the application integration method:
- Public DataWay: Directly receives RUM data without installing the DataKit collector.
- Local Environment Deployment: Receives RUM data after meeting the prerequisites.
Installation¶
Source Code Address: https://github.com/GuanceCloud/datakit-macos
Demo: https://github.com/GuanceCloud/datakit-macos/Example
- Configure the
Podfile
.
- Execute
pod install
in thePodfile
directory to install the SDK.
-
Select
PROJECT
->Package Dependency
, click + under thePackages
section. -
In the search box that appears, input
https://github.com/GuanceCloud/datakit-macos
. This is the repository location for the code. -
After Xcode successfully retrieves the package, it will display the SDK configuration page.
Dependency Rule
: It's recommended to choose Up to Next Major Version
.
Add To Project
: Select the supported project.
After filling out the configurations, click the Add Package
button and wait until loading completes.
- In the pop-up window
Choose Package Products for datakit-macos
, select the Target where the SDK needs to be added, then click theAdd Package
button. At this point, the SDK has been successfully added.
If your project is managed by SPM, add FTMacOSSDK as a dependency by adding dependencies
to Package.swift
.
Add Header Files¶
SDK Initialization¶
Basic Configuration¶
Since the viewDidLoad
method of the first displayed view NSViewController
and the windowDidLoad
method of NSWindowController
are called earlier than the applicationDidFinishLaunching
method of AppDelegate, to avoid abnormal lifecycle collection of the first view, it is recommended to initialize the SDK in the main.m
file.
// main.m file
#import "FTMacOSSDK.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// Local environment deployment, Datakit deployment
FTSDKConfig *config = [[FTSDKConfig alloc]initWithDatakitUrl:datakitUrl];
// Use public DataWay deployment
//FTSDKConfig *config = [[FTSDKConfig alloc]initWithDatawayUrl:datawayUrl clientToken:clientToken];
config.enableSDKDebugLog = YES;
[FTSDKAgent startWithConfigOptions:config];
}
return NSApplicationMain(argc, argv);
}
Create an mian.swift file and remove @main or @NSApplicationMain from AppDelegate.swift.
import Cocoa
import FTMacOSSDK
// Create AppDelegate and set it as delegate
let delegate = AppDelegate()
NSApplication.shared.delegate = delegate
// Initialize SDK
let config = FTSDKConfig.init(datakitUrl: datakitUrl)
// Use public DataWay deployment
//let config = FTSDKConfig(datawayUrl: datawayUrl, clientToken: clientToken)
config.enableSDKDebugLog = true
FTSDKAgent.start(withConfigOptions: config)
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
Property | Type | Required | Meaning |
---|---|---|---|
datakitUrl | NSString | Yes | Datakit access address, example: http://10.0.0.1:9529, default port 9529, the device with installed SDK must be able to access this address. Note: Either datakit or dataway configuration must be chosen |
datawayUrl | NSString | Yes | Public Dataway access address, example: http://10.0.0.1:9528, default port 9528, the device with installed SDK must be able to access this address. Note: Either datakit or dataway configuration must be chosen |
clientToken | NSString | Yes | Authentication token, must be used together with datawayUrl |
enableSDKDebugLog | BOOL | No | Set whether debug logs should be printed. Default NO |
env | NSString | No | Set the collection environment. Default prod , supports customization, can also be set via the provided FTEnv enumeration using -setEnvWithType: method |
service | NSString | No | Set the name of the associated business or service. Affects the service field data in Logs and RUM. Default: df_rum_ios |
globalContext | NSDictionary | No | Add custom tags. Refer to here for rules |
RUM Configuration¶
FTRumConfig *rumConfig = [[FTRumConfig alloc]initWithAppid:appid];
rumConfig.enableTrackAppCrash = YES;
rumConfig.enableTrackAppANR = YES;
rumConfig.enableTrackAppFreeze = YES;
rumConfig.enableTraceUserAction = YES;
rumConfig.enableTraceUserVIew = YES;
rumConfig.enableTraceUserResource = YES;
rumConfig.errorMonitorType = FTErrorMonitorAll;
rumConfig.deviceMetricsMonitorType = FTDeviceMetricsMonitorAll;
[[FTSDKAgent sharedInstance] startRumWithConfigOptions:rumConfig];
let rumConfig = FTRumConfig(appid: appid)
rumConfig.enableTraceUserAction = true
rumConfig.enableTrackAppANR = true
rumConfig.enableTraceUserView = true
rumConfig.enableTraceUserResource = true
rumConfig.enableTrackAppCrash = true
rumConfig.enableTrackAppFreeze = true
rumConfig.errorMonitorType = .all
rumConfig.deviceMetricsMonitorType = .all
rumConfig.monitorFrequency = .rare
FTSDKAgent.sharedInstance().startRum(withConfigOptions: rumConfig)
Property | Type | Required | Meaning |
---|---|---|---|
appid | NSString | Yes | Unique identifier for the User Access Monitoring application ID. Corresponds to setting the RUM appid , enabling RUM collection functionality, get appid method |
sampleRate | int | No | Sampling rate. Range [0,100], 0 means no collection, 100 means full collection, default value is 100. Scope applies to all View, Action, LongTask, Error data under the same session_id |
enableTrackAppCrash | BOOL | No | Set whether crash logs need to be collected. Default NO |
enableTrackAppANR | BOOL | No | Collect ANR unresponsive events. Default NO |
enableTrackAppFreeze | BOOL | No | Collect UI freeze events. Default NO |
enableTraceUserView | BOOL | No | Set whether user View operations need to be tracked. Default NO |
enableTraceUserAction | BOOL | No | Set whether user Action operations need to be tracked. Default NO |
enableTraceUserResource | BOOL | No | Set whether user network requests need to be tracked. DefaultNO , only applicable to native http |
resourceUrlHandler | FTResourceUrlHandler | No | Custom resource collection rules. Default does not filter. Returns: NO indicates to collect, YES indicates not to collect. |
errorMonitorType | FTErrorMonitorType | No | Supplementary error event monitoring types. Adds monitoring information in collected crash data. FTErrorMonitorBattery for battery level, FTErrorMonitorMemory for memory usage, FTErrorMonitorCpu for CPU occupancy. |
monitorFrequency | FTMonitorFrequency | No | Sampling cycle for view performance monitoring |
deviceMetricsMonitorType | FTDeviceMetricsMonitorType | No | View performance monitoring type. Adds corresponding monitoring items in the collected View data. FTDeviceMetricsMonitorMemory monitors current application memory usage, FTDeviceMetricsMonitorCpu monitors CPU jumps, FTDeviceMetricsMonitorFps monitors screen frame rate. |
globalContext | NSDictionary | No | Add custom tags for distinguishing data sources in user monitoring. If tracking functionality is required, parameter key is track_id , value is any number. Refer to here for notes on adding rules. |
Log Configuration¶
// Enable logger
FTLoggerConfig *loggerConfig = [[FTLoggerConfig alloc]init];
loggerConfig.enableCustomLog = YES;
loggerConfig.printCustomLogToConsole = YES;
loggerConfig.enableLinkRumData = YES;
loggerConfig.logLevelFilter = @[@(FTStatusError),@(FTStatusCritical)];
loggerConfig.discardType = FTDiscardOldest;
[[FTSDKAgent sharedInstance] startLoggerWithConfigOptions:loggerConfig];
let loggerConfig = FTLoggerConfig()
loggerConfig.enableCustomLog = true
loggerConfig.enableLinkRumData = true
loggerConfig.printCustomLogToConsole = true
loggerConfig.logLevelFilter = [NSNumber(value: FTLogStatus.statusError.rawValue),NSNumber(value: FTLogStatus.statusCritical.rawValue)] // loggerConfig.logLevelFilter = [2,3]
loggerConfig.discardType = .discardOldest
FTSDKAgent.sharedInstance().startLogger(withConfigOptions: loggerConfig)
Property | Type | Required | Meaning |
---|---|---|---|
sampleRate | int | No | Sampling rate. Range [0,100], 0 means no collection, 100 means full collection, default value is 100. |
enableCustomLog | BOOL | No | Whether to upload custom logs. DefaultNO |
logLevelFilter | NSArray | No | Set the status array of custom logs to be collected. Default collects all |
enableLinkRumData | BOOL | No | Whether to associate with RUM data. DefaultNO |
discardType | FTLogCacheDiscard | No | Set the log discard rule when the limit is reached. Default FTDiscard FTDiscard discards appended data when log data exceeds the maximum (5000). FTDiscardOldest discards old data when log data exceeds the maximum. |
printCustomLogToConsole | BOOL | No | Set whether custom logs should be output to the console. DefaultNO , refer to output format for custom logs |
globalContext | NSDictionary | No | Add custom log tags. Refer to here for rules |
Trace Configuration¶
Property | Type | Required | Meaning |
---|---|---|---|
sampleRate | int | No | Sampling rate. Range [0,100], 0 means no collection, 100 means full collection, default value is 100. |
networkTraceType | NS_ENUM | No | Set the type of link tracing. Default is DDTrace , currently supports Zipkin , Jaeger , DDTrace , Skywalking (8.0+), TraceParent (W3C). If connecting OpenTelemetry and choosing the corresponding link type, please refer to the supported types and agent related configurations |
enableLinkRumData | BOOL | No | Whether to associate with RUM data. DefaultNO |
enableAutoTrace | BOOL | No | Set whether automatic http trace is enabled. DefaultNO , currently only supports NSURLSession |
RUM User Data Tracking¶
You can enable automatic mode through FTRUMConfig
configuration, or manually add it. Rum-related data is passed through the FTGlobalRumManager
singleton. Relevant APIs are as follows:
View¶
If enableTraceUserView = YES
is set to enable automatic collection, the SDK will automatically collect the Window lifecycle. The lifecycle of the window -becomeKeyWindow
defines the View start, and -resignKeyWindow
defines the View end.
Page names are set in the priority order of NSStringFromClass(window.contentViewController.class)
> NSStringFromClass(window.windowController.class)
> NSStringFromClass(window)
.
If the views inside the window are very complex, you can use the following API for custom collection.
Usage Method¶
/// Create a page
///
/// Call before the `-startViewWithName` method. This method records the page loading time. If unable to obtain the load time, this method can be skipped.
/// - Parameters:
/// - viewName: Page name
/// - loadTime: Page load time (nanoseconds)
-(void)onCreateView:(NSString *)viewName loadTime:(NSNumber *)loadTime;
/// Enter the page
/// - Parameters:
/// - viewName: Page name
/// - property: Event custom attributes (optional)
-(void)startViewWithName:(NSString *)viewName property:(nullable NSDictionary *)property;
/// Leave the page
/// - Parameter property: Event custom attributes (optional)
-(void)stopViewWithProperty:(nullable NSDictionary *)property;
/// Create a page
///
/// Call before the `-startViewWithName` method. This method records the page loading time. If unable to obtain the load time, this method can be skipped.
/// - Parameters:
/// - viewName: Page name
/// - loadTime: Page load time (ns)
open func onCreateView(_ viewName: String, loadTime: NSNumber)
/// Enter the page
/// - Parameters:
/// - viewName: Page name
/// - property: Event custom attributes (optional)
open func startView(withName viewName: String, property: [AnyHashable : Any]?)
/// Leave the page
/// - Parameter property: Event custom attributes (optional)
open func stopView(withProperty property: [AnyHashable : Any]?)
Code Example¶
- (void)viewDidAppear{
[super viewDidAppear];
// Scenario 1:
[[FTGlobalRumManager sharedManager] startViewWithName:@"TestVC"];
// Scenario 2: Dynamic parameters
[[FTGlobalRumManager sharedManager] startViewWithName:@"TestVC" property:@{@"custom_key":@"custom_value"}];
}
-(void)viewDidDisappear{
[super viewDidDisappear];
// Scenario 1:
[[FTGlobalRumManager sharedManager] stopView];
// Scenario 2: Dynamic parameters
[[FTGlobalRumManager sharedManager] stopViewWithProperty:@{@"custom_key":@"custom_value"}];
}
override func viewDidAppear() {
super.viewDidAppear()
// Scenario 1:
FTExternalDataManager.shared().startView(withName: "TestVC")
// Scenario 2: Dynamic parameters
FTExternalDataManager.shared().startView(withName: "TestVC",property: ["custom_key":"custom_value"])
}
override func viewDidDisappear() {
super.viewDidDisappear()
// Scenario 1:
FTGlobalRumManager.shared().stopView()
// Scenario 2: Dynamic parameters
FTGlobalRumManager.shared().stopView(withProperty: ["custom_key":"custom_value"])
}
Action¶
Usage Method¶
Code Example¶
Error¶
Usage Method¶
/// Add Error event
/// - Parameters:
/// - type: Error type
/// - message: Error message
/// - stack: Stack trace
/// - property: Event custom attributes (optional)
- (void)addErrorWithType:(NSString *)type message:(NSString *)message stack:(NSString *)stack property:(nullable NSDictionary *)property;
/// Add Error event
/// - Parameters:
/// - type: Error type
/// - state: Program running state
/// - message: Error message
/// - stack: Stack trace
/// - property: Event custom attributes (optional)
- (void)addErrorWithType:(NSString *)type state:(FTAppState)state message:(NSString *)message stack:(NSString *)stack property:(nullable NSDictionary *)property;
/// Add Error event
/// - Parameters:
/// - type: Error type
/// - message: Error message
/// - stack: Stack trace
/// - property: Event custom attributes (optional)
open func addError(withType: String, message: String, stack: String, property: [AnyHashable : Any]?)
/// Add Error event
/// - Parameters:
/// - type: Error type
/// - state: Program running state
/// - message: Error message
/// - stack: Stack trace
/// - property: Event custom attributes (optional)
open func addError(withType type: String, state: FTAppState, message: String, stack: String, property: [AnyHashable : Any]?)
Code Example¶
// Scenario 1
[[FTGlobalRumManager sharedManager] addErrorWithType:@"type" message:@"message" stack:@"stack"];
// Scenario 2: Dynamic parameters
[[FTGlobalRumManager sharedManager] addErrorWithType:@"ios_crash" message:@"crash_message" stack:@"crash_stack" property:@{@"custom_key":@"custom_value"}];
// Scenario 3: Dynamic parameters
[[FTGlobalRumManager sharedManager] addErrorWithType:@"ios_crash" state:FTAppStateUnknown message:@"crash_message" stack:@"crash_stack" property:@{@"custom_key":@"custom_value"}];
// Scenario 1
FTGlobalRumManager.shared().addError(withType: "custom_type", message: "custom_message", stack: "custom_stack")
// Scenario 2: Dynamic parameters
FTGlobalRumManager.shared().addError(withType: "custom_type", message: "custom_message", stack: "custom_stack",property: ["custom_key":"custom_value"])
// Scenario 3: Dynamic parameters
FTGlobalRumManager.shared().addError(withType: "custom_type", state: .unknown, message: "custom_message", stack: "custom_stack", property: ["custom_key":"custom_value"])
LongTask¶
Usage Method¶
Code Example¶
Resource¶
Usage Method¶
/// HTTP request starts
/// - Parameters:
/// - key: Request identifier
/// - property: Event custom attributes (optional)
- (void)startResourceWithKey:(NSString *)key property:(nullable NSDictionary *)property;
/// HTTP adds request data
///
/// - Parameters:
/// - key: Request identifier
/// - metrics: Request related performance attributes
/// - content: Request related data
- (void)addResourceWithKey:(NSString *)key metrics:(nullable FTResourceMetricsModel *)metrics content:(FTResourceContentModel *)content;
/// HTTP request ends
/// - Parameters:
/// - key: Request identifier
/// - property: Event custom attributes (optional)
- (void)stopResourceWithKey:(NSString *)key property:(nullable NSDictionary *)property;
/// HTTP request starts
/// - Parameters:
/// - key: Request identifier
/// - property: Event custom attributes (optional)
open func startResource(withKey key: String, property: [AnyHashable : Any]?)
/// HTTP request ends
/// - Parameters:
/// - key: Request identifier
/// - property: Event custom attributes (optional)
open func stopResource(withKey key: String, property: [AnyHashable : Any]?)
/// HTTP adds request data
///
/// - Parameters:
/// - key: Request identifier
/// - metrics: Request related performance attributes
/// - content: Request related data
open func addResource(withKey key: String, metrics: FTResourceMetricsModel?, content: FTResourceContentModel)
Code Example¶
#import "FTMacOSSDK.h"
// Step 1: Before the request begins
[[FTGlobalRumManager sharedManager] startResourceWithKey:key];
// Step 2: When the request completes
[[FTGlobalRumManager sharedManager] stopResourceWithKey:key];
// Step 3: Concatenate Resource data
//FTResourceContentModel data
FTResourceContentModel *content = [[FTResourceContentModel alloc]init];
content.httpMethod = request.HTTPMethod;
content.requestHeader = request.allHTTPHeaderFields;
content.responseHeader = httpResponse.allHeaderFields;
content.httpStatusCode = httpResponse.statusCode;
content.responseBody = responseBody;
//ios native
content.error = error;
//If stage times can be obtained
//FTResourceMetricsModel
//Obtain NSURLSessionTaskMetrics data directly using FTResourceMetricsModel initialization method
FTResourceMetricsModel *metricsModel = [[FTResourceMetricsModel alloc]initWithTaskMetrics:metrics];
//For other platforms, all time data is in nanoseconds
FTResourceMetricsModel *metricsModel = [[FTResourceMetricsModel alloc]init];
//Step 4: Add resource if there's no time data, pass nil for metrics
[[FTGlobalRumManager sharedManager] addResourceWithKey:key metrics:metricsModel content:content];
import FTMacOSSDK
// Step 1: Before the request begins
FTGlobalRumManager.shared().startResource(withKey: key)
// Step 2: When the request completes
FTGlobalRumManager.shared().stopResource(withKey: resource.key)
// Step 3:① Concatenate Resource data
let contentModel = FTResourceContentModel(request: task.currentRequest!, response: task.response as? HTTPURLResponse, data: resource.data, error: error)
//② If stage times can be obtained
//FTResourceMetricsModel
//Obtain NSURLSessionTaskMetrics data directly using FTResourceMetricsModel initialization method
var metricsModel:FTResourceMetricsModel?
if let metrics = resource.metrics {
metricsModel = FTResourceMetricsModel(taskMetrics:metrics)
}
//For other platforms, all time data is in nanoseconds
metricsModel = FTResourceMetricsModel()
...
//Step 4: Add resource if there's no time data, pass nil for metrics
FTGlobalRumManager.shared().addResource(withKey: resource.key, metrics: metricsModel, content: contentModel)
Logger Log Printing¶
Currently, log content is limited to 30 KB, exceeding characters will be truncated.
Usage Method¶
//
// FTLogger.h
// FTMacOSSDK
/// Add info type custom log
/// - Parameters:
/// - content: Log content
/// - property: Custom attributes (optional)
-(void)info:(NSString *)content property:(nullable NSDictionary *)property;
/// Add warning type custom log
/// - Parameters:
/// - content: Log content
/// - property: Custom attributes (optional)
-(void)warning:(NSString *)content property:(nullable NSDictionary *)property;
/// Add error type custom log
/// - Parameters:
/// - content: Log content
/// - property: Custom attributes (optional)
-(void)error:(NSString *)content property:(nullable NSDictionary *)property;
/// Add critical type custom log
/// - Parameters:
/// - content: Log content
/// - property: Custom attributes (optional)
-(void)critical:(NSString *)content property:(nullable NSDictionary *)property;
/// Add ok type custom log
/// - Parameters:
/// - content: Log content
/// - property: Custom attributes (optional)
-(void)ok:(NSString *)content property:(nullable NSDictionary *)property;
open class FTLogger : NSObject, FTLoggerProtocol {}
public protocol FTLoggerProtocol : NSObjectProtocol {
/// Add info type custom log
/// - Parameters:
/// - content: Log content
/// - property: Custom attributes (optional)
optional func info(_ content: String, property: [AnyHashable : Any]?)
/// Add warning type custom log
/// - Parameters:
/// - content: Log content
/// - property: Custom attributes (optional)
optional func warning(_ content: String, property: [AnyHashable : Any]?)
/// Add error type custom log
/// - Parameters:
/// - content: Log content
/// - property: Custom attributes (optional)
optional func error(_ content: String, property: [AnyHashable : Any]?)
/// Add critical type custom log
/// - Parameters:
/// - content: Log content
/// - property: Custom attributes (optional)
optional func critical(_ content: String, property: [AnyHashable : Any]?)
/// Add ok type custom log
/// - Parameters:
/// - content: Log content
/// - property: Custom attributes (optional)
optional func ok(_ content: String, property: [AnyHashable : Any]?)
}
Log Levels¶
Code Example¶
// Method one: Through FTSDKAgent
// Note: Ensure the SDK is initialized successfully when used, otherwise assertion failure may occur and cause a crash in the test environment.
[[FTSDKAgent sharedInstance] logging:@"test_custom" status:FTStatusInfo];
// Method two: Through FTLogger (recommended)
// If the SDK is not initialized successfully, calling methods in FTLogger to add custom logs will fail but won't cause assertion failure or crashes.
[[FTLogger sharedInstance] info:@"test" property:@{@"custom_key":@"custom_value"}];
// Method one: Through FTSDKAgent
// Note: Ensure the SDK is initialized successfully when used, otherwise assertion failure may occur and cause a crash in the test environment.
FTSDKAgent.sharedInstance().logging("contentStr", status: .statusInfo, property:["custom_key":"custom_value"])
// Method two: Through FTLogger (recommended)
// If the SDK is not initialized successfully, calling methods in FTLogger to add custom logs will fail but won't cause assertion failure or crashes.
FTLogger.shared().info("contentStr", property: ["custom_key":"custom_value"])
Custom Logs Output to Console¶
Set printCustomLogToConsole = YES
to enable custom log output to the console. You will see the following formatted logs in the xcode debugging console:
2023-06-29 13:47:56.960021+0800 App[64731:44595791]
: Standard prefix for os_log log output;
[MACOS APP]
: Prefix to distinguish SDK output custom logs;
[INFO]
: Level of custom logs;
content
: Content of custom logs;
{K=V,...,Kn=Vn}
: Custom attributes.
Trace Network Link Tracing¶
You can enable automatic mode through FTTraceConfig
configuration, or manually add it. Trace-related data is passed through the FTTraceManager
singleton. Relevant APIs are as follows:
Usage Method¶
// FTTraceManager.h
/// Get trace request header parameters
/// - Parameters:
/// - key: Unique identifier that can determine a specific request
/// - url: Request URL
/// - Returns: Dictionary of trace request header parameters
- (NSDictionary *)getTraceHeaderWithKey:(NSString *)key url:(NSURL *)url;
Code Example¶
```objectivec NSString *key = [[NSUUID UUID]UUIDString]; NSURL *url = [NSURL URLWithString:@"http://www.baidu.com"]; //Manual operation needed: Obtain traceHeader before the request and add it to the request header NSDictionary *traceHeader = [[FTTraceManager sharedInstance] getTraceHeaderWithKey:key url:url]; NSMutableURLRequest *request =[previous content continued...]
```objectivec [NSMutableURLRequest requestWithURL:url]; if (traceHeader && traceHeader.allKeys.count>0) { [traceHeader enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) { [request setValue:value forHTTPHeaderField:field]; }]; } NSURLSession *session=[NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { //Your code }];
[task resume];
=== "Swift"
```swift
let url:URL = NSURL.init(string: "https://www.baidu.com")! as URL
if let traceHeader = FTTraceManager.sharedInstance().getTraceHeader(withKey: NSUUID().uuidString, url: url) {
let request = NSMutableURLRequest(url: url)
//Manual operation needed: Obtain traceHeader before the request and add it to the request header
for (a,b) in traceHeader {
request.setValue(b as? String, forHTTPHeaderField: a as! String)
}
let task = URLSession.shared.dataTask(with: request as URLRequest) { data, response, error in
//Your code
}
task.resume()
}
```
## User Binding and Logout
### Usage Method
=== "Objective-C"
```objectivec
/// Bind user information
///
/// - Parameters:
/// - Id: User ID
/// - userName: User name (optional)
/// - userEmail: User email (optional)
/// - extra: Additional user information (optional)
- (void)bindUserWithUserID:(NSString *)Id userName:(nullable NSString *)userName userEmail:(nullable NSString *)userEmail extra:(nullable NSDictionary *)extra;
/// Unbind current user
- (void)unbindUser;
```
=== "Swift"
```swift
/// Bind user information
///
/// - Parameters:
/// - Id: User ID
/// - userName: User name (optional)
/// - userEmail: User email (optional)
/// - extra: Additional user information (optional)
open func bindUser(withUserID Id: String, userName: String?, userEmail: String?, extra: [AnyHashable : Any]?)
/// Unbind current user
open func unbindUser()
```
### Code Example
=== "Objective-C"
```objectivec
// You can call this method after the user logs in successfully to bind user information
[[FTSDKAgent sharedInstance] bindUserWithUserID:USERID];
// or
[[FTSDKAgent sharedInstance] bindUserWithUserID:USERID userName:USERNAME userEmail:USEREMAIL];
// or
[[FTSDKAgent sharedInstance] bindUserWithUserID:USERID userName:USERNAME userEmail:USEREMAIL extra:@{EXTRA_KEY:EXTRA_VALUE}];
// You can call this method after the user logs out to unbind user information
[[FTSDKAgent sharedInstance] unbindUser];
```
=== "Swift"
```swift
// You can call this method after the user logs in successfully to bind user information
FTSDKAgent.sharedInstance().bindUser(withUserID: USERID)
// or
FTSDKAgent.sharedInstance().bindUser(withUserID: USERID, userName: USERNAME, userEmail: USEREMAIL)
// or
FTSDKAgent.sharedInstance().bindUser(withUserID: USERID, userName: USERNAME, userEmail: USEREMAIL,extra:[EXTRA_KEY:EXTRA_VALUE])
// You can call this method after the user logs out to unbind user information
FTSDKAgent.sharedInstance().unbindUser()
```
## Close SDK
Use `FTSDKAgent` to close the SDK.
### Usage Method
=== "Objective-C"
```objective-c
/// Close running objects within the SDK
- (void)shutDown;
```
=== "Swift"
```swift
/// Close running objects within the SDK
func shutDown()
```
### Code Example
=== "Objective-C"
```objective-c
// If dynamically changing SDK configurations, need to close first to avoid incorrect data generation
[[FTSDKAgent sharedInstance] shutDown];
```
=== "Swift"
```swift
// If dynamically changing SDK configurations, need to close first to avoid incorrect data generation
FTSDKAgent.sharedInstance().shutDown()
```
## Add Custom Tags {#user-global-context}
### Static Usage
You can create multiple Configurations and use preprocessor directives to set values:
1. Create multiple Configurations:

2. Set predefined attributes to distinguish different Configurations:

3. Use preprocessor directives:
```objectivec
//Target -> Build Settings -> GCC_PREPROCESSOR_DEFINITIONS configure predefined definitions
#if PRE
#define Track_id @"0000000001"
#define STATIC_TAG @"preprod"
#elif DEVELOP
#define Track_id @"0000000002"
#define STATIC_TAG @"common"
#else
#define Track_id @"0000000003"
#define STATIC_TAG @"prod"
#endif
FTRumConfig *rumConfig = [[FTRumConfig alloc]init];
rumConfig.globalContext = @{@"track_id":Track_id,@"static_tag":STATIC_TAG};
... //Other setting operations
[[FTSDKAgent sharedInstance] startRumWithConfigOptions:rumConfig];
Dynamic Usage¶
Since the globalContext set after RUM starts won't take effect, users can save locally and set during the next app launch.
- Save files locally, such as using
NSUserDefaults
, configure and add code to get tag data when configuring theSDK
.
NSString *dynamicTag = [[NSUserDefaults standardUserDefaults] valueForKey:@"DYNAMIC_TAG"]?:@"NO_VALUE";
FTRumConfig *rumConfig = [[FTRumConfig alloc]init];
rumConfig.globalContext = @{@"dynamic_tag":dynamicTag};
... //Other setting operations
[[FTSDKAgent sharedInstance] startRumWithConfigOptions:rumConfig];
- Add methods to change file data at any location.
- Finally, restart the application for changes to take effect.
Notes¶
-
Special key: track_id (configured in RUM, used for tracking functionality)
-
When users add custom tags via globalContext that overlap with SDK-owned tags, SDK tags will override user settings. It's recommended to prefix tag names with project abbreviations, such as
df_tag_name
. -
Set globalContext before calling -startRumWithConfigOptions to make it effective.
-
Custom tags configured in
FTSDKConfig
will be added to all types of data.
For more detailed information, refer to the SDK Demo.
Frequently Asked Questions¶
About Crash Log Analysis¶
Non-modular Header Included Inside Framework Module Error Appears¶
Because the SDK's .h files include dependent library .h files, you need to set
Target
-> Build Settings
-> CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES
to YES.