Log.mesa
Last modified by D. Swinehart, June 16, 1984 4:58:50 pm PDT
Logging of errors and status reports; Spying for performance measurement
DIRECTORY
AMTypes USING [ TV ],
Basics USING [ BITAND ],
Commander USING [ Handle ],
IO USING [ STREAM, Value ],
Rope USING [ ROPE ]
;
Log: CEDAR DEFINITIONS IMPORTS Basics = {
Variables
PD: TYPE = RECORD [
attended: BOOLEANFALSE,
sysIn: IO.STREAM,
sysOut: IO.STREAM, -- IOs for error and system status reporting
ch: Commander.Handle←NIL
];
pd: REF PD;
Types
ROPE: TYPE=Rope.ROPE;
Text: TYPE = RECORD [
t: SEQUENCE maxLength: CARDINAL OF CHAR
];
Error, Information, Performance Logging
LogInfo: TYPE = RECORD[
logCode: ATOMNIL,
logD1: LONG CARDINAL𡤀,
logD2: LONG CARDINAL𡤀
];
loggingGroups: CARDINAL;
LOG: PROC[group: CARDINAL𡤁, info: LogInfo←[]] = TRUSTED INLINE {
IF Basics.BITAND[group, loggingGroups]#0 THEN {
WriteData[info]; Here[]; }; };
SLOG: PROC[group: CARDINAL𡤁] = TRUSTED INLINE {
IF Basics.BITAND[group, Log.loggingGroups]#0 THEN {
Noop[]; Here[]; }; };
WriteData: PROC[info: LogInfo];
Noop: PROC;
Here: PROC;
DoLog: PROC[groups: CARDINAL�];
Error reporting and management
Report finds an appropriate stream and prints a time-stamped version of remark. Clients can register procedures to interpret the WhereToReport atoms and obtain the appropriate stream for a given call, aided by the lead supplied in the Report call.
Problem is intended for reporting unexpected errors and conditions. It will raise the indicated signal, or an internal one by default, if the system is currently attended (there's an executive command.) In any case, it will report the remark argument. It will return automatically or if the operator proceeds from the signal, so the caller needs to do what is necessary to recover after calling Problem.
The other Problem... functions are for convenience in returning innocuous values from procedures.
The defaultIfNotFound parameter to the registration procedure indicates whether the message should be ignored (FALSE) or printed (TRUE) when the corresponding stream-finding procedure returns NIL.
WhereToReport: TYPE=ATOM;
ThHandle: TYPE = LONG CARDINAL -- Thrush.ThHandle --;
nullHandle: ThHandle = 0;
WhereProc: TYPE = PROC[fixedWhereData: REF, whereData: REF] RETURNS[s: IO.STREAMNIL];
DNFProc: TYPE = PROC[fixedWhereData: REF, whereData: REF] RETURNS[default: BOOL];
RegisterWhereToReport: PROC[
proc: WhereProc←NIL, where: WhereToReport, fixedWhereData: REFNIL, defaultIfNotFound: DNFProc←NIL];
IF defaultIfNotFound=NIL, answer assumed TRUE
FindWhere: PROC[where: WhereToReport, whereData: REF] RETURNS [s: IO.STREAMNIL];
Report: PROC[remark: ROPE, where: WhereToReport←NIL, whereData: REFNIL];
ReportFR: PROC[remark: ROPE, where: WhereToReport←NIL, whereData: REFNIL,
a1, a2: IO.Value ← [rope[NIL]]];
Problem: PROC[
remark: ROPENIL, where: WhereToReport←NIL, whereData: REFNIL];
ProblemFR: PROC[
remark: ROPENIL, where: WhereToReport←NIL, whereData: REFNIL,
a1, a2: IO.Value ← [rope[NIL]]];
ProblemBool: PROC[remark: ROPENIL, where: WhereToReport←NIL,
bool: BOOLFALSE, whereData: REFNIL]
RETURNS[sameBool: BOOL];
ProblemHandle: PROC[remark: ROPENIL, where: WhereToReport←NIL,
handle: ThHandle ← nullHandle, whereData: REFNIL]
RETURNS[sameHandle: ThHandle];
Command Logging, indirect execution.
Originally developed as part of ThMessageDBImpl
CLog: TYPE = REF CLogBody;
CLogBody: TYPE = RECORD [
logStream: IO.STREAM,
logReadPos: INT𡤀,
CommandProc: PROC[CLog]
CommandProc should consume any command in the log, such that if it's the last
command, we're at end of file
];
MakeCLog: PROC[fileName: ROPE, CommandProc: PROC[CLog], new: BOOLFALSE, keep: CARDINAL𡤂]
RETURNS[cLog: CLog];
WriteCLog: PROC[cLog: CLog, entry: ROPE];
CloseCLog: PROC[cLog: CLog] RETURNS[nullCLog: CLog];
DoCLog: PROC[cLog: CLog, entry: ROPE];
Write it at end, then read it and do it, using CommandProc
RedoCLog: PROC[cLog: CLog];
Typical thing to do after a MakeCLog, to replay an old one.
Dynamic "IsBound"; applies to procedures only.
GetBinding: PROC[qualifiedName: ROPE] RETURNS [tv: AMTypes.TV];
qualifiedName is either Interface.variable or Program.variable.
Returns NIL if the Interface, Program, or variable is undefined.
Assumes global context. I suppose there's a way to speed it up by looking for top level.
GetBindingToProc: PROC[qualifiedProcName: ROPE] RETURNS [proc: PROC ANY RETURNS ANY];
qualifiedProcName is either Interface.Proc or Program.Proc.
Returns NIL if the Interface, Program, or Proc is undefined.
}.