## logger.api
#
# (Overview comments are at bottom of file.)
#
# This version of this module is adapted from
# Cliff Krumvieda's utility for logging debug messages
# in threadkit programs.
#
# See also:
#
src/lib/src/lib/thread-kit/src/lib/thread-deathwatch.api#
src/lib/src/lib/thread-kit/src/lib/uncaught-exception-reporting.api# Compiled by:
#
src/lib/std/standard.libstipulate
package fil = file__premicrothread; # file__premicrothread is from
src/lib/std/src/posix/file--premicrothread.pkgherein
api Logger {
#
make_logtree_leaf
:
{ parent: fil::Logtree_Node,
name: String,
default: Bool
}
->
fil::Logtree_Node;
enable: fil::Logtree_Node -> Void;
#
# Turn on all logging controlled by given subtree
# of all_logging.
disable: fil::Logtree_Node -> Void;
#
# Turn off all logging controlled by given subtree
# of all_logging.
enable_node: fil::Logtree_Node -> Void;
#
# Turn on logging controlled by given logtree node
# (i.e., ignoring any children of that node).
set_logger_to: fil::Log_To -> Void;
#
# Set log output destination.
#
# LOG_TO_STREAM can only be specified
# as a destination if threadkit is running.
#
# NOTE: This call does NOT close the previous
# output stream, if any, since the caller
# may not want that. If you want the
# previous log stream closed, do it
# yourself (see next).
subtree_nodes_and_log_flags: fil::Logtree_Node -> List( (fil::Logtree_Node, Bool) );
#
# Return a list of the registered logtree nodes
# in subtree rooted at given node, along with logging
# status (TRUE/FALSE) of each node.
log_if: fil::Logtree_Node -> Int -> (Void -> String) -> Void;
#
# Conditionally generate logging output.
# Int is severity: 0=note 5=warn 9=fatal.
};
end;
# OVERVIEW.
#
# This package supports simple debugging-via-printf
# style logging of concurrent programs. Log
# messages are conditionally generated via calls
# to 'log_if', which may then at runtime be
# enabled or disabled and their output redirected
# to stdout, stderr, a file, or a stream.
#
# A major problem with debugging-via-printf
# is controlling which printf()s are active
# during a given run. Too few means not
# enough information to find the bug; too
# many means being swamped with irrelevant
# output.
#
# Our idea here is to generate log messages
# via calls to 'log_if', each of which is
# controlled by a (probably shared) boolean
# log flag variable.
#
# We expect that typically there will be one
# such log flag variable .pkg file, used
# to switch on/off all 'log_if' calls in
# that file.
#
# Frequently we want to log what is happening
# in quite a few .pkg files. It can be quite
# tedious and time-wasting to individually
# enable and disable all required log flags.
#
# To address this problem, we organize the log
# flags into a tree, and provide calls to turn
# on or off all log flags in any subtree of
# that tree.
#
# The protocol for using this facility is:
#
# o Generate log tree nodes, typically one
# per foo.pkg file. Each must be the child
# of some existing node, the root of the
# tree being logger::all_logging, so your
# first log node will necessarily be a
# child of all_logging; subsequent nodes
# may be children of any pre-existing node.
#
# Normally you will set up a tree structure
# reflecting your application's library hierarchy.
#
# package foo {
#
# include package logger;
#
# logging
# =
# make_logtree_leaf
# { parent => all_logging,
# name => "foo::logging",
# default => FALSE
# };
#
# Note that by convention we name the logtree
# node in foo.pkg
#
# foo_logging
#
# so that later we can interactively do
#
# enable foo_logging;
#
# or
# disable foo_logging;
#
# and have it be readable.
#
# o Put log_if calls at strategic spots through
# each foo.pkg file:
#
# log_if logging 0 {. "Top of function bar()"; };
# ...
# log_if logging 0 {. sprintf "%d zots processed." zots_done; };
# ...
# log_if logging 0 {. "Bottom of function bar()"; };
#
# As illustrated, the third arg to log_if is a (Void -> String) function.
# (You can write them (\\ () = "Bottom of function bar()") if you prefer;
# we have used the equivalent but more compact thunk syntax above.)
# The point of this is to avoid wasting CPU time generating log
# messages which are not going to be logged: The function is called
# only if the corresponding 'foo_logging' log flag is set TRUE.
#
# Also as illustrated, you will often find it useful to use 'sprintf'
# to generate the log message.
#
# o At runtime, select a destination for log messages
# via a call like one of the following:
#
# set_logger_to LOG_TO_STDOUT;
# set_logger_to LOG_TO_STDERR;
# set_logger_to (LOG_TO_FILE "foo.log");
#
# o At runtime, enable the desired set of log_if statements
# by executing one or more statements like:
#
# enable all_logging; # Probably gross overkill!
# enable xlogger::xkit_logging; # Not quite as bad.
# enable foo::logging; # Much more sensible.
#
# One practical approach to using this facility is:
#
# o Open two Linux commandline windows,
# one for interactive commands,
# one to display the log.
#
# (Personally, I use an xemacs shell buffer for the
# interactive command window for convenience, and
# a vanilla xterm or such for log display,
# because that scrolls much faster than an xemacs
# shell buffer.)
#
# o In the log window do
#
# linux% touch foo.log # Create foo.log file if it doesn't exist.
# linux% tail -f foo.log # Set up to display everything written to file.
#
# o In the command window do something like
#
# linux% my
# eval: make "src/lib/x-kit/x-kit.lib"; # Load xkit, making xlogger::io_logging etc accessable.
# eval: make "src/lib/x-kit/tut/plaid/plaid.lib"; # Or whatever your app is.
# eval: include package logger; # Avoid need for 'logger::' prefix on everything.
# eval: set_logger_to (LOG_TO_FILE "foo.log"); # Select logfile watched by log window.
# eval: enable all_logging; # Or something more selective!
# eval: plaid::do_it (); # Or whatever app you like.
#
# o At the end of the run, if you need more detailed
# analysis of the foo.log contents, you can visit
# the file in emacs or grep it for specific regular
# expressions or such.
## COPYRIGHT (c) 1992 AT&T Bell Laboratories
## Subsequent changes by Jeff Prothero Copyright (c) 2010-2015,
## released per terms of SMLNJ-COPYRIGHT.