1
0
mirror of synced 2024-09-07 21:55:05 +00:00

Added: Category support (breaking change)

Fixed: graphic didn't show up in test Named Pipe client due to TJPEGImage not being referenced
This commit is contained in:
Mark van Renswoude 2014-10-20 12:07:44 +00:00
parent ca47ad3f4e
commit 53220780db
16 changed files with 341 additions and 81 deletions

View File

@ -2,7 +2,9 @@ program X2LogNamedPipeClient;
uses
// FastMM4,
System.Classes,
Vcl.Forms,
Vcl.Imaging.jpeg,
X2Log.Intf,
X2Log.Client.NamedPipe,
X2Log.Observer.MonitorForm;
@ -13,6 +15,9 @@ var
client: IX2LogObservable;
begin
{ To deserialize the graphic, make sure GetClass succeeds }
RegisterClass(TJPEGImage);
ReportMemoryLeaksOnShutdown := True;
Application.Initialize;

View File

@ -228,8 +228,6 @@ object MainForm: TMainForm
Caption = 'Monitor Form Observer'
TabOrder = 0
OnClick = btnMonitorFormClick
ExplicitLeft = 151
ExplicitTop = -6
end
object btnLock: TButton
AlignWithMargins = True
@ -246,7 +244,6 @@ object MainForm: TMainForm
Caption = 'Lock'
TabOrder = 2
OnClick = btnLockClick
ExplicitLeft = 149
end
object btnUnlock: TButton
AlignWithMargins = True
@ -263,7 +260,6 @@ object MainForm: TMainForm
Caption = 'Unlock'
TabOrder = 3
OnClick = btnUnlockClick
ExplicitLeft = 359
end
end
object pcDispatch: TPageControl
@ -337,6 +333,15 @@ object MainForm: TMainForm
Text = 'Hello world!'
OnKeyDown = edtMessageKeyDown
end
object btnCategory: TButton
Left = 416
Top = 39
Width = 101
Height = 21
Caption = 'With category'
TabOrder = 5
OnClick = btnCategoryClick
end
end
object tsException: TTabSheet
Caption = 'Exception'
@ -458,7 +463,7 @@ object MainForm: TMainForm
Left = 552
Top = 176
Bitmap = {
494C01010200140048000C000C00FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
494C01010200140050000C000C00FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
0000000000003600000028000000300000000C00000001002000000000000009
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000

View File

@ -61,6 +61,7 @@ type
lbNamedPipeServers: TListBox;
btnLock: TButton;
btnUnlock: TButton;
btnCategory: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
@ -81,13 +82,14 @@ type
procedure btnBinaryRawByteStringClick(Sender: TObject);
procedure btnGraphicClick(Sender: TObject);
procedure btnNamedPipeRefreshClick(Sender: TObject);
procedure btnCategoryClick(Sender: TObject);
private
FLog: IX2Log;
FEventObserver: IX2LogObserver;
FFileObserver: IX2LogObserver;
FNamedPipeObserver: IX2LogObserver;
protected
procedure DoLog(Sender: TObject; Level: TX2LogLevel; DateTime: TDateTime; const Msg: string; Details: IX2LogDetails);
procedure DoLog(Sender: TObject; Level: TX2LogLevel; DateTime: TDateTime; const Msg, Category: string; Details: IX2LogDetails);
end;
@ -149,13 +151,13 @@ begin
end;
procedure TMainForm.DoLog(Sender: TObject; Level: TX2LogLevel; DateTime: TDateTime; const Msg: string; Details: IX2LogDetails);
procedure TMainForm.DoLog(Sender: TObject; Level: TX2LogLevel; DateTime: TDateTime; const Msg, Category: string; Details: IX2LogDetails);
var
text: string;
logDetailsText: IX2LogDetailsText;
begin
text := GetLogLevelText(Level) + ': ' + Msg;
text := GetLogLevelText(Level) + ': ' + Category + ': ' + Msg;
if Supports(Details, IX2LogDetailsText, logDetailsText) then
text := text + ' (' + logDetailsText.AsString + ')';
@ -183,6 +185,7 @@ begin
end;
end;
procedure TMainForm.btnCloseClick(Sender: TObject);
begin
Close;
@ -243,6 +246,12 @@ begin
end;
procedure TMainForm.btnCategoryClick(Sender: TObject);
begin
FLog.Category('Test').Info(edtMessage.Text);
end;
procedure TMainForm.btnMonitorFormClick(Sender: TObject);
begin
TX2LogObserverMonitorForm.ShowInstance(FLog);

View File

@ -19,8 +19,8 @@ type
destructor Destroy; override;
{ IX2LogBase }
procedure Log(ALevel: TX2LogLevel; const AMessage: string; ADetails: IX2LogDetails = nil); overload; virtual;
procedure Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; ADetails: IX2LogDetails = nil); overload; virtual;
procedure Log(ALevel: TX2LogLevel; const AMessage: string; const ACategory: string = ''; ADetails: IX2LogDetails = nil); overload; virtual;
procedure Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; const ACategory: string = ''; ADetails: IX2LogDetails = nil); overload; virtual;
{ IX2LogObservable }
procedure Attach(AObserver: IX2LogObserver);
@ -64,23 +64,23 @@ begin
end;
procedure TX2LogBaseClient.Log(ALevel: TX2LogLevel; const AMessage: string; ADetails: IX2LogDetails);
procedure TX2LogBaseClient.Log(ALevel: TX2LogLevel; const AMessage, ACategory: string; ADetails: IX2LogDetails);
var
observer: IX2LogObserver;
begin
for observer in Observers do
observer.Log(ALevel, AMessage, ADetails);
observer.Log(ALevel, AMessage, ACategory, ADetails);
end;
procedure TX2LogBaseClient.Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; ADetails: IX2LogDetails);
procedure TX2LogBaseClient.Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage, ACategory: string; ADetails: IX2LogDetails);
var
observer: IX2LogObserver;
begin
for observer in Observers do
observer.Log(ALevel, ADateTime, AMessage, ADetails);
observer.Log(ALevel, ADateTime, AMessage, ACategory, ADetails);
end;
end.

View File

@ -345,6 +345,7 @@ var
detailsSize: Cardinal;
detailsStream: TMemoryStream;
serializer: IX2LogDetailsSerializer;
category: string;
begin
if MessageData.Size > 0 then
@ -365,6 +366,9 @@ begin
end else if headerDiff < 0 then
raise EReadError.Create('Header too small');
{ Category }
category := TStreamUtil.ReadString(MessageData);
{ Message }
msg := TStreamUtil.ReadString(MessageData);
@ -393,7 +397,7 @@ begin
end;
end;
Client.Log(header.Level, header.DateTime, msg, details);
Client.Log(header.Level, header.DateTime, msg, category, details);
except
on E:EReadError do
ClosePipe;

View File

@ -11,6 +11,11 @@ resourcestring
LogLevelWarning = 'Warning';
LogLevelError = 'Error';
LogCategorySeparator = ' - ';
// Note: currently not translatable
LogCategoryDefault = '';
{
X2Log.Observer.LogFile
@ -36,6 +41,7 @@ resourcestring
{ Caption of the columns in the live log view }
LogMonitorFormColumnTime = 'Time';
LogMonitorFormColumnCategory = 'Category';
LogMonitorFormColumnMessage = 'Message';
{ Caption of the toolbar buttons }

View File

@ -24,8 +24,10 @@ type
class procedure SetExceptionStrategy(AStrategy: IX2LogExceptionStrategy);
{ Facade for IX2LogBase }
class procedure Log(ALevel: TX2LogLevel; const AMessage: string; ADetails: IX2LogDetails); overload;
class procedure Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; ADetails: IX2LogDetails); overload;
class procedure Log(ALevel: TX2LogLevel; const AMessage: string; const ACategory: string = ''; ADetails: IX2LogDetails = nil); overload;
class procedure Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; const ACategory: string = ''; ADetails: IX2LogDetails = nil); overload;
class function Category(const ACategory: string): IX2Log;
class procedure Verbose(const AMessage: string; const ADetails: string = '');
class procedure VerboseEx(const AMessage: string; ADetails: IX2LogDetails = nil);
@ -82,15 +84,21 @@ begin
end;
class procedure TX2GlobalLog.Log(ALevel: TX2LogLevel; const AMessage: string; ADetails: IX2LogDetails);
class function TX2GlobalLog.Category(const ACategory: string): IX2Log;
begin
Instance.Log(ALevel, AMessage, ADetails);
Result := Instance.Category(ACategory);
end;
class procedure TX2GlobalLog.Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; ADetails: IX2LogDetails);
class procedure TX2GlobalLog.Log(ALevel: TX2LogLevel; const AMessage, ACategory: string; ADetails: IX2LogDetails);
begin
Instance.Log(ALevel, ADateTime, AMessage, ADetails);
Instance.Log(ALevel, AMessage, ACategory, ADetails);
end;
class procedure TX2GlobalLog.Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage, ACategory: string; ADetails: IX2LogDetails);
begin
Instance.Log(ALevel, ADateTime, AMessage, ACategory, ADetails);
end;

View File

