自定义同步日志系统

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 自定义同步日志系统

每个应用都是顺序执行的,在时间序列上都是串行的,每个具体应用在某个时刻只能有一个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天前
|
存储 安全 Java
Spring Boot 3 集成Spring AOP实现系统日志记录
本文介绍了如何在Spring Boot 3中集成Spring AOP实现系统日志记录功能。通过定义`SysLog`注解和配置相应的AOP切面,可以在方法执行前后自动记录日志信息,包括操作的开始时间、结束时间、请求参数、返回结果、异常信息等,并将这些信息保存到数据库中。此外,还使用了`ThreadLocal`变量来存储每个线程独立的日志数据,确保线程安全。文中还展示了项目实战中的部分代码片段,以及基于Spring Boot 3 + Vue 3构建的快速开发框架的简介与内置功能列表。此框架结合了当前主流技术栈,提供了用户管理、权限控制、接口文档自动生成等多项实用特性。
21 8
|
9天前
|
JSON 安全 API
.net 自定义日志类
在.NET中,创建自定义日志类有助于更好地管理日志信息。示例展示了如何创建、配置和使用日志记录功能,包括写入日志文件、设置日志级别、格式化消息等。注意事项涵盖时间戳、日志级别、JSON序列化、线程安全、日志格式、文件处理及示例使用。请根据需求调整代码。
33 13
|
1月前
|
存储 数据采集 监控
阿里云DTS踩坑经验分享系列|SLS同步至ClickHouse集群
作为强大的日志服务引擎,SLS 积累了用户海量的数据。为了实现数据的自由流通,DTS 开发了以 SLS 为源的数据同步插件。目前,该插件已经支持将数据从 SLS 同步到 ClickHouse。通过这条高效的同步链路,客户不仅能够利用 SLS 卓越的数据采集和处理能力,还能够充分发挥 ClickHouse 在数据分析和查询性能方面的优势,帮助企业显著提高数据查询速度,同时有效降低存储成本,从而在数据驱动决策和资源优化配置上取得更大成效。
133 9
|
1月前
|
存储 监控 安全
什么是事件日志管理系统?事件日志管理系统有哪些用处?
事件日志管理系统是IT安全的重要工具,用于集中收集、分析和解释来自组织IT基础设施各组件的事件日志,如防火墙、路由器、交换机等,帮助提升网络安全、实现主动威胁检测和促进合规性。系统支持多种日志类型,包括Windows事件日志、Syslog日志和应用程序日志,通过实时监测、告警及可视化分析,为企业提供强大的安全保障。然而,实施过程中也面临数据量大、日志管理和分析复杂等挑战。EventLog Analyzer作为一款高效工具,不仅提供实时监测与告警、可视化分析和报告功能,还支持多种合规性报告,帮助企业克服挑战,提升网络安全水平。
|
2月前
|
存储 Linux Docker
centos系统清理docker日志文件
通过以上方法,可以有效清理和管理CentOS系统中的Docker日志文件,防止日志文件占用过多磁盘空间。选择合适的方法取决于具体的应用场景和需求,可以结合手动清理、logrotate和调整日志驱动等多种方式,确保系统的高效运行。
200 2
|
2月前
|
JSON Java 数据库
SpringBoot项目使用AOP及自定义注解保存操作日志
SpringBoot项目使用AOP及自定义注解保存操作日志
56 1
|
3月前
|
XML JSON 监控
告别简陋:Java日志系统的最佳实践
【10月更文挑战第19天】 在Java开发中,`System.out.println()` 是最基本的输出方法,但它在实际项目中往往被认为是不专业和不足够的。本文将探讨为什么在现代Java应用中应该避免使用 `System.out.println()`,并介绍几种更先进的日志解决方案。
83 1
|
3月前
|
监控 网络协议 安全
Linux系统日志管理
Linux系统日志管理
69 3
|
3月前
|
监控 应用服务中间件 网络安全
#637481#基于django和neo4j的日志分析系统
#637481#基于django和neo4j的日志分析系统
49 4
|
3月前
|
SQL 存储 关系型数据库
Mysql主从同步 清理二进制日志的技巧
Mysql主从同步 清理二进制日志的技巧
39 1