Skip to content

macOS Application Integration


Guance application monitoring collects metric data from various macOS applications and visualizes the performance of each macOS application end.

Prerequisites

Note

If RUM Headless service is already activated, the prerequisites have been automatically configured. You can directly integrate your application.

Application Integration

  1. Navigate to User Analysis > Create New Application > macOS;
  2. Enter the application name;
  3. Enter the application ID;
  4. Choose the application integration method:

    • Public DataWay: Directly receive RUM data without installing the DataKit collector.
    • Local environment deployment: Receive RUM data after fulfilling the prerequisites.

Installation

Source Code Repository: https://github.com/GuanceCloud/datakit-macos

Demo: https://github.com/GuanceCloud/datakit-macos/Example

  1. Configure Podfile.
   target 'yourProjectName' do

   # Pods for your project
   pod 'FTMacOSSDK', '~>[latest_version]'

   end
  1. Execute pod install in the directory where Podfile resides to install the SDK.
  1. Select PROJECT -> Package Dependency, click on the + under the Packages section.

  2. In the search box on the popped-up page, enter https://github.com/GuanceCloud/datakit-macos, which is the storage location of the code.

  3. After Xcode successfully fetches the package, it will display the SDK configuration page.

Dependency Rule: It is recommended to select Up to Next Major Version.

Add To Project: Select the projects that need support.

Fill in the configuration and click the Add Package button, wait for it to finish loading.

  1. In the pop-up window Choose Package Products for datakit-macos, select the Target to which you want to add the SDK, click the Add Package button. At this point, the SDK has been successfully added.

If your project is managed by SPM, add FTMacOSSDK as a dependency and add dependencies to Package.swift.

  dependencies: [
    .package(url: "https://github.com/GuanceCloud/datakit-macos.git", .upToNextMajor(from: "[latest_version]"))
]

Adding Header Files

#import "FTMacOSSDK.h"
import FTMacOSSDK

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 AppDelegate's applicationDidFinishLaunching, to avoid abnormal collection of the first view's lifecycle, 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];
        // Using public DataWay deployment
        //FTSDKConfig *config = [[FTSDKConfig alloc]initWithDatawayUrl:datawayUrl clientToken:clientToken];
        config.enableSDKDebugLog = YES;
        [FTSDKAgent startWithConfigOptions:config];
    }
    return NSApplicationMain(argc, argv);
}

Create a main.swift file, delete @main or @NSApplicationMain in AppDelegate.swift

import Cocoa
import FTMacOSSDK
// Create AppDelegate and set it as the delegate
let delegate = AppDelegate()
NSApplication.shared.delegate = delegate
// Initialize SDK 
let config = FTSDKConfig.init(datakitUrl: datakitUrl)
// Using 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 Description
datakitUrl NSString Yes Datakit access address, example: http://10.0.0.1:9529, default port 9529, devices installing SDK must be able to access this address. Note: choose one between datakit and dataway configurations
datawayUrl NSString Yes Public Dataway access address, example: http://10.0.0.1:9528, default port 9528, devices installing SDK must be able to access this address. Note: choose one between datakit and dataway configurations
clientToken NSString Yes Authentication token, must be used with datawayUrl
enableSDKDebugLog BOOL No Set whether to allow logging. Default NO
env NSString No Set the collection environment. Default prod, supports customization, or can be set via -setEnvWithType: method using the provided FTEnv enumeration
service NSString No Set the name of the business or service. Affects Log and RUM service field data. Default: df_rum_ios
globalContext NSDictionary No Add custom tags. For adding rules, please refer to here

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 Description
appid NSString Yes Unique identifier for the User Analysis application ID. Corresponding to setting RUM appid, will enable RUM data collection function, how to get appid
sampleRate int No Sampling rate. Range [0,100], 0 means no collection, 100 means full collection, default value is 100. Scope includes all View, Action, LongTask, Error data under the same session_id
enableTrackAppCrash BOOL No Set whether to collect crash logs. Default NO
enableTrackAppANR BOOL No Collect ANR lagging unresponsive events. Default NO
enableTrackAppFreeze BOOL No Collect UI freezing events. Default NO
enableTraceUserView BOOL No Set whether to track user View operations. Default NO
enableTraceUserAction BOOL No Set whether to track user Action operations. Default NO
enableTraceUserResource BOOL No Set whether to track user network requests. Default NO, only applies to native http
resourceUrlHandler FTResourceUrlHandler No Custom resource collection rules. By default, no filtering. Return: NO means collect, YES means do not collect.
errorMonitorType FTErrorMonitorType No Additional error event monitoring types. Add monitoring information to collected crash data. FTErrorMonitorBattery indicates battery level, FTErrorMonitorMemory indicates memory usage, FTErrorMonitorCpu indicates CPU usage, default is none.
monitorFrequency FTMonitorFrequency No Performance monitoring sampling interval for views
deviceMetricsMonitorType FTDeviceMetricsMonitorType No Performance monitoring type for views. Adds corresponding monitoring item information to collected View data. FTDeviceMetricsMonitorMemory monitors current application memory usage, FTDeviceMetricsMonitorCpu monitors CPU spike count, FTDeviceMetricsMonitorFps monitors screen frame rate, default is none.
globalContext NSDictionary No Add custom tags to distinguish sources of user monitoring data. If tracking functionality is needed, parameter key should be track_id, value can be any value. For adding rules, please refer to here

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 Description
sampleRate int No Sampling rate. Range [0,100], 0 means no collection, 100 means full collection, default is 100.
enableCustomLog BOOL No Whether to upload custom log. Default NO
logLevelFilter NSArray No Set status array of custom logs to collect. Default is all collected
enableLinkRumData BOOL No Whether to link with RUM data. Default NO
discardType FTLogCacheDiscard No Set log discard rule when limit is exceeded. Default FTDiscard
When log data exceeds maximum (5000), discard appended data. FTDiscardOldest when log data exceeds maximum, discard old data.
printCustomLogToConsole BOOL No Whether to output custom logs to console. Default NO. Output format of custom logs here
globalContext NSDictionary No Add custom log tags. For adding rules, please refer to here

Trace Configuration

   FTTraceConfig *traceConfig = [[FTTraceConfig alloc]init];
   traceConfig.enableLinkRumData = YES;
     traceConfig.enableAutoTrace = YES;
   traceConfig.networkTraceType = FTNetworkTraceTypeDDtrace;
   [[FTSDKAgent sharedInstance] startTraceWithConfigOptions:traceConfig];
   let traceConfig = FTTraceConfig.init()
   traceConfig.enableLinkRumData = true
   traceConfig.enableAutoTrace = true
   FTSDKAgent.sharedInstance().startTrace(withConfigOptions: traceConfig)
Property Type Required Description
sampleRate int No Sampling rate. Range [0,100], 0 means no collection, 100 means full collection, default is 100.
networkTraceType NS_ENUM No Set the type of distributed tracing. Default is DDTrace, currently supports Zipkin, Jaeger, DDTrace, Skywalking (8.0+), TraceParent (W3C). When integrating OpenTelemetry, please check supported types and agent related configurations
enableLinkRumData BOOL No Whether to link with RUM data. Default NO
enableAutoTrace BOOL No Set whether to enable automatic HTTP tracing. Default NO, currently only supports NSURLSession

RUM User Data Tracking

You can configure auto mode via FTRUMConfig, or manually add. RUM-related data is passed through the FTGlobalRumManager singleton instance. Relevant APIs are as follows:

View

If enableTraceUserView = YES is set to enable auto-collection, the SDK will automatically collect Window lifecycles. The start of a View is defined by the Window lifecycle method -becomeKeyWindow, and the end is defined by -resignKeyWindow.

The page name is set based on priority order: NSStringFromClass(window.contentViewController.class) > NSStringFromClass(window.windowController.class) > NSStringFromClass(window).

If the view within the window is very complex, you can use the following API to customize collection.

Usage

/// Create Page
///
/// Call before `-startViewWithName` method. This method records page load time. If load time cannot be obtained, this method can be omitted.
/// - Parameters:
///  - viewName: Page name
///  - loadTime: Page load time (nanoseconds)
-(void)onCreateView:(NSString *)viewName loadTime:(NSNumber *)loadTime;

/// Enter Page
/// - Parameters:
///  - viewName: Page name
///  - property: Event custom properties (optional)
-(void)startViewWithName:(NSString *)viewName property:(nullable NSDictionary *)property;

/// Leave Page
/// - Parameter property: Event custom properties (optional)
-(void)stopViewWithProperty:(nullable NSDictionary *)property;
/// Create Page
///
/// Call before `-startViewWithName` method. This method records page load time. If load time cannot be obtained, this method can be omitted.
/// - Parameters:
///  - viewName: Page name
///  - loadTime: Page load time (ns)
open func onCreateView(_ viewName: String, loadTime: NSNumber)