@ -48,8 +48,8 @@ type
{ Logging }
IX2LogBase = interface
['{1949E8DC-6DC5-43DC-B678-55CF8274E79D}']
procedure Log(ALevel: TX2LogLevel; const AMessage: string; ADetails: IX2LogDetails = nil); overload;
procedure Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; ADetails: IX2LogDetails = nil); overload;
procedure Log(ALevel: TX2LogLevel; const AMessage: string; const ACategory: string = ''; ADetails: IX2LogDetails = nil); overload;
procedure Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; const ACategory: string = ''; ADetails: IX2LogDetails = nil); overload;
end;
@ -75,6 +75,8 @@ type
['{A6FF38F9-EDA8-4C76-9C95-2C0317560D78}']
procedure SetExceptionStrategy(AStrategy: IX2LogExceptionStrategy);
function Category(const ACategory: string): IX2Log;
procedure Verbose(const AMessage: string; const ADetails: string = '');
procedure VerboseEx(const AMessage: string; ADetails: IX2LogDetails = nil);
@ -102,6 +104,8 @@ type
{
Payload:
CategoryLength: Cardinal
Category: WideString
MessageLength: Cardinal
Message: WideString
DetailsLength: Cardinal
@ -109,6 +113,7 @@ type
}
end;
TX2LogMessageHeader = TX2LogMessageHeaderV1;
const

View File

@ -15,15 +15,15 @@ type
private
FLogLevels: TX2LogLevels;
protected
procedure DoLog(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; ADetails: IX2LogDetails); virtual; abstract;
procedure DoLog(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage, ACategory: string; ADetails: IX2LogDetails); virtual; abstract;
property LogLevels: TX2LogLevels read FLogLevels;
public
constructor Create(ALogLevels: TX2LogLevels = X2LogLevelsDefault);
{ IX2LogBase }
procedure Log(ALevel: TX2LogLevel; const AMessage: string; ADetails: IX2LogDetails = nil); overload;
procedure Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; ADetails: IX2LogDetails = nil); overload;
procedure Log(ALevel: TX2LogLevel; const AMessage: string; const ACategory: string = ''; ADetails: IX2LogDetails = nil); overload;
procedure Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; const ACategory: string = ''; ADetails: IX2LogDetails = nil); overload;
end;
@ -39,16 +39,16 @@ begin
end;
procedure TX2LogCustomObserver.Log(ALevel: TX2LogLevel; const AMessage: string; ADetails: IX2LogDetails);
procedure TX2LogCustomObserver.Log(ALevel: TX2LogLevel; const AMessage, ACategory: string; ADetails: IX2LogDetails);
begin
Log(ALevel, Now, AMessage, ADetails);
Log(ALevel, Now, AMessage, ACategory, ADetails);
end;
procedure TX2LogCustomObserver.Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; ADetails: IX2LogDetails);
procedure TX2LogCustomObserver.Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage, ACategory: string; ADetails: IX2LogDetails);
begin
if ALevel in LogLevels then
DoLog(ALevel, ADateTime, AMessage, ADetails);
DoLog(ALevel, ADateTime, AMessage, ACategory, ADetails);
end;
end.

View File

