Скачать LogPas 1.7 - Writing FrontDoor Style Logs for TP/BP

Скачать файл (16,54 Кб)

This unit implements a Turbo Pascal "Text Device" which formats
output in a form suitable for Opus\Binkley, FrontDoor or D'Bridge
style LOG files. If you find it of use and want to say so (you'd
be the first but still...) I can be reached via Fidonet mail at
2:441/286 or PascalNet 115:4401/1 (Limited hours, no Crash Mail).


Turbo/Borland Pascal versions 4 to 7

You are free to use and adapt this code with the following

1) You MAY NOT use this code in any commercial application or in
   a "Shareware" or any other such application which requests
   payment from the user, without express permission from the
   copyright holder.  Such permission is unlikely to be withheld
   but I shall probably expect a freebi in return!

2) You are free to distribute the original version of this code
   as long as you do not demand payment other than a nominal one
   to cover your costs (such as a BBS registration fee or
   postage) and in any event such a charge is not to exceed 5UKP
   unless it is a BBS Registration fee. Please distribute the
   source code (logdev.pas), the documentation (Logdev.doc) and
   the example program (logtest.pas) together and ensure that the
   distribution file name clearly indicates the version number.
   Preferably as an archive file named LOGPASxx.??? (eg.

3) You MAY NOT distribute altered versions of this code unless
   you distribute them with an altered file name AND with my
   original code included AND with all changes documented (in a
   seperate document). The distributed code MUST retain my
   copyright message and must bear the same restrictions on use
   as the original.

4) Naturally I would be delighted to here from anyone who finds
   this code useful (never have in the past though) and would not
   object at all to being given due credit in any program of
   yours that uses it.

This code is not warranted to do anything except waste space on
your system. If it works, great, if it does not I accept no
responsibliliy for any damage it may do. If you cannot accept
that condition then please do not use LOGDEV.

Of course it works for me, but that may be luck!


*Warning: I wrote the initial LogDev in 1989 planning to release
 it in the near future. Since then it has undergone extensive
 changes. The original documention was written soon after the
 first version of the code and has not always (well alright,
 almost never) been corrected for changes. Until now that is. So
 with the best will in the world (?) it is likely that there are
 still mistakes in it. For these I apologise. Actually the unit
 is quite easy to use so rotten documentation should do little
 harm (who reads it anyway!).

 In fact you could consider it a bonus with free software.  With
 commercial software you have to PAY to get rotten documentation.

This document is broken into the following sections:

        LogDev Usage
        LogDev in use
        Important Notes
        Adding your own log format

No index, find 'em yourself!


This unit implements a Turbo Pascal "Text File Device" which
formats output in a form suitable for Opus\Binkley, FrontDoor or
D'Bridge style LOG files. Assigning a file to this driver makes
it simple for a program to update its log and give users a choice
of log formats.

To use the unit you use the procedure "AssignLog" to assign a
TEXT file to the device, open the file with the normal Turbo
REWRITE or APPEND procedures and then WRITE or WRITELN entries to
the log just as you would to any TEXT file.  LogDev takes care of
forrmatting the entry correctly for your chosen log type and adds
the appropriate date and time stamp to it.

The only change you have to make in your code, once the log is
open, is that you must preceed your entries with a "Level
Number". This, as you will see later, allows you to assign all
log entries a level of importance. Because when you ASSIGN the
log file you also specify the level of entry that is to be
written to the log you can allow users to exclude unimportant
entries. Levels are 1 to 5 with level 1 being the most important
and level 5 being the least (this is based on the Binkley/Opus
log method).

If you assign a log with a level of 3 then only entries with
levels of 3 or below will actually be written to the log, others
will be discarded. To actually assign a level to an entry you
simply preceed it with a number from 1 to 5, for example.
writeln(Log,'1Important: Error ',ErrNum);
  writeln(Log,'5Not important at all!');
