unit logu;{not finished;log logproc}
{$i define.pas}
interface
uses
  {$IFNDEF WINDOWS}
  dos,
  {$ENDIF}
  TVType, MyType, IOType, RTType, LogType,

  ConfType, Confu, Msgu, Dateu, ListType, Listu,
  SysUtils, WinUtl,
  Timer, binhex, stru, mylib, fileu, IOu;


type
  TLogLine = string[160];
  TLogInfo = record
    Time:longint;
    Event:longint;
    Msg:TLogLine;
  end;

  TLogger = class(TObject)
    FileName:string;
    LType:TLogType;

    IO:THIO;
    LastResult:TLogResult;
    LogLine:TLogLine;{buffer for making log string to decrease need of stack}
    Time:TDTO;

    InLogInfo,          {used in Log method}
    OutLogInfo:TLogInfo;{used in LogTask method}

    {$IFDEF RTKERNEL}
    StackSize:TRTStackRange;
    TaskPriority:TRTTaskPriority;
    MailBoxSize:TMBSlotRange;
    MailBox:TRTMailBox;
    TaskHandle:TRTTaskHandle;{handle to TaskLog procedure created for
      this Logger during Create}
    {$ENDIF}
    constructor Create(AFileName:string; ALType:TLogType);
    function LogEvent(ALogEvent:TLogEvent; ATime:TRTDuration; const AMsg:string):TLogResult;
    procedure Log(const s:string);{called by logevent with already formated line
      (without time part); prepends eventual date/time info (according to LType);
      puts logline to MailBox, retrieved by LogTask}
    procedure LogTask;{called from main TaskLog procedure, retrives line
      from MailBox and writes to file}
    destructor Destroy;override;
    function GetFileName:string;
    function Flush:TLogResult;
    function SetProp(lpr:TLogProperty; APValue:pointer):TLogResult;
    procedure ClearResult;
    procedure SetResult(lr:TLogResult);
    procedure RemoveOldFiles(ADaysOld:integer);
  end;
  PLogger = TLogger;

{EXPORT}
{1}function LogsInit:TLogResult;{$IFDEF PMODE}export;{$ENDIF}
  { Initializes LOG - (date/time, log to file) module }
{2}function LogsDone:TLogResult;{$IFDEF PMODE}export;{$ENDIF}
  { Closes all log files, frees all memory allocated for Log module }
{3}function LogsInstalled:boolean;{$IFDEF PMODE}export;{$ENDIF}
  { Returns true if LOG module loaded }
{4}function LogsSetProperty(AProcessID:TProcessID; ALogsProperty:TLogProperty; AValue:pointer):TLogResult;
  {$IFDEF PMODE}export;{$ENDIF}
{5}function LogsGetProperty(AProcessID:TProcessID; ALogsProperty:TLogProperty; var AValue:pointer):TLogResult;
  {$IFDEF PMODE}export;{$ENDIF}

 {*************************************************}
{6}function LogInit(AProcessID:TProcessID; ALogType:TLogType; AFileName:string; var ALogger:PLogger):TLogResult;
{$IFDEF PMODE}export;{$ENDIF}
  { Opens the log file of AFileName and given ALogType,
    filename can be modified according to ALogType (can contain
    day or month info). Copy of common LOG default values
    created for given AProcessID and can be modified by LogsSetProperty. }
{7}function LogEvent(ALogger:PLogger; ALogEvent:TLogEvent; ATime:TRTDuration; const AMsg:string):TLogResult;
{$IFDEF PMODE}export;{$ENDIF}
  { Appends AMsg to the end of ALogger associated file, eventually
    prepends date/time info at the beggining of the AMsg according
    to ALogType of ALogger; if ltEventType is in ALogType and
    ALogEvent is not included in ALogger's  LogEventMask,
    then the call is ignored.
    AEventCode can specified more detailly the event (e.g. error code) }
{8}function LogFlush(ALogger:PLogger):TLogResult;
{$IFDEF PMODE}export;{$ENDIF}
{9}function LogLog(ALogger:PLogger; const AMsg:string):TLogResult;
{$IFDEF PMODE}export;{$ENDIF}
  { Just shorter form of LogEvent without ALogEvent }
{10}function LogSetProp(ALogger:PLogger; ALogProperty:TLogProperty; AValue:pointer):TLogResult;
{$IFDEF PMODE}export;{$ENDIF}
  { Set value of specified property of ALogger }

{11}function LogGetProp(ALogger:PLogger; ALogProperty:TLogProperty; ABufSize:TBufSize;
  var Buf; var AReqBufSize:TBufSize):TLogResult;
{$IFDEF PMODE}export;{$ENDIF}
  { Get value of specified property of ALogger. ABufSize - if = 0 then
    LogGetProp just returns required size for the Buf in AReqBufSize
    otherwise Buf is filled with the wanted property and AReqBufSize
    with number of bytes needed for copying (but max ABufSize bytes
    is really copied)
  }

{12}function LogGetIntProp(ALogger:PLogger; ALogProperty:TLogProperty; var AValue:pointer):TLogResult;
{$IFDEF PMODE}export;{$ENDIF}
  { just shorter form of the previous one, no checks for size of buffer,
    sizeof value wanted < sizeof(longint) then AValue contains the value
    directly otherwise AValue should point to buffer of sufficient size,
    where the value will be copied into
  }

{13}function LogDone(var ALogger:PLogger):TLogResult;
{$IFDEF PMODE}export;{$ENDIF}
(*v0.24 ExeLog component used*)(*/v0.24
{14}procedure SysLogInit;{$IFDEF PMODE}export;{$ENDIF}
{15}procedure SysLogLog(le:TLogEvent; msg:string);{$IFDEF PMODE}export;{$ENDIF}
{procedure SysError(msg:string);{ $IFDEF PMODE}{export;}{ $ENDIF}
{16}procedure SysLogDone;{$IFDEF PMODE}export;{$ENDIF}
*)
{17}procedure PacketLogInit;{$IFDEF PMODE}export;{$ENDIF}
{18}procedure PacketLogLog(msg:string);{$IFDEF PMODE}export;{$ENDIF}
{19}procedure PacketLogDone;{$IFDEF PMODE}export;{$ENDIF}

  { closes the log file associated with ALogger }

{30}procedure LogRegister;{$IFDEF PMODE}export;{$ENDIF}

procedure SysLogWrite(msg:string);{$IFDEF PMODE}export;{$ENDIF}
procedure TaskLog;{$IFDEF PMODE}export;{$ENDIF}
{/EXPORT}

type
  TEventShortName = string[2];

const
  TimeWidth = 5;                     {number of milisecond digits shown}
  DefaultLogDir = 'LOG\';
  LogExt = '.LOG';{logtype}

  RTKernelWindow: boolean = false;   {open rtnewwindow ?}
  FlushAlways: boolean = false;      {hardflush upon every Log?}
  OverwriteLogFiles: boolean = false;{overwrite old logs upon LogInit?}
  DelLogFilesOlderThan: integer = 14;{delete log files every 14 days}

{$IFDEF RTKERNEL}
  UseMailBoxes:byte = 0;             {use MailBoxes for all logfiles to
                                      store log events to log them later
                                      (when there is more cpu time)?
                                      0= use defaults; 1 use mailbox for all
                                      logs, 2 dont use mailboxes at all}
  LogTaskPriority: TRTTaskPriority = 35;
  LogStackSize: TRTStackRange = 8 * 1024;
  LogMailBoxSize: integer = 20;
{$ENDIF}

  LogDir: shortstring = DefaultLogDir;

implementation
uses portlog{for portlogregister}{v0.19},DrvLogu{/v0.19};
{$I-}


const
  CurLogTime:longint = 0;
  CurLogEvent:longint = 0;


  MaxProcesses = 5;

  DefLogParams : TLogParams = (
    {Overwrite:false;}
    LogType:0;
    LogMask:lemAll;{logtype}
    LogDir:'';
    LogName:'LOG';
    LogExt:'.LOG';
    {LogEvent:0;
    Msg:'';
    DT:0;
    {EventCode:0;}
    ProcessID:0;
    LastResult:0
  );
  ProcessParams:array[0..MaxProcesses-1] of PLogParams =
  (nil,nil,nil,nil,nil);


const
  Loggers:TLst = nil;
  CurLogger:PLogger = nil;

  LogDirChecked:boolean = false;

procedure CheckLogDir;
begin
  if LogDirChecked then
    exit;
  LogDirChecked := true;
  if LogDir = DefaultLogDir then
    LogDir := GetExeDir + DefaultLogDir
  else
    LogDir := AddBackSlash(LogDir);
  if not CreateDir(LogDir) then
    LogDir := GetExeDir + DefaultLogDir;
end;

function GetDailyLoggerFileName(AFileName:PathStr; var dt:TDTO):PathStr;
var
  n:namestr;
  d:dirstr;
  e:extstr;
begin
  {AFileName := ReplaceFileNamePart(fpDir, AFileName, LogDir, false);}
  FSplit(FExpand(AFileName), d, n, e);
  n := system.copy(n, 1, 4);
  while (length(n) >= 1) and (n[length(n)] in ['0'..'9']) do begin
    SetLength(n, length(n) - 1);
  end;
  AFileName := d + n + dt.MMDD + e;
  GetDailyLoggerFileName := AFileName;
end;

function GetMonthlyLoggerFileName(AFileName:string; var dt:TDTO):string;
var
  n:namestr;
  d:dirstr;
  e:extstr;
begin
  FSplit(FExpand(AFileName), d, n, e);
  n := system.copy(n, 1, 4);
  while (length(n) >= 1) and (n[length(n)] in ['0'..'9']) do begin
    SetLength(n, length(n) - 1);
  end;
  AFileName := d + n + dt.YYMM{system.copy(dt.YYYYMMDD, 5, 4)} + e;
  GetMonthlyLoggerFileName := AFileName;
end;

function GetEventShortName(ALogEvent:TLogEvent):TEventShortName;
var s:TEventShortName;
begin
  s := '??';
  case LongRec(ALogEvent).Lo of
    leWarning: s:= 'W ';
    leError: s:= 'ER';
    leFatalError: s:= 'FA';
    leUserWarning: s:= 'UW';
    leUserError: s:= 'UE';
    leUserConfirm: s:= 'UC';
    leUserInfo: s:= 'UV';
    leUserAction: s:= 'UA';
    leProgramAction: s:= 'PA';
    leDebug: s:= 'DE';
  end;
  GetEventShortName := s;;
end;

{TLogger}
constructor TLogger.Create(AFileName:string; ALType:TLogType);
var
  d:dirstr;
  n:namestr;
  e:extstr;
  l:longint;

  function IsFileName:boolean;
  begin
    FSplit(FileName, d, n, e);
    if (d = '') and (e = '') and (pos('COM', n) = 1) and (length(n) < 5) then
      IsFileName := false
    else
      IsFileName := true;
  end;

begin
  CheckLogDir;
  inherited Create;
  {Create mem var}
  LType := ALType;
  FileName := AFileName;
  IO := NoHIO;
  LastResult := lrOK;
  LogLine := '';
  Time := TDTO.Create;

  {$IFDEF RTKERNEL}
  StackSize := LogStackSize;
  TaskPriority := LogTaskPriority;
  MailBoxSize:= LogMailBoxSize;
  MailBox := NoMailBox;
  TaskHandle := NoTaskHandle;
  {$ENDIF}

  {UseMailBox := false;}
  {/Create mem var}

  Time.GetSystemTime;
  if IsFileName then begin
    FileName := ReplaceFileNamePart(fpDir, FileName, LogDir, false);
    FileName := ReplaceFileNamePart(fpExt, FileName, LogExt, false);
    if (LType and ltDaily) <> 0 then begin
      FileName := GetDailyLoggerFileName(FileName, Time);
      RemoveOldFiles(DelLogFilesOlderThan);
    end else if (LType and ltMonthly) <> 0 then begin
      FileName := GetMonthlyLoggerFileName(AFileName, Time);
    end;
    if not FExists(GetFileName) then
      CreateFile(GetFileName);
  end;

  if FlushAlways then
    LType := LType or ltFlushAlways;
  if OverwriteLogFiles then
    LType := LType
    or ltOverwrite;
  {$IFDEF RTKERNEL}
  case UseMailBoxes of
    umAll: LType := LType or ltUseMailBox;{logtype}
    umNone: LType := LType and (not ltUseMailBox);
  end;
  {$ENDIF}

  if IOInit(GetFileName, stOpen, IO) <> irOK then
    Fail;

  if (LType and ltFlushAlways) <> 0 then begin
    IOSetProp(IO, ipFlushAlways, @TrueValue);
  end;


  if (LType and ltOverWrite) <> 0 then begin
    IOSetProp(IO, ipTruncate, nil);
  end else begin
    IOGetProp(IO, ipSize, @l);
    IOSetProp(IO, ipPos, @l);
  end;

  Log('*** ' + Time.DateString + ' ' + Time.TimeString + ' logging started. ***');

  {$IFDEF RTKERNEL}
  if (LType and ltUseMailBox) <> 0 then begin
    RTInitMailBox(MailBox, MailBoxSize, sizeof(TLogInfo),
      n + e);
    if MailBox <> NoMailBox then begin
      CurLogger := @Self;
      RTCreateTask(TaskLog, TaskPriority, StackSize, n + e, TaskHandle)
    end;
  end;
  {$ENDIF}
end;

function TLogger.GetFileName:string;
begin
  GetFileName := FileName;{LP.LogDir + LP.LogName + LP.LogExt;}
end;

procedure TLogger.ClearResult;
begin
  LastResult := lrOK;
end;

procedure TLogger.SetResult(lr:TLogResult);
begin
  LastResult := lr;
  if lr <> lrOK then begin
    {v0.24}{/v0.24 SysLogLog(leError, GetFileName + ' Logger error ' + IntToStr(lr));}
  end;
end;

function TLogger.SetProp(lpr:TLogProperty; APValue:pointer):TLogResult;
begin
  ClearResult;
  case lpr of{logtype}
    lpFlushAlways: begin
      if PBoolean(APValue)^ then
        LType := LType or ltFlushAlways
      else
        LType := LType and (not ltFlushAlways);
      SetResult(IOSetProp(IO, ipFlushAlways, APValue));
    end;
    lpFlush: begin
      Flush;
    end;
  else
    SetResult(lrInvalidSetProp);
  end;
  SetProp := LastResult;
end;

function TLogger.Flush:TLogResult;
begin
  SetResult(IOSetProp(IO, ipFlush, nil));{logtype}
  Flush := LastResult;
end;

procedure TLogger.Log(const s:string);
begin
  LogEvent(0, mstime, s);
end;

function TLogger.LogEvent(ALogEvent:TLogEvent; ATime:TRTDuration; const AMsg:string):TLogResult;
begin
  if ATime = 0 then
    ATime := mstime;
  InLogInfo.Event := ALogEvent;
  InLogInfo.Time := ATime;
  InLogInfo.msg := AMsg;
  {$IFDEF RTKERNEL}
  if MailBox <> NoMailBox then
    RTPut(MailBox, InLogInfo)
  else
  {$ENDIF}
  begin
    OutLogInfo := InLogInfo;
    LogTask;
  end;
  LogEvent := lrOK;
end;


procedure TLogger.LogTask;
begin
  {$IFDEF RTKERNEL}
  if MailBox <> NoMailBox then
    RTGet(MailBox, OutLogInfo);
  {$ENDIF}
  Time.GetSystemTime;
  LogLine := '';
  if (LType and ltDate) <> 0 then begin
    LogLine := LogLine + Time.DateString + ' ';
  end;
  if (LType and ltTime) <> 0 then begin
    LogLine := LogLine + Time.TimeString + ' ';
  end;
  if (LType and ltMilisecond) <> 0 then begin
    LogLine := LogLine + right(IntToString(OutLogInfo.Time, 10), TimeWidth) + ' ';
  end;
  if (LType and ltEventType) <> 0 then begin
    if OutLogInfo.Event <> 0 then
      LogLine := LogLine + ' ' + GetEventShortName(OutLogInfo.Event)  + ' '
    else
      LogLine := LogLine + pad('', 2 + sizeof(TEventShortName) - 1);
  end;
  LogLine := LogLine + OutLogInfo.Msg;

  IOWriteLine(IO, LogLine, length(LogLine));

  if (LType and ltFlushAlways) <> 0 then
    Flush;
end;

procedure TLogger.RemoveOldFiles(ADaysOld:integer);
var
  fn:PathStr;
  cnt:integer;
const
  LookBackDays = 10;{improve it later to look just for files in dir
   that match basepath name and check how old they are}
begin
  if ADaysOld = 0 then
    exit;
  Time.GetSystemTime;
  Time.IncDate(incDay, - ADaysOld - 1);
  cnt := 0;
  repeat
    fn := GetDailyLoggerFileName(FileName, Time);
    if FExists(fn) then begin
      EraseFile(fn);
    end;
    Time.IncDate(incDay, -1);
    inc(cnt);
  until cnt = LookBackDays;
end;

destructor TLogger.Destroy;
begin
  {$IFDEF RTKERNEL}
  if TaskHandle <> NoTaskHandle then begin
    RTTerminateTask(TaskHandle);
  end;
  if MailBox <> NoMailBox then begin
    RTDeleteMB(MailBox);
  end;
  {$ENDIF}
  Time.GetSystemTime;
  Log('*** ' + Time.DateString + ' ' + Time.TimeString + ' logging ended.   ***');
  IODone(IO);
  Time.Destroy;
  inherited Destroy;
end;
{/TLogger}

function IsValid(ALogger:PLogger):boolean;
begin
  IsValid := false;
  if (ALogger = nil) or (Loggers = nil) or
    (ListIndexOf(Loggers, ALogger) < 0) then
  begin
    {SysError('Invalid Logger handle - '+ IntToStr(longint(ALogger)));}
    exit;
  end;
  IsValid := true;
end;


function LogsInit:TLogResult;
  { Initializes LOG - (date/time, log to file) module }
begin
  LogsInit := lrOK;
end;

function LogsDone:TLogResult;
  { Closes all log files, frees all memory allocated for Log module }
begin
  LogsDone := lrOK;
end;

function LogsInstalled:boolean;
  { Returns true if LOG module loaded }
begin
  LogsInstalled := true;
end;

function LogsSetProperty(AProcessID:TProcessID; ALogsProperty:TLogProperty; AValue:pointer):TLogResult;
begin
  LogsSetProperty := lrInvalidSetProp;
end;

function LogsGetProperty(AProcessID:TProcessID; ALogsProperty:TLogProperty; var AValue:pointer):TLogResult;
begin
  LogsGetProperty := lrInvalidGetProp;{logtype}
end;

 {*************************************************}

function LogInit(AProcessID:TProcessID; ALogType:TLogType; AFileName:string; var ALogger:PLogger):TLogResult;
  { Opens the log file of AFileName and given ALogType,
    filename can be modified according to ALogType (can contain
    day or month info). Copy of common LOG default values
    created for given AProcessID and can be modified by LogsSetProperty.
  }
var
  res:TLogResult;
  lp:TLogParams;
label ex;
begin
  res := lrInvalidProcessID;

  ALogger := nil;
  if {(AProcessID < 0) or }(AProcessID >= TProcessID(MaxProcesses)) then
    goto ex;

  res := irNotEnoughMemory;
  if ProcessParams[AProcessID] = nil then begin
    New(ProcessParams[AProcessID]);
    if ProcessParams[AProcessID] = nil then begin
      goto ex;
    end;
    ProcessParams[AProcessID]^ := DefLogParams;
  end;

  lp := ProcessParams[AProcessID]^;
  ALogger := TLogger.Create(AFileName, ALogType);

  if ALogger <> nil then begin
    if Loggers = nil then begin
      ListInit(0, NoListInfo, Loggers);
      {Loggers := New(PCollection, Create(10, 5));}
    end;
    if Loggers <> nil then begin
      ListSetPropInt(Loggers, lpCapacity, 10);
      ListAdd(Loggers, ALogger);
      res := lrOK;
    end;
  end;
ex:
  LogInit := res;
end;

function LogEvent(ALogger:PLogger; ALogEvent:TLogEvent; ATime:TRTDuration; const AMsg:string):TLogResult;
  { Appends AMsg to the end of ALogger associated file, eventually
    prepends date/time info at the beggining of the AMsg according
    to ALogType of ALogger; if ltEventType is in ALogType and
    ALogEvent is not included in ALogger's  LogEventMask,
    then the call is ignored.
    AEventCode can specified more detailly the event (e.g. error code)
  }
begin
  LogEvent := lrInvalidLogger;
  if not IsValid(ALogger) then
    exit;
  LogEvent := ALogger.LogEvent(ALogEvent, ATime, AMsg);
end;

function LogFlush(ALogger:PLogger):TLogResult;
begin
  LogFlush := lrInvalidLogger;
  if not IsValid(ALogger) then
    exit;
  LogFlush := ALogger.Flush;
end;

function LogLog(ALogger:PLogger; const AMsg:string):TLogResult;{ghtype}
  { Just shorter form of LogEvent without ALogEvent and AEventCode }
begin
  LogLog := LogEvent(ALogger, CurLogEvent, CurLogTime, AMsg);
end;

function LogSetProp(ALogger:PLogger; ALogProperty:TLogProperty; AValue:pointer):TLogResult;
  { Set value of specified property of ALogger }
begin
  LogSetProp := lrInvalidLogger;
  if IsValid(ALogger) then
    LogSetProp := ALogger.SetProp(ALogProperty, AValue);
end;

function LogGetProp(ALogger:PLogger; ALogProperty:TLogProperty; ABufSize:TBufSize;
  var Buf; var AReqBufSize:TBufSize):TLogResult;
  { Get value of specified property of ALogger }
begin
  LogGetProp := lrInvalidGetProp;
end;

function LogGetIntProp(ALogger:PLogger; ALogProperty:TLogProperty; var AValue:pointer):TLogResult;
  { just shorter form of the previous one, no checks for size of buffer,
    sizeof value wanted < sizeof(longint) then AValue contains the value
    directly otherwise AValue should point to buffer of sufficient size,
    where the value will be copied into
  }
begin
  LogGetIntProp := lrInvalidGetProp;
end;

function LogDone(var ALogger:PLogger):TLogResult;
  { closes the log file associated with ALogger }
begin
  LogDone := lrInvalidLogger;
  if not IsValid(ALogger) then
    exit;
  LogDone := lrOK;
  if Loggers <> nil then begin
    ListRemove(Loggers, ALogger);
    if ListGetPropInt(Loggers, lpCount) = 0 then
      ListDone(Loggers);
  end;
  ClassFree(ALogger);
end;

var
  sout:Text;
const
  sinited:boolean = false;{syslog window inited?}
  syslog:PLogger = nil;
  SysLogName = {'COM2';}'SYS.LOG';
{v0.19}
  UseSysLog: boolean = false;
{/v0.19}

procedure SysLogInit;
begin
  {v0.19}
  if not UseSysLog then
    exit;
  {/v0.19}
  {$IFDEF RTKERNEL}
  if RTKernelWindow then begin
    RTNewWindow(sOut, sOut, 0, 6, 79, 14, BGBlue + White, ' SYSLOG ');
    sinited := true;
  end;
  {$ENDIF}
  LogInit(0, ltSyslog, SysLogName, syslog);
  if syslog <> nil then begin
    SetMsgProc(mtSysError, @SysLogWrite);
  end;
end;

{v0.24}{/v0.24
procedure SysLogLog(le:TLogEvent; msg:string);
begin
  if syslog <> nil then
    SysLog.LogEvent(le, mstime, msg);
end;
}
{$HINTS OFF}
procedure TaskLog;
var
  L:PLogger;
  i:integer;
begin
  L := CurLogger;
  if L = nil then
    exit;
  repeat
    L.LogTask;
    if (L = syslog) and sinited then begin
      {$IFOPT I+} {$DEFINE IOON} {$ENDIF}
      {$I-}
      writeln(sout, L.LogLine);{stru}
      i := ioresult;
      {$IFDEF IOON} {$I+} {$UNDEF IOON} {$ENDIF}
    end;
  until false;
  {RTSignal(LogSem);}
end;
{$HINTS ON}

procedure SysLogWrite(msg:string);
begin
{v0.24}{/v0.24  SysLogLog(leDebug, msg);}
end;

procedure SysLogDone;
begin
  if syslog <> nil then begin
    SetMsgProc(mtSysError, nil);
    LogDone(syslog);
  end;
end;

const
  plog:PLogger = nil;
  PacketLogToSysLog :boolean = true;
  UsePacketLogFile:boolean = false;

procedure PacketLogInit;
begin
  if UsePacketLogFile then
    LogInit(0, ltSyslog, 'PACKET.LOG', plog);
  {RTInitSemaphore(PackSem, Resource, 1, 'PKTLOG');}
end;

procedure PacketLogLog(msg:string);
begin
  if plog <> nil then begin
    plog.LogEvent(CurLogEvent, mstime, msg);
  end;
  if PacketLogToSysLog then
    {v0.24}{/v0.24 SysLogLog(lePacket, msg)};
end;

procedure PacketLogDone;
begin
  LogDone(plog);
end;
{
var
  SavedExit:pointer;

procedure ExitChain;far;
begin
  System.ExitProc := SavedExit;
  ListDone(Loggers);
end;
}
procedure Create;
begin
{  SavedExit := System.ExitProc;
  ExitProc := @ExitChain;}
end;

procedure LogRegister;
begin
  PortLogRegister;
  {v0.19}
  DrvLogRegister;
  AddGlobalVar(LogSec, 'UseSysLog', @UseSysLog, ptByte);
  {/v0.19}
  AddGlobalVar(LogSec, 'RTKernelWindow', @RTKernelWindow, ptByte);
  AddGlobalVar(LogSec, 'FlushAlways', @FlushAlways, ptByte);
  AddGlobalVar(LogSec, 'OverwriteLogFiles', @OverwriteLogFiles, ptByte);
  {$IFDEF RTKERNEL}
  AddGlobalVar(LogSec, 'LogTaskPriority', @LogTaskPriority, ptByte);
  AddGlobalVar(LogSec, 'LogStackSize', @LogStackSize, ptInteger);
  AddGlobalVar(LogSec, 'LogMailBoxSize', @LogMailBoxSize, ptInteger);
  AddGlobalVar(LogSec, 'UseMailBoxes', @UseMailBoxes, ptByte);
  {$ENDIF}
  AddGlobalVar(LogSec, 'PacketLogToSysLog', @PacketLogToSysLog, ptByte);
  AddGlobalVar(LogSec, 'UsePacketLogFile',@UsePacketLogFile, ptByte);
  AddGlobalVar(LogSec, 'DelLogFilesOlderThan', @DelLogFilesOlderThan, ptInteger);
  AddGlobalVar(LogSec, 'LogDir', @LogDir, ptString);
end;


initialization
  Create;
finalization
  ListDone(Loggers);
end.
