SCADA系统的日志模块设计

日志模块是被频繁反复制作的轮子之一。即使了有了log4cpplog4C等,新的日志库仍不断出现。但与这些复杂的模块相比,很多时候仍只愿意用printfSCADA系统是一种实时系统,日志仅用来在异常情况下分析问题,如果在保证实时性的同时加一些调试手段,是设计日志模块的初衷。

 

一、约束

日志模块不属于核心模块,对于现有的SCADA系统,如果增加了日志模块,不能影响的是:

1) 效率:增加日志后,系统的处理效率不至于有明显的下降;系统部分时间敏感的处理过程不应受影响

2) 安全:不能因为增加日志导致某些未知的错误,日志处理应越简单越好。

 

可以想象,现有的程序中或多或少已经有些一些日志处理,比如printf或者输出到文件。应可方便的从已有的日志处理切换到新的统一日志模块,以减少阻力。

3) 调用简单:日志接口使用应符合使用习惯。不应有过多的初始化、清理等过程。简单的一行函数调用即可。

 

此外,由于系统的特性,还必须做到:

4) 多进程/多线程处理:由于是平台公用的日志模块,因此必须支持多进程/多线程处理。

5) 异常时的日志保存:SCADA系统的日志极多,正常情况下,只保存高级别的日志即可;但在异常情况下,如进程异常退出,应能保存这一时间内的全部日志,以供分析。

 

二、设计

1. 共享内存的引入

一个简单的日志函数可能如下:

int DebugLog( char* format , ... );

调用这个函数后,实际输入的信息包括:

1) 日志等级:常用的日志分级一般包括TRACEDEBUGINFOWARNERRORFATALDebugLog意即属于DEBUG级别。

2) 日志分类:上述函数未对日志进行分类,可以认为是采用了默认的分类。分类用来区别不同的进程或者进程内的不同处理。

3) 日志内容:format

4) 附加信息:__FILE____LINE__等。

在调用该函数后,一般进行的处理如下:

1)  格式化日志内容

2)  附加当前时标

3)  输出,比如到文件,控制台,syslog,或者网络分发等。

在以上处理过程中,日志的输出占用较多的资源。因此我们希望,能将日志的输入和输出分开,即接口调用者(应用程序)只管日志的生成,而日志服务负责日志的存储和显示。两者之间通过共享内存进行通讯,如下图。


对于日志接口而已,只是把日志格式化、附加时标并输出到共享内存中。

 

2. 共享内存的设计

在日志处理中当然不希望有锁的存在。频繁的获取锁或释放锁,可能会占用大部分时间;但又很难实现一个完全无锁的日志模块。因此我们希望折衷处理。我们把日志共享内存分成许多段,这样在写入日志时,可针对某个共享内存段进行加锁,而不是针对全部共享内存加锁。段与段之间互不影响。

每个内存段都是一块循环日志缓冲区,可以保持固定条数的日志(比如,1万条),遵循FIFO原则。如果日志写入的速度高于日志存储服务的存储速度,是会造成日志的遗失。但我们可以通过以下方式来预防该问题的出现:

1)内存段可保存日志的条目数只能在编译前设定,或者在配置文件中设定。对于某段时间内某个内存段日志条目不够用的情况,可以增加二级缓存。

2) 每个日志分类均有一个显示等级,一个保存等级。只有不低于显示等级或不低于保存等级的日志才需要进共享内存。这样在日志显示界面不启动的情况下,一般只有WARN等级的日志才会输出。

 

3. 内存段分配的竞争机制

每个内存段可以供一个日志分类或多个日志分类使用;而应用程序所能使用的日志分类数量也是不限制的。理论上如果分配的内存段足够多,达到每个日志分类占用一个内存段,而每个线程使用一个日志分类的话,就会类似于无锁。但是,有以下问题导致无法实现:

1) 进程的开发和日志模块应该尽量的解耦,有哪些日志分类预先是不知道的;

2) 某些进程才是偶尔运行,分配一个内存段太奢侈了;

3) 日志分类个数会相当多,内存不是无限;

因此,需要一种分配机制,在日志分类较少的情况下,每个分类一个内存段;在日志分类较多的情况下,一段时间内日志数量较少的分类共用内存段;某个分类较长时间内无日志产生,可回收该分类占用的日志段。


当某个应用程序启动时,初始化时主动申请内存段,如果存在未使用的内存段则使用之,如果没有未使用的内存段,则使用内存段零。当然,这些都封装在接口中,调用者并不用关心这些问题。

日志存储服务进程定时对内存段的分配进行调度,调度依据为对每个分类某一时间内的日志数量n,每个分类上次输入日志的时间t

最终达到如下效果:

1)当内存段个数>=当前运行的日志分类,每个日志分类均具备独立的内存段;

2)当内存段个数<当前运行的日志分类,由一段时间内日志数量较少的分类占用同一个内存段。

3)日志存储服务和应用进程的先后启动是没有影响的。

 

4. 日志存储服务

日志存储服务作为一个7X24小时运行的进程,主要用来调节内存段的分配,并进行日志的保存。日志的保存可以有多种方式,比如:

1)STDOUTSTDERR

2)文件,固定大小或按日保存

3)SyslogUnix)和事件日志(Windows

4)分发到其他网络服务

5)……

此外,也可以定时检测某些进程是否存在,如果进程退出则把该进程相关分类的日志保存下来。


5. 日志显示及设置界面

一个简单的界面,用来设置日志分类的显示等级,并显示当前的日志。同时也可以用来进行一些配置,如保存等级的设置。

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值