/// Enter Page
/// - Parameters:
///  - viewName: Page name
///  - property: Event custom properties (optional)
open func startView(withName viewName: String, property: [AnyHashable : Any]?)

/// Leave Page
/// - Parameter property: Event custom properties (optional)
open func stopView(withProperty property: [AnyHashable : Any]?)

Example Code

- (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

/// Add Action Event
/// - Parameters:
///   - actionName: Event Name
///   - actionType: Event Type
///   - property: Event Custom Properties (Optional)
- (void)addActionName:(NSString *)actionName actionType:(NSString *)actionType property:(nullable NSDictionary *)property;
/// Add Action Event
/// - Parameters:
///   - actionName: Event Name
///   - actionType: Event Type
///   - property: Event Custom Properties (Optional)
func addActionName(String, actionType: String, property: [AnyHashable : Any]?)

Example Code

// Scenario 1
[[FTGlobalRumManager sharedManager] addActionName:@"UITableViewCell click" actionType:@"click"];
// Scenario 2: Dynamic parameters
[[FTGlobalRumManager sharedManager]  addActionName:@"UITableViewCell click" actionType:@"click" property:@{@"custom_key":@"custom_value"}];
// Scenario 1
FTGlobalRumManager.shared().addActionName("custom_action", actionType: "click")
// Scenario 2: Dynamic parameters
FTGlobalRumManager.shared().addActionName("custom_action", actionType: "click",property: ["custom_key":"custom_value"])

Error

Usage

/// 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 runtime 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 runtime 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]?)

Example Code

// 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

/// Add Stalling Event
/// - Parameters:
///   - stack: Stall stack
///   - duration: Duration of stall (in nanoseconds)
///   - property: Event custom attributes (optional)
- (void)addLongTaskWithStack:(NSString *)stack duration:(NSNumber *)duration property:(nullable NSDictionary *)property;
/// Add Stalling Event
/// - Parameters:
///   - stack: Stall stack
///   - duration: Duration of stall (in nanoseconds)
///   - property: Event custom attributes (optional)
func addLongTask(withStack: String, duration: NSNumber, property: [AnyHashable : Any]?)

Example Code

// Scenario 1
[[FTGlobalRumManager sharedManager] addLongTaskWithStack:@"stack string" duration:@1000000000];
// Scenario 2: Dynamic parameters
[[FTGlobalRumManager sharedManager] addLongTaskWithStack:@"stack string" duration:@1000000000 property:@{@"custom_key":@"custom_value"}];
// Scenario 1
FTGlobalRumManager.shared().addLongTask(withStack: "stack string", duration: 1000000000)
// Scenario 2: Dynamic parameters
FTGlobalRumManager.shared().addLongTask(withStack: "stack string", duration: 1000000000 ,property: [["custom_key":"custom_value"]])

Resource

Usage

/// Start of HTTP request
/// - Parameters:
///   - key: Request identifier
///   - property: Event custom attributes (optional)
- (void)startResourceWithKey:(NSString *)key property:(nullable NSDictionary *)property;

/// Add request data for HTTP
///
/// - Parameters:
///   - key: Request identifier
///   - metrics: Performance properties related to the request
///   - content: Data related to the request
- (void)addResourceWithKey:(NSString *)key metrics:(nullable FTResourceMetricsModel *)metrics content:(FTResourceContentModel *)content;

/// End of HTTP request
/// - Parameters:
///   - key: Request identifier
///   - property: Event custom attributes (optional)
- (void)stopResourceWithKey:(NSString *)key property:(nullable NSDictionary *)property;
/// Start of HTTP request
/// - Parameters:
///   - key: Request identifier
///   - property: Event custom attributes (optional)
open func startResource(withKey key: String, property: [AnyHashable : Any]?)

/// End of HTTP request
/// - Parameters:
///   - key: Request identifier
///   - property: Event custom attributes (optional)
open func stopResource(withKey key: String, property: [AnyHashable : Any]?)

/// Add request data for HTTP
///
/// - Parameters:
///   - key: Request identifier
///   - metrics: Performance properties related to the request
///   - content: Data related to the request
open func addResource(withKey key: String, metrics: FTResourceMetricsModel?, content: FTResourceContentModel)

Example Code

#import "FTMacOSSDK.h"

// Step 1: Before request starts
[[FTGlobalRumManager sharedManager] startResourceWithKey:key];

// Step 2: Request completes
[[FTGlobalRumManager sharedManager] stopResourceWithKey:key];

// Step 3: Assemble 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 phase timing data can be obtained 
// FTResourceMetricsModel
// For iOS native, if NSURLSessionTaskMetrics data is available, directly use the initialization method of FTResourceMetricsModel
FTResourceMetricsModel *metricsModel = [[FTResourceMetricsModel alloc]initWithTaskMetrics:metrics];

// For other platforms, all timing data is in nanoseconds
FTResourceMetricsModel *metricsModel = [[FTResourceMetricsModel alloc]init];

// Step 4: Add resource; if no timing data, pass nil for metrics
[[FTGlobalRumManager sharedManager] addResourceWithKey:key metrics:metricsModel content:content];
import FTMacOSSDK

// Step 1: Before request starts
FTGlobalRumManager.shared().startResource(withKey: key)

// Step 2: Request completes
FTGlobalRumManager.shared().stopResource(withKey: resource.key)

// Step 3: ① Assemble Resource data
let contentModel = FTResourceContentModel(request: task.currentRequest!, response: task.response as? HTTPURLResponse, data: resource.data, error: error)

// ② If phase timing data can be obtained 
// FTResourceMetricsModel
// For iOS native, if NSURLSessionTaskMetrics data is available, directly use the initialization method of FTResourceMetricsModel
var metricsModel:FTResourceMetricsModel?
if let metrics = resource.metrics {
   metricsModel = FTResourceMetricsModel(taskMetrics:metrics)
}
// For other platforms, all timing data is in nanoseconds
metricsModel = FTResourceMetricsModel()
...

// Step 4: Add resource; if no timing data, pass nil for metrics
FTGlobalRumManager.shared().addResource(withKey: resource.key, metrics: metricsModel, content: contentModel)

Logger Logging

Currently, log content is limited to 30 KB, and exceeding characters will be truncated.

Usage

//
//  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

/// Event level and status, default: FTStatusInfo
typedef NS_ENUM(NSInteger, FTLogStatus) {
    /// Info
    FTStatusInfo         = 0,
    /// Warning
    FTStatusWarning,
    /// Error
    FTStatusError,
    /// Critical
    FTStatusCritical,
    /// Ok
    FTStatusOk,
};
/// Event level and status, default: FTStatusInfo
public enum FTLogStatus : Int, @unchecked Sendable {
    /// Info
    case statusInfo = 0
    /// Warning
    case statusWarning = 1
    /// Error
    case statusError = 2
    /// Critical
    case statusCritical = 3
    /// Ok
    case statusOk = 4
}

Example Code

// Method 1: Through FTSDKAgent
// Note: Ensure the SDK has been initialized successfully when using, otherwise it will assert failure and crash in test environment.
[[FTSDKAgent sharedInstance] logging:@"test_custom" status:FTStatusInfo];

// Method 2: Through FTLogger (recommended)
// If the SDK hasn't been initialized successfully, calling methods in FTLogger to add custom logs will fail but won't cause an assertion failure crash.
[[FTLogger sharedInstance] info:@"test" property:@{@"custom_key":@"custom_value"}];
// Method 1: Through FTSDKAgent
// Note: Ensure the SDK has been initialized successfully when using, otherwise it will assert failure and crash in test environment.
FTSDKAgent.sharedInstance().logging("contentStr", status: .statusInfo, property:["custom_key":"custom_value"])

// Method 2: Through FTLogger (recommended)
// If the SDK hasn't been initialized successfully, calling methods in FTLogger to add custom logs will fail but won't cause an assertion failure crash.
FTLogger.shared().info("contentStr", property: ["custom_key":"custom_value"])

Custom Log Output to Console

Set printCustomLogToConsole = YES to enable outputting custom logs to the console. You will see logs in the xcode debug console in the following format:

2023-06-29 13:47:56.960021+0800 App[64731:44595791] [MACOS APP] [INFO] content ,{K=V,...,Kn=Vn}

2023-06-29 13:47:56.960021+0800 App[64731:44595791]: Standard prefix for os_log output;

[MACOS APP]: Prefix used to distinguish custom logs output by the SDK;

[INFO]: Level of the custom log;

content: Content of the custom log;

{K=V,...,Kn=Vn}: Custom attributes.

You can configure auto mode via FTTraceConfig, or manually add. Trace-related data is passed through the FTTraceManager singleton instance. Relevant APIs are as follows:

Usage

// FTTraceManager.h

/// Get trace request header parameters
/// - Parameters:
///   - key: Unique identifier for a certain request
///   - url: Request URL
/// - Returns: Dictionary of trace request header parameters
- (NSDictionary *)getTraceHeaderWithKey:(NSString *)key url:(NSURL *)url;
/// Get trace request header parameters
/// - Parameters:
///   - key: Unique identifier for a certain request
///   - url: Request URL
/// - Returns: Dictionary of trace request header parameters
open func getTraceHeader(withKey key: String, url: URL) -> [AnyHashable : Any]

Example Code

NSString *key = [[NSUUID UUID]UUIDString];
NSURL *url = [NSURL URLWithString:@"http://www.baidu.com"];
// Manual operation required: Get traceHeader before request and add to request headers
NSDictionary *traceHeader = [[FTTraceManager sharedInstance] getTraceHeaderWithKey:key url:url];
NSMutableURLRequest *request = [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];
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 required: Get traceHeader before request and add to request headers
     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()
}

