当前位置 博文首页 > 流浪若相惜的专栏:日志文件设计学习(一)

    流浪若相惜的专栏:日志文件设计学习(一)

    作者:[db:作者] 时间:2021-08-01 08:38

    日志的设计
    首先说明, 这里的日志, 是指用于的调试,查错的系统日志, 而不是应用日志。
    应用日志可以看作是产品功能的一部分, 因为他会被用户使用。 比如帐户的明细。
    系统日志是调试和维护程序非常有用的工具。因为经常会被用到, 所以我总结了一下日志设计时的一些经验。
    首先, 对日志的需求:
    1. 日志接口必须尽量简单,比如java 中的Log.log(Object ob)。不要throw 任何exception, 因为日志不因对程序的运行逻辑产生任何影响,
    因此, 返回值也是不需要的
    2. 日志作为程序的最底层模块, 必须是最可靠, 依赖性最小, 以保证在任何环境中, 在系统运行在任何状态时都能产生日志供程序员查看。
    3. 为了提高performance, 日志模块的所有接口的实现都应该是异步的,并且使用cache, 避免日志的I/O操作占用主程序的运行时间
    ?如果eable cache, 日志接口被调用时,都只是被写进cache, 另外有一个线程负责定时把cache刷新到文件
    ?该线程每隔一定时间查看cache满足下列两个条件之一的话就flush cache
    ?1. cache里有日志内容, 并且长度超过了设定的cache的最大值.
    ?2. cache里有内容, 但是没有超过cache max size, 但是已经超过了一定时间没有flush cache了, 这时也要刷新cache,
    ?这是为了不让日志被cache太长时间,从而用户无法从文件中看到最后的日志(这是新的feature, 再也不用担心一定要手工flush日志了, 呵呵)

    4。 为了灵活性,日志应分成log, event, warning, error, trace, 每一种都可以被单独关闭和打开。对于trace, 还有一个level作为参数,如果trace的level
    低于系统运行的level, 则被记录, 否则不被记录。系统运行时的trace level应该在系统启动时从配置文件中载入。
    5。 为了增加日志的可用性。日志模块在写日志时应该自动输出时间,日志类型, 级别,线程ID, 发生该日志的文件, 行号,类名(java可以)和函数名(java和gcc可以)。
    例如:
    2005-04-14 15:58:51.477 [trace-100 CXI] thread:SAPEngine_Application_Thread[impl:3]_4?? enter(com.sap.aci.lom.cxi.CXIHandler.handleRequest(CXIHandler.java:25))
    2005-04-14 15:58:51.487 [log CXI]?????? thread:SAPEngine_Application_Thread[impl:3]_4?? username=Administrator(com.sap.aci.lom.cxi.CXIHandler.handleRequest(CXIHandler.java:35))
    2005-04-12 15:32:23.211 [error SolMgrCon]?????? thread:SAPEngine_System_Thread[impl:5]_56?????? com.sap.mw.jco.JCO$Exception: (101) RFC_ERROR_PROGRAM: 'ashost' is missing^M
    ****stack***^M
    com.sap.mw.jco.JCO$Exception: (101) RFC_ERROR_PROGRAM: 'ashost' is missing^M
    com.sap.mw.jco.MiddlewareJRfc.generateJCoException(MiddlewareJRfc.java:413)^M
    com.sap.mw.jco.MiddlewareJRfc$Client.connect(MiddlewareJRfc.java:823)^M
    com.sap.mw.jco.JCO$Client.connect(JCO.java:2923)^M
    com.sap.mw.jco.JCO$Pool.initPool(JCO.java:4380)^M
    com.sap.mw.jco.JCO$PoolManager.getClient(JCO.java:5758)^M
    com.sap.mw.jco.JCO$PoolManager.getClient(JCO.java:5713)^M
    com.sap.mw.jco.JCO.getClient(JCO.java:7995)^M
    com.sap.mw.jco.JCO$Repository.queryFunctionInterface(JCO.java:19517)^M
    com.sap.mw.jco.JCO$Repository.getFunctionInterface(JCO.java:19641)^M
    com.sap.mw.jco.JCO$BasicRepository.getFunctionTemplate(JCO.java:18709)^M
    com.sap.aci.lom.SolManConnect.Messenger.createFunction(Messenger.java:178)^M
    com.sap.aci.lom.SolManConnect.Messenger.RegisterACPage(Messenger.java:292)^M
    com.sap.aci.lom.SolManConnect.Messenger.RegisterACPage(Messenger.java:329)^M
    com.sap.aci.lom.SolManConnect.SolManConnect.initialize(SolManConnect.java:56)^M
    com.sap.aci.lom.Lom.Init(Lom.java:61)^M
    com.sap.aci.DAL.ACCService.containerStarted(ACCService.java:340)^M
    com.sap.engine.core.service630.container.ContainerEventListenerWrapper.processEvent(ContainerEventListenerWrapper.java:141)^M
    com.sap.engine.core.service630.container.ContainerEventListenerWrapper.run(ContainerEventListenerWrapper.java:101)^M
    com.sap.engine.frame.core.thread.Task.run(Task.java:60)^M
    com.sap.engine.core.thread.impl5.SingleThread.execute(SingleThread.java:73)^M
    com.sap.engine.core.thread.impl5.SingleThread.run(SingleThread.java:145)^M
    ^M
    ****end of stack***^M
    (com.sap.aci.base.log.Log.error(Log.java:112))^M
    6。当系统有很多模块组成时, 日志的接口可以提供模块名称作为参数, 把不同的模块产生的日志写到不同的文件中。这样可以方便调试单个模块。
    7. 日志模块可以提供一些utility的方法, 比如getStack, WriteToFile供用户使用。
    8。日志文件最好以日期区分, 比如ACC-20050102.LOG, ACC-20050103.LOG
    9. 日志模块的设置和行为可以在运行时被改变, 比如是否使用cache, 日志文件的路径, 日志的级别等等。
    10. 注意日志模块关闭时停止cache的管理线程。

    cs