home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ARM Club 3
/
TheARMClub_PDCD3.iso
/
hensa
/
internet
/
netplex_2
/
!SysLog
/
!Help
< prev
next >
Wrap
Text File
|
1996-12-15
|
21KB
|
534 lines
============================================================================
SysLog Documentation
----------------------------------------------------------------------------
Version: 0.16
Author: Jon Ribbens <jon@doggysoft.co.uk>
(c) DoggySoft Ltd., 1995, 1996
This program is Freeware and may be freely distributed so long as it is
not charged for, and none of the files are changed or removed. It may be
included with a commercial program which is charged for. There is no
warranty, express or implied. DoggySoft Ltd. is not liable for any loss
or damages caused by the use or misuse of this program.
Things done:
* facility to insert arbitrary line
* considered format of datestamp
* implemented backoff system for errors writing to logs (partly a bugfix)
* fixed bug which left files open on errors (e.g. disk full)
* added Indent/UnIndent/NoIndent
* do 'temporary logs' thingy for Termite session logs
* implement log truncation at specified maximum size
* read <SysLog$Dir> once and once only at startup
* do automatic tidy-up of 'temporary logs'
* fixed bug which corrupted the very last line in the options file
* get allocation for SWI chunk and module name and OS commands
* user options to disable session logs
* added "*" line in options file to specify default values
* reserve disk space option
* make entry point use two-layer task, so RMEnsuring works
* add *SysLog ON|OFF and *SysLog <log> <new priority>
* LogData routine to log a block of hex data (e.g. IP packets)
* add debugf routine for assembler people
* add C front-end for C people
* added SysLog_ReadErrorMessage
* added %<reg>p and %<reg>a to LogFormatted
* fixed order of %<reg>a (it was backwards)
* made log buffer size dependent on logging level
* made log buffer get de-allocated after ten minutes
* added SysLog_LogComplete
* made buffer size be recalculated when log level is changed
* made setting log level also apply to session logs of that log
* fixed tidying up of stray session logs (sometimes missed some)
* fixed a few problems with sessions
* termination of strings is now by zero-byte or carriage return
* add log_forget and call it in CloseSessionLog
To do:
* add expression evaluation to LogFormatted
* add optional checking of pointer validity
* add 'features flags'
============================================================================
Rationale
----------------------------------------------------------------------------
Termite is currently lacking in logging facilities. In fact, most
communications software for the Arc is rather poor at logging. This module
is designed to make it easy for comprehensive logging to be added to any
RISC OS program.
The logging level can be altered by the user for individual log files, and
buffering is used to speed logging, so it is safe for programs to log large
quantities of data, provided that they use sensible priorities for each type
of message. The logs are also automatically kept to user-specified maximum
lengths, so there is no need to worry about filling up the user's hard disk.
Separate log files are used for each application, on the basis that such
segregation of information makes it much easier for the user to find what
they're looking for.
A back-off system is used for dealing with errors when writing to logs. Each
error is logged in the "SysLog" log, and the offending log is marked as
"dead". SysLog will then not attempt to write to that log again for one
second. If we again get an error writing to the log, we multiply the
"back-off" time by 1.5, and again mark the log as dead. The back-off time is
not allowed to grow longer than ten minutes.
============================================================================
Session logs
----------------------------------------------------------------------------
Usually, log entries are stored strictly chronologically. Sometimes, though,
it may be more useful to store them grouped by 'session'. For example,
NewsBite can have several incoming NNTP connections at once. It is nice to
group the log messages that are coming from each separate connection
together. This can be done using SysLog_OpenSessionLog.
SysLog_OpenSessionLog creates a specially-named temporary log file. The log
entries for the session are stored in this log file. When the temporary log
file is closed using SysLog_CloseSessionLog, this data is appended in one
chunk to the end of the main log.
SysLog checks for stray temporary log files when it initialises and
finalises, and appends them to the relevant logs. This copes with the
situation where an application crashes or otherwise exits without calling
SysLog_CloseSessionLog.
============================================================================
Priorities
----------------------------------------------------------------------------
Message priorities can be in the range 0 to 255, with 0 being the highest
priority and 255 being the lowest. Unless otherwise specified by the user,
only messages with priorities of less than 125 are stored in the log files.
You should therefore think about what things the user is likely to want to
have logged by default, and ensure that these things are logged at
a priority of 124 or less.
The priority of errors often depends on how significant the consequences of
the error are, not what the cause of it is. e.g. sometimes "out of memory"
will be an extremely important unrecoverable error (because the program
can't start up), and sometimes it will be unimportant (because the program
can use disk instead, or maybe try again later).
============================================================================
Log names
----------------------------------------------------------------------------
Log names are used as the leafnames to store the logs as, so they must
comply with the rules for RISC OS leafnames. They must also not be longer
than ten characters.
It is intended that each application have its own log, so an obvious choice
for the log name is the application name (without the '!'). Very large
applications could have more than one log file - in which case the naming
scheme is unspecified. Try and choose sensible log names.
If your application is going to be distributed, you should write to
support@doggysoft.co.uk, to request that your log name be formally
allocated. This will hopefully avoid having more than one program using the
same log file.
The following log names are reserved for internal use:
any name beginning with a '-' character
any name beginning with "SysLog"
"Old"
============================================================================
OS commands
----------------------------------------------------------------------------
*SysLog <log name> <priority> <message>
------
Adds a time-stamped message to the log file, if and only if the specified
log file is set up to log messages of this priority. The priority must be in
the range 0-255.
*SysLog <log name> <new priority>
------
Temporarily (but with immediate effect) changes the logging priority of the
specified log. The priority must be in the range 0-256.
*SysLog ON|OFF
------
*SysLog OFF will temporary disable SysLog - all log messages received after
this command is issued will be ignored. *SysLog ON resumes normal operation.
*SysLog_Flush ON|OFF
------------
*SysLog_Flush with no paramaters flushes all currently open log files to
disk. If it used with the parameter 'ON' then it causes all log files to be
flushed immediately after each message is written to them. *SysLog_Flush OFF
disables this behaviour. (This is intended for use when the a program is
being debugged, and keeps crashing the computer. With SysLog_Flush ON,
you're guaranteed that all the log information your program produces before
it crashes will actually be available after a re-boot. It also makes logging
*very slow*.)
============================================================================
SWIs
----------------------------------------------------------------------------
SysLog_LogMessage (&4C880)
-----------------
R0-> log name, or = session log handle
R1-> text to log
R2 = priority
Adds a time-stamped message to the log file, if and only if the specified
log file is set up to log messages of this priority. The text to log must
not be longer than 1024 bytes. The priority must be in the range 0-255.
SysLog_GetLogLevel (&4C881)
------------------
R0-> log name, or = session log handle
exit:
R0 = priority
Reads the logging level for the specified log. Messages of *less than* the
returned priority are being logged. This can be used to avoid creation of
logging information that is only going to be discarded by SysLog_LogMessage
anyway. In some cases it could even be used to decide which version of
a program to load (e.g. whether to load a debugging version of TermiteIP).
SysLog_FlushLog (&4C882)
---------------
R0-> log name, or = session log handle, or = 0 to flush all logs
Ensures the specified log (or all logs) are fully written to disk, and the
files closed. This can be useful to make sure that the user is immediately
able to read data that has just been written to the log.
SysLog_SetLogLevel (&4C883)
------------------
R0-> log name, or = session log handle
R1 = new logging level
Sets the logging level for the specified log. This SWI is provided for
debugging and internal use only, and SHOULD NOT BE USED in distribution
code. The logging level is the user's decision, not the programmer's.
SysLog_LogUnstamped (&4C884)
-------------------
R0-> log name, or = session log handle
R1-> text to log
R2 = priority
Adds a message to the log file, if and only if the specified log file is set
to log messages of this priority. The text to log must not be longer than
1024 bytes. The priority must be in the range 0-255. It is recommended that
you use SysLog_LogMessage for all normal log entries.
SysLog_Indent (&4C885)
-------------
R0-> log name, or = session log handle
Increments the log indent level. In log lines generated by
SysLog_LogMessage, there are <indent_level + 1> spaces in between the
priority and the message. This can be useful to show the hierarchy of the
functions which are producing logging output. The indent level is initially
zero.
SysLog_UnIndent (&4C886)
---------------
R0-> log name, or = session log handle
Decrements the log indent level. (If it is zero it is not decremented.)
SysLog_NoIndent (&4C887)
---------------
R0-> log name, or = session log handle
Sets the log indent level to zero. This should be called when your program
loads, if you are using SysLog_Indent/UnIndent.
SysLog_OpenSessionLog (&4C888)
---------------------
R0-> log name
R1 = priority
exit:
R0 = session log handle (or 0)
Creates a temporary session log file. When the session log is closed (using
SysLog_CloseSessionLog, below), the session log is appended to the main log
as specified in R0 on entry to this SWI. If the main log is set to ignore
log entries of the priority specified then zero will be returned for the
session log handle. This does not necessarily require special case code, as
other SWIs which accept session log handles will accept a handle of zero and
do nothing.
SysLog_CloseSessionLog (&4C889)
----------------------
R0 = session log handle
Closes the specified temporary session log and appends it to the appropriate
main log file. The specified session log handle is no longer valid.
SysLog_LogData (&4C88A)
--------------
R0-> log name, or = session log handle
R1 = priority
R2-> data to log
R3 = number of bytes to log
R4 = value to report as block offset (-1 not to show block offset)
Logs a block of data, in a hex-and-ASCII format similar to that produced by
*Dump. The block offset is the value that is printed at the beginning of
each line, which is equal to the value given on entry plus the number of
bytes already displayed. If -1 is used as the block offset then the field
will be omitted. Note that if the number of bytes to log is over 10KB then
the SWI will return with an error - logging such a large amount of data in
one go is almost certainly a bug, so SysLog faults it to prevent the
computer going into a semi-infinite loop while it writes huge amounts of
data to disk.
SysLog_LogFormatted (&4C88B)
-------------------
R0-> log name, or = session log handle
R1-> format string
R2 = priority
R3-> block containing R0-R3,R8-R12,R14
R4-R7 = parameters
Evaluates a formatted string using registers R4-R7, and R0-R3, R8-R12 and
R14 from the block passed in R3, and logs the result. See the section
"LogFormatted", below.
SysLog_ReadErrorMessage (&4C88C)
-----------------------
R0 = error number
exit:
R0-> error message
Converts an error number as returned by the FreeNet/Internet/etc modules
into a string describing the error. e.g. SysLog_ReadErrorMessage 60 would
return "Connection timed out".
SysLog_LogComplete (&4C88D)
------------------
R0-> log name
Flushes the specified log, and de-allocates the buffer associated with it.
This should only be called if the log is definitely not going to be used for
a while (e.g. if your application is the only one which can be writing to
the log, and it's exiting). If this isn't called explicity, SysLog
automatically de-allocates the log buffer after ten minutes of inactivity in
the log.
============================================================================
LogFormatted
----------------------------------------------------------------------------
SWI SysLog_LogFormatted provides C "printf"-style functionality for
assembler programmers. A format string is passed in R1, which is a template
for the output. The string is copied directly to the output, except for '%'
characters, which inserts a string calculated when the SWI is called:
%% - the literal '%' character
%<reg>a - the network-byte-ordered IP address in register <reg>
%<reg>c - the character in register <reg>
%<reg>d - the signed decimal integer in register <reg>
%<reg>e - the message for the FreeNet error number in register <reg>
%<reg>f - the filename of the file handle in register <reg>
%<reg>p - the object pointed to by register <reg>
%<reg>s - the control-terminated string pointed to by register <reg>
%<reg>x - the unsigned hexadecimal integer in register <reg>
%<reg>z - the zero-terminated string pointed to by register <reg>
where <reg> is a number which can be any of 0 to 12 or 14.
Note that the %<reg>p type must be followed by another type indicator. For
example, to log a character pointed to by register R3, use "%3pc". More than
one 'p' can be used to indicate more than one level of indirection.
Null pointers are explicitly checked for wherever used, and the string
"(null)" is logged in place of whatever should have been output. Hence it
is explicity defined that it is safe to allow null pointers to be in
registers used by the format string.
Registers R4-R7 are taken directly from the registers passed to the SWI.
Registers R0-R3, R8-R12 and R14 are taken from the block passed in R3.
It is expected that this SWI would be packaged in a macro in your assembler
source code. For example:
...
.stricmp
FNlogf("stricmp: comparing %0z and %1z",200)
...
DEF FNlogf(t$,p%)
[OPT p
STMFD R13!,{R0-R3,R8-R12,R14}
ADR R0,txt_logname
ADD R1,R15,#12
MOV R2,#p%
MOV R3,R13
SWI "SysLog_LogFormatted"
B P%+(LENt$+8)ANDNOT3
EQUS t$+STRING$(4-(LENt$AND3),CHR$0)
LDMFD R13!,{R0-R3,R8-R12,R14}
]
=p
or the ObjAsm equivalent:
MACRO
LOGF $t,$p
STMFD R13!,{R0-R3,R8-R12,R14}
ADR R0,txt_logname
ADR R1,%ft90
MOV R2,#$p
MOV R3,R13
SWI SysLog_LogFormatted
B %ft91
90
= "$t",0
ALIGN
91 LDMFD R13!,{R0-R3,R8-R12,R14}
MEND
...
stricmp ROUT
LOGF "stricmp: comparing %0z and %1z",200
...
============================================================================
Using SysLog from C programs
----------------------------------------------------------------------------
To make SysLog easy to use from C programs, I have written an APCS veneer
for the module. This takes the form of a "syslog.h" header file which you
should #include from your C source, and a "syslog.o" object file which you
should link your program with.
There are two calls for each SWI, one which uses the non-X form and one
which uses the X form and returns a _kernel_oserror *. The non-X forms are
generally nicer as values can be returned in the usual manner, rather than
having to pass a pointer to a location to be filled in with the return code.
I would suggest only using the X forms when you absolutely must - i.e. in
module code, etc.
There's also a bonus function "syslogf" (and "xsyslogf") which is like
"printf" except it outputs to the log. The first two arguments are the
logname and priority, and the rest are the usual printf arguments (i.e.
the format string followed by a variable number of arguments).
Note that a temporary buffer is used to hold the string before it is passed
to the SysLog module and *THIS BUFFER IS ONLY 1024 BYTES LONG*. i.e. you
must ensure that your format string cannot ever produce more than 1024 bytes
of output. This is especially important in networking software where the
input may be coming from a Bad Miscreant who is trying to hack into or crash
your machine.
The ObjAsm source to the veneer object file is provided. If you make any
changes which you think people might find useful, or you find any bugs,
please e-mail me and tell me about it.
Thanks go to Stewart Brodie for assistance with vsprintf ;-).
============================================================================
Options
----------------------------------------------------------------------------
The options file is stored as !SysLog.Options. Each line of the options file
specifies the options for a single log. This line is of the format:
<logname> [Reserve <size>|NoReserve] [Sessions|NoSessions]
[<level> [<max. size>]]
<size> and <max. size> are specified in kilobytes.
An entry for log "*" is treated as the default values, which are used if
the log doesn't have a specific entry in the Options file. So, for example,
to specify "NoSessions" for every log except "NewsBite" you could use:
* NoSessions
NewsBite Sessions
The options have the following meanings:
Reserve <size>
SysLog will make sure that at least <size> KB of disk space is free for
this log, by padding the log file with zeros which are later overwritten
by the real log data.
NoReserve
SysLog won't reserve disk space for this log as described above. This is
the default.
Sessions
SysLog will use Session Logs for this log (as described above) where
instructed. This is the default.
NoSessions
Session Logs are disabled for this log, and log entries will appear
strictly in chronological order.
<level>
SysLog will ignore log entries for this log which have a priority
greater to or equal than this value. The default value is 125.
<max. size>
The log will be moved to the "Old" directory when it becomes larger
than this size. The default value is 256KB.
============================================================================
Usage guidelines
----------------------------------------------------------------------------
Previously in this section I recommended that programs should not fail to
work if logging is not available. This is reasonable - however there are
very few reasons that logging will fail, and all of these reasons are very
likely to cause the main function of the program to fail. I would suggest
therefore that programs should RMEnsure the SysLog module in their !Run
files, and then use it as any other SWI.
Errors from SysLog SWIs, while strictly speaking non-fatal for the main
program, are indicative of something being badly wrong with the system. Use
'X' SWIs in situations such as modules where you have to, of course, but in
application code where you have an error handler, you might as well use the
non-'X' form and treat the errors as you would any other.
Programs which use SysLog should RMEnsure it in their !Run files. The
suggested lines to use are as follows:
If "<SysLog$Dir>"="" then Error !SysLog application not seen by filer
RMEnsure SysLog 0.16 Run <SysLog$Dir>.!Run
RMEnsure SysLog 0.16 Error MyApp needs SysLog 0.16 or later
Note that you should *not* just RMLoad the SysLog module, as it requires its
Wimp task to be activated, and this will not happen if you just RMLoad the
module. The module has a two-stage application entry point, so it will
return immediately when you RMRun it, allowing the !Run file to continue as
normal.