@ -20,7 +20,7 @@ type
protected
function CreateWorkerThread: TX2LogObserverWorkerThread; virtual; abstract;
procedure DoLog(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; ADetails: IX2LogDetails); override;
procedure DoLog(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage, ACategory: string; ADetails: IX2LogDetails); override;
property WorkerThread: TX2LogObserverWorkerThread read FWorkerThread;
public
@ -34,9 +34,10 @@ type
FDetails: IX2LogDetails;
FLevel: TX2LogLevel;
FDateTime: TDateTime;
FCategory: string;
FMessage: string;
public
constructor Create(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; ADetails: IX2LogDetails); overload;
constructor Create(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage, ACategory: string; ADetails: IX2LogDetails); overload;
constructor Create(AEntry: TX2LogQueueEntry); overload;
procedure Assign(Source: TPersistent); override;
@ -44,6 +45,7 @@ type
property DateTime: TDateTime read FDateTime;
property Details: IX2LogDetails read FDetails;
property Level: TX2LogLevel read FLevel;
property Category: string read FCategory;
property Message: string read FMessage;
end;
@ -71,7 +73,7 @@ type
constructor Create;
destructor Destroy; override;
procedure Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; ADetails: IX2LogDetails);
procedure Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage, ACategory: string; ADetails: IX2LogDetails);
end;
@ -97,20 +99,21 @@ begin
end;
procedure TX2LogCustomThreadedObserver.DoLog(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; ADetails: IX2LogDetails);
procedure TX2LogCustomThreadedObserver.DoLog(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage, ACategory: string; ADetails: IX2LogDetails);
begin
WorkerThread.Log(ALevel, ADateTime, AMessage, ADetails);
WorkerThread.Log(ALevel, ADateTime, AMessage, ACategory, ADetails);
end;
{ TX2LogQueueEntry }
constructor TX2LogQueueEntry.Create(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; ADetails: IX2LogDetails);
constructor TX2LogQueueEntry.Create(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage, ACategory: string; ADetails: IX2LogDetails);
begin
inherited Create;
FLevel := ALevel;
FDateTime := ADateTime;
FCategory := ACategory;
FMessage := AMessage;
FDetails := ADetails;
end;
@ -135,6 +138,7 @@ begin
FLevel := entrySource.Level;
FDateTime := entrySource.DateTime;
FCategory := entrySource.Category;
FMessage := entrySource.Message;
FDetails := entrySource.Details;
end else
@ -168,11 +172,11 @@ begin
end;
procedure TX2LogObserverWorkerThread.Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; ADetails: IX2LogDetails);
procedure TX2LogObserverWorkerThread.Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage, ACategory: string; ADetails: IX2LogDetails);
begin
TMonitor.Enter(LogQueue);
try
LogQueue.Enqueue(TX2LogQueueEntry.Create(ALevel, ADateTime, AMessage, ADetails));
LogQueue.Enqueue(TX2LogQueueEntry.Create(ALevel, ADateTime, AMessage, ACategory, ADetails));
finally
TMonitor.Exit(LogQueue);
end;

View File

@ -7,7 +7,7 @@ uses
type
TX2LogEvent = procedure(Sender: TObject; Level: TX2LogLevel; DateTime: TDateTime; const Msg: string; Details: IX2LogDetails) of object;
TX2LogEvent = procedure(Sender: TObject; Level: TX2LogLevel; DateTime: TDateTime; const Msg, Category: string; Details: IX2LogDetails) of object;
TX2LogEventObserver = class(TX2LogCustomObserver)
@ -15,7 +15,7 @@ type
FOnLog: TX2LogEvent;
FRunInMainThread: Boolean;
protected
procedure DoLog(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; ADetails: IX2LogDetails); override;
procedure DoLog(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage, ACategory: string; ADetails: IX2LogDetails); override;
public
constructor Create(ALogLevels: TX2LogLevels = X2LogLevelsDefault); overload;
constructor Create(AOnLog: TX2LogEvent; ALogLevels: TX2LogLevels = X2LogLevelsDefault); overload;
@ -48,7 +48,7 @@ begin
end;
procedure TX2LogEventObserver.DoLog(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; ADetails: IX2LogDetails);
procedure TX2LogEventObserver.DoLog(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage, ACategory: string; ADetails: IX2LogDetails);
begin
if Assigned(FOnLog) then
begin
@ -58,10 +58,10 @@ begin
procedure
begin
if Assigned(FOnLog) then
FOnLog(Self, ALevel, ADateTime, AMessage, ADetails);
FOnLog(Self, ALevel, ADateTime, AMessage, ACategory, ADetails);
end);
end else
FOnLog(Self, ALevel, ADateTime, AMessage, ADetails);
FOnLog(Self, ALevel, ADateTime, AMessage, ACategory, ADetails);
end;
end;

View File

