iOS 收集打印日志

news/2025/1/16 3:35:08/

可以将要在Xcode 控制台打印的日志写在沙盒,最后导出分享,进行问题分析。

正式版本不建议使用,避免增加用户内存。配合解决顽固 Bug 可以通过该方法收集打印日志

.h头文件

@interface LogManager : NSObject
+ (FSLogManager *)shareInstance;
- (void)redirectNSlogToDocumentFolder;
- (NSString *)logDirPath;
- (void)clearAllLog;
- (float)sizeOfLogs;
@end

.m实现文件

#import "LogManager.h"
#import <UIKit/UIKit.h>#define LOG_TIME_FORMAT @"yyyy-MM-dd HH:mm:ss.SSS"
#define LOG_QUEUE_ID "log_queue"static LogManager *manager = nil;/// 是否运行收集日志,如果为 YES , 将不会在日志控制台打印。
static BOOL const kAllowSaveLog = YES;@implementation LogManager
+ (LogManager *)shareInstance{static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{manager = [[LogManager alloc] init];if (kAllowSaveLog) {[self setDefaultUncaughtExceptionHandler];}});return manager;
}
- (void)clearAllLog {NSArray<NSString *> *allPath = [self allLogPath];if (allPath.count == 0) {return;}[allPath enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {NSError *error;[[NSFileManager defaultManager] removeItemAtPath:obj error:&error];}];
}
- (void)redirectNSlogToDocumentFolder{if (kAllowSaveLog == NO) {return;}UIDevice *device = [UIDevice currentDevice];if ([[device model] isEqualToString:@"Simulator"]) {return;}NSDateFormatter *formatter = [[NSDateFormatter alloc] init];[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];NSString *dateString = [formatter stringFromDate:[NSDate date]];NSString *documentDirectory = [self logDirPath];NSString *fileName = [NSString stringWithFormat:@"%@-log.txt",dateString];NSString *logFilePath = [documentDirectory stringByAppendingPathComponent:fileName];// Delete existing files[[NSFileManager defaultManager] removeItemAtPath:logFilePath error:nil];//Enter the log into the file  (所有的打印都会存在该文件)freopen([logFilePath cStringUsingEncoding:NSUTF8StringEncoding], "a+", stdout);freopen([logFilePath cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);}- (float)sizeOfLogs{NSDirectoryEnumerator *direnum = [[NSFileManager defaultManager] enumeratorAtPath:[self logDirPath]];NSString *pname;int64_t s=0;while (pname = [direnum nextObject]){NSDictionary *currentdict=[direnum fileAttributes];NSString *filesize=[NSString stringWithFormat:@"%@",[currentdict objectForKey:NSFileSize]];NSString *filetype=[currentdict objectForKey:NSFileType];if([filetype isEqualToString:NSFileTypeDirectory]) continue;s=s+[filesize longLongValue];}return s*1.0;
}
- (NSString *)logDirPath {NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);NSString *documentDirectory = [paths objectAtIndex:0];NSString *logPath = [documentDirectory stringByAppendingPathComponent:@"Logs"];BOOL isDir = NO;BOOL isExist = [[NSFileManager defaultManager] fileExistsAtPath:logPath isDirectory:&isDir];if (isExist && isDir) {} else {NSError * createDirError;[[NSFileManager defaultManager] createDirectoryAtPath:logPath withIntermediateDirectories:YES attributes:nil error:&createDirError];}return logPath;
}
- (NSArray<NSString *> *)allLogPath {NSArray<NSString *> *items = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[self logDirPath] error:nil];NSMutableArray<NSString *> *paths = [NSMutableArray array];NSString *dirPath = [self logDirPath];[items enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {[paths addObject:[dirPath stringByAppendingPathComponent:obj]];}];return paths;
}#pragma mark -设置crash
+ (void)setDefaultUncaughtExceptionHandler
{NSSetUncaughtExceptionHandler (&chUncaughtExceptionHandler);signal(SIGABRT, SignalHandler);signal(SIGILL, SignalHandler);signal(SIGSEGV, SignalHandler);signal(SIGFPE, SignalHandler);signal(SIGBUS, SignalHandler);signal(SIGPIPE, SignalHandler);}#pragma mark -获取崩溃日志
void chUncaughtExceptionHandler(NSException *exception)
{NSLog(@"Exception info --> %@",exception);
}void SignalHandler(int signal)
{//拦截signal
}@end

