📄 audit.pas
字号:
//
// Thread safe method of recording messages in an audit file.
//
// To disable the audit, simply create the object with no filename (an
// empty string)
//
// (c) Chicony Software 2001
//
// When Who Why
// --------- --- ------------------------------------------------------------
// 2001.6.7 century Initial version
//
unit audit;
interface
uses windows, sysutils, classes, filectrl, syncobjs, dbtables,
// Prexim modules
dbfuncs, reqint, utils;
//
// Events that can be audited
// See Audit method
//
type
AUDIT_TYPES = (
AUDIT_OPEN, // Audit file opened
AUDIT_CLOSE, // Audit file closed
AUDIT_ACTIVE, // Server active
AUDIT_SHUTDOWN, // Server shutdown activated
AUDIT_MANUAL_SHUTDOWN, // Manual server shutdown activated
AUDIT_REQUEST, // Database request
AUDIT_DBTRAN_ROLLBACK, // Rollback of database transaction
AUDIT_DBTRAN_COMMIT // Commit of database transaction
);
type
TPreximAudit = class
private
g_AuditFileCrit: TCriticalSection; // For controlling access
g_AuditFile: TFileStream; // Audit log file
procedure p_OpenAuditFile(var audit_file: TFileStream; filename: String);
public
function Audit(audit_type: AUDIT_TYPES;
user, location: String;
request: REQUEST_TYPES=REQUEST_NOT_VALID;
request_handle: String='';
query: TPreximQuery=nil): boolean;
constructor Create(audit_file: String);
destructor Free;
end;
implementation
//=============================================================================
//
// Class creator
//
// For example: g_Audit:=TPreximAudit.Create('C:\PXM_LOGS\DatabaseServer.Audit');
//
// Note that the audit file will be prefixed by the current date. In the above
// example the audit file would actually be:
// C:\PXM_LOGS\19980131_DatabaseServer.Audit
// if the current date was 31st Jan 1998
//
// Args: audit filename (full path - empty string to not use an audit file)
//
constructor TPreximAudit.Create(audit_file: String);
begin
// Initialise
g_AuditFileCrit:=nil;
g_AuditFile:=nil;
// Create & open the audit file
if audit_file<>'' then begin
g_AuditFileCrit:=TCriticalSection.Create;
p_OpenAuditFile(g_AuditFile, audit_file);
end;
// Continue with creation of object
inherited Create;
end;
//
// Class destructor - closes audit file
//
destructor TPreximAudit.Free;
begin
// Record in audit file
Audit(AUDIT_CLOSE, '', '');
// Free memory & resources used
try
if g_AuditFile<>nil then g_AuditFile.Free;
if g_AuditFileCrit<>nil then g_AuditFileCrit.Free;
except
// Ignore
end;
end;
//
// Open/create an audit file for appending
//
// The filename is treated as a suffix. The current date will be placed
// before the filename, e.g.
//
// e.g. 'C:\PXMLOGS\CSAUDIT.TXT' will become 'C:\PXMLOGS\19981231_CSAUDIT.TXT'
//
procedure TPreximAudit.p_OpenAuditFile(var audit_file: TFileStream; filename: String);
var fdir, fname, newfname: String;
year, month, day: Word;
begin
// Create directory
try
ForceDirectories(ExtractFileDir(filename));
except
// Ignore
end;
try
fdir:=ExtractFileDir(filename);
fname:=ExtractFileName(filename);
// Modify filename
DecodeDate(Now, year, month, day);
if fdir<>'' then FmtStr(newfname, '%s\%.4d%.2d%.2d_%s', [fdir, year, month, day, fname])
else FmtStr(newfname, '%.4d%.2d%.2d_%s', [year, month, day, fname]);
except
raise;
end;
// Open audit file
try
// Do we need to create the audit file?
if not FileExists(newfname) then begin
g_AuditFile:=TFileStream.Create(newfname, fmCreate);
g_AuditFile.Free;
Sleep(100);
end;
// (Re)-open file
g_AuditFile:=TFileStream.Create(newfname, fmOpenWrite + fmShareDenyWrite);
g_AuditFile.Seek(0, soFromEnd);
self.Audit(AUDIT_OPEN, '', '');
except on E:Exception do begin
// Failed to open file
raise;
end;
end;
end;
//
// Record an audit message
//
// Args: audit event to record, e.g. AUDIT_SHUTDOWN
// user we are auditing
// location of user we are auditing
// request (optional)
// request handle (optional)
// database query (optional)
//
// Returns TRUE on success
//
function TPreximAudit.Audit(audit_type: AUDIT_TYPES;
user, location: String;
request: REQUEST_TYPES;
request_handle: String;
query: TPreximQuery): boolean;
var pfx_msg: string;
str, field_type: integer;
begin
// Is there an audit file?
if g_AuditFile=nil then begin
Result:=FALSE;
Exit;
end;
// Construct complete messages
pfx_msg:='"'+DateTimeToStr(now)+'",'+
'"'+IntToStr(Integer(audit_type))+'",'+
'"'+IntToStr(Integer(request))+'",'+
'"'+request_handle+'",'+
'"'+user+'",'+
'"'+location+'"';
// Optional SQL statement & parameters
if (query<>nil) and (query.SQLCount > 0) then begin
// SQL Statement
pfx_msg:=pfx_msg + ',"' + IntToStr(query.SQLCount) + '"';
for str:=0 to query.SQLCount - 1 do
pfx_msg:=pfx_msg + ',"' + query.SQLStrings(str) + '"';
// Parameters
if query.ParamsCount > 0 then begin
pfx_msg:=pfx_msg + ',"' + IntToStr(query.ParamsCount) + '"';
for str:=0 to query.ParamsCount - 1 do begin
// Parameter name
pfx_msg:=pfx_msg + ',"' + query.ParamName(str) + '"';
// Parameter type
field_type:=Integer(query.ParamDataType(str));
if query.ParamIsNull(str) then field_type:=0;
pfx_msg:=pfx_msg + ',"' + IntToStr(field_type) + '"';
// Parameter value
pfx_msg:=pfx_msg + ',"' + query.ParamText(str) + '"';
end;
end else
// No parameters (zero query count, no query string, zero
// parameter count, no parameter name, zero parameter type, no
// parameter value
pfx_msg:=pfx_msg + ',"0","","0","","0",""';
end;
// Dump to audit file
g_AuditFileCrit.Acquire;
try
g_AuditFile.WriteBuffer(PChar(pfx_msg+#13+#10)^, Length(pfx_msg)+2);
FlushFileBuffers(g_AuditFile.Handle);
finally
g_AuditFileCrit.Release;
end;
Result:=True;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -