home *** CD-ROM | disk | FTP | other *** search
/ H4CK3R 5 / hacker05 / 05_HACK_05.ISO / programacao / freewrap / TCLLIBsampleApp.exe / sample / tcllib / tcllib1.0 / log / log.tcl next >
Encoding:
Text File  |  2001-08-17  |  14.6 KB  |  708 lines

  1. # log.tcl --
  2. #
  3. #    Tcl implementation of a general logging facility
  4. #    (Reaped from Pool_Base and modified to fit into tcllib)
  5. #
  6. # Copyright (c) 2001 by ActiveState Tool Corp.
  7. # See the file license.terms.
  8.  
  9. package require Tcl 8
  10. package provide log 1.0
  11.  
  12. namespace eval ::log {
  13.     namespace export *
  14.  
  15.     # The known log-levels.
  16.  
  17.     variable levels [list \
  18.         emergency \
  19.         alert \
  20.         critical \
  21.         error \
  22.         warning \
  23.         notice \
  24.         info \
  25.         debug]
  26.  
  27.     # Array mapping from all unique prefixes for log levels to their
  28.     # corresponding long form.
  29.  
  30.     # *future* Use a procedure from 'textutil' to calculate the
  31.     #          prefixes and to fill the map.
  32.  
  33.     variable  levelMap
  34.     array set levelMap {
  35.     a        alert
  36.     al        alert
  37.     ale        alert
  38.     aler        alert
  39.     alert        alert
  40.     c        critical
  41.     cr        critical
  42.     cri        critical
  43.     crit        critical
  44.     criti        critical
  45.     critic        critical
  46.     critica        critical
  47.     critical    critical
  48.     d        debug
  49.     de        debug
  50.     deb        debug
  51.     debu        debug
  52.     debug        debug
  53.     em        emergency
  54.     eme        emergency
  55.     emer        emergency
  56.     emerg        emergency
  57.     emerge        emergency
  58.     emergen        emergency
  59.     emergenc    emergency
  60.     emergency    emergency
  61.     er        error
  62.     err        error
  63.     erro        error
  64.     error        error
  65.     i        info
  66.     in        info
  67.     inf        info
  68.     info        info
  69.     n        notice
  70.     no        notice
  71.     not        notice
  72.     noti        notice
  73.     notic        notice
  74.     notice        notice
  75.     w        warning
  76.     wa        warning
  77.     war        warning
  78.     warn        warning
  79.     warni        warning
  80.     warnin        warning
  81.     warning        warning
  82.     }
  83.  
  84.     # Map from log-levels to the commands to execute when a message
  85.     # with that level arrives in the system. The standard command for
  86.     # all levels is '::log::Puts' which writes the message to either
  87.     # stdout or stderr, depending on the level. The decision about the
  88.     # channel is stored in another map and modifiable by the user of
  89.     # the package.
  90.  
  91.     variable  cmdMap
  92.     array set cmdMap {}
  93.  
  94.     variable lv
  95.     foreach  lv $levels {set cmdMap($lv) ::log::Puts}
  96.     unset    lv
  97.  
  98.     # Map from log-levels to the channels ::log::Puts shall write
  99.     # messages with that level to. The map can be queried and changed
  100.     # by the user.
  101.  
  102.     variable  channelMap
  103.     array set channelMap {
  104.     emergency  stderr
  105.     alert      stderr
  106.     critical   stderr
  107.     error      stderr
  108.     warning    stdout
  109.     notice     stdout
  110.     info       stdout
  111.     debug      stdout
  112.     }
  113.  
  114.     # Graphical user interfaces may want to colorize messages based
  115.     # upon their level. The following array stores a map from levels
  116.     # to colors. The map can be queried and changed by the user.
  117.  
  118.     variable  colorMap
  119.     array set colorMap {
  120.     emergency red
  121.     alert     red
  122.     critical  red
  123.     error     red
  124.     warning   yellow
  125.     notice    seagreen
  126.     info      {}
  127.     debug     lightsteelblue
  128.     }
  129.  
  130.     # To allow an easy comparison of the relative importance of a
  131.     # level the following array maps from levels to a numerical
  132.     # priority. The higher the number the more important the
  133.     # level. The user cannot change this map (for now). This package
  134.     # uses the priorities to allow the user to supress messages based
  135.     # upon their levels.
  136.  
  137.     variable  priorityMap
  138.     array set priorityMap {
  139.     emergency 7
  140.     alert     6
  141.     critical  5
  142.     error     4
  143.     warning   3
  144.     notice    2
  145.     info      1
  146.     debug     0
  147.     }
  148.  
  149.     # The following array is internal and holds the information about
  150.     # which levels are suppressed, i.e. may not be written.
  151.     #
  152.     # 0 - messages with with level are written out.
  153.     # 1 - messages with this level are suppressed.
  154.  
  155.     variable  suppressed
  156.     array set suppressed {
  157.     emergency 0
  158.     alert     0
  159.     critical  0
  160.     error     0
  161.     warning   0
  162.     notice    0
  163.     info      0
  164.     debug     0
  165.     }
  166.  
  167.     # Internal static information. Map from levels to a string of
  168.     # spaces. The number of spaces in each string is just enough to
  169.     # make all level names together with their string of the same
  170.     # length.
  171.  
  172.     variable  fill
  173.     array set fill {
  174.     emergency ""    alert "    "    critical " "    error "    "
  175.     warning "  "    notice "   "    info "     "    debug "    "
  176.     }
  177. }
  178.  
  179.  
  180. # log::levels --
  181. #
  182. #    Retrieves the names of all known levels.
  183. #
  184. # Arguments:
  185. #    None.
  186. #
  187. # Side Effects:
  188. #    None.
  189. #
  190. # Results:
  191. #    A list containing the names of all known levels,
  192. #    alphabetically sorted.
  193.  
  194. proc ::log::levels {} {
  195.     variable levels
  196.     return [lsort $levels]
  197. }
  198.  
  199. # log::lv2longform --
  200. #
  201. #    Converts any unique abbreviation of a level name to the full
  202. #    level name.
  203. #
  204. # Arguments:
  205. #    level    The prefix of a level name to convert.
  206. #
  207. # Side Effects:
  208. #    None.
  209. #
  210. # Results:
  211. #    Returns the full name to the specified abbreviation or an
  212. #    error.
  213.  
  214. proc ::log::lv2longform {level} {
  215.     variable levelMap
  216.  
  217.     if {[info exists levelMap($level)]} {
  218.     return $levelMap($level)
  219.     }
  220.  
  221.     return -code error "\"$level\" is no unique abbreviation of a level name"
  222. }
  223.  
  224. # log::lv2color --
  225. #
  226. #    Converts any level name including unique abbreviations to the
  227. #    corresponding color.
  228. #
  229. # Arguments:
  230. #    level    The level to convert into a color.
  231. #
  232. # Side Effects:
  233. #    None.
  234. #
  235. # Results:
  236. #    The name of a color or an error.
  237.  
  238. proc ::log::lv2color {level} {
  239.     variable colorMap
  240.     set level [lv2longform $level]
  241.     return $colorMap($level)
  242. }
  243.  
  244. # log::lv2priority --
  245. #
  246. #    Converts any level name including unique abbreviations to the
  247. #    corresponding priority.
  248. #
  249. # Arguments:
  250. #    level    The level to convert into a priority.
  251. #
  252. # Side Effects:
  253. #    None.
  254. #
  255. # Results:
  256. #    The numerical priority of the level or an error.
  257.  
  258. proc ::log::lv2priority {level} {
  259.     variable priorityMap
  260.     set level [lv2longform $level]
  261.     return $priorityMap($level)
  262. }
  263.  
  264. # log::lv2cmd --
  265. #
  266. #    Converts any level name including unique abbreviations to the
  267. #    command prefix used to write messages with that level.
  268. #
  269. # Arguments:
  270. #    level    The level to convert into a command prefix.
  271. #
  272. # Side Effects:
  273. #    None.
  274. #
  275. # Results:
  276. #    A string containing a command prefix or an error.
  277.  
  278. proc ::log::lv2cmd {level} {
  279.     variable cmdMap
  280.     set level [lv2longform $level]
  281.     return $cmdMap($level)
  282. }
  283.  
  284. # log::lv2channel --
  285. #
  286. #    Converts any level name including unique abbreviations to the
  287. #    channel used by ::log::Puts to write messages with that level.
  288. #
  289. # Arguments:
  290. #    level    The level to convert into a channel.
  291. #
  292. # Side Effects:
  293. #    None.
  294. #
  295. # Results:
  296. #    A string containing a channel handle or an error.
  297.  
  298. proc ::log::lv2channel {level} {
  299.     variable channelMap
  300.     set level [lv2longform $level]
  301.     return $channelMap($level)
  302. }
  303.  
  304. # log::lvCompare --
  305. #
  306. #    Compares two levels (including unique abbreviations) with
  307. #    respect to their priority. This command can be used by the
  308. #    -command option of lsort.
  309. #
  310. # Arguments:
  311. #    level1    The first of the levels to compare.
  312. #    level2    The second of the levels to compare.
  313. #
  314. # Side Effects:
  315. #    None.
  316. #
  317. # Results:
  318. #    One of -1, 0 or 1 or an error. A result of -1 signals that
  319. #    level1 is of less priority than level2. 0 signals that both
  320. #    levels have the same priority. 1 signals that level1 has
  321. #    higher priority than level2.
  322.  
  323. proc ::log::lvCompare {level1 level2} {
  324.     variable priorityMap
  325.  
  326.     set level1 $priorityMap([lv2longform $level1])
  327.     set level2 $priorityMap([lv2longform $level2])
  328.  
  329.     if {$level1 < $level2} {
  330.     return -1
  331.     } elseif {$level1 > $level2} {
  332.     return 1
  333.     } else {
  334.     return 0
  335.     }
  336. }
  337.  
  338. # log::lvSuppress --
  339. #
  340. #    (Un)suppresses the output of messages having the specified
  341. #    level. Unique abbreviations for the level are allowed here
  342. #    too.
  343. #
  344. # Arguments:
  345. #    level        The name of the level to suppress or
  346. #            unsuppress. Unique abbreviations are allowed
  347. #            too.
  348. #    suppress    Boolean flag. Optional. Defaults to the value
  349. #            1, which means to suppress the level. The
  350. #            value 0 on the other hand unsuppresses the
  351. #            level.
  352. #
  353. # Side Effects:
  354. #    See above.
  355. #
  356. # Results:
  357. #    None.
  358.  
  359. proc ::log::lvSuppress {level {suppress 1}} {
  360.     variable suppressed
  361.     set level [lv2longform $level]
  362.  
  363.     switch -exact -- $suppress {
  364.     0 - 1 {} default {
  365.         return -code error "\"$suppress\" is not a member of \{0, 1\}"
  366.     }
  367.     }
  368.  
  369.     set suppressed($level) $suppress
  370.     return
  371. }
  372.  
  373. # log::lvSuppressLE --
  374. #
  375. #    (Un)suppresses the output of messages having the specified
  376. #    level or one of lesser priority. Unique abbreviations for the
  377. #    level are allowed here too.
  378. #
  379. # Arguments:
  380. #    level        The name of the level to suppress or
  381. #            unsuppress. Unique abbreviations are allowed
  382. #            too.
  383. #    suppress    Boolean flag. Optional. Defaults to the value
  384. #            1, which means to suppress the specified
  385. #            levels. The value 0 on the other hand
  386. #            unsuppresses the levels.
  387. #
  388. # Side Effects:
  389. #    See above.
  390. #
  391. # Results:
  392. #    None.
  393.  
  394. proc ::log::lvSuppressLE {level {suppress 1}} {
  395.     variable suppressed
  396.     variable levels
  397.     variable priorityMap
  398.  
  399.     set level [lv2longform $level]
  400.  
  401.     switch -exact -- $suppress {
  402.     0 - 1 {} default {
  403.         return -code error "\"$suppress\" is not a member of \{0, 1\}"
  404.     }
  405.     }
  406.  
  407.     set prio  [lv2priority $level]
  408.  
  409.     foreach l $levels {
  410.     if {$priorityMap($l) <= $prio} {
  411.         set suppressed($l) $suppress
  412.     }
  413.     }
  414.     return
  415. }
  416.  
  417. # log::lvIsSuppressed --
  418. #
  419. #    Asks the package wether the specified level is currently
  420. #    suppressed. Unique abbreviations of level names are allowed.
  421. #
  422. # Arguments:
  423. #    level    The level to query.
  424. #
  425. # Side Effects:
  426. #    None.
  427. #
  428. # Results:
  429. #    None.
  430.  
  431. proc ::log::lvIsSuppressed {level} {
  432.     variable suppressed
  433.     set level [lv2longform $level]
  434.     return $suppressed($level)
  435. }
  436.  
  437. # log::lvCmd --
  438. #
  439. #    Defines for the specified level with which command to write
  440. #    the messages having this level. Unique abbreviations of level
  441. #    names are allowed. The command is actually a command prefix
  442. #    and this facility will append 2 arguments before calling it,
  443. #    the level of the message and the message itself, in this
  444. #    order.
  445. #
  446. # Arguments:
  447. #    level    The level the command prefix is for.
  448. #    cmd    The command prefix to use for the specified level.
  449. #
  450. # Side Effects:
  451. #    See above.
  452. #
  453. # Results:
  454. #    None.
  455.  
  456. proc ::log::lvCmd {level cmd} {
  457.     variable cmdMap
  458.     set level [lv2longform $level]
  459.     set cmdMap($level) $cmd
  460.     return
  461. }
  462.  
  463. # log::lvCmdForall --
  464. #
  465. #    Defines for all known levels with which command to write the
  466. #    messages having this level. The command is actually a command
  467. #    prefix and this facility will append 2 arguments before
  468. #    calling it, the level of the message and the message itself,
  469. #    in this order.
  470. #
  471. # Arguments:
  472. #    cmd    The command prefix to use for all levels.
  473. #
  474. # Side Effects:
  475. #    See above.
  476. #
  477. # Results:
  478. #    None.
  479.  
  480. proc ::log::lvCmdForall {cmd} {
  481.     variable cmdMap
  482.     variable levels
  483.  
  484.     foreach l $levels {
  485.     set cmdMap($l) $cmd
  486.     }
  487.     return
  488. }
  489.  
  490. # log::lvChannel --
  491. #
  492. #    Defines for the specified level into which channel ::log::Puts
  493. #    (the standard command) shall write the messages having this
  494. #    level. Unique abbreviations of level names are allowed. The
  495. #    command is actually a command prefix and this facility will
  496. #    append 2 arguments before calling it, the level of the message
  497. #    and the message itself, in this order.
  498. #
  499. # Arguments:
  500. #    level    The level the channel is for.
  501. #    chan    The channel to use for the specified level.
  502. #
  503. # Side Effects:
  504. #    See above.
  505. #
  506. # Results:
  507. #    None.
  508.  
  509. proc ::log::lvChannel {level chan} {
  510.     variable channelMap
  511.     set level [lv2longform $level]
  512.     set channelMap($level) $chan
  513.     return
  514. }
  515.  
  516. # log::lvChannelForall --
  517. #
  518. #    Defines for all known levels with which which channel
  519. #    ::log::Puts (the standard command) shall write the messages
  520. #    having this level. The command is actually a command prefix
  521. #    and this facility will append 2 arguments before calling it,
  522. #    the level of the message and the message itself, in this
  523. #    order.
  524. #
  525. # Arguments:
  526. #    chan    The channel to use for all levels.
  527. #
  528. # Side Effects:
  529. #    See above.
  530. #
  531. # Results:
  532. #    None.
  533.  
  534. proc ::log::lvChannelForall {chan} {
  535.     variable channelMap
  536.     variable levels
  537.  
  538.     foreach l $levels {
  539.     set channelMap($l) $chan
  540.     }
  541.     return
  542. }
  543.  
  544. # log::lvColor --
  545. #
  546. #    Defines for the specified level the color to return for it in
  547. #    a call to ::log::lv2color. Unique abbreviations of level names
  548. #    are allowed.
  549. #
  550. # Arguments:
  551. #    level    The level the color is for.
  552. #    color    The color to use for the specified level.
  553. #
  554. # Side Effects:
  555. #    See above.
  556. #
  557. # Results:
  558. #    None.
  559.  
  560. proc ::log::lvColor {level color} {
  561.     variable colorMap
  562.     set level [lv2longform $level]
  563.     set colorMap($level) $color
  564.     return
  565. }
  566.  
  567. # log::lvColorForall --
  568. #
  569. #    Defines for all known levels the color to return for it in a
  570. #    call to ::log::lv2color. Unique abbreviations of level names
  571. #    are allowed.
  572. #
  573. # Arguments:
  574. #    color    The color to use for all levels.
  575. #
  576. # Side Effects:
  577. #    See above.
  578. #
  579. # Results:
  580. #    None.
  581.  
  582. proc ::log::lvColorForall {color} {
  583.     variable colorMap
  584.     variable levels
  585.  
  586.     foreach l $levels {
  587.     set colorMap($l) $color
  588.     }
  589.     return
  590. }
  591.  
  592. # log::log --
  593. #
  594. #    Log a message according to the specifications for commands,
  595. #    channels and suppression. In other words: The command will do
  596. #    nothing if the specified level is suppressed. If it is not
  597. #    suppressed the actual logging is delegated to the specified
  598. #    command. If there is no command specified for the level the
  599. #    message won't be logged. The standard command ::log::Puts will
  600. #    write the message to the channel specified for the given
  601. #    level. If no channel is specified for the level the message
  602. #    won't be logged. Unique abbreviations of level names are
  603. #    allowed. Errors in the actual logging command are *not*
  604. #    catched, but propagated to the caller, as they may indicate
  605. #    misconfigurations of the log facility or errors in the callers
  606. #    code itself.
  607. #
  608. # Arguments:
  609. #    level    The level of the message.
  610. #    text    The message to log.
  611. #
  612. # Side Effects:
  613. #    See above.
  614. #
  615. # Results:
  616. #    None.
  617.  
  618. proc ::log::log {level text} {
  619.     variable cmdMap
  620.  
  621.     if {[lvIsSuppressed $level]} {
  622.     # Ignore messages for suppressed levels.
  623.     return
  624.     }
  625.  
  626.     set level [lv2longform $level]
  627.  
  628.     set cmd $cmdMap($level)
  629.     if {$cmd == {}} {
  630.     # Ignore messages for levels without a command
  631.     return
  632.     }
  633.  
  634.     # Delegate actual logging to the command
  635.  
  636.     lappend cmd $level $text
  637.     eval $cmd
  638.     return
  639. }
  640.  
  641. # log::logMsg --
  642. #
  643. #    Convenience wrapper around ::log::log. Equivalent to
  644. #    '::log::log info text'.
  645. #
  646. # Arguments:
  647. #    text    The message to log.
  648. #
  649. # Side Effects:
  650. #    See ::log::log.
  651. #
  652. # Results:
  653. #    None.
  654.  
  655. proc ::log::logMsg {text} {
  656.     log info $text
  657. }
  658.  
  659. # log::logError --
  660. #
  661. #    Convenience wrapper around ::log::log. Equivalent to
  662. #    '::log::log error text'.
  663. #
  664. # Arguments:
  665. #    text    The message to log.
  666. #
  667. # Side Effects:
  668. #    See ::log::log.
  669. #
  670. # Results:
  671. #    None.
  672.  
  673. proc ::log::logError {text} {
  674.     log error $text
  675. }
  676.  
  677.  
  678. # log::Puts --
  679. #
  680. #    Standard log command, writing messages and levels to
  681. #    user-specified channels. Assumes that the supression checks
  682. #    were done by the caller. Expects full level names,
  683. #    abbreviations are *not allowed*.
  684. #
  685. # Arguments:
  686. #    level    The level of the message. 
  687. #    text    The message to log.
  688. #
  689. # Side Effects:
  690. #    Writes into channels.
  691. #
  692. # Results:
  693. #    None.
  694.  
  695. proc ::log::Puts {level text} {
  696.     variable channelMap
  697.     variable fill
  698.  
  699.     set chan $channelMap($level)
  700.     if {$chan == {}} {
  701.     # Ignore levels without channel.
  702.     return
  703.     }
  704.  
  705.     puts $chan "$level$fill($level) $text"
  706.     return
  707. }
  708.