Внедрить поточно-безопасное ведение журнала - PullRequest
5 голосов
/ 15 ноября 2011

Моя задача - создать класс, который будет собирать активность пользователей вокруг нескольких приложений.

Допустим, у меня есть класс TLogging и глобальный объект с именем Logging.

Действия пользователя (открытие экрана и т. Д.) Должны быть собраны в памяти (возможно, помещены в (строковый) список TLogging) и сохранены в файле журнала через некоторый интервал времени (каждые 10 минут), или когда Приложение закрыто.

Наиболее важным является то, что ведение журнала должно осуществляться в «тихом режиме», оно никоим образом не должно влиять на рабочий процесс пользователя: без зависания экрана, без исключений.

Пожалуйста, дайте мне направление для этой задачи.

Ответы [ 2 ]

15 голосов
/ 15 ноября 2011

Это очень широкий вопрос, который касается нескольких областей.Несколько советов:

  • По крайней мере, рассмотрите для этого установленную структуру ведения журнала.Более новые версии Delphi поставляются с CodeSite . SmartInspect - другая альтернатива.

  • Используйте примитивы синхронизации, чтобы сделать ваш класс потокобезопасным: TCriticalSection , TMREWSync

  • Убедитесь, что вы понимаете проблемы, связанные с многопоточностью и синхронизацией, прежде чем пытаться написать многопоточную среду ведения журналов.Хорошее начало - руководство Мартина Харви Многопоточность - путь Delphi .

  • Используйте фоновый поток, который регулярно выгружает содержимое журнала на диск или, если имеется достаточно данныхбыл буферизован.

  • Задайте более конкретные вопросы здесь, на SO, если у вас возникнут конкретные проблемы.

3 голосов
/ 15 ноября 2011

Используя 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;

(Отказ от ответственности: "Он компилируется на моем компьютере", в противном случае не проверено.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...