iOS 上传错误日志

公司服务器错误日志 & 微软日志 上传
一. 公司服务器错误日志

简介
上传自己公司的服务器,需要的流程大概为:

1. 和服务器端讨论,具体上传什么内容,例如:上传的API接口,请求类型和格式。
   一种上传的格式大概为:Request Header: Logger--类型(日志管理器名称,即用来区分App类型,又用来区分日志所存路径);
 然后是body内容:定义格式,然后在Http Request Body内直接将日志内容进行请求

上传内容例如:

{
    "date":"2017-08-02 15:30:25",    // log date
    "time":"202545454124411",        // 系统的毫秒时间
    "login_status":"true",           // user login status
    "log_version":"1.0",             // 日志版本

    "device_info":{  
        "brand":"samsung",
        "model":"N9508",
        "network_type":"wifi",
        "network_available":"true",
                "operators":"46003",
        "platform_type":"iOS",   // android  / ios
        "system_sdk":"20",
        "system_version":"5.1.0",
        "system_id":"",              // android id  /  ios ad id
             "locale":"zh_CN",
            "screen_width":"720",
            "screen_height":"1280",
            "free_sd_card":"1526MB",
    },

    "app_info":{
        "app_type":"android",
        "app_version":"3.2.5",
        "app_code":"325",
        "app_flavor":"yingyongbao"
                "use_proxy": "true"
               "total_memory":"2048MB",
            "max_memory":"512MB",
            "free_memory":"68MB",
    },

    "user_info":{
        "user_id":"3.2.5",
        "user_phone":"325",
        "user_name":"yingyongbao",
        "user_verfiy_status":"true",
        "user_city":"南京",
        "user_org":"上海宜信惠普"
    },

    "log_info":{
        "type":"crash",         // crash log   /  normal log   or 业务上的异常, 跟踪日志(后台控制是否记录)
        "msg":"",    // 错误信息
        "cause":""   // 引起错误的原因
              "api_url" : ""         //     接口url
                "api_request":""  // 请求头
               "api_response":"" // 服务器响应内容
               
    }
}

这些信息通过iOS 自带的获取设备信息的库 和 本地存储的一些app的信息中得到。

  1. 既然要上传错误日志内容,当然需要得到这个错误信息
获取app接口请求发生错误的信息,存储到本地:
a. 大都是用的afnetworking三方库,在接口调用的时候,有successBlock和failureBlock。
   可以获取successBlock 中code != 0 时,和failureBlock中的 这两个地方的错误信息。
b. 例如在successBlock 中code != 0 时,获取错误信息。
  e.g..{            [self errorRecordApiUrl:url requestHead:parameters responseData:responseObject];
         }
方法的实现:{- (void)errorRecordApiUrl:(NSString *)url requestHead:(NSDictionary*)head responseData:(NSDictionary *)responseData{
//组建上传内容
    NSMutableDictionary *errorInfo = [NSMutableDictionary dictionary];
    [errorInfo addEntriesFromDictionary:[ErrorRecordModel errorBaseInfoDict]];
    errorInfo[ErrorDeviceInfo] = [ErrorRecordModel errorDeviceInfoDict];
    errorInfo[ErrorAppInfo] = [ErrorRecordModel errorAppInfoDict];
    errorInfo[ErrorUserInfo] = [ErrorRecordModel errorUserInfoDict];
    errorInfo[ErrorLogInfoHttpHeader] = @{@"Logger":@"RZR_IOS_trace"};
    
    // 出现异常的原因 这里的reason 对应到 msg
    
    LogInfoModel *apiErrorInfo = [LogInfoModel new];
    apiErrorInfo.api_response = [responseData mj_JSONString];
    apiErrorInfo.api_url = url;
    //忽略掉上传图片的数据
    if([url containsString:@"mi/Account/Upload"] || [url containsString:@"mi/Account/Upload"] ||
       [url containsString:@"mi/Account/Upload"] ||
       [url containsString:@"mi/provider/ProfileUpload"]){
        apiErrorInfo.api_request = @"image data ingore";
    }
    else{
        apiErrorInfo.api_request = [head mj_JSONString];
    }
    apiErrorInfo.type = @"normal log";
    errorInfo[ErrorLogInfoModel] = apiErrorInfo.mj_keyValues;

//创建路径,存到本地    
    //客户端日志 逐个上传 2 每个异常写到一个文件,文件加上时间戳
    NSDate *localeDate = [NSDate date];
    NSString *timeSp = [NSString stringWithFormat:@"%f", (double)[localeDate timeIntervalSince1970]];
    NSString *fileName = [NSString md5:timeSp];
    NSString *filePath = [NSString stringWithFormat:@"%@.plist",[[ApplicationDelegate businessErrorsPath] stringByAppendingPathComponent:fileName]];
//只有在release情况下,才进行写入
#ifdef RELEASE
    [errorInfo writeToFile:filePath atomically:YES];
#endif
}

}

  1. 上传app的接口错误信息
    例如,可以在app进到前台的时候,调用上传的接口。
    具体:
a. 获取 错误信息存放的路径地址,这个地址文件夹中存放了n多个错误信息的文件。
b. 利用fileManager 从路径文件夹中,获取文件数组,并赋给一个新的数组,方便以下使用。
c. 找出每个错误信息的文件,转换为data,然后再换为上传的内容格式--这里是字典类型。
d. 调用上传接口,上传日志,上传成功后,则在本地移除相关的存储。

针对每个存储错误信息文件的上传:
e.g.

- (void)dealEveryBusinessError{
    if(businessErrorCount > 0 && businessErrorIndex < businessErrorCount){
        NSString *fileName = businessErrorFilesList[businessErrorIndex];
        NSString *currentFilePath = [[self businessErrorsPath] stringByAppendingPathComponent:fileName];
        NSData *fileData = [NSData dataWithContentsOfFile:currentFilePath];
        if(!fileData){
            businessErrorIndex++;
            [self dealEveryBusinessError];
            return;
        }
        NSDictionary *errorDict = [NSDictionary dictionaryWithContentsOfFile:currentFilePath];
        NSFileManager *fileManager = [NSFileManager defaultManager];
        LogResponseFuchsia(@"business currentFilePath:%@,errorDict:%@",currentFilePath,errorDict);
        if(errorDict){
            BaseNetWork *baseWork = [[BaseNetWork alloc] init];
            
            [baseWork sendErrorLogRequestWithUrl:@"https://openapi.*****.com/Log/Log/Write" httpHead:@{@"Logger":@"***_IOS_trace"} parameter:errorDict timeout:30 success:^(id responseData) {
                LogResponseGreen(@"errorDict:%@\n responseData:%@",errorDict,responseData);

                //为了避免占用存储,不管微软日志是否上传成功,只要openApi上传成功就删除日志
                //AZSClient
                [self uploadBlobToContainerWithPath:currentFilePath];
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    [fileManager removeItemAtPath:currentFilePath error:nil];
                });
                businessErrorIndex++;
                [self dealEveryBusinessError];
            } failure:^(NSInteger code, NSString *message) {
                LogResponseRed(@"failure netWork error:%@",message);
                businessErrorIndex++;
                [self dealEveryBusinessError];
            }];
            

        }else{
            businessErrorIndex++;
            [self dealEveryBusinessError];
        }
    
    }else{
        return;
    }
}

  1. 完成操作。
二 . 微软日志
  1. 上传日志:
在上面上传自己公司服务器的上传操作中,在调用上传接口成功后,有一句代码:
[self uploadBlobToContainerWithPath:currentFilePath];这个方法其实就是执行的微软日志上传的操作。
这个微软上传的操作,放在了这里面;在一般的工作中,可以放到自己需要放的位置。