分享

收集到的日志可以通过云端上传,也可以直接通过系统原生分享。

/// items 可以传文件路径path。 
+ (void)shareItems:(NSArray *)items  fromController:(UIViewController *)controller cancel:(void(^)(void))cancel completion:(void(^)(NSError * _Nullable error))completion {if (items.count == 0) {return;}//初始化:UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:nil];activityVC.completionWithItemsHandler = ^(UIActivityType  _Nullable activityType, BOOL completed, NSArray * _Nullable returnedItems, NSError * _Nullable activityError) {// 如果取消, completed返回 NOif (completed) {if (completion) {completion(activityError);}} else {if (cancel) {cancel();}}};//禁掉不用的服务activityVC.excludedActivityTypes = @[UIActivityTypePrint,UIActivityTypeAssignToContact];[controller presentViewController:activityVC animated:YES completion:nil];
}

http://www.ppmy.cn/news/1520648.html

相关文章

冲刺蓝桥杯第三章字符串

ASCII码值、字母大小写转换、‘0’~‘9’ //数字转字符:A(65)a(97)0(48) char A=char(65); char a=char(97); char c

终极解决 docker 拉取镜像失败的问题,其他类似场景也适用

国内的网络环境&#xff0c;想必大家都是知道的&#xff0c;虽说技术无罪&#xff0c;但奈何政策不允许啊&#xff0c;以下内容我在 CSDN 上发不了&#xff0c;请大家移步我的个人公 * 号&#xff1a;新质程序猿&#xff0c;查看更多原创内容&#xff0c;这里只介绍相关背景和需…

字节6面,面爆炸了

字节跳动 昨晚在牛客网刷到一篇"深夜 EMO 贴"&#xff0c;又是讲字节 N 面挂的。 原本的 4HR 面都过了&#xff0c;结果 Offer 审批的时候&#xff0c;被 HR 通知加一轮交叉面&#xff0c;一共 6 面。 加面时&#xff0c;两个面试官全程黑脸&#xff0c;最后两道算法…

软考 -- 软件设计师 -- 二轮复习(2) -- 程序设计语言(持续更新)

软考 – 软件设计师 – 二轮复习(2) – 程序设计语言(持续更新) 文章目录 软考 -- 软件设计师 -- 二轮复习(2) -- 程序设计语言(持续更新)前言一、编译、解释、基本控制结构二、数据类型三、变量和常量、逻辑表达式(短路&#xff1a;&&、||、&#xff01;)四、传值调用…

【qt】多线程实现倒计时

1.界面设计 设置右边的intvalue从10开始倒计时 2.新建Thread类 新建Thread类&#xff0c;使其继承QThread类&#xff0c;多态重写run函数&#xff0c;相当于线程执行函数 3.重写run函数 重写run函数&#xff0c;让另一个进程每隔1s发出一个信号&#xff0c;主线程使用conne…

Ps:渲染视频

Ps菜单&#xff1a;文件/导出/渲染视频 File/Export/Render Video 在 Photoshop 中创建视频或动画内容后&#xff0c;可以通过渲染视频 Render Video命令对其进行优化、渲染和导出。 “渲染视频”对话框中提供了两种编码器&#xff1a;Adobe Media Encoder 及 Photoshop 图像序…

【Postgresql】地理空间数据的存储与查询,查询效率优化策略,数据类型与查询速度的影响

注:使用postgresql数据库会用到PostGIS 扩展。 一、安装PostGIS 扩展 在 PostgreSQL 中遇到错误 “type geography does not exist” 通常意味着你的 PostgreSQL 数据库还没有安装 PostGIS 扩展,或者 PostGIS 扩展没有被正确地安装在你的数据库中。geography 类型是 PostGI…

(前端)面试300问之(3)this的指向判断

一、this的相关理解与解读 1、各角度看this。 1&#xff09;ECMAScript规范&#xff1a; this 关键字执行为当前执行环境的 ThisBinding。 2&#xff09;MDN&#xff1a; In most cases, the value of this is determined by how a function is called. 在绝大多数情况下&…