chicken-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Chicken-users] Logging Utility


From: Kon Lovett
Subject: [Chicken-users] Logging Utility
Date: Sun, 30 Sep 2007 06:50:39 -0700

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi All,

Below is a set of notes for a logging utility. Comments are welcome. The format is loose at best, but I think the idea will swim clear.

There is no real capability beyond that provided by the existing 'logging' egg except the concept of "composition." Which seems to be a big win to me.


Logger
======

A log library for Chicken Scheme.


Example
- -------

- - External Notation One

stream          : channel
                | ( channel stream )
                | ( 'not stream )
                | ( 'seq stream )
                | ( 'alt stream )

channel         : functioncall

There is an implicit 'alt' at the toplevel.

(define-log example-log
  "A slightly silly example of a log definition"
  ((level foo bar)
    (seq (console) (syslog "foo") ) )
  ((level debug)
((prefix (srfi-19-date-format "[%d-%m-%Y/%H:%M:%S] " (current- date)))
      ((buffer #:size 16384)
        (file "foo.log" #:mode truncate))))
  ((level error)
    ((prefix timestamp " " level " " (? source " ") pid)
      (syslog "foo" #:facility user #:host "syslog.example.com")))
  ((level panic)
    (smtp "mail.example.com" "address@hidden")) )

- - External Notation Two

stream          : channel
                | channel -> stream
                | ~ channel -> stream
                | channel & stream
                | channel : stream

channel         : ( identifier parameters )

parameter       : object
                | identifier = object

parameters      : parameter parameters

(define-log example-log
  "A slightly silly example of a log definition"
  (level foo bar)
    -> (console) & (syslog "foo")
  :
  (level debug)
-> (prefix (srfi-19-date-format "[%d-%m-%Y/%H:%M:%S] " (current- date)))
      -> (buffer size = 16384)
        -> (file "foo.log" mode = truncate)
  :
  (level error)
    -> (prefix timestamp " " level " " (? source " ") pid)
      -> (syslog "foo" facility = user host = "syslog.example.com")
  :
  (level panic)
    -> (smtp "mail.example.com" "address@hidden") )

; Log a message using the example
(example-log "a message" #:level 'foo #:source "bar" #:indent 2)


Channel
- -------

All built-in log channels take log context & extendend lambda list.

({channel-procedure} ctx [required ...] [#!optional ...] [#!rest rest] [#!key ...])

All channel exceptions are caught & collected in a tree, which is then re-signaled at the top-level should the entire operation abort. The aborted branch exceptions can
be "logged".

  ((exn log) conditions ({condition} ...))

A log is a channel stream. Channels are divided into filters (interior node)
& outputs (leaf node). Some filters perform flow control.


Filters
- -------

noop    ; passes everything

alt  ; try each stream until success
  stream ...

seq  ; try each stream
  stream ...

neg  ; continue downstream on failure
  stream

asynchronous  ; in own thread
  stream      ;
  [quantum]   ;
  [error]     ; error procedure

level   ; pass matching severity level(s)
  op            ; < | > | <= | >= | <> | =
  name ...      ; severity level name

match  ; pass matching message (not the prefix!)
    regexp  ; compiled patten or string
    [ci]    ; case insensitive?
    [si]    ; space insensitive?
    [utf8]  ; UTF8 string?

prefix  ; construct message prefix
        ; downstream prefix is appended to existing prefix!
  [constructor ...]   ; field-object
                      | string
                      | symbol {symbol string}
                      | (field symbol) {a cataloged field name}
| (? constructor ...) {(invoke ctor) != "" -> "ctor-result ..."}
                      | (procedure [parameter ...])

buffer  ; pend output until flush criteria met
  [size]          ; string length to buffer before flush
  [interval]      ; seconds between flush
  [level-flush]   ; level change causes flush?

call  ; (procedure message [parameter ...]) -> #f | string
  procedure
  [parameter ...]

filter  ; raw filter definition
  procedure
  [parameter ...]


Outputs
- -------

null  ; writes nothing

console ; /dev/console

port  ; display message on specified port
  output-port

uri ; send message to uri
  uri   ; uri object or string

pipe  ; pipe message to process
  command       ; string - command to execute

file  ; filesystem
  pathanme        ; pathname object or string
  [mode]          ; append | truncate
  [permissions]   ;
  [jitter]        ; # of writes before reopen
[monitor] ; # of seconds between checking file non-existence & reopen
  [keep]          ; keep open

socket  ;
  [kind]        ; tcp | udp | unix | ssl
  [name]        ; hostname | hostname:port | pathname
  [port]        ; integer | service-name
  [timeout]
  [keep]        ; keep open

syslog  ; syslog, syslogd, ... message
  [facility]   ; default is user
  [host]       ; hostname | hostname:port
  [port]

smtp  ; e-mail message
  host          ; hostname | hostname:port
  to ...        ; one or more recipients
  [domain]      ; default is local hostname
  [user]        ; default is "uid#N"
  [from]        ; default is "address@hidden:{domain}"
  [subject]     ; default is "[LOGGER] log channel output on {domain}"
  [port]
  [timeout]

output  ; raw output definition
  open              ; (-> [parameter ...] port)
  close             ; (-> port undefined)
  display           ; (-> message port undefined)
[flush] ; (-> port undefined) - default is (begin ({close} ...) ({open} ...))
  [keep]            ; keep open
  [parameter ...]   ; optional parameters for open


Data Structures
- ---------------

- - Context

  levels      ; level domain
  fields      ; field domain
  level       ; symbol
  source      ; string
prefix ; list of thunk - indent is done by (lambda () (spaces indent))
  message     ; string
  channel     ; downstream
  cached      ; actual message

Cached message is built just before call of first leaf (output) channel & invalidated after last. The actions for this are built by the 'alt' & 'seq' compilers.
The 'call' filter also builds the cached message.

- - Channel

  name          ; symbol
  description   ; string
  action        ; procedure

- - Level

  name          ; symbol
  description   ; string
  priority      ; integer

- - Field

  name          ; symbol
  description   ; string
  action        ; procedure (-> [parameter ...] string)

- - Log

  name          ; symbol
  description   ; string
  definition    ; string - string form of surface notation or #f
  sources       ; source domain
  levels        ; level domain
  fields        ; field domain
  stream        ; channel

- - Channel Catalog

  name          ; symbol
  description   ; string
  channels      ; set of channel

- - Level Catalog

  name          ; symbol
  description   ; string
  levels        ; set of level

- - Field Catalog

  name          ; symbol
  description   ; string
  fields        ; set of level

- - Log Catalog

  name          ; symbol
  description   ; string
  logs          ; set of log


Internals
- ---------

- - Use of Chicken namespace is provisional.

- - The syntax expanded example

(define example-log
  (##log#create
    "A slightly silly example of a log definition"
    (##log#alt
      ((##log#level '= 'foo 'bar)
        (##log#seq (##log#console) (##log#syslog "foo") ) )
      ((##log#level '= 'debug)
((##log#prefix (lambda () (srfi-19-date-format "[%d-%m-%Y/%H: %M:%S] " (current-date))))
          ((##log#buffer #:size 16384)
            (##log#file "foo.log" #:mode 'truncate) ) ) )
      ((##log#level '= 'error)
((##log#prefix (##log#field 'timestamp) " " (##log#field 'level) " " (##log#field-conditional (##log#field 'source) " ") (##log#field 'pid)) (##log#syslog "foo" #:facility 'user #:host "syslog.example.com") ) )
      ((##log#level '= 'panic)
        (##log#smtp "mail.example.com" "address@hidden")) )
    #:definition
"((level foo bar) -> (console) & (syslog \"foo\") : (level debug) -> (prefix (srfi-19-date-format \"[%d-%m-%Y/%H:%M:%S] \" (current-date))) -> (buffer size = 16384) -> (file \"foo.log\" mode = truncate) : (level error) -> (prefix timestamp \" \" level \" \" (? source \" \") pid) -> (syslog \"foo\" facility = user host = \"syslog.example.com\") : (level panic) -> (smtp \"mail.example.com\" \"address@hidden"))" ) )


- - Not

((neg (match ...)) (output ...))

  AND

~ (match ...) -> (output ...)

  =>

((##log#neg (##log#match ...)) (##log#output))

- -

Each channel has syntax & semantic action. The syntax action transforms the surface notation into the semantic notation. The semantic action creates a
channel procedure, providing any necessary flow control and side-effect
operations.


API (todo)
- ---

(log-levels LOG)
(log-levels-set! LOG LEVEL-CATALOG | LEVEL ...)

(log-fields LOG)
(log-fields-set! LOG FIELD-CATALOG | FIELD ...)

(log-sources LOG)
(log-sources-set! LOG SOURCE-CATALOG | SOURCE ...)
(log-restrict LOG SOURCE-CATALOG | SOURCE ...)

(log-definition LOG)
(log-definition-set! LOG STRING)

(log-description LOG)
(log-description-set! LOG STRING)

(log-channel LOG)
(log-channel-set! LOG CHANNEL)

...


Best Wishes,
Kon


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (Darwin)

iEYEARECAAYFAkb/qbAACgkQJJNoeGe+5O47kwCePInh/VA5VynC+9EdG7C9FNii
Tz0An0oUobtfG4zcBz3gbjzBg7b4RN03
=0rQm
-----END PGP SIGNATURE-----




reply via email to

[Prev in Thread] Current Thread [Next in Thread]