PreviousUpNext

15.3.397  src/lib/src/lib/thread-kit/src/lib/logger.api

## 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.lib


stipulate
    package fil = file__premicrothread;                 # file__premicrothread          is from   src/lib/std/src/posix/file--premicrothread.pkg
herein

    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.


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext