Level: ★☆☆ Tag: “iOS View and export project run logs” “iOS View logs” “iOS view crash logs” author: WYW


Previous: Recently, when I was working remotely from home, I ran into a problem with my classmate’s test, which I couldn’t reproduce on my side. So I sorted out iOS to view and export project run logs. You can check out the details if you want.

This section describes how to view and export project run logs on iOS. The full text is divided into the following seven parts.

  1. Console view logs;
  2. Redirects NSLog logs.
  3. Use Xcode to download Containers to view logs.
  4. View the contents of Documents by PAirSandbox: AirSandbox;
  5. View log files in Documents through file App;
  6. Custom capture of ordinary logs and crash logs, etc.
  7. QiLogTool Demo address, usage, and effect demonstration.

One, console view logs

Using the console while the iPhone is connected to the Mac, search for the project name (QiLogTool in my case) and find the corresponding log. Regardless of whether the project is running with Xcode or not, the logs in the iPhone can be viewed in the console.

2. Redirect NSLog logs

Note: After the NSLog redirect, the console will not print the log.

Use the following code to redirect NSLog logs to the specified file directory.

+ (void)redirectNSLog {
    
    NSString *fileName = @"NSLog.log";
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory.NSUserDomainMask.YES);
    NSString *documentDirectory = paths.firstObject;
    NSString *saveFilePath = [documentDirectory stringByAppendingPathComponent:fileName];
    // Delete existing files first
    NSFileManager *defaultManager = [NSFileManager defaultManager];
    [defaultManager removeItemAtPath:saveFilePath error:nil];

    // Enter log into the file
    freopen([saveFilePath cStringUsingEncoding:NSASCIIStringEncoding]."a+", stdout);
    freopen([saveFilePath cStringUsingEncoding:NSASCIIStringEncoding]."a+", stderr);
}
Copy the code

Freopen is a function included in the C library header <stdio.h> that redirects input and output streams. This function can change the input and output environments without changing the original code, but should be used to ensure that the stream is reliable.

Quote from Encyclopedia 360: Freopen

FILE	*freopen(
    const char * __restrict,
    const char * __restrict, 
    FILE * __restrict)
    __DARWIN_ALIAS(freopen); Parameter description: filename: indicates the filename or file path to be redirected. Mode: indicates the character string of file access permission. For example,"r"said"Read-only access","w"said"Write access only","a"said"Append write". Stream: file stream to be redirected.Copy the code

The following is a screenshot after the author redirects the contents of NSLog to nslog.log.

3. Use Xcode to download Containers to view logs

Get logs from the Container section of Xcode

Below is the author’s sandbox directory in the official document screenshot.

The screenshots below are screenshots of the sandbox files in the installation package obtained by the author through Xcode.

4. View the content in Documents through PAirSandbox

Using PAirSandbox: AirSandbox, from the right edge of the phone screen, the left swipe gesture triggers a window that displays the contents of the current sandbox. And you can share the contents of the sandbox with others through third-party software. To Close the sandbox directory interface, click the Close button in the upper right corner.

#ifdef DEBUG
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [[PAirSandbox sharedInstance] enableSwipe];
        });
    #endif
Copy the code

The effect is shown as follows:

5. View the log files in Documents through the file App

You need to configure the following information in the info. plist file to view the contents of the sandbox in the file App in real time.

Set Application Supports iTunes File Sharing to YES. Sets Supports opening Documents in place to YES.

The schematic diagram of setting is as follows:

The effect of viewing logs in real time through the file App is shown as follows.

Custom capture of ordinary logs and crash logs, etc

1. Try catch the code that may crash

/** * QiLogTool[18371:4064396] exception: * 2020-03-25 10:47:11.179085+0800 *** * -[__NSSingleObjectArrayI objectAtIndex:]: Index 2 beyond bounds [0.. 0] * 2020-03-25 10:47:11.179310+0800 QiLogTool[18371:4064396] finally */
@try {
    NSArray *arr = @[@(1)];
    arr[2];
} @catch (NSException *exception) {
    NSLog(Exception: % @ "@", exception);
} @finally {
    NSLog(@"finally");
}
Copy the code

If there are many possible exceptions in your project, using a try catch approach can be cumbersome. Consider catching global exceptions for your project.

2. Handle exceptions globally

The following code can view exceptions and record logs. On the user side, crash logs can be uploaded to the server for log analysis. However, the App will still flash back when encountering exceptions.

#ifdef DEBUG
	Summary Changes the top-level error handler.
	NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
#endif
Copy the code
#pragma mark - Catches exceptions without breaking
void UncaughtExceptionHandler(NSException *exception) {
    
    // Get abnormal crash information
    NSArray *callStack = [exception callStackSymbols];
    NSString *reason = [exception reason];
    NSString *name = [exception name];
    NSString *crashDetail = [NSString stringWithFormat:@ "= = = = = = = = exception error reporting = = = = = = = = \ n name: % @ \ n" reason: \ n % @ \ n callStackSymbols: \ n % @", name, reason, [callStack componentsJoinedByString:@"\n"]].NSLog(@ "% @", crashDetail);
    [QiLogTool logFile:@"crash.log" content:crashDetail];
}
Copy the code

3. Use RunLoop to ensure the App continues running once after a crash

RunLoop application Scenarios (5)

QiLogTool also has code for this. If you are interested, you can download it yourself.

The code that catches the exception part is similar to the way I caught exceptions globally in Step 2 above. Also, we can log exceptions and use Runloop-related code to keep the application from crashing the first time it encounters an exception.

The main code that keeps the App running once the RunLoop handler encounters an exception is:

    // Get the CFRunLoop object of the current thread and the Modes array containing the specified CFRunLoop object
    CFRunLoopRef runLoop = CFRunLoopGetCurrent(a);CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);
    
    while(! ignore) {for (NSString *mode in (__bridge NSArray *)allModes) {
            // Runs the current thread’s CFRunLoop object in a particular mode.
            CFRunLoopRunInMode((CFStringRef)mode, 0.001.false); }}CFRelease(allModes);

