LogImpl.mesa
Simple Logging output, other general utilities; support for spy log stuff.
Last modified by D. Swinehart, June 16, 1984 4:53:57 pm PDT
DIRECTORY
AMBridge USING [ TVToProc ],
AMEvents USING [ CallDebugger ],
AMTypes USING [ Error, TV ],
Atom USING [ PutProp, GetPName, GetProp, PropList ],
BasicTime USING [ GMT, Now, Unpack, Unpacked ],
Commander USING [ CommandProc, GetProperty, Handle, Register ],
FS USING [ StreamOpen, Error ],
Interpreter USING [ Evaluate ],
IO,
Log,
PrincOps USING [ BytePC, FrameHandle, GFTIndex ],
PrincOpsUtils USING [ LongCOPY, GetReturnFrame ],
ProcessProps USING [ GetPropList ],
RefTab USING [ Create, Fetch, Ref, Store ],
Rope USING [ Flatten, InlineLength, ROPE, Text ],
SpyTypes USING [ DoWriteDataProc, IsActiveProc, WriteTraceProc ]
;
LogImpl: CEDAR MONITOR -- for CLog
IMPORTS
AMBridge,
AMEvents,
AMTypes,
Atom,
BasicTime,
Commander,
FS,
Interpreter,
IO,
PrincOpsUtils,
ProcessProps,
RefTab,
Rope
EXPORTS Log = {
OPEN IO, SpyTypes;
Variables
pd: PUBLIC REF Log.PDNEW[Log.PD←[]];
Copies
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
ThHandle: TYPE = LONG CARDINAL;
WhereToReport: TYPE = Log.WhereToReport;
WhereProc: TYPE = Log.WhereProc;
Reporting and Suspending
WP: TYPE = REF WPRec;
WPRec: TYPE = RECORD [
proc: WhereProc,
fixedWhereData: REF,
defaultIfNotFound: Log.DNFProc←NIL
];
RegisterWhereToReport: PUBLIC PROC[
proc: WhereProc, where: WhereToReport, fixedWhereData: REF,
defaultIfNotFound: Log.DNFProc] = {
Atom.PutProp[$ReportStreams, where, NEW[WPRec←[proc: proc, fixedWhereData: fixedWhereData, defaultIfNotFound: defaultIfNotFound]]];
};
FindWhere: PUBLIC PROC[where: WhereToReport, whereData: REF] RETURNS [s: IO.STREAM] = {
wp: WP;
IF where=NIL THEN RETURN[pd.sysOut];
wp ← NARROW[Atom.GetProp[$ReportStreams, where]];
IF wp=NIL THEN RETURN[pd.sysOut];
s←wp.proc[wp.fixedWhereData, whereData];
IF s#NIL THEN RETURN[s];
RETURN[IF s#NIL THEN s ELSE IF wp.defaultIfNotFound=NIL OR wp.defaultIfNotFound[where, whereData] THEN pd.sysOut ELSE NIL];
};
Report: PUBLIC PROC[remark: ROPE, where: WhereToReport, whereData: REFNIL] = {
reportS: STREAM ← FindWhere[where, whereData];
seconds: INT;
IF remark=NIL OR reportS = NIL THEN RETURN;
seconds ← LogTime[reportS, where];
reportS.PutF[" %02d: %s\n", int[seconds], rope[remark]]; -- wish I could affort looking up caller.
};
ReportFR: PUBLIC PROC[remark: ROPE, where: WhereToReport, whereData: REF,
a1, a2: IO.Value] = {
Report[IO.PutFR[remark, a1, a2], where, whereData];
};
Problem: PUBLIC PROC[
remark: ROPE, where: WhereToReport, whereData: REF] = TRUSTED {
IF remark=NIL THEN remark←"Unspecified problem";
Report[remark, where, whereData];
IF pd.attended THEN AMEvents.CallDebugger[remark];
};
ProblemFR: PUBLIC PROC[
remark: ROPE, where: WhereToReport, whereData: REF, a1, a2: IO.Value] = TRUSTED {
Problem[IO.PutFR[remark, a1, a2], where, whereData];
};
ProblemBool: PUBLIC PROC[
remark: ROPE, where: WhereToReport, bool: BOOL, whereData: REF]
RETURNS[sameBool: BOOL] = {
sameBool𡤋ool;
Problem[remark, where, whereData];
};
ProblemHandle: PUBLIC PROC[ remark: ROPE, where: WhereToReport,
handle: ThHandle, whereData: REF]
RETURNS[sameHandle: ThHandle] = {
sameHandle←handle;
Problem[remark, where, whereData];
};
CmdWhere: WhereProc = {
pl: Atom.PropList ← ProcessProps.GetPropList[];
ch: Commander.Handle;
IF pl=NIL THEN RETURN[NIL];
ch ← NARROW[Commander.GetProperty[$CommanderHandle, pl]];
IF ch=NIL THEN RETURN[NIL];
RETURN[ch.err];
};
SetAttended: Commander.CommandProc = {
pd.attended ← TRUE;
Report["Attended[TRUE]", $Cmd, NIL];
};
ClearAttended: Commander.CommandProc = {
pd.attended ← FALSE;
Report["Attended[FALSE]", $Cmd, NIL];
};
LogTime: PROC[s: IO.STREAM, where: ATOM] RETURNS [seconds: INT] = {
oldT: REF BasicTime.Unpacked ← NARROW[RefTab.Fetch[logTimes, where].val];
now: BasicTime.GMT ← BasicTime.Now[];
nowU: BasicTime.Unpacked ← BasicTime.Unpack[now];
seconds ← nowU.second;
nowU.second ← 0;
nowU.secondsThisYear ← 0;
IF oldT=NIL THEN {
oldT←NEW[BasicTime.Unpacked];
[]←RefTab.Store[logTimes, where, oldT];
};
IF nowU=oldT^ THEN RETURN;
oldT^ ← nowU;
s.PutF["%g\n", time[now]];
};
logTimes: RefTab.Ref ← RefTab.Create[];
Associates Where atoms with print times.
Procedures for performance monitoring and debugging
loggingGroups: PUBLIC CARDINAL𡤀
Noop: PUBLIC PROC = {NULL};
RealLogInfo: TYPE = RECORD [
logD1: LONG CARDINAL,
logD2: LONG CARDINAL,
length: CARDINAL,
logCode: PACKED SEQUENCE maxLength: CARDINAL OF CHAR
];
rli: REF RealLogInfo ← NEW[RealLogInfo];
WriteTrace: WriteTraceProc ← NIL;
DoWriteData: DoWriteDataProc ← NIL;
IsActive: IsActiveProc ← NIL;
WriteData: PUBLIC PROC[info: Log.LogInfo] = TRUSTED {
logCode: Rope.Text;
nbytes: NAT;
IF loggingGroups=0 OR info.logCode =NIL THEN RETURN;
logCode←Rope.Flatten[Atom.GetPName[info.logCode]];
rli.logD1←info.logD1;
rli.logD2←info.logD2;
nbytes ← MIN[logCode.InlineLength[], 20];
rli.length←nbytes;
PrincOpsUtils.LongCOPY[
from: LOOPHOLE[logCode, LONG POINTER]+2,
to: LOOPHOLE[rli, LONG POINTER]+6, nwords: (nbytes+1)/2];
DoWriteData[type: CODE[RealLogInfo], size: SIZE[RealLogInfo[nbytes]], data: LOOPHOLE[rli]];
};
Here: PUBLIC PROC = TRUSTED {
frame: PrincOps.FrameHandle;
IF loggingGroups=0 OR ~IsActive[] THEN RETURN;
frame ← PrincOpsUtils.GetReturnFrame[];
IF frame=NIL THEN RETURN;
WriteTrace[frame.accesslink.gfi, frame.pc];
};
DoLog: PUBLIC PROC[groups: CARDINAL�] = {
IF WriteTrace=NIL THEN {
WriteTrace ← NARROW[FetchBinding[$WriteTrace], REF WriteTraceProc]^;
DoWriteData ← NARROW[FetchBinding[$WriteData], REF DoWriteDataProc]^;
IsActive ← NARROW[FetchBinding[$IsActive], REF IsActiveProc]^;
};
loggingGroups← IF WriteTrace#NIL THEN groups ELSE 0;
};
FetchBinding: PROC[field: ATOM] RETURNS [REF] = {
RETURN[Atom.GetProp[$Interfaces, field]];
};
Command Logging, indirect execution.
Originally developed as part of ThMessageDBImpl
CLog: TYPE = Log.CLog;
MakeCLog: PUBLIC PROC[fileName: ROPE, CommandProc: PROC[CLog]←NIL, new: BOOLFALSE, keep: CARDINAL𡤂]
RETURNS[cLog: CLog←NIL] = {
logStream: IO.STREAM;
logStream ← FS.StreamOpen[fileName: fileName, keep: keep,
accessOptions: IF new THEN $create ELSE $append!
FS.Error => logStream←NIL];
IF logStream=NIL THEN RETURN[NIL];
cLog←NEW[Log.CLogBody←[logStream: logStream, CommandProc: CommandProc]];
logStream.SetIndex[0];
};
WriteCLog: PUBLIC ENTRY PROC[cLog: CLog, entry: ROPE] = {
WriteLog[cLog, entry];
};
CloseCLog: PUBLIC ENTRY PROC[cLog: CLog] RETURNS[nullCLog: CLog←NIL] = {
IF cLog=NIL THEN RETURN;
IF cLog.logStream#NIL THEN cLog.logStream.Close[];
cLog.logStream←NIL;
};
WriteLog: INTERNAL PROC[cLog: CLog, entry: ROPE] = {
cLog.logStream.SetIndex[cLog.logStream.GetLength[]];
cLog.logStream.PutRope[entry];
cLog.logStream.Flush[];
};
DoCLog: PUBLIC ENTRY PROC[cLog: CLog, entry: ROPE] = {
IF entry#NIL THEN WriteLog[cLog, entry];
DO
pos: INT ← cLog.logReadPos;
IF pos >= cLog.logStream.GetLength[] THEN EXIT;
cLog.logStream.SetIndex[cLog.logReadPos];
cLog.CommandProc[cLog];
cLog.logReadPos ← cLog.logStream.GetIndex[];
IF pos=cLog.logReadPos THEN ERROR; -- Not making progress!
ENDLOOP;
};
RedoCLog: PUBLIC PROC[cLog: CLog] = {
cLog.logReadPos𡤀
DoCLog[cLog, NIL];
};
Runtime Binding
GetBinding: PUBLIC PROC[qualifiedName: ROPE] RETURNS [tv: AMTypes.TV] = {
tv ← Interpreter.Evaluate[qualifiedName].result;
};
GetBindingToProc: PUBLIC PROC[qualifiedProcName: ROPE]
RETURNS [proc: PROC ANY RETURNS ANY] = TRUSTED {
tv: AMTypes.TV = Interpreter.Evaluate[qualifiedProcName].result;
IF tv=NIL THEN RETURN[NIL];
proc ← LOOPHOLE[AMBridge.TVToProc[tv!AMTypes.Error=>CONTINUE]];
};
Initialization
pd.ch ← NARROW[Commander.GetProperty[$CommanderHandle, ProcessProps.GetPropList[]]];
IF pd.ch#NIL THEN { pd.sysIn ← pd.ch.in; pd.sysOut ← pd.ch.out; };
RegisterWhereToReport[CmdWhere, $Cmd, NIL, NIL];
Commander.Register["Attended", SetAttended, "Break on errors"];
Commander.Register["Unattended", ClearAttended, "Log on errors, then muddle on."];
}.