2011-11-15 64 views
5

我的任务是创建一个类来收集围绕几个应用程序的用户活动。实现线程安全日志记录

比方说,我有一个类TLogging和一个名为Logging的全局对象。 (可能放入TLogging的(字符串)列表中),并在一定的时间间隔(每10分钟)后保存到日志文件中,或者应用程序在应用程序中收集用户活动(屏幕打开等)关闭了。

最重要的是日志记录必须处于“静默模式”,它不得以任何方式影响用户工作流程:没有屏幕挂起,没有例外。

请给我这个任务的方向。

+2

你把所有这些功能(以及其他功能,例如异常跟踪,方法分析,线程安全或可选的每(我们的OpenSource TSynLog类)(http://blog.synopse.info/post/2011/04/14/Enhanced-logging-in-SynCommons)。对于德尔福5至XE2。包括日志查看器和基于集合的级别(不是一个全局级别,而是一组自定义级别)。 –

+2

@Arnaud这不就是答案吗? – NGLN

+0

另请参阅:[日志和同步](http://stackoverflow.com/questions/659094),[哪个日志库更好?](http://stackoverflow.com/questions/72983)和其他所有[Delphi日志](http://stackoverflow.com/search?q=%5Bdelphi%5D+logging)相关的问答。 – NGLN

回答

14

这是一个涉及多个领域的非常广泛的问题。一些提示:

  • 至少考虑一个建立的日志框架。较新的Delphi版本附带CodeSiteSmartInspect是另一种选择。

  • 使用同步原语,使你的类是线程安全的:TCriticalSectionTMREWSync

  • 确保您了解尝试写一个线程安全的日志框架之前参与了多线程和同步的问题。 Martin Harvey的指导Multithreading - The Delphi Way是一个好的开始。

  • 使用后台线程将日志内容定期刷新到磁盘或缓冲了足够的数据。

  • 如果遇到特定问题,可以在此处询问更具体的问题。

3

使用OmniThreadLibrary并假设记录对象是一个单身人士,这非常简单。我还会限制等待写入的最大消息数量,以便内部队列不能使用太多的内存。

const 
    CMaxMsgCount = 1000; 
    CMaxLogTimeout_ms = 10{min}*60{sec/min}*1000{ms/sec}; 

type 
    TLogging = class 
    strict private 
    FLogMsgCount: IOmniResourceCount; 
    FLogQueue: IOmniBlockingCollection; 
    FWriter: IOmniTaskControl; 
    strict protected 
    procedure Logger(const task: IOmniTask); 
    public 
    constructor Create; 
    destructor Destroy; 
    procedure Log(const msg: string); 
    end; 

var 
    Logging: TLogging; 

constructor TLogging.Create; 
begin 
    FLogMsgCount := CreateResourceCount(CMaxMsgCount); 
    FLogQueue := TOmniBlockingCollection.Create; 
    FWriter := CreateTask(Logger, 'Logger').Run; 
end; 

destructor TLogging.Destroy; 
begin 
    FWriter.Terminate; 
end; 

procedure TLogging.Log(const msg: string); 
begin 
    FLogQueue.Add(msg); 
    FLogMsgCount.Allocate; 
end; 

procedure TLogging.Logger(const task: IOmniTask); 

    procedure Flush; 
    var 
    logData: TOmniValue; 
    begin 
    // open file, possibly with retry 
    while FLogQueue.TryTake(logData) do begin 
     FLogMsgCount.Release; 
     // write logData.AsString 
    end; 
    // close file 
    end; 

begin 
    while DSiWaitForTwoObjects(task.TerminateEvent, FLogMsgCount.Handle, false, CMaxLogTimeout_ms) <> WAIT_OBJECT_0 do 
    Flush; 
    Flush; 
end; 

(声明:“它编译我的机器上”,否则未经考验的。)