log.pas

来自「详细说明:毕业论文中关于小型宾馆管理系统的详细设计毕 业论文中关于小型宾馆...」· PAS 代码 · 共 338 行

PAS
338
字号
//
// Thread safe method of recording messages in a log file. Error messages can
// optionally be recorded in the Event Log on an NT server (can be a remote
// server)
//
// If the filenames are empty strings ('') then no log files are created
// or written to
//                     
// (c) Chicony Software 20001
//
unit log;

interface

uses windows, sysutils, classes, filectrl, syncobjs;

const RECENT_MESSAGES_COUNT = 50;       // Number of recent messages stored in
                                        // g_RecentMessages and g_RecentErrors

type
  TPodmsLog = class
  private
    g_LogFileCrit: TCriticalSection;    // For controlling access
    g_ErrLogFileCrit: TCriticalSection; // For controlling access

    g_LogFile: TFileStream;             // Log file (for non-error messages)
    g_ErrLogFile: TFileStream;          // Log file for error messages

    g_RecentMessages: TStringList;      // Recent messages
    g_RecentErrors: TStringList;        // Recent error messages

    g_use_eventlog: Boolean;            // If TRUE then error messages are
                                        // recorded in an NT Servers event log
    g_h_elog: HWND;                     // Event log handle

    procedure p_OpenLogFile(var logfile: TFileStream; filename: String);
  public
    function LogMessage(const msg: string; const obj: TObject=nil): boolean;
    function LogErrMessage(const thefunc, msg: string; const err: integer=0; const obj: TObject=nil): boolean;
    procedure RecentMessages(var message_list, error_list: TStringList); overload;
    procedure RecentMessages(var message_list, error_list: OleVariant); overload;
    constructor Create(nt_server, el_name, logfile, errlogfile: String);
    destructor Free;
  end;

implementation

//=============================================================================

//
// Class creator
//
// For example: g_LogFiles:=TPodmsLog.Create('', 'PodmsDS',
//                                            'C:\PXM_LOGS\DS_LOG.TXT',
//                                            'C:\PXM_LOGS\DS_ERRLOG.TXT);
//
// Note that the log files will be prefixed by the current date. In the above
// example the error log would actually be C:\PXM_LOGS\19980131_DS_ERRLOG.TXT
// if the current date was 31st Jan 1998
//
// Args: UNC name of NT server to record events on (empty string for local)
//       name of event log application (empty string not to use event log)
//       log filename (empty string not to use a log file)
//       error log filename (empty string not to use an error log log)
//
constructor TPodmsLog.Create(nt_server, el_name, logfile, errlogfile: String);
begin
   // Initialise
   g_LogFileCrit:=nil;
   g_ErrLogFileCrit:=nil;
   g_LogFile:=nil;
   g_ErrLogFile:=nil;

   g_RecentMessages:=TStringList.Create;
   g_RecentErrors:=TStringList.Create;

   // Create & open the log file
   g_LogFileCrit:=TCriticalSection.Create;
   if logfile<>'' then p_OpenLogFile(g_LogFile, logfile);

   // Create & open the error log file
   g_ErrLogFileCrit:=TCriticalSection.Create;
   if errlogfile<>'' then p_OpenLogFile(g_ErrLogFile, errlogfile);

   try
      // Open NT event
      if el_name='' then
         // Do not record to event log
         g_use_eventlog:=FALSE
      else begin
         // Record to event log
         if nt_server='' then g_h_elog:=RegisterEventSource(nil, PChar(el_name))
         else g_h_elog:=RegisterEventSource(PChar(nt_server), PChar(el_name));

         if g_h_elog<1 then g_use_eventlog:=FALSE
         else g_use_eventlog:=TRUE;
      end;
   except on E:Exception do begin
         // Cannot use event log
         g_use_eventlog:=FALSE;
         LogErrMessage('LOG', 'Exception raised opening event log:'+E.Message, 0);
      end;
   end;

   // Continue with creation of object
   inherited Create;
end;

//
// Class destructor - closes log files
//
destructor TPodmsLog.Free;
begin
   // Record in log file
   LogMessage('CLOSING LOG');
   //LogErrMessage('LOG', 'CLOSING LOG', 0);

   try
      // Close event log
      if g_use_eventlog then DeregisterEventSource(g_h_elog);
   except
      // Ignore
   end;

   // Free memory & resources used
   try
      g_LogFile.Free;
      g_RecentMessages.Free;
      g_LogFileCrit.Free;

      g_ErrLogFile.Free;
      g_RecentErrors.Free;
      g_ErrLogFileCrit.Free;
   except
      // Ignore
   end;
   g_LogFile:=nil;
   g_ErrLogFile:=nil;
   g_LogFileCrit:=nil;
   g_ErrLogFileCrit:=nil;
   g_RecentMessages:=nil;
   g_RecentErrors:=nil;
end;

