Унифицированное логирование событий из потоков в компоненте TMemo в Delphi
В современных приложениях, особенно в многопоточных, важно иметь возможность отслеживать события, происходящие в различных частях программы. Это позволяет разработчикам понимать, как работает приложение, и быстро находить и устранять возможные ошибки. В Delphi, компонент TMemo часто используется для отображения логов.
Проблема
Разработчик столкнулся с необходимостью вывода лог-сообщений из разных потоков в один компонент TMemo на форме. В приложении запущены следующие сервисы:
idHTTPServer с idContext, обрабатывающий запросы;
поток, загружающий обновления из Dropbox;
idUDPServer, отвечающий на UDP-запросы;
еще один поток, занимающийся базой данных;
основной поток приложения, который также должен добавлять логи.
Необходимо создать единый, безопасный в многопоточном доступе способ отображения лог-сообщений в TMemo, чтобы пользователь был в курсе текущих событий в приложении.
Решение
Для решения этой задачи можно использовать подход с использованием потока, который будет собирать все сообщения, добавлять их в очередь и выводить в TMemo при возможности. Важно также обрабатывать исключения и очищать TMemo, если он переполняется.
Пример реализации такого подхода:
TThreadedMsgEvent = class(TThread)
private
FLock: TCriticalSection;
FStr: TQueue<String>;
FMemo: TMemo;
function GetEvent: String;
protected
procedure Execute; override;
public
procedure AddEvent(const AMsg: String);
constructor Create(AMemo: TMemo);
destructor Destroy; override;
end;
procedure TThreadedMsgEvent.AddEvent(const AMsg: String);
begin
FLock.Acquire;
FStr.Enqueue(FormatDateTime('DD/MM/YY HH:NN:SS.ZZZ', Now) + ' : ' + AMsg);
FLock.Release;
end;
constructor TThreadedMsgEvent.Create(AMemo: TMemo);
begin
inherited Create(True);
FreeOnTerminate := False;
FStr := TQueue<String>.Create;
FLock := TCriticalSection.Create;
FMemo := AMemo;
Resume;
end;
destructor TThreadedMsgEvent.Destroy; override;
begin
FStr.Free;
FLock.Free;
inherited;
end;
procedure TThreadedMsgEvent.Execute;
begin
while not Terminated do
begin
try
if (FStr.Count > 0) then
begin
TThread.Synchronize(
procedure
begin
FMemo.Lines.Add(GetEvent);
end
);
end;
except
end;
TThread.Sleep(1);
end;
end;
function TThreadedMsgEvent.GetEvent: String;
begin
FLock.Acquire;
Result := FStr.Dequeue;
FLock.Release;
end;
Альтернативное решение
Используя библиотеку Indy, можно применить класс TIdNotify для безопасного доступа к TMemo из различных потоков. Пример использования:
type
TLog = class(TIdNotify)
protected
FMsg: string;
procedure DoNotify; override;
public
class procedure LogMsg(const AMsg: string);
end;
procedure TLog.DoNotify;
begin
Form1.Memo1.Lines.Add(FMsg);
end;
class procedure TLog.LogMsg(const AMsg: string);
begin
with TLog.Create do
try
FMsg := AMsg;
Notify;
except
Free;
raise;
end;
end;
Вызов TLog.LogMsg('some text message here'); позволит добавить сообщение в лог из любого потока.
Подводные камни
Использование блокирующей очереди с событием, сигнализирующим о доступности элементов, является предпочтительным.
В Delphi 2009 и выше можно использовать статические версии TThread.Synchronize() и TThread.Queue(), что делает использование классов Indy не обязательным.
Заключение
Для унифицированного логирования событий из потоков в Delphi, разработчики могут использовать различные подходы, включая создание специализированного потока для логирования или применение готовых решений из сторонних библиотек, таких как Indy. Выбор метода зависит от конкретных требований проекта и предпочтений разработчика.
Унифицированное логирование событий из разных потоков в компоненте `TMemo` в Delphi для обеспечения единого и безопасного отображения логов в многопоточной среде.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.