newLISP Fan Club
Forum => Anything else we might add? => Topic started by: hartrock on August 27, 2015, 08:55:22 AM
Introduction to multiple loggers usecase Modules needed Session Explanation and interpretation of some session results What do you think?
If you want to skip the details, you may directly jump to 'Interpretation of some session results'.
publishing for reuse[/i] by others (this is not intended here).
Util.lsp :
(context 'Util)
(define (sym? strOrSym ctx)
(sym strOrSym ctx nil))
(define (lambda-or-macro-symbol? expr)
(and (symbol? expr)
(or (lambda? (eval expr))
(macro? (eval expr)))))
(define (sym-string s , symStr)
(set 'symStr (string s))
(if (find ":" symStr)
(letn ((prefixCtx (prefix s))
(parsedStr (parse symStr ":"))
(prefixStr (first parsedStr))
(termStr (last parsedStr))
(prefixCtxStr (string prefixCtx)))
(if (!= prefixStr prefixCtxStr)
(append symStr " [" prefixStr ":] " prefixCtxStr ":" termStr)
symStr))
(string (prefix s) ":" (term s))))
(define (add-prefix-to-sym prefixStr symbol)
(sym (append prefixStr (term symbol))
(prefix symbol))) ; get correct ctx prefix
(define (add-postfix-to-sym postfixStr symbol)
(sym (append (term symbol) postfixStr)
(prefix symbol))) ; get correct ctx prefix
(define (add-prefix-to-syms prefixStr symList)
(map (curry add-prefix-to-sym prefixStr) symList))
(define (add-postfix-to-syms postfixStr symList)
(map (curry add-postfix-to-sym postfixStr) symList))
(define (swap-symbols symList_1 symList_2)
(map (fn (s_1 s_2) (swap (eval s_1) (eval s_2)))
symList_1 symList_2))
;; These functions are an intermediate between
;; - (new srcCtx dstCtx) : not overwriting the vals of existing syms in dstCtx;
;; and
;; - (new srcCtx dstCtx true) : overwriting the val of existing syms in dstCtx.
;; They overwrite the vals of existing syms in dstCtx, but only then, if they
;; are:
;; 1. Variant: *not* nil in srcCtx (overwrite in case of non-nil conflicts).
;; 2. Variant: nil in dstCtx (*no* overwrite in case of non-nil conflicts).
;; Motivation:
;; - There may be nil syms in srcCtx just by referencing syms expected to be in
;; dstCtx, which *should* *not* be overwritten in dstCtx.
;; - There may be nil syms in dstCtx by referencing syms expected to be in
;; srcCtx, which *should* be overwritten.
;; Notes:
;; - *non*-existent syms in dstCtx will be created even with nil vals from
;; srcCtx.
;; - in case of a conflict between not-nil values of a sym in both contexts,
;; srcCtx losses (1.) or wins (2.).
;;
;; 1. this variant does not overwrite non-nils by non-nils.
;; Note: to be preferred against 2. variant below, if overwritng not needed (for
;; the reason see note there).
(define (mixin-no-overwrite-of-non-nil srcCtx dstCtx)
(dolist
(s (symbols srcCtx))
(if (or (not (sym? s dstCtx))
(nil? (eval (sym s dstCtx))))
(def-new s (sym s dstCtx))
"skip (no overwrite of non-nil vals)")))
;; 2. this variant overwrites non-nils by non-nils.
;; Note: this may overwrite *** just created *** non-nils - by recursively
;; created deps during creation of former symbols.
(define (mixin-no-overwrite-with-nil srcCtx dstCtx)
(dolist
(s (symbols srcCtx))
(if (or (not (sym? s dstCtx))
(eval s)) ; not nil
(def-new s (sym s dstCtx))
"skip (no overwrite with nil vals)")))
(context MAIN)
FOOPReference.lsp :
(context 'FOOPReference)
;; indices of elems in FOOP list
(constant 's_class 0 's_ref 1)
;; helpers
(define (ref-context-sym ix)
(sym (string (context) "_" ix) MAIN))
(define (new-ref-context-sym)
(ref-context-sym (++ foopCount))) ; foopCount for identifying FR instances
(define (new-ref-context)
(let (ref_contextSym (new-ref-context-sym))
(prefix (sym ref_contextSym ref_contextSym)))); without switching to new ctx
;; standard functor: each call increases foopCount
(define (FOOPReference:FOOPReference)
(letn ((ref_context (new-ref-context)) ; increments foopCount
(foop (cons (context) (cons ref_context (args)))))
(set (sym (string ref_context) ref_context) foop) ; set ref context default
ref_context))
;; accessors
(define (class) ; FOOP Class
(self s_class))
(define (reference) ; FOOP reference context
(self s_ref))
;; cleaners
(define (delete-ref ctxSym)
(delete ctxSym) ; syms in context including foop default
(delete ctxSym)) ; context in MAIN
(define (delete-ref-ix ix)
(delete-ref (ref-context-sym ix)))
(define (delete-all-refs) ; robust against missing refs/foops already deleted
(while (> foopCount 0)
(delete-ref-ix foopCount)
(-- foopCount)))
(context MAIN)
Logger.lsp :
(when (not (context? FOOPReference))
(write-line 2 "[FATAL] Logger needs module FOOPReference.lsp.")
(exit 1))
(when (not (context? Util))
(write-line 2 "[FATAL] Logger needs module Util.lsp.")
(exit 1))
(when (context? Logger)
(write-line 2 "[Warning] Context Logger already defined."))
(new FOOPReference 'Logger)
(context Logger)
;;
;; script properties
;; - should probably become part of getopts or an own module
;;
;; *** old basename (now scriptname) too limited ***
;;
;;;; works for both newLisp and #!/.../newlisp
;;(define (basename)
;; (setq execPath (or (main-args 1) (main-args 0)))
;; (last (parse execPath "/")))
;;
;; A (scriptpath), (scriptname), (scriptargs) solution for skipping newlisp opts
;; and their args: could be a helper for getopts.
;;
;; Should be correct for typical shebang (#!/...) cases, but of interest here
;; are newlisp calls like:
;; newlisp -s 4096 -m 10 someScript.lsp
;; .
;;
;; But it has limitations: it is only correkt, if *first* non-option arg of
;; newlisp is the script of interest.
;; E.g. calling
;; newlisp -m 10 nonExistentFile
;; results into
;; > (Logger:scriptname)
;; "nonExistentFile"
;; .
;; Therefrom it should be allowed and documented how to override; this can be
;; done by setting scriptpath_ix explicitely, in case of used heuristics fails.
;;
;; See file:///usr/share/doc/newlisp/newlisp_manual.html#options:
;;
;; -h this help -> OK (enters interpreter)
;; -n no init.lsp (must be first) -> OK
;; -x <source> <target> link -> error: should not been reached by script
;; -v version -> OK (enters interpreter)
;; -s <stacksize> -> OK
;; -m <max-mem-MB> cell memory -> OK
;; -e <quoted lisp expression> -> OK (enters interpreter)
;; -l <path-file> log connections -> OK
;; -L <path-file> log all -> OK
;; -w <working dir> -> OK
;; -c no prompts, HTTP -> OK
;; -C force prompts -> OK
;; -t <usec-server-timeout> -> OK
;; -p <port-no> -> OK
;; -d <port-no> demon mode -> OK
;; -http only -> OK
;; -6 IPv6 mode -> OK
;;
(set'opt_without_arg
'("-h" ; enters interpreter
"-n" ; -> skipped
"-v" ; enters interpreter
"-c" ; -> skipped
"-C" ; -> skipped
"-http" ; -> skipped
"-6" ; -> skipped
)
'opt_with_arg
'("-s" ; -> skipped
"-e" ; enters interpreter
"-m" ; -> skipped
"-l" ; -> skipped
"-L" ; -> skipped
"-w" ; -> skipped
"-t" ; -> skipped
"-p" ; -> skipped
"-d" ; -> skipped
)
'opt_with_2_args
'("-x" ; should not been reached by script
;;"-y" ; for testing errorcase...
))
(local (breakFlag skip_next ix execPath)
(set 'ix 0) ; without any args ix 0 refers to newlisp bin
(dolist
(o (1 (main-args)) breakFlag) ; without args, there is no loop here
(cond
(skip_next
(++ ix)
(set 'skip_next nil)) ; skip once
((find o opt_without_arg)
(++ ix))
((find o opt_with_arg)
(++ ix)
(set 'skip_next true))
((find o opt_with_2_args)
(throw-error "should not been reached"))
("default" ; end loop: first newlisp noopt should be script
(++ ix) ; needed: loop started with ix of previous element
(set 'breakFlag true))))
(set 'scriptpath_ix ix ; 0 or index of first element not being a newlisp option with its args
'scriptargs_ ((+ 1 scriptpath_ix) (main-args))
'scriptpath_ (main-args scriptpath_ix)
'scriptname_ (last (parse scriptpath_ "/"))))
;; iface
(define (scriptpath-ix)
scriptpath_ix)
(define (scriptargs) ; good as getopts arg
scriptargs_)
(define (scriptpath)
scriptpath_)
(define (scriptname) ; Linux (to be extended for other OSes)
scriptname_)
(define (shebang?) ; works for Linux; to be extended for other OSes
(and (= (main-args 0) "/usr/local/bin/newlisp")
(!= (scriptname) "newlisp")))
;;
;; .. script properties
;;
;; helper
;;
(define (write-string str)
(write-line (fd) str))
(define (prefix-loc-string (locStrOrSym "") (extraPrefix ""))
(format
(if (null? locStrOrSym)
"%s[%s%s]%s "
"%s[%s %s]%s ")
(preprefix-string) (scriptname) (string locStrOrSym) extraPrefix))
(define (prefix-string (extraPrefix ""))
(prefix-loc-string "" extraPrefix))
(define (to-string arguments)
;;(println "arguments: " arguments)
(if (null? arguments)
"? (no msg)"
(apply string arguments)))
(define (msg-format arguments)
(write-string (to-string arguments)))
(constant 'c_fatalStr "[FATAL]"
'c_errorStr "[ERROR]"
'c_warningStr "[Warning]"
'c_infoStr "[Info]")
;; iface
;;
;; (msg arg [arg [...]]) : like args for println
(define (msg)
(when (<= (level) level_debug)
(write-string (append (prefix-string)
(to-string (args))))))
(define (msg-loc locStrOrSym)
(when (<= (level) level_debug)
(write-string (append (prefix-loc-string locStrOrSym)
(to-string (args))))))
(define (info)
(when (<= (level) level_info)
(write-string (append (prefix-string c_infoStr)
(to-string (args))))))
(define (info-loc locStrOrSym)
(when (<= (level) level_info)
(write-string (append (prefix-loc-string locStrOrSym c_infoStr)
(to-string (args))))))
(define (warn)
(when (<= (level) level_warn)
(write-string (append (prefix-string c_warningStr)
(to-string (args))))))
(define (h_warn-loc-string locStrOrSym arguments)
(append (prefix-loc-string locStrOrSym c_warningStr)
(to-string arguments)))
(define (warn-loc locStrOrSym)
(when (<= (level) level_warn)
(write-string (h_warn-loc-string locStrOrSym (args)))))
(define (error)
(when (<= (level) level_error)
(write-string (append (prefix-string c_errorStr)
(to-string (args))))))
(define (error-loc locStrOrSym)
(when (<= (level) level_error)
(write-string (append (prefix-loc-string locStrOrSym c_errorStr)
(to-string (args))))))
(define (fatal)
(when (<= (level) level_fatal)
(write-string (append (prefix-string c_fatalStr)
(to-string (args))))))
(define (fatal-loc locStrOrSym)
(when (<= (level) level_fatal)
(write-string (append (prefix-loc-string locStrOrSym c_fatalStr)
(to-string (args))))))
;; helper
;;
(constant 'indentIncrement 2)
(define (indent-string)
(let (str "")
(dotimes (n (indent)) ; uses foop indent
(extend str " "))
str))
;;
;; iface
;;
;; overload global begin: this is *dangerous* for all contexts ..
(define (Logger:begin (what "")) ; .. getting syms from here!
(when (<= (level) level_debug)
(write-string (append
(prefix-string)
(indent-string)
"(" (string what) "..."))
(++ (self s_indent) indentIncrement)))
(define (end (what ""))
(when (<= (level) level_debug)
(-- (self s_indent) indentIncrement)
(write-string (append
(prefix-string)
(indent-string)
"..." (string what) ")"))))
;; macro to show expr unevaluated; returns evaluation
(define-macro (wrap expr (what (string expr)))
(begin what) ; Logger:begin
(let (res (eval expr))
(end what)
res))
(define (convenience-forward FunSym ctx)
(let (Ctx (sym (string ctx) MAIN)) ; alt (slower): use (context) ..
(set (sym FunSym ctx)
(expand '(lambda ()
(:FunSym Ctx ; .. instead of Ctx here. avoid ..
(apply string (args)))))))) ; .. forwarding as list
(define (convenience-forward-first-rest FunSym ctx)
(let (Ctx (sym (string ctx) MAIN))
(set (sym FunSym ctx)
(expand '(lambda ()
(:FunSym Ctx
(args 0) ; unchanged first (loc) and stringified ..
(apply string (rest (args))))))))) ; .. rest args
(when (not standard_constructor) ; be robust against module reload
(set 'standard_constructor Logger)) ; store ctor from FOOPReference for reuse
;; FOOP Logger ctor with check for int fd
(define (Logger (fd 2) ; stderr
(preprefix-string (fn () "")) ; optional
(log-level level_default)) ; optional
(if (not (integer? fd))
(MAIN:begin ; avoid Logger:begin
;; difficult to use a logger here...
(write-line 2 "[FATAL] fd arg has to be an int.")
(exit 1)))
(let (ref_ctx (standard_constructor fd
preprefix-string
log-level
0)) ; indent starting with 0
;; convenience func forwards from ref context to foop
[text] ;(convenience-forward 'info ref_ctx) results into (for first logger):
(lambda () (: Logger:info Logger_1 (apply string (args))))
[/text]
(convenience-forward 'msg ref_ctx)
(convenience-forward-first-rest 'msg-loc ref_ctx)
(convenience-forward 'info ref_ctx)
(convenience-forward-first-rest 'info-loc ref_ctx)
(convenience-forward 'warn ref_ctx)
(convenience-forward-first-rest 'warn-loc ref_ctx)
(convenience-forward 'error ref_ctx)
(convenience-forward-first-rest 'error-loc ref_ctx)
(convenience-forward 'fatal ref_ctx)
(convenience-forward-first-rest 'fatal-loc ref_ctx)
;; log level forwards
(set (sym 'level-debug ref_ctx) (lambda () (:level-debug (context))))
(set (sym 'level-all ref_ctx) (lambda () (:level-all (context))))
(set (sym 'level-info ref_ctx) (lambda () (:level-info (context))))
(set (sym 'level-warn ref_ctx) (lambda () (:level-warn (context))))
(set (sym 'level-error ref_ctx) (lambda () (:level-error (context))))
(set (sym 'level-fatal ref_ctx) (lambda () (:level-fatal (context))))
(set (sym 'level ref_ctx) (lambda () (:level (context))))
(set (sym 'begin ref_ctx) (lambda ((what ""))
(:begin (context) what)))
(set (sym 'end ref_ctx) (lambda ((what ""))
(:end (context) what)))
;; mixins
(setq ref_ctx:mixin-expr
(lambda ()
(Util:mixin-no-overwrite-of-non-nil MAIN:LoggerExpr (context))))
(setq ref_ctx:mixin-expr-debug
(lambda ()
((eval (sym "mixin-expr" (context)))) ; not elegant, but it works
(Util:mixin-no-overwrite-of-non-nil MAIN:LoggerDebug (context))))
;; default logger for being used by other modules
(if (not Logger:default) ; overload MAIN:default
(set 'Logger:default ref_ctx))
ref_ctx))
;; foop accessor indices (starting with 2)
(constant 's_fd 2 's_preprefixStr_func 3 's_logLevel 4 's_indent 5)
;; loglevels
(constant 'level_all 0
'level_debug 0
'level_info 1
'level_warn 2
'level_error 3
'level_fatal 4
'level_default level_info)
;; accessors
(define (fd) (self s_fd))
(define (set-fd fd) (setq (self s_fd) fd))
(define (preprefix-func) (self s_preprefixStr_func))
(define (set-preprefix-func fun) (setq (self s_preprefixStr_func) fun))
(define (log-level) (self s_logLevel))
(define (set-log-level l) (setq (self s_logLevel) l))
(define (indent) (self s_indent))
(define (set-indent indent) (setq (self s_indent) indent))
;; indirect getters
(define (preprefix-string)
((self s_preprefixStr_func))) ; call func
;; indirect setters
(define (use-timestamp-prefix)
(set-preprefix-func (fn () (date (date-value) 0 "[%Y-%m-%d %X]"))))
(define (use-debug-prefix)
(set-preprefix-func (fn () "[dbg]")))
(define (use-no-prefix)
(setq (set-preprefix_func (fn () ""))))
(define (use-prefix-fun prefixFun)
(set-preprefix-func prefixFun))
;; loglevel getters
(define (level)
(self s_logLevel))
(define (get-level-default) ; needed?
level_default)
;; loglevel setters
(define (level-default)
(setq (self s_logLevel) level_default))
(define (level-all)
(setq (self s_logLevel) level_all))
;;
(define (level-debug)
(setq (self s_logLevel) level_debug))
(define (level-info)
(setq (self s_logLevel) level_info))
(define (level-warn)
(setq (self s_logLevel) level_warn))
(define (level-error)
(setq (self s_logLevel) level_error))
(define (level-fatal)
(setq (self s_logLevel) level_fatal))
(context MAIN) ; ...Logger
;; Logger extended for expression info: shows expressions both unevaluated and
;; evaluated. Evaluation happens before forwarding to foop, which is not suited,
;; because it changes (self).
(context 'LoggerExpr)
(define (default? symbol)
(and (context? symbol)
(default symbol)))
;;
(define (rep a)
(if
(float? a) (format "%f" a)
(string? a) (append """ a """)
(array? a) (append "[]" (string a))
(quote? a) (append "'" (rep (eval a)))
(context? a) (append
"[ctx] " (string a)
(let (default_flag (Util:sym? (string a) a)) ; no new sym by check
(if default_flag
(append ", " (string a) ":" (string a)
" -> " (string (default a)))
"")))
(symbol? a) (Util:sym-string a)
(string a)))
(define (name-rep a sepFlag restFlag)
(local (sym_identical_flag)
(append
(if restFlag (if sepFlag "n, " "; ") "")
(if (number? a) (string a) ; source rep: 1 for 1.0 !
(symbol? a) (begin
(set 'sym_identical_flag (= a (eval a)))
(rep a))
(rep a))
(if sym_identical_flag " == " " -> ")
(if sepFlag ">>n" "")
(rep (setq lastExprEval (eval a)))
(if sepFlag "n<<" ""))))
(define (expr-info-string arguments sepFlag)
(local (nameReps)
(if (null? arguments)
(format "%s %s:expr: no argument" Logger:c_warningStr (string (context)))
(begin
(push (name-rep (first arguments) sepFlag) nameReps)
(dolist (a (rest arguments))
(push (name-rep a sepFlag true) nameReps -1))
(join nameReps)))))
(define (tloc2string loc) ; used by lib/assert.lsp
(format "%s %d"
(string (last loc))
(first loc)))
(define (expr-info-string-tloc tloc arguments sepFlag)
(append
(string "[" (tloc2string tloc) "] ")
(expr-info-string arguments sepFlag)))
;;
;; iface (to be moved to corresponding context (instead of using by FOOP)
;; to be fully functional)
;;
;; without output, just expr info string
(define-macro (expr-str)
(expr-info-string (args)))
;; new:
(define-macro (expr-str-sep)
(expr-info-string (args) true))
;;
;; with output into log channel
(define-macro (expr)
; after mixin into created Logger reference is (context) ..
(:msg (context) ; .. a FOOPReference with foop default getting :msg call
(expr-info-string (args)))
lastExprEval)
;; robustness against missing locStrOrSym
(define-macro (expr-loc (locStrOrSym ""))
(:msg-loc (context)
(string (eval locStrOrSym))
(expr-info-string (args)))
lastExprEval) ;)
;;
(define-macro (expr-sep)
(:msg (context)
(expr-info-string (args) true))
lastExprEval)
(define-macro (expr-loc-sep (locStrOrSym ""))
(:msg-loc (context)
(string (eval locStrOrSym))
(expr-info-string (args) true))
lastExprEval)
;; convenience forward to macro in foop; returns wrapped expr
(define-macro (wrap)
(eval (append '(:wrap (context)) (args))))
(context MAIN) ; ...LoggerExpr
(context 'LoggerDebug) ; specific dbg: functions
;; on/off switching of debug messages ...
(set 'symbols-to-be-switched
'(msg msg-loc LoggerDebug:begin end wrap ; not defined as tweakable below
;; expr-str[-sep][_tweaked] not to be switched
expr expr-loc
expr-sep expr-loc-sep
info info-loc) ; not defined as tweakable below
'symbols-to-be-switched-store (Util:add-prefix-to-syms
"_"
symbols-to-be-switched))
;; use empty non-evaluating macros for switched off versions
(dolist (s symbols-to-be-switched-store)
(set s (lambda-macro ())))
(setq LoggerDebug:debug true) ; default (overload MAIN:debug)
(define (switch)
(setq LoggerDebug:debug (not LoggerDebug:debug)) ; does not change nodebug flag!
;; to be swapped with their prefixed stored counterparts
(Util:swap-symbols symbols-to-be-switched
symbols-to-be-switched-store))
(define (on)
(if (not debug) ; LoggerDebug:debug
(MAIN:begin ; overloaded above
(switch)
"Now on.")
"Already on."))
(define (off)
(if debug ; LoggerDebug:debug
(MAIN:begin ; overloaded above
(switch)
"Off.")
"Already off."))
(context MAIN) ; ...LoggerDebug
;; loading modules:
(map load '("Util.lsp" "FOOPReference.lsp" "Logger.lsp"))
;;
(set 'l (Logger))
(global 'l) ; for being visible in contexts loaded later
;;
(l:info "an info") (l:warn "a warning") (l:error "an error") (l:fatal "a fatal condition")
;; but:
(l:msg "a message needing level-debug")
(l:level-debug) ; (default is level-info)
(l:msg "a message needing level-debug")
;;
;;
;; There are more features by mixing-in some additional functionality:
;;
(set 'le (Logger 2 (fn () "[le]") Logger:level_all)) ; stderr, preprefix fun
(global 'le) ; for being visible in contexts loaded later
(le:info "an info")
;; now let's mixin
(le:mixin-expr)
;; now this works:
(le:expr (+ 1 2))
;; or showing itself
(le:expr le)
;; -> shows it being a context having a default Logger FOOP
;; (this is due to being a FOOPReference)
;;
;;
;; show properties of loggers l and le
;;
(le:expr l) (le:expr le)
;;
;;
;;
;; syms of minimal logger's FOOPReference
;;
(symbols l)
;;
;;
;; syms of extended logger's FOOPReference
;;
(symbols le)
;;
;;
;; *shared* FOOP part (used by *both* loggers)
;;
(symbols Logger)
;;
;;
;; mixin part (visible in syms of le)
;;
(symbols LoggerExpr)
[/code]
Session as a whole (by copy/paste session commands):
newLISP v.10.6.4 64-bit on Linux IPv4/6 UTF-8 libffi, options: newlisp -h
> ;; loading modules:
> (map load '("Util.lsp" "FOOPReference.lsp" "Logger.lsp"))
(MAIN MAIN MAIN)
> ;;
> (set 'l (Logger))
Logger_1
> (global 'l) ; for being visible in contexts loaded later
l
> ;;
> (l:info "an info") (l:warn "a warning") (l:error "an error") (l:fatal "a fatal condition")
[newlisp][Info] an info
24
[newlisp][Warning] a warning
29
[newlisp][ERROR] an error
26
[newlisp][FATAL] a fatal condition
35
> ;; but:
> (l:msg "a message needing level-debug")
nil
> (l:level-debug) ; (default is level-info)
0
> (l:msg "a message needing level-debug")
[newlisp] a message needing level-debug
40
> ;;
> ;;
> ;; There are more features by mixing-in some additional functionality:
> ;;
> (set 'le (Logger 2 (fn () "[le]") Logger:level_all)) ; stderr, preprefix fun
Logger_2
> (global 'le) ; for being visible in contexts loaded later
le
> (le:info "an info")
[le][newlisp][Info] an info
28
> ;; now let's mixin
> (le:mixin-expr)
Logger_2:wrap
> ;; now this works:
> (le:expr (+ 1 2))
[le][newlisp] (+ 1 2) -> 3
3
> ;; or showing itself
> (le:expr le)
[le][newlisp] MAIN:le -> [ctx] Logger_2, Logger_2:Logger_2 -> (Logger Logger_2 2 (lambda () "[le]") 0 0)
Logger_2
> ;; -> shows it being a context having a default Logger FOOP
> ;; (this is due to being a FOOPReference)
> ;;
> ;;
> ;; show properties of loggers l and le
> ;;
> (le:expr l) (le:expr le)
[le][newlisp] MAIN:l -> [ctx] Logger_1, Logger_1:Logger_1 -> (Logger Logger_1 2 (lambda () "") 0 0)
Logger_1
[le][newlisp] MAIN:le -> [ctx] Logger_2, Logger_2:Logger_2 -> (Logger Logger_2 2 (lambda () "[le]") 0 0)
Logger_2
> ;;
> ;;
> ;;
> ;; syms of minimal logger's FOOPReference
> ;;
> (symbols l)
(Logger_1:Logger_1 Logger_1:begin Logger_1:end Logger_1:error Logger_1:error-loc
Logger_1:fatal Logger_1:fatal-loc Logger_1:info Logger_1:info-loc Logger_1:level
Logger_1:level-all Logger_1:level-debug Logger_1:level-error Logger_1:level-fatal
Logger_1:level-info Logger_1:level-warn Logger_1:mixin-expr Logger_1:mixin-expr-debug
Logger_1:msg Logger_1:msg-loc Logger_1:warn Logger_1:warn-loc)
> ;;
> ;;
> ;; syms of extended logger's FOOPReference
> ;;
> (symbols le)
(Logger_2:Logger_2 Logger_2:a Logger_2:arguments Logger_2:begin Logger_2:default?
Logger_2:default_flag Logger_2:end Logger_2:error Logger_2:error-loc Logger_2:expr
Logger_2:expr-info-string Logger_2:expr-info-string-tloc Logger_2:expr-loc Logger_2:expr-loc-sep
Logger_2:expr-sep Logger_2:expr-str Logger_2:expr-str-sep Logger_2:fatal Logger_2:fatal-loc
Logger_2:info Logger_2:info-loc Logger_2:lastExprEval Logger_2:level Logger_2:level-all
Logger_2:level-debug Logger_2:level-error Logger_2:level-fatal Logger_2:level-info
Logger_2:level-warn Logger_2:loc Logger_2:locStrOrSym Logger_2:mixin-expr Logger_2:mixin-expr-debug
Logger_2:msg Logger_2:msg-loc Logger_2:name-rep Logger_2:nameReps Logger_2:rep Logger_2:restFlag
Logger_2:sepFlag Logger_2:sym_identical_flag Logger_2:symbol Logger_2:tloc Logger_2:tloc2string
Logger_2:warn Logger_2:warn-loc Logger_2:wrap)
> ;;
> ;;
> ;; *shared* FOOP part (used by *both* loggers)
> ;;
> (symbols Logger)
(Logger:Ctx Logger:FunSym Logger:Logger Logger:arguments Logger:begin Logger:breakFlag
Logger:c_errorStr Logger:c_fatalStr Logger:c_infoStr Logger:c_warningStr Logger:class
Logger:convenience-forward Logger:convenience-forward-first-rest Logger:ctx Logger:ctxSym
Logger:default Logger:delete-all-refs Logger:delete-ref Logger:delete-ref-ix Logger:end
Logger:error Logger:error-loc Logger:execPath Logger:expr Logger:extraPrefix Logger:fatal
Logger:fatal-loc Logger:fd Logger:foop Logger:foopCount Logger:fun Logger:get-level-default
Logger:h_warn-loc-string Logger:indent Logger:indent-string Logger:indentIncrement
Logger:info Logger:info-loc Logger:ix Logger:l Logger:level Logger:level-all Logger:level-debug
Logger:level-default Logger:level-error Logger:level-fatal Logger:level-info Logger:level-warn
Logger:level_all Logger:level_debug Logger:level_default Logger:level_error Logger:level_fatal
Logger:level_info Logger:level_warn Logger:locStrOrSym Logger:log-level Logger:msg
Logger:msg-format Logger:msg-loc Logger:n Logger:new-ref-context Logger:new-ref-context-sym
Logger:o Logger:opt_with_2_args Logger:opt_with_arg Logger:opt_without_arg Logger:prefix-loc-string
Logger:prefix-string Logger:prefixFun Logger:preprefix-func Logger:preprefix-string
Logger:ref-context-sym Logger:ref_context Logger:ref_contextSym Logger:ref_ctx Logger:reference
Logger:res Logger:s_class Logger:s_fd Logger:s_indent Logger:s_logLevel Logger:s_preprefixStr_func
Logger:s_ref Logger:scriptargs Logger:scriptargs_ Logger:scriptname Logger:scriptname_
Logger:scriptpath Logger:scriptpath-ix Logger:scriptpath_ Logger:scriptpath_ix Logger:set-fd
Logger:set-indent Logger:set-log-level Logger:set-preprefix-func Logger:set-preprefix_func
Logger:shebang? Logger:skip_next Logger:standard_constructor Logger:str Logger:to-string
Logger:use-debug-prefix Logger:use-no-prefix Logger:use-prefix-fun Logger:use-timestamp-prefix
Logger:warn Logger:warn-loc Logger:what Logger:wrap Logger:write-string)
> ;;
> ;;
> ;; mixin part (visible in syms of le)
> ;;
> (symbols LoggerExpr)
(LoggerExpr:a LoggerExpr:arguments LoggerExpr:default? LoggerExpr:default_flag LoggerExpr:expr
LoggerExpr:expr-info-string LoggerExpr:expr-info-string-tloc LoggerExpr:expr-loc
LoggerExpr:expr-loc-sep LoggerExpr:expr-sep LoggerExpr:expr-str LoggerExpr:expr-str-sep
LoggerExpr:lastExprEval LoggerExpr:loc LoggerExpr:locStrOrSym LoggerExpr:msg LoggerExpr:msg-loc
LoggerExpr:name-rep LoggerExpr:nameReps LoggerExpr:rep LoggerExpr:restFlag LoggerExpr:sepFlag
LoggerExpr:sym_identical_flag LoggerExpr:symbol LoggerExpr:tloc LoggerExpr:tloc2string
LoggerExpr:wrap)
>
> ;; syms of minimal logger's FOOPReference
> ;;
> (symbols l)
(Logger_1:Logger_1 Logger_1:begin Logger_1:end Logger_1:error Logger_1:error-loc
Logger_1:fatal Logger_1:fatal-loc Logger_1:info Logger_1:info-loc Logger_1:level
Logger_1:level-all Logger_1:level-debug Logger_1:level-error Logger_1:level-fatal
Logger_1:level-info Logger_1:level-warn Logger_1:mixin-expr Logger_1:mixin-expr-debug
Logger_1:msg Logger_1:msg-loc Logger_1:warn Logger_1:warn-loc)
> ;;
> ;;
> ;; syms of extended logger's FOOPReference
> ;;
> (symbols le)
(Logger_2:Logger_2 Logger_2:a Logger_2:arguments Logger_2:begin Logger_2:default?
Logger_2:default_flag Logger_2:end Logger_2:error Logger_2:error-loc Logger_2:expr
Logger_2:expr-info-string Logger_2:expr-info-string-tloc Logger_2:expr-loc Logger_2:expr-loc-sep
Logger_2:expr-sep Logger_2:expr-str Logger_2:expr-str-sep Logger_2:fatal Logger_2:fatal-loc
Logger_2:info Logger_2:info-loc Logger_2:lastExprEval Logger_2:level Logger_2:level-all
Logger_2:level-debug Logger_2:level-error Logger_2:level-fatal Logger_2:level-info
Logger_2:level-warn Logger_2:loc Logger_2:locStrOrSym Logger_2:mixin-expr Logger_2:mixin-expr-debug
Logger_2:msg Logger_2:msg-loc Logger_2:name-rep Logger_2:nameReps Logger_2:rep Logger_2:restFlag
Logger_2:sepFlag Logger_2:sym_identical_flag Logger_2:symbol Logger_2:tloc Logger_2:tloc2string
Logger_2:warn Logger_2:warn-loc Logger_2:wrap)
> ;;
[/code]
Note: many of these functions are convenience forwards from FOOPReference to FOOP; e.g. from (l:warn "a warning") to (:warn l "a warning").
Symbols of shared FOOP part (code used by both loggers):
> ;;
> ;; *shared* FOOP part (used by *both* loggers)
> ;;
> (symbols Logger)
(Logger:Ctx Logger:FunSym Logger:Logger Logger:arguments Logger:begin Logger:breakFlag
Logger:c_errorStr Logger:c_fatalStr Logger:c_infoStr Logger:c_warningStr Logger:class
Logger:convenience-forward Logger:convenience-forward-first-rest Logger:ctx Logger:ctxSym
Logger:default Logger:delete-all-refs Logger:delete-ref Logger:delete-ref-ix Logger:end
Logger:error Logger:error-loc Logger:execPath Logger:expr Logger:extraPrefix Logger:fatal
Logger:fatal-loc Logger:fd Logger:foop Logger:foopCount Logger:fun Logger:get-level-default
Logger:h_warn-loc-string Logger:indent Logger:indent-string Logger:indentIncrement
Logger:info Logger:info-loc Logger:ix Logger:l Logger:level Logger:level-all Logger:level-debug
Logger:level-default Logger:level-error Logger:level-fatal Logger:level-info Logger:level-warn
Logger:level_all Logger:level_debug Logger:level_default Logger:level_error Logger:level_fatal
Logger:level_info Logger:level_warn Logger:locStrOrSym Logger:log-level Logger:msg
Logger:msg-format Logger:msg-loc Logger:n Logger:new-ref-context Logger:new-ref-context-sym
Logger:o Logger:opt_with_2_args Logger:opt_with_arg Logger:opt_without_arg Logger:prefix-loc-string
Logger:prefix-string Logger:prefixFun Logger:preprefix-func Logger:preprefix-string
Logger:ref-context-sym Logger:ref_context Logger:ref_contextSym Logger:ref_ctx Logger:reference
Logger:res Logger:s_class Logger:s_fd Logger:s_indent Logger:s_logLevel Logger:s_preprefixStr_func
Logger:s_ref Logger:scriptargs Logger:scriptargs_ Logger:scriptname Logger:scriptname_
Logger:scriptpath Logger:scriptpath-ix Logger:scriptpath_ Logger:scriptpath_ix Logger:set-fd
Logger:set-indent Logger:set-log-level Logger:set-preprefix-func Logger:set-preprefix_func
Logger:shebang? Logger:skip_next Logger:standard_constructor Logger:str Logger:to-string
Logger:use-debug-prefix Logger:use-no-prefix Logger:use-prefix-fun Logger:use-timestamp-prefix
Logger:warn Logger:warn-loc Logger:what Logger:wrap Logger:write-string)
> ;;
Here the difference in amount of minimal logger's FOOPReference symbols and its shared (with other loggers like le in the example) FOOP symbols is obvious.
If there are multiple loggers - e.g. by logging to different file descriptors or with different functionality -, sharing the FOOP code becomes effective.
This shared FOOP code will be applied to the FOOPs of loggers l and le:
> ;;
> ;; show properties of loggers l and le
> ;;
> (le:expr l) (le:expr le)
[le][newlisp] MAIN:l -> [ctx] Logger_1, Logger_1:Logger_1 -> (Logger Logger_1 2 (lambda () "") 0 0)
Logger_1
[le][newlisp] MAIN:le -> [ctx] Logger_2, Logger_2:Logger_2 -> (Logger Logger_2 2 (lambda () "[le]") 0 0)
Logger_2
> ;;
; whose FOOPs are shown after last '->' in output line as '(Logger Logger_...'.
[size=150]What do you think?[/size]