iOS 日志系统 本地日志打包上传到服务器
日志系统主要包含两个部分
1.本地保存
我们知道NSLog打印的日志一般都是直接输出到控制台,开发人员可以在控制台直接看到实时打印的log,既然可以在控制台输出,那么能否将日志输出到其他地方呢,比如说自己定义的text文件?答案是肯定的 ,在iOS中可以通过一些方法将文件重定向到指定输出位置:
    freopen([filePath cStringUsingEncoding:NSASCIIStringEncoding],"a+", stdout);
    freopen([filePath cStringUsingEncoding:NSASCIIStringEncoding], "a+", stderr);
实现了上述方法,就可以将log重定向到指定的filePath中了,既然文件中保存到了本地,那么怎么处理,怎么加密完全看你们公司的业务需求咯
2.日志上传
日志上传首先需要将本地日志打包成zip格式的文件,这样可以减小上传的size,通过ZipArchive将日志文件打包好,通过afnetworking的 formData将文件上传了
    [formData appendPartWithFileURL:url name:@"zipFile" fileName:[NSString stringWithFormat:@"%@.zip",[self getCurrentTime]] mimeType:@"multipart/form-data" error:nil];
具体部分实现代码如下:
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface LogServer : NSObject
+(instancetype)shareInstance;
///开启写日志
-(void)writeLog;
///上传日志
-(void)uploadLog;
///清空本地日志
-(void)clearLog;
@end
NS_ASSUME_NONNULL_END
#import "LogServer.h"
#import <ZipArchive/ZipArchive.h>
#define MaxCount   30    //只保留最近的30条数据
#define MaxSize    (1024*4)   //4M
@interface LogServer (){
    NSString *filePath_;  //文件存放路径
}
@end
static LogServer * instance = nil;
@implementation LogServer
+(instancetype)shareInstance{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[LogServer alloc] init];
        [instance initLogServer];
    });
    return instance;
}
-(void)initLogServer{
    NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
    //初始化log路径
    filePath_ = [path stringByAppendingPathComponent:@"Log"];
    NSFileManager *manager = [NSFileManager defaultManager];
    if (![manager fileExistsAtPath:filePath_]) {
        //如果Log文件夹不存在,就创建文件夹
        [manager createDirectoryAtPath:filePath_ withIntermediateDirectories:YES attributes:nil error:nil];
    }
}
-(void)writeLog{
    // Do any additional setup after loading the view.
    //如果文件有zip格式则直接移除掉 可能是上次打包上传的
    [self removeZipFile];
    //如果文件夹中的文件超过最大限制 咋移除旧数据
    [self removeExpireFile];
    //加密文件
    [self encryptLastFile];
    //将日志写入到文件中
    NSString *filePath = [filePath_ stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.text",[self fileNameAtTime]]];
    freopen([filePath cStringUsingEncoding:NSASCIIStringEncoding],"a+", stdout);
    freopen([filePath cStringUsingEncoding:NSASCIIStringEncoding], "a+", stderr);
    NSLog(@"filePath:%@",filePath);
    //异常日志报告
    NSSetUncaughtExceptionHandler(&caughtExceptionHandler);
}
-(void)uploadLog{
    //将需要上传的文件加密zip格式上传到服务器
    NSArray *sortArray = [self sortFileAscending];
    if (sortArray.count > 0) {
        ZipArchive *zip = [[ZipArchive alloc] init];
        NSString *path = [filePath_ stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.zip",[self fileNameAtTime]]];
        BOOL ret = [zip CreateZipFile2:path];
        if (ret) {
            //便利所有文件内容
            for (int i = sortArray.count - 1; i>=0; i--) {
                NSString *fileName = sortArray[i];
                NSString *filePath = [filePath_ stringByAppendingPathComponent:fileName];
                [zip addFileToZip:filePath newname:fileName];
                //判断zip文件大小 如果文件大小大于最大限制 则停止剩余文件的压缩
                long long zipSize = [self getFileSize:path];
                if (zipSize > MaxSize) {
                    break;
                }
            }
            [zip CloseZipFile2];
            //将zip文件上传到服务器
//            afnetworking  文件上传到指定服务器即可
        }
    }
}
-(void)clearLog{
    NSFileManager *manager = [NSFileManager defaultManager];
    if ([manager fileExistsAtPath:filePath_]) {
        NSError *error = nil;
        [manager removeItemAtPath:filePath_ error:&error];
        if (error) {
            NSLog(@"日志清空失败:%@",error);
        }else{
            NSLog(@"日志清空成功");
        }
    }
}
#pragma mark - private
#pragma mark 异常处理日志
void caughtExceptionHandler(NSException *exception){
    /**
     *  获取异常崩溃信息
     */
    NSArray *callStack = [exception callStackSymbols];
    NSString *reason = [exception reason];
    NSString *name = [exception name];
    NSString *content = [NSString stringWithFormat:@"========异常错误报告========\nname:%@\nreason:\n%@\ncallStackSymbols:\n%@",name,reason,[callStack componentsJoinedByString:@"\n"]];
    NSLog(@"%@",content);
}
#pragma mark 获取文件大小
-(long long)getFileSize:(NSString *)path{
    unsigned long long fileLength = 0;
    NSNumber *fileSize;
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if([fileManager fileExistsAtPath:path]){
        NSDictionary *fileAttributes = [fileManager attributesOfItemAtPath:path error:nil];
        if ((fileSize = [fileAttributes objectForKey:NSFileSize])) {
            fileLength = [fileSize unsignedLongLongValue]; //单位是 B
        }
        return fileLength / 1024;
    }
    return 0;
}
#pragma mark 用时间创建文件名
-(NSString *)fileNameAtTime{
    NSDate *date = [NSDate date];
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    formatter.dateFormat = @"yyyy-MM-dd-HH-mm-ss";
    NSString *timeStr = [formatter stringFromDate:date];
    return timeStr;
}
#pragma mark 加密文件内容
-(void)encryptLastFile{
    //这里根据自己的需要将文件内容进行加密
    NSFileManager *manager = [NSFileManager defaultManager];
    NSArray *sortArray = [self sortFileAscending];
    if (sortArray.count > 0) {
        NSString *lastPath = sortArray.lastObject;
        NSString *lastFilePath = [filePath_ stringByAppendingPathComponent:lastPath];
        NSData *data = [manager contentsAtPath:lastFilePath];
        NSString *base64String = [data base64EncodedStringWithOptions:0];
        //
        [base64String writeToFile:lastFilePath atomically:YES];
    }
}
#pragma mark 移除过期数据
-(void)removeExpireFile{
    NSFileManager *manager = [NSFileManager defaultManager];
    //将文件中数据排序
    NSArray *sortFileArray = [self sortFileAscending];
    if(sortFileArray.count > MaxCount){
        NSInteger count = sortFileArray.count - MaxCount;
        //因为是升序排在前面的都是比较老的数据 移除前面的count个数据即可
        for (int i = 0; i < count; i++) {
            NSString *path = sortFileArray[i];
            NSString *filePath = [filePath_ stringByAppendingPathComponent:path];
            [manager removeItemAtPath:filePath error:nil];
        }
    }
}
#pragma mark 移除zip格式文件
-(void)removeZipFile{
    NSFileManager *manager = [NSFileManager defaultManager];
    if ([manager fileExistsAtPath:filePath_]) {  //如果文件夹存在
        NSArray *filesArray = [manager contentsOfDirectoryAtPath:filePath_ error:nil];
        NSString *filePath = filePath_;
        [filesArray enumerateObjectsUsingBlock:^(NSString *  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if (![obj containsString:@".text"]) {
                NSString *nPath = [filePath stringByAppendingPathComponent:obj];
                [manager removeItemAtPath:nPath error:nil];
            }
        }];
    }
}
#pragma mark 将文件夹中的文件按照创建时间进行排序
-(NSArray *)sortFileAscending{
    //拿到文件
    NSFileManager *manager = [NSFileManager defaultManager];
    if ([manager fileExistsAtPath:filePath_]) {  //如果文件夹存在
        NSArray *filesArray = [manager contentsOfDirectoryAtPath:filePath_ error:nil];
        NSString *filePath = filePath_;
        //便利文件夹中的所有文件
        NSArray *array = [filesArray sortedArrayUsingComparator:^NSComparisonResult(NSString*  _Nonnull file1, NSString *  _Nonnull file2) {
            //file1 file2全路径
            NSString *file1Path = [filePath stringByAppendingPathComponent:file1];
            NSString *file2Path = [filePath stringByAppendingPathComponent:file2];
            //file1 file2 Info
            NSDictionary *file1Dict = [[NSFileManager defaultManager] attributesOfItemAtPath:file1Path error:nil];
            NSDictionary *file2Dict = [[NSFileManager defaultManager] attributesOfItemAtPath:file2Path error:nil];
            //file1CreatTime file2CreatTime
            NSDate *file1Date = [file1Dict objectForKey:NSFileCreationDate];
            NSDate *file2Date = [file2Dict objectForKey:NSFileCreationDate];
            //升序
            return [file1Date compare:file2Date];
        }];
        return  array;
    }
    return nil;
}
@end
iOS 日志系统 本地日志打包上传到服务器的更多相关文章
- Maven配置jar(war)包自动打包上传Maven服务器的配置
		Maven配置jar(war)包自动打包上传Maven服务器的配置 创建jar(war)包工程 创建一个maven工程 在工程中穿件一个测试类 配置pom.xml <distributionMa ... 
- ios使用xcode进行Archive打包上传出现的常见错误
		error itms 90362上传appstore 一直报错ERROR ITMS-90362: "Invalid Info.plist value. The value for the k ... 
- iOS通过切片仿断点机制上传文件
		项目开发中,有时候我们需要将本地的文件上传到服务器,简单的几张图片还好,但是针对iPhone里面的视频文件进行上传,为了用户体验,我们有必要实现断点上传.其实也不是真的断点,这里我们只是模仿断点机制. ... 
- Nuget多项目批量打包上传服务器的简明教程
		本篇不会介绍Nuget是什么,如何打包上传Nuget包,怎么搭建私有Nuget服务器.这些问题园子里都有相应的文章分享,这里不做过多阐述.另外本文假设你已经下载了Nuget.exe,并且已经设置好了环 ... 
- DedeCMS使用方法----如何将网站上传到服务器
		我们如果在本地已经把网站做好了,上传到服务器上去的正确姿势是什么样的呢?简单的很~跟着我的步调来~ 方法一(推荐此方法): 1.把你本地所有的文件压缩,上传至服务器上的根目录,再解压. 2.把本地的数 ... 
- iOS 打包上传AppStore相关(2)-Xcode相应配置
		上一篇描述了如何在AppleDeveloper创建Certificates.App IDs和Provisioning Profiles的过程.本篇将详细描述在Xcode部分我们需要做的配置. 1.配置 ... 
- iOS APP打包上传到APPstore的最新步骤
		一.前言: 作为一名iOS开发者,把辛辛苦苦开发出来的App上传到App Store是件必要的事.但是很多人还是不知道该怎么上传到App Store上 下面就来详细讲解一下具体流程步骤. 二.准备: ... 
- LocalResizeIMG前端HTML5本地压缩图片上传,兼容移动设备IOS,android
		LocalResizeIMG前端HTML5本地压缩图片上传,兼容移动设备IOS,android jincon 发表于 2015-02-26 18:31:01 发表在: php开发 localresiz ... 
- iOS开发进阶 - 使用shell脚本自动打包上传到fir.im上-b
		用fir.im测试已经好长时间了,感觉每次打包上传都很麻烦,想着是不是可以用脚本自动打包,在网上搜了一下确实有,下面总结一下如何使用脚本自动打包上传到fir.im,以及打包过程中遇到的问题和解决办法 ... 
随机推荐
- 新疆大学ACM-ICPC程序设计竞赛五月月赛(同步赛)- XOR(二进制使用)
			链接:https://www.nowcoder.com/acm/contest/116/H来源:牛客网 题目描述 Once there was a king called XOR, he had a ... 
- 数学【p1412】 经营与开发(秦九韶算法)
			顾z 你没有发现两个字里的blog都不一样嘛 qwq 题目描述-->P1412 经营与开发 分析 虽然看到\(Rank_1\)已经有了解释. 但我认为我能BB的更好 我还是决定来写一篇题解. q ... 
- js   timestamp 转换 date   和     将秒数整理为时分秒格式
			// 获得的后台json 时间格式转化 例如:1520305366000 转化为XXXX-XX-XX类似这种 function timeStamp2String(time){ var datetim ... 
- Sort Transformed Array -- LeetCode
			Given a sorted array of integers nums and integer values a, b and c. Apply a function of the form f( ... 
- 用swift开发自己的MacOS锁屏软件(一)
			最近看到了NearLock这款软件,感觉还是很不错的,当我兴致勃勃的安装了体验之后,发现效果和自己所想的差太多了,所以,便想着自己写一个吧. 刚开始当然是查资料之类的,不查不知道,一查吓一跳,国内基本 ... 
- PHP生成GUID的函数
			GUID: 即Globally Unique Identifier(全球唯一标识符) 也称作 UUID(Universally Unique IDentifier) . GUID是一个通过特定算法产生 ... 
- ASP.NET 5基础之中间件
			来源https://docs.asp.net/en/latest/fundamentals/middleware.html 一些可以整合进http请求管道的小的应用组件称做中间件.ASP.NET 5集 ... 
- mysql 将多个查询结果合并成一行
			mysql中的多行查询结果合并成一个 SELECT GROUP_CONCAT(md.data1) FROM DATA md,contacts cc WHERE md.conskey=cc.id AND ... 
- 【Hadoop】Hadoop MR 性能优化 Combiner机制
			1.概念 2.参考资料 提高hadoop的mapreduce job效率笔记之二(尽量的用Combiner) :http://sishuo(k).com/forum/blogPost/list/582 ... 
- 2017.4.18 putty和fileZilla的使用
			putty:用来连接环境. fileZila:用来传递文件. (1)连接环境 centOS 7 点击putty.exe,输入地址.用户名.密码进行连接.端口输入22.用账号和密码登录. 进入到目录下, ... 