Binding and Unbinding Users

Usage

/// Bind user information
///
/// - Parameters:
///   - Id:  User ID
///   - userName: User name (optional)
///   - userEmail: User email (optional)
///   - extra: Extra user information (optional)
- (void)bindUserWithUserID:(NSString *)Id userName:(nullable NSString *)userName userEmail:(nullable NSString *)userEmail extra:(nullable NSDictionary *)extra;

/// Unbind current user
- (void)unbindUser;
/// Bind user information
///
/// - Parameters:
///   - Id:  User ID
///   - userName: User name (optional)
///   - userEmail: User email (optional)
///   - extra: Extra user information (optional)
open func bindUser(withUserID Id: String, userName: String?, userEmail: String?, extra: [AnyHashable : Any]?)

/// Unbind current user
open func unbindUser()

Example Code

// Can call this method after user login success 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}];

// Can call this method after user logout to unbind user information
[[FTSDKAgent sharedInstance] unbindUser];
// Can call this method after user login success 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])

// Can call this method after user logout to unbind user information
FTSDKAgent.sharedInstance().unbindUser()

Shut Down SDK

Use FTSDKAgent to shut down the SDK.

Usage

/// Shut down objects running inside the SDK
- (void)shutDown;
/// Shut down objects running inside the SDK
func shutDown()