which is the same as
s := 'Not Important at all!';
If you do not give an entry a level it will be treated as having level the same level as the previous entry. Only entries that start a new line need to be given a level so that the following has the same effect as the above...
write(Log,#13#10'1Important: Error');    { Start a line }
  writeln(Log,ErrNum);                     { On the same line }
In addition to writing entries to your log file LogDev also echos entries to the console. As with the log you can set a maximum level of entry that is to be echoed when you ASSIGNLOG the log. Entries echoed to the screen are exactly as you wrote them (that is, they do not have the date/time stamp added). You can also ASSIGLOG to stdout with ASSIGNLOG(f,''....) just as you can with Turbo's "Output" file. Then users can redirect log output. A simple method is to AssignLog(Output,''...) so that all WRITE/WRITELN statements that do not specify a file are written via LogDev. This allows you to take an existing program and have all its output formatted by LogDev (though unless you make some changes you loose the ablility to control output levels). However you should NOT echo output to the screen if the primary log is the console and you should not allow users to redirect output if the primary log is a disk file (in case they redirect output to the same file which would lead to a screwed up disk!!!). Normally LogDev's console output goes to the stderr handle to avoid this (stderr is not normally redirectable). Any I/O errors that occur while writing to the log file will be returned as usual in IORESULT. ----------------------------------------------------------------- LogDev in use. ----------------------------------------------------------------- The way it works is this. When assigning a file with AssignLog you specify a "Level". This is the MINIMUM level of log entry that will be allowed. Whenever you WRITE a new line to the log file you preceed the entry with one of the "Entry Levels". IF and only if the entry has a priority greater than or equal to the MINIMUM level you set with ASSIGN then the entry is written to the log otherwise it is ignored. For example
  Logdev_Intro := 'MyProg v1.0';
        { Log file is MYPOG.LOG
        Each entry will be identified by 'MYPRG'
        No entrys below level 3 will be written
        No echo to screen }
  APPEND(Lf);    { Append to existing log if any}
  IF IORESULT <> 0 THEN REWRITE(Lf); { else new log }
  WRITELN(Lf,'1A Serious error');  { WILL go to log }
  WRITELN(Lf,'4Progress report');  { will NOT as < Level 3 }
  WRITELN(Lf,'5Booring info');     { will NOT as < Level 3 }
What happens if the Level Number is missing from the start of a new line? well there are two possibilities. Normally the line will be treated as though it had actually had the same level as the preceeding entry. However the CONSTant "LogDev_AssumeLastFlag" may be set FALSE by your program and in this case any line lacking a flag assumes level 5. Eg.
{ Starts with AssumeLastFlag TRUE }
  Logdev_Intro := 'MyProg v1.0';
          { Log Level 1, only priority 1 messages ('!','*')
            will be seen }
  APPEND(Lf);    { Append to existing log if any}
  WRITELN(Lf,'1Eeek, an Error,(Code: ',ErrorCode,')');
  WRITELN(lf,'Oh dear, a second error')
  WRITELN('Oh dear, another error');
          { Now this line assumes the same flag as the
            previous line, "!" with priority 1,
            and will be written to the log.
  { Log looks like this
  + 01 Jan 00:10:01 MPRG Begin, MyProg V1.0
  ! 01 Jan 00:10:01 MPRG Eeek, an error (Code 102)
  ! 01 Jan 00:10:02 MPRG Oh dear, a second error
  ! 01 Jan 00:10:03 MPRG And a third error }
  AssumeLastFlag := FALSE;
  WRITELN(Lf,'1Eeek, an Error (Code: ',ErrorCode,')');
  WRITELN(lf,'Oh dear, a second error')
  WRITELN(lf,'1And a third error');
        { The second line will default to priority
          5 and will not be added to the log}
  { Log looks like this
  ! 01 Jan 00:10:01 MPRG Eeek, an error (Code 102)
  ! 01 Jan 00:10:03 MPRG And a third error }
If you need to change the logs priority level after opening the file you can call "SetLogLevel" Eg:
Or you can totally ignore the level of entries and have everything go into the log by setting "LogDev_IgnoreLevel := TRUE" * You cannot change the level of a log created with an original level of ZERO because in this case no file was ever actually created. Level ZERO exists only so that you can give users the option to switch logging off completely (or perhaps just keep that which is echoed to the screen). Echoing output to the screen. Messages with flag levels >= "ScreenLevel" will be written to the screen using STDERR (DOS Handle 2). Only your own text will be written, the flag, date, time and progID added when writing to the log are NOT sent to the screen. STDERR is used because it is not (normally) redirectable. You can make this screen output go to other standard devices by changing the interface CONST LogDev_ScreenHandle. Default is 2 (STDERR) but you may change it to 1 (STDOUT), 3 (STDAUX) or 4 (STDPRN) DO NOT use the screen facility if you are assigning the log file to STDOUT (by using a null file name - see below) as the output will be garbled. NEVER use Screen output to STDOUT if assigning the log file also to STDOUT (ditto see below) because this will corrupt your disk if the user redirects STDOUT to a file (DOS and your program both open, write to, and close the same file!!). Assigning to STDOUT. This is exactly the same as with Turbo's ASSIGN. If you AssignLog and give a null file name the file is linked to STDOUT and the user is able to redirect. ENSURE that, if output is echoed to the screen it goes to STDERR (the default). Best not to use echo at all because if the user does NOT redirect STDOUT they will get garbage on the screen as every character is displayed twice! ----------------------------------------------------------------- Adding your own log format ----------------------------------------------------------------- There are no special facilities in the code to allow you to add your own log format, however it is not hard to do. 1) Add a new type to the LogTypes (INTERFACE block) type LogTypes = (Binkley,FrontDoor,DBridge,MineOwn); ^^^^^ 2) Add a set of flags to be used if you want them (IMPLEMENTATION) BinkleyFlags = '!+:# '; FrontDoorFlags = ' '; DBridgeFlags = ' '; MineOwnFlags = '12345'; 3) To the CASE Ltyp OF in function LogDateString add code to return your desired date format (or use the existing one). 4) To the CASE LType OF in function Stamp add code to return your desired log entry stamp. This function returns the date/time stamp that preceeds log entries, for instance for Binkley style logs it returns something like '01 May 04:52:34' 5) Add code to CASE LogType OF in Procedure LogNewLine to set string "S" to the text required to start a new entry on the log. This might consist of a flag and a time stamp appropriately formatted. So for Binkley style logs S is set to '+ 01 May 01:45:56 PROGID ' If you are using flag characters the one you want can be found in FlagChars[LastFlag], Function Stamp amended above provides the appropriate form of time stamp. 6) In Function LogOpen is a CASE Params(UserData).LogType OF which adds any automatic entries to a newly opened log. If you want to do this add your own code to do it. Note that for Binkley style logs the variable Mode (part of a TextRec) is used to determine if the file was opened by an APPEND call (Mode = fminout) so as to add a blank line to an existing log. 7) If you are using flag characters add code to the CASE LogType OF in procedure AssignLog. You must set FlagChars equal to your flag characters defined earlier. 8) If you want to do anything special when CLOSEing a log add code to Procedure LogClose (see the example used by Binkley log type). That should about do it. Note though that I have not actually tested the above suggestions (should be right though).