我的任务是创建一个用于围绕多个应用程序收集用户活动的类。
假设我有一个类TLogging
和一个名为Logging
的全局对象。
应该在内存中收集用户活动(屏幕打开等等)(可能放入TLogging
的(字符串)列表)并在一段时间间隔(每10分钟)后保存到日志文件中,或申请被关闭时。
最重要的是,日志记录必须处于“静默模式”,它不得以任何方式影响用户工作流程:没有屏幕挂起,没有例外。
请告诉我这项任务的方向。
答案 0 :(得分:15)
这是一个涉及多个领域的非常广泛的问题。一些提示:
至少考虑一个既定的日志框架。较新的Delphi版本附带CodeSite。 SmartInspect是另一种选择。
使用同步原语使您的类具有线程安全性:TCriticalSection,TMREWSync
在尝试编写线程安全日志记录框架之前,请确保您了解多线程和同步中涉及的问题。一个好的开始是Martin Harvey的指南Multithreading - The Delphi Way。
使用后台线程定期将日志内容刷新到磁盘,或者缓冲了足够的数据。
如果您遇到特定问题,请在此处提出更具体的问题。
答案 1 :(得分:3)
使用OmniThreadLibrary并假设Logging对象是单例,这非常简单。我还会限制等待写入的最大消息数,以便内部队列不会占用太多内存。
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;
(免责声明:“它在我的机器上编译”,否则未经测试。)