首先看一下:

     
-(void)uploadBlobToContainerWithPath:(NSString *)path{
    
    //将文件读取出来然后append
    NSData *fileData = [NSData dataWithContentsOfFile:path];
    if(!fileData){
        NSLog(@"日志已被删除");
        return;
    }
    
    NSError *accountCreationError;
    // Create a storage account object from a connection string.
    AZSCloudStorageAccount *account = [AZSCloudStorageAccount accountFromConnectionString:[self getAZSClientAccountAndKey] error:&accountCreationError];
    if(accountCreationError){
        NSLog(@"Error in creating account.");
        return;
    }
    
    //以下为两种上传Blob到容器中的操作==========
    
    //-------在容器blobContainer中创建多个blob块,每一次上传成功,作为一个文件-------------
    // Create a blob service client object.
    AZSCloudBlobClient *blobClient = [account getBlobClient];
    
    // Create a local container object.
    AZSCloudBlobContainer *blobContainer = [blobClient containerReferenceFromName:AZSClientRZRContainer];
    
    [blobContainer createContainerIfNotExistsWithAccessType:AZSContainerPublicAccessTypeContainer requestOptions:nil operationContext:nil completionHandler:^(NSError *error, BOOL exists)
     {
         if (error){
             NSLog(@"Error in creating container.");
         }
         else{
             // 格式化时间
             NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
             [formatter setDateFormat:@"yyyyMMdd HH:mm:ss"];
             NSString *dateTime = [formatter stringFromDate:[NSDate date]];
             // Create a local blob object
             AZSCloudBlockBlob *blockBlob = [blobContainer blockBlobReferenceFromName:dateTime];
             
             // Upload blob to Storage
             [blockBlob uploadFromData:fileData completionHandler:^(NSError * _Nonnull nullable) {
                 if (error){
                     NSLog(@"Error in creating blob.");
                 }
             }];
//             [blockBlob uploadFromText:@"This text will be uploaded to Blob Storage." completionHandler:^(NSError *error) {
//                 if (error){
//                     NSLog(@"Error in creating blob.");
//                 }
//             }];
         }
     }];
    
    //-----------在容器blobContainer中,一天只创建一个blob块,blob里面的内容,每次追加,一天只有一个文件--------
//    // Create a blob service client object.
//    AZSCloudBlobClient *blobClient = [account getBlobClient];
//    // Create a local container object.
//    AZSCloudBlobContainer *blobContainer = [blobClient containerReferenceFromName:AZSClientRZRContainer];
//    //服务端创建容器,如果已存在也是返回成功
//    [blobContainer createContainerIfNotExistsWithCompletionHandler:^(NSError * _Nullable error, BOOL exits) {
//        if(error){
//            NSLog(@"创建容器失败");
//            return;
//        }else{
//            // 格式化时间
//            NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
//            [formatter setDateFormat:@"yyyyMMdd"];
//            NSString *dateTime = [formatter stringFromDate:[NSDate date]];
//            //本地blob
//            //日志日期为blob的名字
//            AZSCloudAppendBlob *blob = [blobContainer appendBlobReferenceFromName:dateTime];
//            [blob createIfNotExistsWithCompletionHandler:^(NSError * _Nullable error, BOOL exist) {
//                if(!error){
//                    [blob appendBlockWithData:fileData contentMD5:nil completionHandler:^(NSError * _Nullable error, NSNumber * _Nonnull appendOffset) {
//                        if(!error){
//                            NSLog(@"追加日志成功");
//                        }else{
//                            NSLog(@"追加日志失败");
//                        }
//                    }];
//                }else{
//                    NSLog(@"创建blob失败");
//                }
//            }];
//        }
//    }];
}
  1. 上传的代码都有了,然后一脸懵逼,怎么集成微软sdk呢

微软sdk--相关文档:https://docs.azure.cn/zh-cn/storage/blobs/storage-ios-how-to-use-blob-storage

  1. 在上传中,需要account_name 和account_key, 这个怎么获取呢
- (NSString *)getAZSClientAccountAndKey{
    return [NSString stringWithFormat:@"DefaultEndpointsProtocol=https;AccountName=%@;AccountKey=%@;EndpointSuffix=core.chinacloudapi.cn",AZSClientDFRZLog,AZSClientKey1];
}

a. 打开Microsoft Azure的门户(www.azure.cn ),然后输入账号和密码,登录。
b. 找到存储账号,例如:dfrzlog
c. 点击存储账号,进入,访问密钥,可以看到key.
d.代码中account_name 就是:dfrzlog--这个存储账号;key就是:密钥key值。

  1. 客户端的Microsoft Azure Storage 管理器,可以在文档中,有相关链接获取。
    客户端:


    01.png

门户:


02.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容