Repository navigation
Expand file tree
/
Copy pathLoggerPro.StringsAppender.pas
More file actions
128 lines (115 loc) · 3.88 KB
/
Copy pathLoggerPro.StringsAppender.pas
File metadata and controls
128 lines (115 loc) · 3.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// *************************************************************************** }
//
// LoggerPro
//
// Copyright (c) 2010-2026 Daniele Teti
//
// https://github.com/danieleteti/loggerpro
//
// ***************************************************************************
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// ***************************************************************************
unit LoggerPro.StringsAppender;
{ Appends formatted log items to any TStrings instance (TStringList, TMemo.Lines, etc.)
The TStrings instance is NOT owned by this appender. The caller is
responsible for its lifetime and must ensure it outlives the ILogWriter. }
interface
uses
LoggerPro,
System.Classes;
type
{ @abstract(Appends formatted @link(TLogItem) to a TStrings instance.
Cross-platform: works with TStringList, TMemo.Lines, TRichEdit.Lines, etc.
Default: MaxLogLines = 100, ClearOnStartup = False.) }
TStringsLogAppender = class(TLoggerProAppenderBase)
private
FStrings: TStrings;
FMaxLogLines: Word;
FClearOnStartup: Boolean;
public
{ Default maximum number of log lines retained before oldest is deleted. }
const DEFAULT_MAX_LOG_LINES: Word = 100;
{ aMaxLogLines must be > 0. The TStrings instance is not owned here. }
constructor Create(aStrings: TStrings;
aMaxLogLines: Word = 100;
aClearOnStartup: Boolean = False;
aLogItemRenderer: ILogItemRenderer = nil); reintroduce;
procedure Setup; override;
{ Nils the TStrings reference so any TThread.Queue closures still pending
on the main-thread queue exit safely. Does NOT free the TStrings. }
procedure TearDown; override;
procedure WriteLog(const aLogItem: TLogItem); override;
end;
implementation
uses
System.SysUtils;
{ TStringsLogAppender }
constructor TStringsLogAppender.Create(aStrings: TStrings; aMaxLogLines: Word;
aClearOnStartup: Boolean; aLogItemRenderer: ILogItemRenderer);
begin
if aMaxLogLines = 0 then
raise EArgumentOutOfRangeException.Create('aMaxLogLines must be greater than zero');
inherited Create(aLogItemRenderer);
FStrings := aStrings;
FMaxLogLines := aMaxLogLines;
FClearOnStartup := aClearOnStartup;
end;
procedure TStringsLogAppender.Setup;
begin
inherited;
if FClearOnStartup then
begin
TThread.Synchronize(nil,
procedure
begin
FStrings.Clear;
end);
end;
end;
procedure TStringsLogAppender.TearDown;
begin
// Nil the reference so any TThread.Queue closures still pending on the
// main-thread message queue will safely exit without accessing freed memory.
// The TStrings instance is not owned here and must not be freed.
FStrings := nil;
end;
procedure TStringsLogAppender.WriteLog(const aLogItem: TLogItem);
var
lText: string;
lStrings: TStrings;
begin
// Snapshot the reference: TearDown may nil FStrings concurrently
lStrings := FStrings;
if not Assigned(lStrings) then
Exit;
lText := FormatLog(aLogItem);
TThread.Queue(nil,
procedure
begin
// Re-check: the TStrings may have been freed between WriteLog and execution
if not Assigned(lStrings) then
Exit;
lStrings.BeginUpdate;
try
// Use >= to handle pre-populated lists that already exceed MaxLogLines
while lStrings.Count >= FMaxLogLines do
lStrings.Delete(0);
lStrings.Add(lText);
finally
lStrings.EndUpdate;
end;
end);
end;
end.