//
// Open/create a log 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\CSLOG.TXT' will become 'C:\PXMLOGS\19981231_CSLOG.TXT'
//
procedure TPodmsLog.p_OpenLogFile(var logfile: TFileStream; filename: String);
var line, 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 log file
     try
        // Do we need to create the log file?
        if not FileExists(newfname) then begin
           LogFile:=TFileStream.Create(newfname, fmCreate);
           LogFile.Free;
           Sleep(100);
        end;

        // (Re)-open file
        LogFile:=TFileStream.Create(newfname, fmOpenWrite + fmShareDenyWrite);
        LogFile.Seek(0, soFromEnd);
        line:=DateTimeToStr(now)+'=OPENING LOG '+newfname+#13+#10;
        LogFile.WriteBuffer(PChar(line)^, Length(line));
        FlushFileBuffers(LogFile.Handle);
     except on E:Exception do begin
            // Failed to open file
            raise;
        end;
     end;
end;

//
// Log a message (not an error, just information)
//
// Args: message to record
//       current class (optional), e.g. self 
//
// Returns TRUE on success
//
function TPodmsLog.LogMessage(const msg: string; const obj: TObject): boolean;
var pfx_msg: string;
begin
     // Construct complete messages
     pfx_msg:=DateTimeToStr(now)+'=';
     if obj<>nil then pfx_msg:=pfx_msg+'['+obj.ClassName+'],';
     pfx_msg:=pfx_msg + msg;

     // Dump to log file
     g_LogFileCrit.Acquire;
     try
        // Add to recent messages
        g_RecentMessages.Add(pfx_msg);
        if g_RecentMessages.Count > RECENT_MESSAGES_COUNT then
           g_RecentMessages.Delete(0);

        // Add to file
        if g_LogFile<>nil then begin
           g_LogFile.WriteBuffer(PChar(pfx_msg+#13+#10)^, Length(pfx_msg)+2);
           FlushFileBuffers(g_LogFile.Handle);
        end;
     finally
        g_LogFileCrit.Release;
     end;
     Result:=True;
end;

//
// Log an error message
//
// Args: the name of the function that failed, e.g. procedure name
//       error message to record
//       error value (optional), e.g. -1
//       current class (optional), e.g. self
//
// NOTE: If enabled, error messages are recorded to the event log
//
// Returns TRUE on success
//
function TPodmsLog.LogErrMessage(const thefunc, msg: string;
         const err: integer; const obj: TObject): boolean;
var pfx_msg: string;
begin
     // Save to event log (if enabled)
     if g_use_eventlog then begin
        try
           if obj<>nil then pfx_msg:=obj.ClassName+'.' else pfx_msg:='';
           pfx_msg:=pfx_msg + thefunc + ',Err#' + IntToStr(err);
           ReportEvent(g_h_elog, EVENTLOG_ERROR_TYPE, 0, 0, nil, 1, Length(pfx_msg), PChar(@msg), PChar(pfx_msg));
        except
           // Ignore
        end;
     end;

     // Construct complete messages
     pfx_msg:=DateTimeToStr(now)+' ';
     if obj<>nil then pfx_msg:=pfx_msg + obj.ClassName+'.';
     pfx_msg:=pfx_msg + thefunc + '(Err#' + IntToStr(err)+ '):' + msg;

     // Dump to error log file
     g_ErrLogFileCrit.Acquire;
     try
        // Add to recent messages
        g_RecentErrors.Add(pfx_msg);
        if g_RecentErrors.Count > RECENT_MESSAGES_COUNT then
           g_RecentErrors.Delete(0);

        // Add to file
        if g_ErrLogFile<>nil then begin
           g_ErrLogFile.WriteBuffer(PChar(pfx_msg+#13+#10)^, Length(pfx_msg)+2);
           FlushFileBuffers(g_ErrLogFile.Handle);
        end;
     finally
        g_ErrLogFileCrit.Release;
     end;
     Result:=True;
end;

//
// Return the most recent messages recorded. This works even if there is no
// messages file.
//
// Args: message_list is filled with the most recent messages
//       error_list if filled with the most recent error messages
//
procedure TPodmsLog.RecentMessages(var message_list, error_list: TStringList);
begin
     g_LogFileCrit.Acquire;
     try
        message_list:=g_RecentMessages;
        error_list:=g_RecentErrors;
     finally
        g_LogFileCrit.Release;
     end;
end;

//
// Return the most recent messages and error messages recorded. This works even
// if there is no message and/or error messages file.
//
// Args: message_list is filled with the most recent messages
//       error_list if filled with the most recent error messages
//
procedure TPodmsLog.RecentMessages(var message_list, error_list: OleVariant);
var ml, el: TStringList;
    i: Integer;
begin
     // Initialise
     message_list:=Unassigned;
     error_list:=Unassigned;

     // Quickly grab a list of the messages
     g_LogFileCrit.Acquire;
     try
        ml:=g_RecentMessages;
        el:=g_RecentErrors;
     finally
        g_LogFileCrit.Release;
     end;

     // Now copy them to an OLE variant
     if ml.Count > 0 then begin
        message_list:=VarArrayCreate([0, ml.Count - 1], varOLEStr);
        for i:=0 to ml.Count - 1 do message_list[i]:=ml[i];
     end;
     if el.Count > 0 then begin
        error_list:=VarArrayCreate([0, el.Count - 1], varOLEStr);
        for i:=0 to el.Count - 1 do error_list[i]:=el[i];
     end;
end;

end.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?