自定义同步日志系统

简介: 自定义同步日志系统

每个应用都是顺序执行的,在时间序列上都是串行的,每个具体应用在某个时刻只能有一个cpu正常处理,就是多线程也遵循cpu时间串行序列,只有时间一个线程调用中断函数(如:sleep)或一个处理事件完成才调度cpu,若调用了中断函数,线程被挂起,释放cpu控制权,仍保留部分自己线程的资源,以便与该线程再次获取到cpu继续后续处理。这就是我理解的多线程原理和普通应用在时间序列上的串行性。

同步处理就是该处理阻塞应用的其它操作,直到处理该应用处理完成;异步处理是起了另外的线程去处理自己的事情,不阻塞应用的其它处理。

同步处理的优缺点:实现简单便于管理,耗电量较少,可以立即看到处理结果,由于阻塞应用,所以处理要简单,处理不能耗费太长时间,否则严重影响系统性能;异步的优点:实现较复杂,因为起线程耗所以电量较大,得到结果不及时,由于不阻塞线程和结果不需要很及时,所以异步处理可以处理很复杂,可以加入相对较费时间的处理(发送邮件,上传文件到服务器等)。

CocoaLumberjack日志系统就是异步处理,所以它可以继续扩充功能,如:把日志以邮件的形式发送,把日志上传服务器。我设计的同步日志系统就是同步处理,同步日志系统最好别加入超耗时的处理(发送邮件,上传文件到服务器等),以免影响应用的性能。由于是同步日志,是影响性能的,快速打印它吃不消,只能进行间隔时间比较久的个别打印。如:拦截到app崩溃可以使用同步日志实时记录下来,若你用CocoaLumberjack等异步日志打印,由于它有延迟,app都挂了不可能记录下崩溃日志的。

异步日志系统CocoaLumberjack的使用见文章:http://blog.csdn.net/jia12216/article/details/44412697 。

简单的同步日志(就是对系统日志函数的NSLog进一步封装)可以只实现控制台日志打印,对系统性能基本没有影响(除非出现在循环里打印大量日志会影响系统性能),由于打印信息较少,它对开发人员同步定位问题有用,对普通的测试人员和其它使用人员帮助不大,稍微强过NSLog。

Macro.h实现代码:

//自定义日志开关
#ifdef DEBUG
static const int g_printLogLevel =  3;   // 仅当  isPrintLog 值大于0的时候才输出日志,关闭日志打印改为0即可
#else
static const int g_printLogLevel =  0;   // 仅当  isPrintLog 值大于0的时候才输出日志,关闭日志打印改为0即可
#endif

#ifndef LogInfo
#define LogInfo(format, ...)            \
{                                       \
if(2 < g_printLogLevel)                 \
{                                   \
NSLog((@"%@.m:%d Info:" format), NSStringFromClass([self class]), __LINE__, ## __VA_ARGS__); \
}                                   \
}
#endif

#ifndef LogDebug
#define LogDebug(format, ...)            \
{                                       \
if(1 < g_printLogLevel)                 \
{                                   \
NSLog((@"%@.m:%d Debug:" format), NSStringFromClass([self class]), __LINE__, ## __VA_ARGS__); \
}                                   \
}
#endif

#ifndef LogError
#define LogError(format, ...)            \
{                                       \
if(0 < g_printLogLevel)                 \
{                                   \
NSLog((@"%@.m:%d Error:" format), NSStringFromClass([self class]), __LINE__, ## __VA_ARGS__); \
}                                   \
}
#endif

PrefixHeader.pch文件

#ifndef MapDemoLocation_PrefixHeader_pch
#define MapDemoLocation_PrefixHeader_pch

#ifdef __OBJC__
#import "Macro.h"
#endif

#endif

使用例子:

LogError(@“LOGERR :%@”, @“TEST”);

自定义4级别同步日志系统实现控制台日志打印,写日志文件,可以指定写的日志文件的最大行数和最多的日志文件个数,超过制定的日志文件个数就删除最早的日志文件并且重新建立一个新的文件,可以自定义release版本是否写日志文件以及何种日志级别需要写日志文件。若功能有百度地图等用到.mm文件打印日志需要修改把Compile Sources As的选项选为Objective-C++(参考文章:http://blog.csdn.net/wangyuchun_799/article/details/7729222)。

WriteLog.h代码:

//
//  WriteLog.h
//  MapDemoLocation
//
//  Created by 郏国上 on 15/6/8.
//  Copyright (c) 2015年 gaos. All rights reserved.
//

#ifndef WriteLog_h
#define WriteLog_h
#define ERR_LOG 1 /* 应用程序无法正常完成操作,比如网络断开,内存分配失败等 */
#define WARN_LOG 2 /* 进入一个异常分支,但并不会引起程序错误 */
#define INFO_LOG 3 /* 日常运行提示信息,比如登录、退出日志 */
#define DEBUG_LOG 4 /* 调试信息,打印比较频繁,打印内容较多的日志 */

#ifndef LOGERR
#define LOGERR(format,...) WriteLog(ERR_LOG,__FUNCTION__,__LINE__,format,##__VA_ARGS__)
#endif

#ifndef LOGWARN
#define LOGWARN(format,...) WriteLog(WARN_LOG,__FUNCTION__,__LINE__,format,##__VA_ARGS__)
#endif

#ifndef LOGINFO
#define LOGINFO(format,...) WriteLog(INFO_LOG,__FUNCTION__,__LINE__,format,##__VA_ARGS__)
#endif

#ifndef LOGDEBUG
#define LOGDEBUG(format,...) WriteLog(DEBUG_LOG,__FUNCTION__,__LINE__,format,##__VA_ARGS__)
#endif

//#ifndef WRITELOGS
//#define WRITELOGS(format,...) WriteFileLog(NSString *string)
//#endif

void WriteLog(int ulErrorLevel, const char *func, int lineNumber, NSString *format, ...);

#endif

WriteLog.m代码:

#import <Foundation/Foundation.h>
#import “WriteLog.h”

NSString getTime(void)
{
NSDateFormatter * formatter = [[NSDateFormatter alloc]init];
[formatter setDateFormat:@“YYYY-MM-dd HH:mm:ss:SSS”];
NSString dateTime = [formatter stringFromDate:[NSDate date]];
return dateTime;
}

void WriteFileLog(NSString format, …)
{
va_list args;
va_start(args, format);
NSString string = [[NSString alloc] initWithFormat:format arguments:args];
va_end(args);
if(!string)
{
return;
}
NSFileManager fm = [NSFileManager defaultManager];
NSString str = nil;
BOOL flag = NO;
NSArray myPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString myDocPath = [myPaths objectAtIndex:0];
NSString* path = [myDocPath stringByAppendingPathComponent:@“Log”];
[fm fileExistsAtPath:path isDirectory:&flag];
NSArray dirarray = nil;
NSString filePath = nil;
NSArray *lines = nil;
NSError error = nil;
NSData data = nil;
NSInteger n = 0, i = 0, m = 0;
NSMutableArray *filesMutableArr = [NSMutableArray array];
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/jia12216/article/details/46425891
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
NSString *app_Name = [infoDictionary objectForKey:@"CFBundleDisplayName"];

if(flag)
{
    //        dirarray = [fm contentsOfDirectoryAtPath:filePath];
    //        FLDDLogDebug(@"%@ ",dirarray);
    dirarray = [fm contentsOfDirectoryAtPath:path error:nil];
    NSLog(@"%@ ",dirarray);
    n = dirarray.count;
    for(i = 0; i < n; i++)
    {
        filePath = [path stringByAppendingPathComponent:dirarray[i]];
        if ([fm fileExistsAtPath:filePath])
        {
            [filesMutableArr addObject:filePath];
        }
        
    }
    m = filesMutableArr.count;
    if(m > g_logFilesCount)
    {
        for(i = m - g_logFilesCount; i > 0; i++)
        {
            filePath = filesMutableArr[m - 1];
            [fm removeItemAtPath:filePath error:nil];
        }
    }
    else if(g_logFilesCount == m)
    {
        filePath = filesMutableArr[m - 1];
        lines = [[NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]
                 componentsSeparatedByString:@"\n"];
        if(lines.count < g_logFileLines)
        {
            data = [NSData dataWithContentsOfFile:filePath];
            str =[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            str = [NSString stringWithFormat:@"%@\n%@",str,string];
            [str writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
        }
        else
        {
            [fm removeItemAtPath:filePath error:nil];
            str = [NSString stringWithFormat:@"%@ %@.text", app_Name, getTime()];
            filePath = [path stringByAppendingPathComponent:str];
            str = string;
            [str writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
        }
    }
    else if(m > 0)
    {
        filePath = filesMutableArr[m - 1];
        //            str =[NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];
        //            str = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
        //            NSLog(@"str :%@", str);
        lines = [[NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]
                 componentsSeparatedByString:@"\n"];
        //            if(lines.count < 65535)
        if(lines.count < g_logFileLines)
        {
            data = [NSData dataWithContentsOfFile:filePath];
            str =[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            str = [NSString stringWithFormat:@"%@\n%@",str,string];
            [str writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
        }
        else
        {
            str = [NSString stringWithFormat:@"%@ %@.text", app_Name, getTime()];
            filePath = [path stringByAppendingPathComponent:str];
            str = string;
            [str writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
        }
        
    }
    else
    {
        str = [NSString stringWithFormat:@"%@ %@.text", app_Name, getTime()];
        filePath = [path stringByAppendingPathComponent:str];
        str = string;
        [str writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
    }
    
    
}
else
{
    BOOL res = [fm createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
    if (res) {
        //            NSLog(@"文件夹创建成功");
        str = [NSString stringWithFormat:@"%@ %@.text", app_Name, getTime()];
        filePath = [path stringByAppendingPathComponent:str];
        str = string;
        //            NSLog(@"filePath :%@", filePath);
        [str writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:&error];
        //            NSLog(@"error :%@", error);
    }
    else
    {
        NSLog(@"文件夹创建失败");
    }
    
}

}

void WriteLog(int ulErrorLevel, const char *func, int lineNumber, NSString *format, …)

{

va_list args;

va_start(args, format);

NSString *string = [[NSString alloc] initWithFormat:format arguments:args];

va_end(args);

NSString *strFormat = [NSString stringWithFormat:@"%@%s, %@%i, %@%@",@"Function: ",func,@"Line: ",lineNumber, @"Format: ",string];

NSString * strModelName = @"文件日志"; //模块名

NSString *strErrorLevel = [[NSString alloc] init];
NSString *str = nil;
switch (ulErrorLevel) {
    case ERR_LOG:
    {
        strErrorLevel = @"Error";
        str = [NSString stringWithFormat:@"ModalName: %@, ErrorLevel: %@, %@.",strModelName, strErrorLevel, strFormat];
        //写该级别日志,注释了就不写该级别日志了日志文件了

// WriteFileLog(str);

break;

}

case WARN_LOG:

{

strErrorLevel = @“Warning”;

str = [NSString stringWithFormat:@“ModalName: %@, ErrorLevel: %@, %@.”,strModelName, strErrorLevel, strFormat];

//写该级别日志,注释了就不写该级别日志了日志文件了

// WriteFileLog(str);

break;

}

case INFO_LOG:

{

strErrorLevel = @“INFO”;

str = [NSString stringWithFormat:@“ModalName: %@, ErrorLevel: %@, %@.”,strModelName, strErrorLevel, strFormat];

//写该级别日志,注释了就不写该级别日志了日志文件了

// WriteFileLog(str);

break;

}

case DEBUG_LOG:

{

strErrorLevel = @“Debug”;

str = [NSString stringWithFormat:@“ModalName: %@, ErrorLevel: %@, %@.”,strModelName, strErrorLevel, strFormat];

//写该级别日志,注释了就不写该级别日志了日志文件了

// WriteFileLog(str);

break;

}

default:

break;

}

str = [NSString stringWithFormat:@"ModalName: %@, ErrorLevel: %@, %@.",strModelName, strErrorLevel, strFormat];
NSLog(@"%@", str);
//打印全部级别日志,注释了就不写日志文件了
WriteFileLog(str);

}

PrefixHeader.pch文件

#ifndef MapDemoLocation_PrefixHeader_pch
#define MapDemoLocation_PrefixHeader_pch

// Include any system framework and library headers here that should be included in all compilation units.
// You will also need to set the Prefix Header build setting of one or more of your targets to reference this file.

#ifdef __OBJC__
#ifdef DEBUG
#import "WriteLog.h"
#else   //若想release版本也想打印日志就把下面12行注释了。
#ifndef LOGERR
#define LOGERR(format,...) {};
#endif
#ifndef LOGWARN
#define LOGWARN(format,...) {};
#endif
#ifndef LOGINFO
#define LOGINFO(format,...) {};
#endif
#ifndef LOGDEBUG
#define LOGDEBUG(format,...) {};
#endif
#endif
#endif
static const long g_logFilesCount = 10;
static const long g_logFileLines = 65535;
#endif

自定义同步日志函数和NSLOG完全相同,只是函数名不同。默认只debug版本写日志(工程的Scheme要是debug模式),release版本是否写日志。使用例子:

LOGERR(@“LOGERR :%@”, @“TEST”);

LOGWARN(@“LOGWARN :%@”, @“TEST”);

LOGINFO(@“LOGINFO :%@”, @“TEST”);

LOGDEBUG(@“LOGDEBUG :%@”, @“TEST”);

为了倒出日志文件需要在Info.plist文件里增加Application supports iTunes file sharing属性,类型是Boolean,值设置为YES(若设置为NO就不可以通过iTunes导出文件了,可以等发布正式版本时设置为NO).

demo的下载地址是:http://download.csdn.net/detail/jia12216/8787079

自定义同步日志文件目录:Log

日志文件的导出:

异步日志CocoaLumberjack文件目录:Log

百度地图位置信息csv格式记录目录:LngLat

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
1月前
|
SQL 关系型数据库 MySQL
我使用flinkcdc的sql形式进行全量同步,4张表,有两张表数据没进去,看日志,id怎么是null呢?
我使用flinkcdc的sql形式进行全量同步,4张表,有两张表数据没进去,看日志,id怎么是null呢?
129 40
|
14天前
|
SQL 数据采集 DataWorks
DataWorks产品使用合集之pyodps的线程限制是什么意思
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
|
14天前
|
DataWorks 数据可视化 安全
DataWorks产品使用合集之SLS日志中新增了存在iotId这个字段,同步的时候怎么手动增加
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
|
1月前
|
SQL Oracle 关系型数据库
实时计算 Flink版产品使用合集之从Oracle数据库同步数据时,checkpoint恢复后无法捕获到任务暂停期间的变更日志,如何处理
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStreamAPI、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
1天前
spdlog 日志库部分源码说明——让你可以自定义的指定自动切换日志时间
spdlog 日志库部分源码说明——让你可以自定义的指定自动切换日志时间
15 7
|
9天前
|
监控 Java Spring
自定义注解+AOP切面日志+源码
自定义注解+AOP切面日志+源码
16 1
|
9天前
|
应用服务中间件 nginx
Nginx 配置,自定义日志格式 log_format
Nginx 配置,自定义日志格式 log_format
20 0
|
13天前
|
SQL 分布式计算 DataWorks
DataWorks产品使用合集之如何同步SLS日志到odps上
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
|
1月前
|
运维 Java Devops
云效产品使用报错问题之自定义环境构建没有日志,也没有报错,如何解决
本合集将整理呈现用户在使用过程中遇到的报错及其对应的解决办法,包括但不限于账户权限设置错误、项目配置不正确、代码提交冲突、构建任务执行失败、测试环境异常、需求流转阻塞等问题。阿里云云效是一站式企业级研发协同和DevOps平台,为企业提供从需求规划、开发、测试、发布到运维、运营的全流程端到端服务和工具支撑,致力于提升企业的研发效能和创新能力。
云效产品使用报错问题之自定义环境构建没有日志,也没有报错,如何解决
|
1月前
|
C++
闪退日志的同步写入文件记录
闪退日志的同步写入文件记录
23 0

热门文章

最新文章