@ -19,7 +19,7 @@ object X2LogObserverMonitorForm: TX2LogObserverMonitorForm
PixelsPerInch = 96
TextHeight = 13
object splDetails: TSplitter
Left = 602
Left = 682
Top = 0
Width = 6
Height = 496
@ -29,9 +29,9 @@ object X2LogObserverMonitorForm: TX2LogObserverMonitorForm
ExplicitHeight = 519
end
object pnlDetails: TPanel
Left = 608
Left = 688
Top = 0
Width = 382
Width = 302
Height = 496
Align = alRight
BevelOuter = bvNone
@ -39,7 +39,7 @@ object X2LogObserverMonitorForm: TX2LogObserverMonitorForm
object tbDetails: TToolBar
Left = 0
Top = 0
Width = 382
Width = 302
Height = 22
AutoSize = True
ButtonWidth = 80
@ -76,7 +76,7 @@ object X2LogObserverMonitorForm: TX2LogObserverMonitorForm
object pnlBorder: TPanel
Left = 0
Top = 22
Width = 382
Width = 302
Height = 474
Align = alClient
BevelKind = bkFlat
@ -85,21 +85,21 @@ object X2LogObserverMonitorForm: TX2LogObserverMonitorForm
object hcDetails: THeaderControl
Left = 0
Top = 0
Width = 378
Width = 298
Height = 19
Sections = <
item
AutoSize = True
ImageIndex = -1
Text = 'Details'
Width = 378
Width = 298
end>
NoSizing = True
end
object reDetails: TRichEdit
Left = 0
Top = 19
Width = 378
Width = 298
Height = 451
Align = alClient
BorderStyle = bsNone
@ -118,7 +118,7 @@ object X2LogObserverMonitorForm: TX2LogObserverMonitorForm
object sbDetailsImage: TScrollBox
Left = 0
Top = 19
Width = 378
Width = 298
Height = 451
HorzScrollBar.Tracking = True
VertScrollBar.Tracking = True
@ -141,7 +141,7 @@ object X2LogObserverMonitorForm: TX2LogObserverMonitorForm
object pnlLog: TPanel
Left = 0
Top = 0
Width = 602
Width = 682
Height = 496
Align = alClient
BevelOuter = bvNone
@ -149,10 +149,10 @@ object X2LogObserverMonitorForm: TX2LogObserverMonitorForm
object vstLog: TVirtualStringTree
Left = 0
Top = 22
Width = 602
Width = 682
Height = 474
Align = alClient
Header.AutoSizeIndex = 2
Header.AutoSizeIndex = 3
Header.Font.Charset = DEFAULT_CHARSET
Header.Font.Color = clWindowText
Header.Font.Height = -11
@ -182,14 +182,19 @@ object X2LogObserverMonitorForm: TX2LogObserverMonitorForm
end
item
Position = 2
Width = 428
Width = 150
WideText = 'Category'
end
item
Position = 3
Width = 354
WideText = 'Message'
end>
end
object tbLog: TToolBar
Left = 0
Top = 0
Width = 602
Width = 682
Height = 22
AutoSize = True
ButtonWidth = 67
@ -216,7 +221,7 @@ object X2LogObserverMonitorForm: TX2LogObserverMonitorForm
Left = 116
Top = 0
Width = 46
Height = 13
Height = 22
Caption = ' Filter: '
Layout = tlCenter
end
@ -267,7 +272,7 @@ object X2LogObserverMonitorForm: TX2LogObserverMonitorForm
Left = 448
Top = 48
Bitmap = {
494C01010A004000EC0010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
494C01010A004000F40010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
0000000000003600000028000000400000003000000001002000000000000030
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000

View File

@ -183,8 +183,8 @@ type
procedure Unlock;
{ IX2LogObserver }
procedure Log(ALevel: TX2LogLevel; const AMessage: string; ADetails: IX2LogDetails); overload;
procedure Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; ADetails: IX2LogDetails); overload;
procedure Log(ALevel: TX2LogLevel; const AMessage, ACategory: string; ADetails: IX2LogDetails); overload;
procedure Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage, ACategory: string; ADetails: IX2LogDetails); overload;
property FreeOnClose: Boolean read FFreeOnClose write FFreeOnClose;
property MaxEntries: Cardinal read FMaxEntries write FMaxEntries;
@ -212,10 +212,11 @@ type
Time: TDateTime;
Paused: Boolean;
Level: TX2LogLevel;
Category: string;
Message: string;
Details: IX2LogDetails;
procedure Initialize(APaused: Boolean; ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; ADetails: IX2LogDetails);
procedure Initialize(APaused: Boolean; ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage, ACategory: string; ADetails: IX2LogDetails);
end;
PLogEntryNodeData = ^TLogEntryNodeData;
@ -224,17 +225,19 @@ type
const
ColumnLevel = 0;
ColumnTime = 1;
ColumnMessage = 2;
ColumnCategory = 2;
ColumnMessage = 3;
LevelImageIndex: array[TX2LogLevel] of TImageIndex = (0, 1, 2, 3);
{ TLogEntryNode }
procedure TLogEntryNodeData.Initialize(APaused: Boolean; ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; ADetails: IX2LogDetails);
procedure TLogEntryNodeData.Initialize(APaused: Boolean; ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage, ACategory: string; ADetails: IX2LogDetails);
begin
Self.Time := ADateTime;
Self.Paused := APaused;
Self.Level := ALevel;
Self.Category := ACategory;
Self.Message := AMessage;
Self.Details := ADetails;
end;
@ -345,6 +348,7 @@ begin
vstLog.NodeDataSize := SizeOf(TLogEntryNodeData);
vstLog.Header.Columns[ColumnTime].Text := GetLogResourceString(@LogMonitorFormColumnTime);
vstLog.Header.Columns[ColumnCategory].Text := GetLogResourceString(@LogMonitorFormColumnCategory);
vstLog.Header.Columns[ColumnMessage].Text := GetLogResourceString(@LogMonitorFormColumnMessage);
mmMainFile.Caption := GetLogResourceString(@LogMonitorFormMenuFile);
@ -456,13 +460,13 @@ begin
end;
procedure TX2LogObserverMonitorForm.Log(ALevel: TX2LogLevel; const AMessage: string; ADetails: IX2LogDetails);
procedure TX2LogObserverMonitorForm.Log(ALevel: TX2LogLevel; const AMessage, ACategory: string; ADetails: IX2LogDetails);
begin
Log(ALevel, Now, AMessage, ADetails);
Log(ALevel, Now, AMessage, ACategory, ADetails);
end;
procedure TX2LogObserverMonitorForm.Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; ADetails: IX2LogDetails);
procedure TX2LogObserverMonitorForm.Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage, ACategory: string; ADetails: IX2LogDetails);
var
node: PVirtualNode;
nodeData: PLogEntryNodeData;
@ -486,7 +490,7 @@ begin
{ BeginUpdate causes OnInitNode to be triggered on-demand,
moved Initialize call here }
Initialize(nodeData^);
nodeData^.Initialize(Paused, ALevel, ADateTime, AMessage, ADetails);
nodeData^.Initialize(Paused, ALevel, ADateTime, AMessage, ACategory, ADetails);
vstLog.IsVisible[node] := (not Paused) and (ALevel in VisibleLevels);
@ -762,7 +766,7 @@ begin
for node in vstLog.Nodes do
begin
nodeData := vstLog.GetNodeData(node);
ALog.Log(nodeData^.Level, nodeData^.Time, nodeData^.Message, nodeData^.Details);
ALog.Log(nodeData^.Level, nodeData^.Time, nodeData^.Message, nodeData^.Category, nodeData^.Details);
end;
end;
@ -790,6 +794,9 @@ begin
ColumnTime:
CellText := DateTimeToStr(nodeData^.Time);
ColumnCategory:
CellText := nodeData^.Category;
ColumnMessage:
CellText := nodeData^.Message;
end;

