2011-11-15 91 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; 

(聲明:「它編譯我的機器上」,否則未經考驗的。)