Command Logging |
|
|
Command logging allows an application to create a detailed audit log of every command executed, including those from within Procs, paragraphs, menus, etc. The QM command processor passes the command and its origin to an optional user supplied logging subroutine, leaving the application designer free to determine what information is actually logged.
The logging is performed by a QMBasic class module globally catalogued as !CLOG. This has a public subroutine named LOG that two arguments; the command and its origin. The source code for the default version of !CLOG is provided in the BP file of the QMSYS account.
The origin is one of the following:
Where a command includes an inline prompt construct, the command is logged a second time after expansion of the inline prompt.
Logging may be enabled in two mutually exclusive manners. If the CMDLOG configuration parameter is not null, it specifies the pathname of the directory in which logging data is to be recorded. Logging is enabled across all processes and merged into a single log file per day in the specified directory using a name formed from the date in yymmdd format with a .log suffix.
If the CMDLOG configuration parameter is null, logging may be enabled in individual processes by use of the COMMAND.LOGGING ON command. In this mode, the logged data is written to a file named clog.nnn.log in the QM temporary directory (as set by the TEMPDIR configuration parameter) where nnn is the QM user number.
The default command logger shown below is catalogued as part of QM and is also issued in source form in the BP file of the QMSYS account. Users may adapt this to meet their own needs.
class clog $catalogue !clog
$include keys.h
private log.f, log.date, log.dir
public subroutine create.object log.date = 0 log.dir = config('CMDLOG') end
public subroutine log(cmd, origin) tm = epoch()
if not(fileinfo(log.f, FL$OPEN)) then if log.dir = '' then ;* Single process logging log.path = system(SYS$TEMP) : @ds : 'clog.' : @user.no : '.log' end else dt = mvdate(tm) if log.date # dt then ;* New date - switch log files closeseq log.f ;* No effect if file was not open log.date = dt end
log.path = log.dir : @ds : oconv(log.date, 'D2YMD["",""]') : '.log' end openseq log.path shared to log.f else return end
* Construct and write log data
log.rec = tm log.rec<-1> = @user.no log.rec<-1> = @logname log.rec<-1> = origin log.rec<-1> = cmd writeseq change(log.rec, @fm, char(9)) to log.f else null
return end end
This example logger constructs a dynamic array that it then converts to be tab delimited. The logged data is the epoch value (allowing consistent logging across time zones), the QM user number, user name, command origin and the command itself.
|