View File

@ -220,6 +220,9 @@ begin
WriteBuffer.WriteBuffer(header, SizeOf(header));
{ Category }
TStreamUtil.WriteString(WriteBuffer, AEntry.Category);
{ Message }
TStreamUtil.WriteString(WriteBuffer, AEntry.Message);

View File

@ -19,6 +19,7 @@ begin
SetLogResourceString(@LogMonitorFormCaption, '%s - Live Log');
SetLogResourceString(@LogMonitorFormColumnTime, 'Tijd');
SetLogResourceString(@LogMonitorFormColumnCategory, 'Categorie');
SetLogResourceString(@LogMonitorFormColumnMessage, 'Melding');
SetLogResourceString(@LogMonitorFormButtonClear, 'Wissen');

222
X2Log.pas
View File

@ -11,10 +11,19 @@ uses
type
TX2Log = class(TX2LogBaseClient, IX2Log)
IX2LogExceptionCategory = interface
['{ED076237-65AA-4B0C-8A25-4A6B28D2F0CB}']
procedure Exception(AException: Exception; const AMessage: string = ''; const ACategory: string = '');
end;
TX2Log = class(TX2LogBaseClient, IX2Log, IX2LogExceptionCategory)
private
FExceptionStrategy: IX2LogExceptionStrategy;
private
protected
{ IX2LogExceptionCategory }
procedure Exception(AException: Exception; const AMessage: string = ''; const ACategory: string = ''); overload;
property ExceptionStrategy: IX2LogExceptionStrategy read FExceptionStrategy;
public
constructor Create;
@ -22,6 +31,49 @@ type
{ IX2Log }
procedure SetExceptionStrategy(AStrategy: IX2LogExceptionStrategy);
function Category(const ACategory: string): IX2Log;
procedure Verbose(const AMessage: string; const ADetails: string = '');
procedure VerboseEx(const AMessage: string; ADetails: IX2LogDetails = nil);
procedure Info(const AMessage: string; const ADetails: string = '');
procedure InfoEx(const AMessage: string; ADetails: IX2LogDetails = nil);
procedure Warning(const AMessage: string; const ADetails: string = '');
procedure WarningEx(const AMessage: string; ADetails: IX2LogDetails = nil);
procedure Error(const AMessage: string; const ADetails: string = '');
procedure ErrorEx(const AMessage: string; ADetails: IX2LogDetails = nil);
procedure Exception(AException: Exception; const AMessage: string = ''); overload;
end;
TX2LogCategoryDecorator = class(TInterfacedObject, IX2Log)
private
FCategoryName: string;
FDecoratedLog: IX2Log;
protected
function GetCategory(const ACategory: string = ''): string;
property CategoryName: string read FCategoryName write FCategoryName;
property DecoratedLog: IX2Log read FDecoratedLog;
public
constructor Create(ADecoratedLog: IX2Log; const ACategory: string);
{ IX2LogBase }
procedure Log(ALevel: TX2LogLevel; const AMessage: string; const ACategory: string = ''; ADetails: IX2LogDetails = nil); overload;
procedure Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage: string; const ACategory: string = ''; ADetails: IX2LogDetails = nil); overload;
{ IX2LogObservable }
procedure Attach(AObserver: IX2LogObserver);
procedure Detach(AObserver: IX2LogObserver);
{ IX2Log }
procedure SetExceptionStrategy(AStrategy: IX2LogExceptionStrategy);
function Category(const ACategory: string): IX2Log;
procedure Verbose(const AMessage: string; const ADetails: string = '');
procedure VerboseEx(const AMessage: string; ADetails: IX2LogDetails = nil);
@ -36,10 +88,12 @@ type
procedure Exception(AException: Exception; const AMessage: string = '');
end;
implementation
uses
X2Log.Constants,
X2Log.Details.Default,
X2Log.Exception.Default;
@ -62,55 +116,67 @@ begin
end;
function TX2Log.Category(const ACategory: string): IX2Log;
begin
Result := TX2LogCategoryDecorator.Create(Self, ACategory);
end;
procedure TX2Log.Verbose(const AMessage, ADetails: string);
begin
Log(TX2LogLevel.Verbose, AMessage, TX2LogStringDetails.CreateIfNotEmpty(ADetails));
Log(TX2LogLevel.Verbose, AMessage, LogCategoryDefault, TX2LogStringDetails.CreateIfNotEmpty(ADetails));
end;
procedure TX2Log.VerboseEx(const AMessage: string; ADetails: IX2LogDetails);
begin
Log(TX2LogLevel.Verbose, AMessage, ADetails);
Log(TX2LogLevel.Verbose, AMessage, LogCategoryDefault, ADetails);
end;
procedure TX2Log.Info(const AMessage, ADetails: string);
begin
Log(TX2LogLevel.Info, AMessage, TX2LogStringDetails.CreateIfNotEmpty(ADetails));
Log(TX2LogLevel.Info, AMessage, LogCategoryDefault, TX2LogStringDetails.CreateIfNotEmpty(ADetails));
end;
procedure TX2Log.InfoEx(const AMessage: string; ADetails: IX2LogDetails);
begin
Log(TX2LogLevel.Info, AMessage, ADetails);
Log(TX2LogLevel.Info, AMessage, LogCategoryDefault, ADetails);
end;
procedure TX2Log.Warning(const AMessage, ADetails: string);
begin
Log(TX2LogLevel.Warning, AMessage, TX2LogStringDetails.CreateIfNotEmpty(ADetails));
Log(TX2LogLevel.Warning, AMessage, LogCategoryDefault, TX2LogStringDetails.CreateIfNotEmpty(ADetails));
end;
procedure TX2Log.WarningEx(const AMessage: string; ADetails: IX2LogDetails);
begin
Log(TX2LogLevel.Warning, AMessage, ADetails);
Log(TX2LogLevel.Warning, AMessage, LogCategoryDefault, ADetails);
end;
procedure TX2Log.Error(const AMessage, ADetails: string);
begin
Log(TX2LogLevel.Error, AMessage, TX2LogStringDetails.CreateIfNotEmpty(ADetails));
Log(TX2LogLevel.Error, AMessage, LogCategoryDefault, TX2LogStringDetails.CreateIfNotEmpty(ADetails));
end;
procedure TX2Log.ErrorEx(const AMessage: string; ADetails: IX2LogDetails);
begin
Log(TX2LogLevel.Error, AMessage, ADetails);
Log(TX2LogLevel.Error, AMessage, LogCategoryDefault, ADetails);
end;
procedure TX2Log.Exception(AException: Exception; const AMessage: string);
begin
Exception(AException, AMessage, LogCategoryDefault);
end;
procedure TX2Log.Exception(AException: Exception; const AMessage, ACategory: string);
var
msg: string;
details: IX2LogDetails;
@ -120,7 +186,139 @@ begin
details := nil;
ExceptionStrategy.Execute(AException, msg, details);
Log(TX2LogLevel.Error, msg, details);
Log(TX2LogLevel.Error, msg, LogCategoryDefault, details);
end;
{ TX2LogCategoryDecorator }
constructor TX2LogCategoryDecorator.Create(ADecoratedLog: IX2Log; const ACategory: string);
begin
inherited Create;
FDecoratedLog := ADecoratedLog;
FCategoryName := ACategory;
end;
procedure TX2LogCategoryDecorator.Log(ALevel: TX2LogLevel; const AMessage, ACategory: string; ADetails: IX2LogDetails);
begin
if Assigned(DecoratedLog) then
DecoratedLog.Log(ALevel, AMessage, GetCategory(ACategory), ADetails);
end;
procedure TX2LogCategoryDecorator.Log(ALevel: TX2LogLevel; ADateTime: TDateTime; const AMessage, ACategory: string; ADetails: IX2LogDetails);
begin
if Assigned(DecoratedLog) then
DecoratedLog.Log(ALevel, AMessage, GetCategory(ACategory), ADetails);
end;
procedure TX2LogCategoryDecorator.Attach(AObserver: IX2LogObserver);
begin
if Assigned(DecoratedLog) then
DecoratedLog.Attach(AObserver);
end;
procedure TX2LogCategoryDecorator.Detach(AObserver: IX2LogObserver);
begin
if Assigned(DecoratedLog) then
DecoratedLog.Detach(AObserver);
end;
procedure TX2LogCategoryDecorator.SetExceptionStrategy(AStrategy: IX2LogExceptionStrategy);
begin
if Assigned(DecoratedLog) then
DecoratedLog.SetExceptionStrategy(AStrategy);
end;
function TX2LogCategoryDecorator.Category(const ACategory: string): IX2Log;
begin
if Assigned(DecoratedLog) then
Result := Self.Create(DecoratedLog, GetCategory(ACategory));
end;
procedure TX2LogCategoryDecorator.Verbose(const AMessage, ADetails: string);
begin
if Assigned(DecoratedLog) then
DecoratedLog.Log(TX2LogLevel.Verbose, AMessage, CategoryName, TX2LogStringDetails.CreateIfNotEmpty(ADetails));
end;
procedure TX2LogCategoryDecorator.VerboseEx(const AMessage: string; ADetails: IX2LogDetails);
begin
if Assigned(DecoratedLog) then
DecoratedLog.Log(TX2LogLevel.Verbose, AMessage, CategoryName, ADetails);
end;
procedure TX2LogCategoryDecorator.Info(const AMessage, ADetails: string);
begin
if Assigned(DecoratedLog) then
DecoratedLog.Log(TX2LogLevel.Info, AMessage, CategoryName, TX2LogStringDetails.CreateIfNotEmpty(ADetails));
end;
procedure TX2LogCategoryDecorator.InfoEx(const AMessage: string; ADetails: IX2LogDetails);
begin
if Assigned(DecoratedLog) then
DecoratedLog.Log(TX2LogLevel.Info, AMessage, CategoryName, ADetails);
end;
procedure TX2LogCategoryDecorator.Warning(const AMessage, ADetails: string);
begin
if Assigned(DecoratedLog) then
DecoratedLog.Log(TX2LogLevel.Warning, AMessage, CategoryName, TX2LogStringDetails.CreateIfNotEmpty(ADetails));
end;
procedure TX2LogCategoryDecorator.WarningEx(const AMessage: string; ADetails: IX2LogDetails);
begin
if Assigned(DecoratedLog) then
DecoratedLog.Log(TX2LogLevel.Warning, AMessage, CategoryName, ADetails);
end;
procedure TX2LogCategoryDecorator.Error(const AMessage, ADetails: string);
begin
if Assigned(DecoratedLog) then
DecoratedLog.Log(TX2LogLevel.Error, AMessage, CategoryName, TX2LogStringDetails.CreateIfNotEmpty(ADetails));
end;
procedure TX2LogCategoryDecorator.ErrorEx(const AMessage: string; ADetails: IX2LogDetails);
begin
if Assigned(DecoratedLog) then
DecoratedLog.Log(TX2LogLevel.Error, AMessage, CategoryName, ADetails);
end;
procedure TX2LogCategoryDecorator.Exception(AException: Exception; const AMessage: string);
var
exceptionCategory: IX2LogExceptionCategory;
begin
if not Assigned(DecoratedLog) then
exit;
if Supports(DecoratedLog, IX2LogExceptionCategory, exceptionCategory) then
exceptionCategory.Exception(AException, AMessage, CategoryName)
else
DecoratedLog.Log(TX2LogLevel.Error, AMessage, CategoryName);
end;
function TX2LogCategoryDecorator.GetCategory(const ACategory: string): string;
begin
Result := CategoryName;
if Length(ACategory) > 0 then
Result := Result + LogCategorySeparator + ACategory;
end;
end.