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,以及打包过程中遇到的问题和解决办法 ...
随机推荐
- 记录git rebase用法
git 是基于文件系统的版本管理工具,文档和详细介绍可以查看git 一.git commit --amend 如果你对文件做了修改需要和上一次的修改合并为一个change git add . git ...
- bzoj 4338: BJOI2015 糖果
4338: BJOI2015 糖果 Time Limit: 2 Sec Memory Limit: 256 MBSubmit: 200 Solved: 93[Submit][Status][Dis ...
- delphi程序全屏显示无标题栏覆盖整个屏幕
delphi 简单实现程序全屏显示无标题栏,覆盖整个屏幕,这个在做工控机或屏保时有用的,具体代码如下,感兴趣的朋友可以参考下哈 delphi 程序全屏显示无标题栏,覆盖整个屏幕,这个在做工控机或屏保时 ...
- AFNetworking 2.0 Tutorial
Update 1/18/2014: Fully updated for iOS 7 and AFNetworking 2.0 (original post by Scott Sherwood, upd ...
- 基本数据类型,包装类型,String类型数据之间的转换
java中所有的类都从java.lang.Object类派生而来,在java语言中,除基本数据类型以外,基本数据类型有java类库体统了包装类:Integer类保存整形变量,Boolean类保存布尔变 ...
- 使用echarts简单制作中国地图,echarts中国地图
网站需要一张中国地图,并且鼠标经过某个省份,该省份的省份名字显示,而且该省份的地区会变色显示. 第一种方法: 将每个省份的图片定位(先隐藏),拼合成一张中国地图,然后再定位省份名称,鼠标经过省份名字, ...
- smarty在循环的时候计数来显示这是第几次循环的功能
想必有很多人比较喜欢这个smarty循环的时候有个变量增加的功能或比较需要这个功能吧?其实不需要额外的变量,当然你也许根本用不了.我们用smarty内置的就可以了.就是smarty有foreach和s ...
- WO+开放平台:API调用开发手记(话费计费接口2.0)
WO+能力共享平台(http://open.wo.com.cn)是中国联通推出的开放平台.拥有的丰富电信能力资源以及深度整合挖掘的第三方能力资源等.WO+平台提供的API均为简洁优雅的RESTful风 ...
- javaweb项目自定义错误页面
当我们把一个web项目成功发布出去,但是有些页面还有待完善的时候,会出现404错误页面.这个会给用户很差的体验.如何将这些错误页面修改为自定义的错误页界面,给用户一些友好的提示呢? 首先我们在web. ...
- C#程序不包含适合于入口点的静态“Main”方法怎么办
如下图所示,一般程序上次运行还好好的,而且不管你复制粘贴再简单的程序也出现这种错误提示. 先点击右侧的显示所有文件,下面列举了所有CS文件,右击点击包括在项目中,则该文件呈现绿色,再运行即可.不过 ...