Copy the code

4. Other methods for viewing Crash logs

4.1 Viewing information in the Mac Directory

It is incorrect to view crash logs in the following ways.

~/Library/Logs/CrashReporter/MobileDevice
Copy the code

4.2 Other Ways to View crash logs using Xcode

The 1,2 of the red arrow above can be used to view the log of the project installed by Xcode on the device side;

The 1,2 of the blue arrow below can be used to view the logs of Crash uploaded to the AppStore project.

4.3 View online crash logs using Other Three Parties

QiLogTool Demo address, use and effect demonstration

1. QiLogTool Demo address

QiLogTool

2. QiLogTool usage:

Add CrashHandler and files from the AirSandBox and QiLogTool folders to your project. Call the following code when the application starts:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    if (@available(iOS 13.0{}, *))else {
        self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
        self.window.backgroundColor = [UIColor whiteColor];
        self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[ViewController new]];
        [self.window makeKeyAndVisible];
    }
    // Whether to access the contents of the sandbox directly
    #ifdef DEBUG
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [[PAirSandbox sharedInstance] enableSwipe];
        });
    #endif
    
    // Redirect NSLog content Note: after redirecting NSLog content to another file, the console will no longer output the content
    [QiLogTool redirectNSLog];
    
    #ifdef DEBUG
        // Catch the exception Changes the top-level error handler.
         NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
    #endif
    
    // #ifdef DEBUG
    #ifdef RELEASE
        // Catch exceptions and once an application encounters an exception, it does not flash back
        [CrashHandler sharedInstance];
    #endif
    return YES;
}
Copy the code

#pragma mark - Catches exceptions without breaking
void UncaughtExceptionHandler(NSException *exception) {
    
    // Get abnormal crash information
    NSArray *callStack = [exception callStackSymbols];
    NSString *reason = [exception reason];
    NSString *name = [exception name];
    NSString *crashDetail = [NSString stringWithFormat:@ "= = = = = = = = exception error reporting = = = = = = = = \ n name: % @ \ n" reason: \ n % @ \ n callStackSymbols: \ n % @", name, reason, [callStack componentsJoinedByString:@"\n"]].NSLog(@ "% @", crashDetail);
    [QiLogTool logFile:@"crash.log" content:crashDetail];
    // Upload the logs to the server at a proper time. Delete the logs after the logs are successfully uploaded
}
Copy the code

3. QiLogTool use effect demonstration:

The following demo calls the code when the application starts:

// Whether to access the contents of the sandbox directly
    #ifdef DEBUG
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [[PAirSandbox sharedInstance] enableSwipe];
        });
    #endif
    
    // Redirect NSLog content Note: after redirecting NSLog content to another file, the console will no longer output the content
    [QiLogTool redirectNSLog];
    
    #ifdef DEBUG
    // #ifdef RELEASE
        // Catch exceptions and once an application encounters an exception, it does not flash back
        [CrashHandler sharedInstance];
    #endif
Copy the code

After clicking the test Log button in the middle of the screen, the following methods are invoked:

- (void)logTest {
    
    NSLog(@"NSLog log content");
    // Test the logging tool
    [QiLogTool logFile:@"logfile.log" content:[NSString stringWithFormat:@" Time: %@\n Content: %@\n"The [[NSDate date] dateByAddingTimeInterval:8.0 * 60 * 60].@"logContent"]].// Test the crash logging effect
    NSArray *arr = @[@(1)];
    NSLog(@ "arr [2] : % @", arr[2]);
}
Copy the code

Due to the large size of the GIF recorded by the author, direct upload is limited. If you want to view the effect picture in the process of use, you can click the link QiLogTool below to use the effect picture

Refer to study website

File System Programming Guide iOS Save the handling of iOS crash exceptions by redirecting NSLog logs to a File


To learn more about iOS and related new technologies, please follow our official account:

You can add the following xiaobian wechat, and note to join the QiShare technical exchange group, xiaobian will invite you to join the QiShare technical Exchange Group.

QiShare(Simple book) QiShare(digging gold) QiShare(Zhihu) QiShare(GitHub) QiShare(CocoaChina) QiShare(StackOverflow) QiShare(wechat public account)

How to use the Flutter Platform Channel? Vector icon (iconFont) Getting started with guide DarkMode, WKWebView, Apple login must be adapted? IOS Access To Google and Facebook login (2) iOS access to Google and Facebook login (1) Nginx Getting started 3D transformation in iOS (2) 3D transformation in iOS (1) WebSocket dual-end practice (iOS/ Golang) Today we are going to talk about WebSocket (iOS/Golang) strange dance team Android team — aTaller strange dance weekly