Example Code

// If dynamically changing SDK configuration, need to shut down first to avoid generating incorrect data
[[FTSDKAgent sharedInstance] shutDown];
// If dynamically changing SDK configuration, need to shut down first to avoid generating incorrect data
FTSDKAgent.sharedInstance().shutDown()

Add Custom Tags

Static Use

Multiple Configurations can be created using precompiled directives for setting values:

  1. Create multiple Configurations:

  1. Set preset properties to differentiate between different Configurations:

  1. Use precompiled directives:
//Target -> Build Settings -> GCC_PREPROCESSOR_DEFINITIONS for configuring preset 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 setup operations
[[FTSDKAgent sharedInstance] startRumWithConfigOptions:rumConfig];

Dynamic Use

Because settings made to globalContext after RUM has started will not take effect, users can save locally and apply them upon next app launch.

  1. Save locally via files, e.g., NSUserDefaults, configure the use of SDK, and add code to retrieve tag data at the configuration point.
NSString *dynamicTag = [[NSUserDefaults standardUserDefaults] valueForKey:@"DYNAMIC_TAG"]?:@"NO_VALUE";

FTRumConfig *rumConfig = [[FTRumConfig alloc]init];
rumConfig.globalContext = @{@"dynamic_tag":dynamicTag};
... //Other setup operations
[[FTSDKAgent sharedInstance] startRumWithConfigOptions:rumConfig];
  1. Add a method to change file data anywhere.
 [[NSUserDefaults standardUserDefaults] setValue:@"dynamic_tags" forKey:@"DYNAMIC_TAG"];
  1. Restart the app to take effect.

Notes

  1. Special key: track_id (configured in RUM, used for tracking functionality)

  2. When a user adds a custom tag via globalContext that conflicts with an SDK-owned tag, the SDK’s tag will overwrite the user's setting. It is recommended to add a project abbreviation prefix to tag names, e.g., df_tag_name.

  3. Setting globalContext before calling the -startRumWithConfigOptions method to start RUM is necessary for it to take effect.

  4. Custom tags configured in FTSDKConfig will be added to all types of data.

For more detailed information, please refer to the SDK Demo.

Frequently Asked Questions

About Crash Log Analysis

Include of non-modular header inside framework module error occurs

Because the .h files of the SDK include dependent library .h files, the following needs to be set

Target -> Build Settings -> CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES set to YES.好的,请提供需要继续翻译的内容。

Feedback

Is this page helpful? ×