公司服务器错误日志 & 微软日志 上传
一. 公司服务器错误日志
简介
上传自己公司的服务器,需要的流程大概为:
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的信息中得到。
- 既然要上传错误日志内容,当然需要得到这个错误信息
获取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
}
}
- 上传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;
}
}
- 完成操作。
二 . 微软日志
- 上传日志:
在上面上传自己公司服务器的上传操作中,在调用上传接口成功后,有一句代码:
[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失败");
// }
// }];
// }
// }];
}
- 上传的代码都有了,然后一脸懵逼,怎么集成微软sdk呢
微软sdk--相关文档:https://docs.azure.cn/zh-cn/storage/blobs/storage-ios-how-to-use-blob-storage
- 在上传中,需要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值。
-
客户端的Microsoft Azure Storage 管理器,可以在文档中,有相关链接获取。
客户端:
门户: