log4r-1.1.10/0000755000004100000410000000000011702744173012657 5ustar www-datawww-datalog4r-1.1.10/doc/0000755000004100000410000000000011702744173013424 5ustar www-datawww-datalog4r-1.1.10/doc/rdoc-log4r.css0000644000004100000410000003006311702744173016114 0ustar www-datawww-data/* * "Darkfish" Rdoc CSS * $Id$ * * Author: Michael Granger * */ /* Base Green is: #660000 */ *{ padding: 0; margin: 0; } body { background: #efefef; font: 14px "Helvetica Neue", Helvetica, Tahoma, sans-serif; } body.class, body.module, body.file { margin-left: 40px; } body.file-popup { font-size: 90%; margin-left: 0; } h1 { font-size: 300%; text-shadow: rgba(135,145,135,0.65) 2px 2px 3px; color: #660000; } h2,h3,h4 { margin-top: 1.5em; } a { color: #660000; text-decoration: none; } a:hover { border-bottom: 1px dotted #660000; } pre { background: #ddd; padding: 0.5em 0; } /* @group Generic Classes */ .initially-hidden { display: none; } .quicksearch-field { width: 98%; background: #ddd; border: 1px solid #aaa; height: 1.5em; -webkit-border-radius: 4px; } .quicksearch-field:focus { background: #f1edba; } .missing-docs { font-size: 120%; background: white url(images/wrench_orange.png) no-repeat 4px center; color: #FFC200; line-height: 2em; border: 1px solid #d00; opacity: 1; padding-left: 20px; text-indent: 24px; letter-spacing: 3px; font-weight: bold; -webkit-border-radius: 5px; -moz-border-radius: 5px; } .target-section { border: 2px solid #dcce90; border-left-width: 8px; padding: 0 1em; background: #fff3c2; } /* @end */ /* @group Index Page, Standalone file pages */ body.indexpage { margin: 1em 3em; } body.indexpage p, body.indexpage div, body.file p { margin: 1em 0; } .indexpage ul, .file #documentation ul { line-height: 160%; list-style: none; } .indexpage ul a, .file #documentation ul a { font-size: 16px; } .indexpage li, .file #documentation li { padding-left: 20px; background: url(images/bullet_black.png) no-repeat left 4px; } .indexpage li.module { background: url(images/package.png) no-repeat left 4px; } .indexpage li.class { background: url(images/ruby.png) no-repeat left 4px; } .indexpage li.file { background: url(images/page_white_text.png) no-repeat left 4px; } /* @end */ /* @group Top-Level Structure */ .class #metadata, .file #metadata, .module #metadata { float: left; width: 260px; } .class #documentation, .file #documentation, .module #documentation { margin: 2em 1em 5em 300px; min-width: 340px; } .file #metadata { margin: 0.8em; } #validator-badges { clear: both; margin: 1em 1em 2em; } /* @end */ /* @group Metadata Section */ #metadata .section { background-color: #F2F5ED; -moz-border-radius: 5px; -webkit-border-radius: 5px; border: 1px solid #aaa; margin: 0 8px 16px; font-size: 90%; overflow: hidden; } #metadata h3.section-header { margin: 0; padding: 2px 8px; background: #FFC200; color: #505050; -moz-border-radius-topleft: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-left-radius: 4px; -webkit-border-top-right-radius: 4px; border-bottom: 1px solid #aaa; } #metadata ul, #metadata dl, #metadata p { padding: 8px; list-style: none; } #file-metadata ul { padding-left: 28px; list-style-image: url(images/page_green.png); } dl.svninfo { color: #505050; margin: 0; } dl.svninfo dt { font-weight: bold; } ul.link-list li { white-space: nowrap; } ul.link-list .type { font-size: 8px; text-transform: uppercase; color: white; background: #969696; padding: 2px 4px; -webkit-border-radius: 5px; } /* @end */ /* @group Project Metadata Section */ #project-metadata { margin-top: 3em; } .file #project-metadata { margin-top: 0em; } #project-metadata .section { border: 1px solid #aaa; } #project-metadata h3.section-header { border-bottom: 1px solid #aaa; position: relative; } #project-metadata h3.section-header .search-toggle { position: absolute; right: 5px; } #project-metadata form { color: #777; background: #FFC200; padding: 8px 8px 16px; border-bottom: 1px solid #bbb; } #project-metadata fieldset { border: 0; } #no-class-search-results { margin: 0 auto 1em; text-align: center; font-size: 14px; font-weight: bold; color: #aaa; } /* @end */ /* @group Documentation Section */ #description { font-size: 100%; color: #333; } #description p { margin: 1em 0.4em; } #description ul { margin-left: 2em; } #description ul li { line-height: 1.4em; } #description dl, #documentation dl { margin: 8px 1.5em; border: 1px solid #FFC200; } #description dl { font-size: 14px; } #description dt, #documentation dt { padding: 2px 4px; font-weight: bold; background: #ddd; } #description dd, #documentation dd { padding: 2px 12px; } #description dd + dt, #documentation dd + dt { margin-top: 0.7em; } #documentation .section { font-size: 90%; } #documentation h3.section-header { margin-top: 2em; padding: 0.75em 0.5em; background-color: #F2F5ED; color: #333; font-size: 150%; border: 1px solid #bbb; -moz-border-radius: 3px; -webkit-border-radius: 3px; } #constants-list > dl, #attributes-list > dl { margin: 1em 0 2em; border: 0; } #constants-list > dl dt, #attributes-list > dl dt { padding-left: 0; font-weight: bold; font-family: Monaco, "Andale Mono"; background: inherit; } #constants-list > dl dt a, #attributes-list > dl dt a { color: inherit; } #constants-list > dl dd, #attributes-list > dl dd { margin: 0 0 1em 0; padding: 0; color: #505050; } /* @group Method Details */ #documentation .method-source-code { display: none; } #documentation .method-detail { margin: 0.5em 0; padding: 0.5em 0; cursor: pointer; } #documentation .method-detail:hover { background-color: #f1edba; } #documentation .method-alias { font-style: oblique; } #documentation .method-heading { position: relative; padding: 2px 4px 0 20px; font-size: 125%; font-weight: bold; color: #333; background: url(images/brick.png) no-repeat left bottom; } #documentation .method-heading a { color: inherit; } #documentation .method-click-advice { position: absolute; top: 2px; right: 5px; font-size: 10px; color: #9b9877; visibility: hidden; padding-right: 20px; line-height: 20px; background: url(images/zoom.png) no-repeat right top; } #documentation .method-detail:hover .method-click-advice { visibility: visible; } #documentation .method-alias .method-heading { color: #505050; background: url(images/brick_link.png) no-repeat left bottom; } #documentation .method-description, #documentation .aliases { margin: 0 20px; line-height: 1.2em; color: #505050; } #documentation .aliases { padding-top: 4px; font-style: italic; cursor: default; } #documentation .method-description p { padding: 0; } #documentation .method-description p + p { margin-bottom: 0.5em; } #documentation .attribute-method-heading { background: url(images/tag_green.png) no-repeat left bottom; } #documentation #attribute-method-details .method-detail:hover { background-color: transparent; cursor: default; } #documentation .attribute-access-type { font-size: 60%; text-transform: uppercase; vertical-align: super; padding: 0 2px; } /* @end */ /* @end */ /* @group Source Code */ a.source-toggle { font-size: 90%; } a.source-toggle img { } div.method-source-code { background: #262626; color: #efefef; margin: 1em; padding: 0.5em; border: 1px dashed #999; overflow: hidden; } div.method-source-code pre { background: inherit; padding: 0; color: white; overflow: hidden; } /* @group Ruby keyword styles */ .standalone-code { background: #221111; color: #ffdead; overflow: hidden; } .ruby-constant { color: #7fffd4; background: transparent; } .ruby-keyword { color: #00ffff; background: transparent; } .ruby-ivar { color: #eedd82; background: transparent; } .ruby-operator { color: #00ffee; background: transparent; } .ruby-identifier { color: #ffdead; background: transparent; } .ruby-node { color: #ffa07a; background: transparent; } .ruby-comment { color: #b22222; font-weight: bold; background: transparent; } .ruby-regexp { color: #ffa07a; background: transparent; } .ruby-value { color: #7fffd4; background: transparent; } /* @end */ /* @end */ /* @group File Popup Contents */ .file #metadata, .file-popup #metadata { } .file-popup dl { font-size: 80%; padding: 0.75em; background-color: #F2F5ED; color: #333; border: 1px solid #bbb; -moz-border-radius: 3px; -webkit-border-radius: 3px; } .file dt { font-weight: bold; padding-left: 22px; line-height: 20px; background: url(images/page_white_width.png) no-repeat left top; } .file dt.modified-date { background: url(images/date.png) no-repeat left top; } .file dt.requires { background: url(images/plugin.png) no-repeat left top; } .file dt.scs-url { background: url(images/wrench.png) no-repeat left top; } .file dl dd { margin: 0 0 1em 0; } .file #metadata dl dd ul { list-style: circle; margin-left: 20px; padding-top: 0; } .file #metadata dl dd ul li { } .file h2 { margin-top: 2em; padding: 0.75em 0.5em; background-color: #F2F5ED; color: #333; font-size: 120%; border: 1px solid #bbb; -moz-border-radius: 3px; -webkit-border-radius: 3px; } /* @end */ /* @group ThickBox Styles */ #TB_window { font: 12px Arial, Helvetica, sans-serif; color: #333333; } #TB_secondLine { font: 10px Arial, Helvetica, sans-serif; color:#505050666; } #TB_window a:link {color: #505050666;} #TB_window a:visited {color: #505050666;} #TB_window a:hover {color: #000;} #TB_window a:active {color: #505050666;} #TB_window a:focus{color: #505050666;} #TB_overlay { position: fixed; z-index:100; top: 0px; left: 0px; height:100%; width:100%; } .TB_overlayMacFFBGHack {background: url(images/macFFBgHack.png) repeat;} .TB_overlayBG { background-color:#000; filter:alpha(opacity=75); -moz-opacity: 0.75; opacity: 0.75; } * html #TB_overlay { /* ie6 hack */ position: absolute; height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px'); } #TB_window { position: fixed; background: #ffffff; z-index: 102; color:#000000; display:none; border: 4px solid #525252; text-align:left; top:50%; left:50%; } * html #TB_window { /* ie6 hack */ position: absolute; margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px'); } #TB_window img#TB_Image { display:block; margin: 15px 0 0 15px; border-right: 1px solid #FFC200; border-bottom: 1px solid #FFC200; border-top: 1px solid #505050; border-left: 1px solid #505050; } #TB_caption{ height:25px; padding:7px 30px 10px 25px; float:left; } #TB_closeWindow{ height:25px; padding:11px 25px 10px 0; float:right; } #TB_closeAjaxWindow{ padding:7px 10px 5px 0; margin-bottom:1px; text-align:right; float:right; } #TB_ajaxWindowTitle{ float:left; padding:7px 0 5px 10px; margin-bottom:1px; font-size: 22px; } #TB_title{ background-color: #660000; color: #F2F5ED; height:40px; } #TB_title a { color: white !important; border-bottom: 1px dotted #F2F5ED; } #TB_ajaxContent{ clear:both; padding:2px 15px 15px 15px; overflow:auto; text-align:left; line-height:1.4em; } #TB_ajaxContent.TB_modal{ padding:15px; } #TB_ajaxContent p{ padding:5px 0px 5px 0px; } #TB_load{ position: fixed; display:none; height:13px; width:208px; z-index:103; top: 50%; left: 50%; margin: -6px 0 0 -104px; /* -height/2 0 0 -width/2 */ } * html #TB_load { /* ie6 hack */ position: absolute; margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px'); } #TB_HideSelect{ z-index:99; position:fixed; top: 0; left: 0; background-color:#fff; border:none; filter:alpha(opacity=0); -moz-opacity: 0; opacity: 0; height:100%; width:100%; } * html #TB_HideSelect { /* ie6 hack */ position: absolute; height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px'); } #TB_iframeContent{ clear:both; border:none; margin-bottom:-1px; margin-top:1px; _margin-bottom:1px; } /* @end */ /* @group Debugging Section */ #debugging-toggle { text-align: center; } #debugging-toggle img { cursor: pointer; } #rdoc-debugging-section-dump { display: none; margin: 0 2em 2em; background: #FFC200; border: 1px solid #999; } /* @end */ log4r-1.1.10/doc/content/0000755000004100000410000000000011702744173015076 5ustar www-datawww-datalog4r-1.1.10/doc/content/index.html0000644000004100000410000000743411702744173017103 0ustar www-datawww-dataTitle: Log4r - Manual Template: main.html Id: $Id$ A Powerful Logging Library for Ruby  

What Log4r Is

Log4r is a comprehensive and flexible logging library written in Ruby for use in Ruby programs. It features a hierarchical logging system of any number of levels, custom level names, logger inheritance, multiple output destinations, execution tracing, custom formatting, thread safteyness, XML and YAML configuration, and more.

Log4r is an adherent to the philosophy of logging using simple print statements. What Log4r adds to this philosophy is a flexible way of controling the information being logged. Log information can be sent to any kind of destination and with varying degrees of importance. Log4r is designed so that logging statements can remain in production code with almost no extra computational cost.

Log4r intends to be easy to use and configure, no matter the complexity. Casual scripts can use Log4r right away with minimal configuration, while more sophisticated applications can set up a structured configuration file in XML or YAML. Comprehensive documentation is provided, with a user's manual, a reference API, and over a dozen examples. Log4r attempts to abide by the Principle of Least Surprise, which means that it works as intended at all points.

Log4r was inspired by and provides much of the features of the Apache Log4j project, but is not a direct implementation or clone. Aside from superficial similarities, the projects are not related in any way and the code base is completely distinct. Log4r was developed without even looking at the Apache Log4j code.

Log4r is an Open Source project and intends to remain that way. The Log4r license is similar to the Ruby Language license. It resides on this page and in the distribution in a file named LICENSE.


Getting Started with Log4r

  1. Download the latest version from this page
  2. Try out the examples in the examples directory of the distribution
  3. Install by running ruby install.rb
  4. Read the nice manual
  5. Use Log4r
  6. Consult the Log4r RDoc API for reference
  7. Get REXML to take advantage of the XML config
  8. Contribute!

Install Using RubyGems

If you have RubyGems, install the Log4r gem!

log4r-1.1.10/doc/content/contact.html0000644000004100000410000000116411702744173017421 0ustar www-datawww-dataTitle: Log4r - Contact Template: main.html Id: $Id$ Contact the Developers   Lead developer:

Leon Torres <leon(at)ugcs dot caltech dot edu>
Pasadena, CA, USA (UTC-8)

Contributors:

log4r-1.1.10/doc/content/license.html0000644000004100000410000000427011702744173017411 0ustar www-datawww-dataTitle: Log4r License Template: main.html Id: $Id$ Log4r License  
Log4r is copyrighted free software by Leon Torres <leon@ugcs.caltech.edu>.
You can redistribute it and/or modify it under either the terms of the GPL, 
or the conditions below:

  1. You may make and give away verbatim copies of the source form of the
     software without restriction, provided that you duplicate all of the
     original copyright notices and associated disclaimers.

  2. You may modify your copy of the software in any way, provided that
     you do at least ONE of the following:

       a) place your modifications in the Public Domain or otherwise
          make them Freely Available, such as by posting said
	  modifications to Usenet or an equivalent medium, or by allowing
	  the author to include your modifications in the software.

       b) use the modified software only within your corporation or
          organization.

       c) rename any non-standard executables so the names do not conflict
	  with standard executables, which must also be provided.

       d) make other distribution arrangements with the author.

  3. You may distribute the software in object code or executable
     form, provided that you do at least ONE of the following:

       a) distribute the executables and library files of the software,
	  together with instructions (in the manual page or equivalent)
	  on where to get the original distribution.

       b) accompany the distribution with the machine-readable source of
	  the software.

       c) give non-standard executables non-standard names, with
          instructions on where to get the original software distribution.

       d) make other distribution arrangements with the author.

  4. You may modify and include the part of the software into any other
     software (possibly commercial).

  5. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
     IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     PURPOSE.
log4r-1.1.10/doc/content/manual.html0000644000004100000410000004351611702744173017252 0ustar www-datawww-dataTitle: #{version} Log4r Manual Template: main.html Id: $Id$ #{version} Log4r Manual  

Table of Contents


Scope of this Manual

Most of the API documentation resides in the Log4r RDoc API, so this manual will be brief and targeted to people starting to learn about Log4r or who want to see what Log4r has to offer.

Besides the general overview, a section called The Art of Logging provides tricks and tips in using Log4r efficiently.

Click on the section title to go back to the Table of Contents at any time.


What Log4r Is

Log4r is a comprehensive and flexible logging library written in Ruby for use in Ruby programs. It features a hierarchical logging system of any number of levels, custom level names, logger inheritance, multiple output destinations, execution tracing, custom formatting, thread safteyness, XML and YAML configuration, and more.

Log4r is an adherent to the philosophy of logging using simple print statements. What Log4r adds to this philosophy is a flexible way of controling the information being logged. Log information can be sent to any kind of destination and with varying degrees of importance. Log4r is designed so that logging statements can remain in production code with almost no extra computational cost.

Log4r intends to be easy to use and configure, no matter the complexity. Casual scripts can use Log4r right away with minimal configuration, while more sophisticated applications can set up a structured configuration file in XML or YAML. Comprehensive documentation is provided, with a user's manual, a reference API, and over a dozen examples. Log4r attempts to abide by the Principle of Least Surprise, which means that it works as intended at all points.

Log4r was inspired by and provides much of the features of the Apache Log4j project, but is not a direct implementation or clone. Aside from superficial similarities, the projects are not related in any way and the code base is completely distinct. Log4r was developed without even looking at the Apache Log4j code.

Log4r is an Open Source project and intends to remain that way. The Log4r license is similar to the Ruby Language license. It resides on

While Log4r is interpreted, it attempts to achieve optimal performance and scale well. Already, plans are being made to write the performance-critical components as a C extension to Ruby.

Log4r was inspired by and provides much of the features of the Apache Log4j project, but is not a direct implementation or clone. Aside from superficial similarities, the projects are not related in any way and the code base is completely distinct. Log4r was developed without even looking at the Apache Log4j code.

Log4r is an Open Source project and intends to remain that way. The Log4r license is similar to the Ruby Language license. It resides on this page and in the distribution in a file


Out of the Box

Here's an example of how to use Log4r right away.
require 'log4r'
include Log4r

# create a logger named 'mylog' that logs to stdout
mylog = Logger.new 'mylog'
mylog.outputters = Outputter.stdout

# Now we can log.
def do_log(log)
  log.debug "This is a message with level DEBUG"
  log.info "This is a message with level INFO"
  log.warn "This is a message with level WARN"
  log.error "This is a message with level ERROR"
  log.fatal "This is a message with level FATAL"
end
do_log(mylog)
The output will look something like this:
DEBUG mylog: This is a message with level DEBUG
 INFO mylog: This is a message with level INFO
 WARN mylog: This is a message with level WARN
ERROR mylog: This is a message with level ERROR
FATAL mylog: This is a message with level FATAL
For ease of access, the logger is stored in a hashtable keyed to its name:
mylog = Logger['mylog']        # Get our logger back
Suppose we want to turn off DEBUG, INFO and WARN messages and see only ERROR and FATAL. To do this, we set the level threshold for mylog to ERROR:
mylog.level = ERROR
Running do_log(mylog) yields:
ERROR mylog: This is a message with level ERROR
FATAL mylog: This is a message with level FATAL


Overview

We will now go over the components of Log4r. A summary of each is provided, and links to the Log4r RDoc API are provided for further perusal.


Levels

Log4r uses a hierarchical system of logging. That is, certain log events can have a higher priority than other log events. Hence, one can control how much information one wants to log by adjusting the level threshold of logging. By default, the logging levels and priorities are:
DEBUG < INFO < WARN < ERROR < FATAL
In the previous section, we saw how setting the level to ERROR prevented messages with levels DEBUG, INFO and WARN from showing up. The names and numbers of these levels are configurable. You can have any number of levels and name them whatever you wish. The logging methods we saw in the last section will be named after the custom levels. Log4r adjusts itself to suit your needs.

To find out more about levels, please see rdoc/files/log4r_rb.html.


Loggers

The principle interface in Log4r is a Logger. Loggers have one logging method for each level and any number of output destinations. A logger's level threshold and output destinations may be changed dynamically. Loggers are stored within a Repository for retrieval at any time. Loggers provide all kinds of data for logging: the log message itself, the line number and file it was called in, a timestamp, the log priority, and so on.

Loggers can inherit other Loggers. Inheritance means that a Logger initially adopts the characteristics of its parent if none are specified. A Logger's level is inherited once, and a Logger will write to its parents output destinations as well as its own. This behavior is optional, but allows one to structure a powerful, and easily configurable logging system.

To find out more about loggers, please see rdoc/files/log4r/logger_rb.html.


Outputters

An output destination (file, raw IO, stdout, etc.) is represented by an Outputter object. An Outputter has a particular means of formatting data (Formatter) and has a level threshold of its own. Outputters, like Loggers, are stored in a repository and can be retrieved and manipulated at any time. Every outputter is thread-safe, meaning that multiple threads can log to the same Outputter without worrying about race conditions.

There is a growing collection of outputters provided: raw IO, to stdout, to stderr, to files (including one that splits and zips up logs periodically), to syslog and to an email address. If a specialized Outputter is needed, one can be created from scratch in almost no time, thanks to the ease of extending log4r outputters, the well documented code and the open source license.

To find out more about outputters, please see rdoc/files/log4r/outputter/outputter_rb.html.


Formatters

A Formatter is responsible for rendering a log message into an output format. Several Formatters are provided, including the powerful PatternFormatter. PatternFormatter uses sprintf-like directives to format log messages and eliminates the need for custom Formatters.

To find out more about formatters, please see rdoc/files/log4r/formatter/formatter_rb.html.
To find out more about PatternFormatter, please see rdoc/files/log4r/formatter/patternformatter_rb.html.


Configuration

Configuring Log4r is accomplished via the Configurator and YamlConfigurator classes. They allow one to set custom levels and load up XML or YAML configurations. The XML and YAML grammar used by Log4r is extremely flexible and can accomodate the configuration of custom Outputters and Formatters with no extra work. That is, if a custom Outputter is created, it can immedieately be configured without needing to write extra code. This is acomplished by taking advantage of Ruby's powerful reflection capabilities.

To find out more about configuration, please see rdoc/files/log4r/configurator_rb.html.
For YAML configuration, also see rdoc/files/log4r/yamlconfigurator.html


Remote Logging

It is possible to send log events from an Outputter to a Logger over a network. This is accomplished using the distributed Ruby library ROMP, a subclass of Logger called LogServer, and a RemoteOutputter.

To find out more about remote logging, please see rdoc/files/log4r/logserver_rb.html

Alternatively, one can just send log reports via email using EmailOutputter.

To find out more about EmailOutputter, please see rdoc/classes/Log4r/EmailOutputter.html


The Art of Logging

Log4r in itself does not automatically enable people to understand logging, however it does provide tools to assist in The Art of Logging. We will now cover some of the techniques in this art and how to use Log4r to accomplish them.


Avoiding Parameter Evaluation

Suppose we have a complex structure and don't have the time to make a special to_s method. When we want to log the contents of the object, we end up doing something like this:
log.debug( myobj.collect{|e| e.collect{|p| p.to_s}} )
It is expensive to do this because every time the debug method is called, the parameters passed to it will be evaluated. Because this is a feature of Ruby, setting the logger to OFF will not prevent the evaluation. There are two ways to get around parameter evaluation. The first is to perform a simple if condition:
if log.debug?
  log.debug( myobj.collect{|e| e.collect{|p| p.to_s}} )
end
Here we are introduced to log.debug?, which is called a query method. It returns true if DEBUG messages are being logged, otherwise it returns false. Query methods are very cheap to invoke and are a great way to encapsulate complext logging statements. The query methods, like the logging ones, are named after the levels, but with a question mark at the end. As another example, log.info? will find out if INFO is being logged and so on.

The second way around parameter evaluation is to pass a block to the logging method:

log.debug { myobj.collect{|e| e.collect{|p| p.to_s} }
The block will be evaluated if and only if the logger is capable of handling DEBUG log events.


How Many?

How many loggers should one have? Only experience can tell, but a general rule of thumb is to create one static logger per class and one per service or state.

When dealing with a large number of loggers, logger inheritance and additivity can help organize what gets logged and to where.

The configuration possibilities in Log4r are uncountable and can sometimes be daunting. It's best to start with something simple and evolve it over time. To assist in this task, Log4r can be set up using XML or YAML configuration files.


Where To?

Log4r lets one associate any number of Outputters to a Logger. Logger additivity enables propagation of a log event upwards in the logger hierarchy. The outputters themselves can have their own level thresholds. Unlike normal loggers, Outputters can log at certain specific log levels. this allows one to channel particular data to a particular output. All things considered, log4r offers tremendous flexibility in deciding what gets logged where.


Where From?

Want to find out where a particular log statement came from? Loggers have tracers which record the call stack when turned on:
Logger['mylog'].trace = true
The trace is then accesible by a Formatter.


Who's Talking?

If there are many loggers that use logger inheritance, it's occasionally a good idea to show the full ancestry of a logger in the log statement. Here's how to set up PatternFormatter to show the full ancestry of a logger in a logging statement (in XML):
<formatter type="PatternFormatter">
  <!-- %C shows full ancestry -->
  <pattern>[%l %C] %m</pattern>
</formatter>
For a logger named 'me' with ancestors 'cain::grandpa::pa', it will produce:
[DEBUG cain::grandpa::pa::me] Log message


The Null Logger

In addition to being the parent of all loggers, Logger.root is a null object. That means that it does absolutely nothing when its log methods are invoked. Its query methods always return false and it has no outputters. It is useful to turn loggers off from within code:
noisylog = Logger.root
noisy.debug "This won't do anything"


Gotchas

If you are using Log4r, there are a few gotchas that you should be aware of:


Performance

Profiling has revealed that log4r is typically an order of magnitude or two slower than log4j. However, this is still damn fast! In particular, if a logger is set to OFF, the overhead of checking to see if a log event should be logged nearly vanishes. This was accomplished by dynamically redefining the unloggable logging methods to do nothing.

In the future, Log4r's performance critical features will be written as a C extension to Ruby. It will still be optional, but it will be available for those who absolutely need to squeeze every last ounce of performance out of Log4r. (No longer in the works, unfortunately.)


The Project Itself

Log4r was initially developed by one person and is slowly but surely gaining popularity and new developers. Please refer to the contact page for more information on the developers. log4r-1.1.10/doc/content/contribute.html0000644000004100000410000000124711702744173020146 0ustar www-datawww-dataTitle: Log4r - Contribute Template: main.html Id: $Id$ Contributing to Log4r   If you wish to contribute something to Log4r or assist in development, please drop an email to Leon: leon(at)ugcs dot caltech dot edu. There will always be work to do. Some things that come to mind are:

log4r-1.1.10/doc/log4r.css0000644000004100000410000000375211702744173015174 0ustar www-datawww-databody { background-color: #FFFFFF; font-family:sans-serif; } a:link { color:#014DA3 } a:active { color:#AA0000 } a:visited { color:#014DA3 } a:hoover { color:#AA0000 } .example { font-family: monospace; border:1px solid #007; background:#FFFFFF; margin:1em; } pre.box { margin:0px 1em 1em 1em; color:#AA0000; } .menu { font-family:sans-serif; font-size:10px; border-left: 1px solid #AA0000; border-right: 1px solid #AA0000; border-bottom: 1px solid #AA0000; background:#EEEEEE; color:#AA0000; } .menutitle { font-family:sans-serif; font-size:medium; color:#FFFFFF; font-weight:bold; background:#AA0000; border-right: 1px solid #AA0000; border-left: 1px solid #AA0000; border-top: 1px solid #AA0000; border-bottom: 1px solid #AA0000; } .menubuff { font-family:sans-serif; font-size:1px; color:#000000; border-left: 1px solid #AA0000; border-right: 1px solid #AA0000; font-weight:bold; background-color: #99CCFF; height:5; padding-bottom: 0; } .contentbuff { font-family:sans-serif; font-size:10px; border-left: 1px solid #AA0000; border-right: 1px solid #AA0000; font-weight:bold; background-color: #99CCFF; height:5; padding-bottom: 0; } .header { font-family:sans-serif; color:#AA0000; } .content { font-family:sans-serif; font-size:medium; color:#000000; background:#EEEEEE; border-right: 2px solid #AA0000; border-left: 2px solid #AA0000; border-bottom: 2px solid #AA0000; padding-bottom: 5; padding-right: 5; padding-left: 5; padding-top: 0; } .contenttitle { font-family:sans-serif; font-size:medium; color:#FFFFFF; font-weight:bold; background-color:#AA0000; border-left: 2px solid #AA0000; border-top: 1px solid #AA0000; border-right: 2px solid #AA0000; padding: 2; } .contentbuff { font-family:sans-serif; font-size:10px; color:#014DA3; border-left: 2px solid #AA0000; border-right: 2px solid #AA0000; font-weight:bold; background-color:#99CCFF; height:13; padding-bottom: 0; } br { padding-bottom: 200 } log4r-1.1.10/doc/images/0000755000004100000410000000000011702744173014671 5ustar www-datawww-datalog4r-1.1.10/doc/images/logo2.png0000644000004100000410000003260711702744173016431 0ustar www-datawww-dataPNG  IHDRd̄=gAMA aPLTEeEDDDDĪ Ƅed((Ǥedd`44ddDD ((wFD脄饤~#$TTtt ćdd~54tt88TTvTTȔȵ암ԉtt鳴VUT64CDddTT((ut44tt$$STddSTDD DD utt99]DD ٥ؔكسddtt|('ġll//~=< *, (' /. 24><"$><><"$><>< 44tt$$< IDATx] \UeFkT2) Blsk}{$C3ֽ~ַ#t4oW:A\Z>Ã.2g fZEQAOԆUdV->a%[X9iJ~@qbx9<$,-ܿ4hX`l[A-m[qEV=?\#o_9fh\IEV@@@ڭ>o ڟ]Gc0?VC0I1@gSpRS8Ϩ6ŢN|`zêhOz`xpVNzzxX̯ܱ51#k[Nk:i Z^<~yJCDS=Sa$Z{z"\\] sݞ,Oެ_d6X9ī"\ /1%WG- H 9*M^~U 2pqK ;y˫+o\:<dz;؋Wa6bn [\ϳ2q\ B9V?Xtj@1'OMުVkWl7*uY9Z8+"dm\P+yf;K܍>Q;q4? /&~֪YY 5԰_tt8Eʼn66q!UC ¢#j95,,w3s0b%(Uw qI .)$-xHtA QX߰e A1Fe1/qSgnEQ?V,߁wtθVz{^Z\-Zla1}'vLp!8' q~mE)yF<=yK<_j'~Qb)UxwŏE/G}K V\ev8r\5OwgY '-RHv<)ݻ=I_e,RdEnw U wMΝ]VR-Kх'\zHp$kX_}h-PM /&@k7ϝܯJAc᝸plww/^ģ-m6opκ )xQ!L[^q**xrR&kq`ܸS6 Vzr<"IePcz%}͂{<EbQ׉k.}AF(ƁS={*X(w*eA{Ō~t_EaHnQݵ)/;.5- 5.frshaN*%sAilpd8++KA3&xu?U(0ZGW t #rb!E^zFXGx{g"nvxf :F> wU\pD[YE%ûmoHwskll}oK+, 0cŽ44x._Sו#w{.s K=gM}>0rPog/{zI4DK*,ZTctǾw; mO֗ujI?a=7vpSyT*QKY{ 5t98;=ݦ.&v/gȒHzݔ;z-PkƆwMRR{nWXȮ]όDds8f}[{,2h֜K\5Zʤ߷BeRY얚L~颥x^D=,YU ||V6z' %Za9eF\5UxWK$Q/ ք?2&\mR-QI19r šJkt6pN{%XЇ=6I1!gT == ̓2T}b6EXV8hrzXK{3zIޢA5vb/-s/4ͼ߄ڸg"ja&Su쒜{FŔhQQJ݈;(p4Osul/{#N´i3ǝ~Z-( JWWWLew22W<͡/*\PJ ļ[KKkXxf fgYv'&ՂOC~f\5˷۫c#sr_q26H@)bT]F".w;YS* z=xR`RLnj p1F#f-6ౡ2E=,q`',=QFSMeelM};)I'l{b-3&yt2 3.`=:2 'HD@\YZ돬*7@UQ9t:ĪJģ{ d(~on 6y̙Ͼ§k9>lE֠!M,J=3^A>_#YXO;Xٴqk3ʎ\MAz+XHdYY-\3-bLӍ2`A {~_>1nxZXO!QfnvC9yȓI0QeU{q_\^:/-"YuiF/l'>@m\WMQQq K̠O\2B渔Y׀6kn;(\j#(es%~=vIsp ,dٻg͏(7-i%D%(f$ZK݌ %% J$Z|R֏x_b/+iwӼpİE݆c? ɕP\BBMeUUel=kё!x1o9֌Yi֚06=(x dk z6yyBWcԯj<+N9xٽaXy;hϞd-;rnDcTUމpՖ>;@JDM*p( J~Tx㬚OjxҁxM\<'h@?b4asYuɹQSMj!E/ X6 /.ߚx)"Y-?_QTlZYSm${,˜dy\]zt?|#Xxg׮ysʁC^l& 4}=g Hڕ&>v QȰV)AEJ<"1 bG5g@ʰU%AAѪ\,7('2Df-saK}v|Xc(Rc3s"#DS]7*ĺ@SrʄM<brMؼ]J>~ULaf8\n]GvIhfXxZI@ %vꗶ:e%ep?z#.ͅO{2 #^?t!Ik{Uʪ={G]>k.ـ}p >zv<3헾勋|1 ﲴ糲ߣ@c^?CYyֆQv0Ȫ"aJp+B{Y  W@j5]U^$ \-n({ս)nC W^5@ /z-WǷ]H.'k]E#'%8Lq*e2&3otf Ѩ Ŵd^ Vn^ZY;z￾|q/Gܧ.QQv%WXDJ/Fen.l:eLVi5I*8 Ut`/#p`Z0퓵F~+EH]Ip盛]{o%$t2O('5iH}`)je>BǷǦp*lӋ3ƍ_܈6d<3Z#̛rz <ܩkaY,1#Rc,%28i FC+]Zu)vS4)}~Q6~=$I7Yc4(}VB)mIIy޼"V7ov]-1=v=p{N𔁰Wןu;QE%v%$ [<QMrXଳDIwlDUOtU\2@T ubp+v=BB_€>}jq3裤D+.nۋO?_aܠEpI'˭]Pn<)]\'lz=/f.  )C -ڎD<Tdb~gXFpN: [eVx< -Holu瞜>۷.*%z%J52d2)V "6*C QQQvoxAl"h]Vgzc_9b{CSir;2.(ngk)enȻ/$OיFVOu̔vzNKĢ$tB۵)E {ohk9xT"JeUdFVdAp!#5ݒb[^:k,^]ZM'.\B[!I]P i t͂E9U&7r0)Qk E{q?Y1ka ; .e];B2Q1(Bete蓾\28j촔N4 cLk{xJҖ2mhf,4Ϛ{]]Ok&y~lLdjkًqEc&}aC_kt(s!ګEb4=B~2b&I =qy1 F}e?44R{?'HAn4.=bn+ؙVgR%x>?TƋkOIU׼}!Ωy"A+yj OemsP[+tģAV$Z\8J]?1 `I, zW"\n|9}Sʔa\jhLD}_|ۧ u%Eμ6>CJV.4Ah|+2XGp$9?mh{bW}_Nt F&IDAT\fK :~őt=v%މ!IZp&cR6˚4tu N<ÀqWKRaVcbHHZ6cު%K^˻wts s:(aRn X] #,,,##(-u46?yDyl(^F^M[ kn*'e.-V4xM_p{'bя軷(uL˫N=㋅ ! -@XD?0ࣟtx𵅎Ͳ1Sm[t555D|Kxb= "jzƹ_)$WزeLH,n]3wΜٽh Bs$Ol4[A3:Fhbu$imͦJ]jy}bcDt)%n~*X1$Kk Dv`/; f^۫ p|r__ߥeKʖxcTeX~sۚ@!Ր|xRs\ڴ ;f\]Й&*O>F&~ ̼Qì6=:`Ќ&^HZN5F@mK%Yݪ@!*]z1%7 O_XA^|+ˏ̊:P WŅHʃȎ^[󍍈 Y?*-kzxdxNV#+kLV|ξ}bBoE[;- e) }t׽0bb&VAR[?eﳘ&*⵾o 5Q? ʮQ[:Yq-k~W $}Lңp+rʭc✑A0v^`=DOxB(̜*0 7~m[ 3G$r?o[B)((Y C_y(sɓFc:ZGf]uh1Hk^ NWGAz*Ju˗O;Hjbяe[Q?=zv>S{*%LTGm-\NCkW=j<7(vdDln዇ =4P65:\*0cK!ȑs+\Olf)E7"`R"|ܦ}{hiR[{Ou>(J|3fb" <ы3'W F܄?#G,a$_Vff\fi+]':ߐ}qODIz!QbKZT?pdHwSv+f9=JrJw3R nbI 8PĶ뵾#U4g<|.ux!+QX~v߭D4P[ʑHgĉIIxq˜X$@ws r( %Xv)6ZYFl5fF$WV[Kw9@j~agŊUJؙѫ}&Y kW<⢥_vikjߓ~ρ c+ $_qkP9_]'?lI0K@Y P|R3g?q_x/#BBrpeP]UBS" p &c#}|y",мf#cәs8d&r%X6pErxIO36I#vn:A2"5[4C#$ [^}?/!΍V;;}DHIYT'b/$ڢc6|Wy`yˡm0w62bGg!CxǏn;>~P 7 ?~ ˍAsv9*%>7;: O ֓O˶:Fne ]]hE?5?ϲYC&Ьs'(b ![4leVQ]\dSa[$\BBb78>74kVN(*8ܼ~'gO{uJ3+u"GxZR1 !bgt k|-dgK.:`kX_y֭v5%VR.zocE=ٳ?rC'mBbD4p>sk:Cp`8zT-!cءTߢ[~x`[qI||`VX,`XG\,P5, n, i_miJ*f bPAD[SX6[lvK ֭ %l|/s1/0@Da8x,=o'p3ʢ۝U?hKb%J% ¥zpCBɏVLm!]d̛wyOO4``J%H/m ~-d@Il* mQY1+ wpAeٓ#W~WSF~EԷ T6kIg %!,XegC3( 3)vgDdxork xaKgRRz tn|2o^`+Ɲ%/y=7fn} FI6w]em?7"=Y,I (;s̘'QRďQ0G|ـGLOfѵM&R9<_/}c8|=O}Ac|Z"v@IEi'H,>KW@* Rh.+ ڻ G8'x1 _ VfvnU$LԳso?!z f?]'?z yQm9DŽu{fI0Xq(i%imcQҽ:VT(?jd ؼ?|*'t O؟^ȟp9Y!"c8UU5MSQ`i)"ʲ(,ˈ'qOEk9c  !3(B>!8|!/D,l6VQW:<<\ZZz뭷j$IQ `3 #?K&~||bϔR1".4"0rRIUUJt:!t(j糧av V!ߺuÇR)csiZUV*_pEz-\PQ˲EɲN3EM8?[ZwW^y",|.0 )j5 Fi8߾=<9u]m4$ `<F(įuEQȊT^(I`prr2 1$IƓIީX,0۪Jqݽ8I Ȳ̲K.a)YG'w僚IE-ϓsNJiʖ\i$94T*MtzrrbeYm;#ES- `oojIicpB3 K(sDMBdjښDhFZp9&IJ,˲t]O+ONqF~ᡜeB@ !>P!(ks]iMUk_s]Rzvv&J|R " pQcUVMGB΁s2!m'2&d6F|ek_AERy>=?/t]cIrQf3CdYu0PKK:8:bq4 0 N,MS#I!7<=̈́Ji4;w$33Θ*DUQжPeӃ~r"/lRq8,a( 7nrh( l"yoɲ,°QHE 9L9KQ\۶Gmɶea:.-A}hVIR4#^W.m<}Jiir9Y_hѿAoLDRq6Zx1`|,RldYo`˜S,6G/?N8p?wEzF\׍h, ; F 9猙痖 ժY(ŢXaƃݾ(ǜJta$L_\~ӟiAy8\>:F#qSDNm[ZeeR666\Yzd4ű$˹\n^e0ZffqgY(F}Axj(Ba<Kq0B,,յQ)*)RAi}2 )EΧt:uVj5Q̝NqGQ)c`B^(@R]Xˣ1@H ,+)J^./2l8d NYd#*˪!$I mX,(x"EiA@)YF8b?$Y/ ++榶$`q $I8g T,X, USe c?q׮^߽rxxߗ*@.TҖKK;;՝ꪾ `4ɄAJi atZQ4M4-c-ZP]?wyGAn4yS8gs\&D4ݲtUyXrUw:|2 q9Σ0DD0mٜ B1v{=EQ^냁@.H8bbQH*Jucai:!{>CLSђ$9t̨j GQ3sZl04!CA8fYqD3T,/Jc*r"^靟*Vus.Nҿ>Q=<7n,i5L3,z]Y_\p76e)!ǐ$<˨(mZI"BХiO'6 BW/H<TU]@!DQUUӈl(J9c++Z===]l^3R-e!#c1$!%(r4 c UU`?Wj5qR=cb۶[ǾKd_)qMU[ׯ~Gپ Bb J%XZmlԶjW旗jUs$p.](a\> Id2ps/(Y9,Iu)MҢa0Ȳ?kג$i6ju{{;˲X]]MӴn?O&+W0 `pBj)QJݻ㭭ʯ]('! jT,NlsZ]\R ˒e9 Q>1s[,ΒD?`` qǝNw߽y_OOO?oۢr?7ߌ8(~˿TUUt^B8 V*mRTUDZU($Iz,ˎH,KX' *Dӝ90Фdrev/}ۧ>??j fY0Za(f4lfۃ"+ w`}=faX{%X8;; tIF!ZEIӴuv~fB1Fh++ж; p4M_u|>_V;Ǐ{NSVݽ;?|l0rqhZӳ Dl6-rGx*'g7Շ+4ǵE<(JR.665cmW$ c08i_x!N"8 #{wΝׯy~VF6>qc8p0 ߿J%q!doo/"#^q(Ul;[Zb  _~EkO}VVV\hA]=9Ew9u.Jx6 QIpT(G9G#{2)d^($ 7(E]wT5裁e:$+++GD$|l6wCIѰC9$ w۷ [,ڲn M.]4 nn-x$Ya(t0lPִ"2xl.%IǏ;bu:Ǐ=WzxyF0 jVx/G䓤 %MQPUgib!'^{jYVKxLgKMۋ8O}y6J%y4 &Jv.k4GnΜ^oӑ|_NỻiR|jWgZ@ql"{^T׋Ţ\' !s`1o6SV}"GᏤHtN&vrrrw4^n09g7/f4 @Y)j8>m(h6mmmLwYP0 ,g]OOɄ,4g%E8Vw:֖Z*Jx|{SR2o[ NOprDWaLv {ݹsuh4߸~ b,˳MpZrd$ABq D$ B$I4\,04m{{۱m~ڽ{s.le<8@B PSnmM=/sgZm& pR2; i:pssZ*Qͦ <"4]&r8i5J˗u]4E#uzt:%߿ܽRyLz֞2(c C'''v6ۍ^{-,VV%f$Y[7(A1׿w߭:B@جŹDJIJSpXn˗9cic3Cs/i?%TDE4QJFR\`-$FݽkjeBX\쭯0ZdRHS08&<0  })]QQǂ/fÇFC.JfY(}9''ɔyJ#--ekk^-K6HI[]]-2 cuuIx4cl:Xg1I\NsB0 N?xΛ :M(M f"'FgCSHk6io߾3w{府h4 ߟN>q·ύw7oS~H7\@$ggղPvF#r$jSϋ8DQP XLWW)8v-AF |4My/_Βd_}9,eYTWL76R3vMU&P(c8ȃum/PNNO~l/y-Lfsww7MR+EDsŻ㘟F99$ DeͲ5ʕe&I죏`P,޽w~_^ZZA3X\$>}BT*-F/>mO+;(ѕ7+Z_]8cJiǿӯk6tt裍{$ f)"CIL2ID @fL22LSRXZў8KSؐ$iw7nx/s_==燃0SDA9o$2( QȄ H)OSI4@hRcƹ꺟1DT-+_$h%!ƹ͘26`E ٫&IRTYG]N* 1@ 82ƀsg8!aEĹ #ڈb1q);>&HhA}iiv۲\. H a1EC |`0dzw>Ƽ$@B,3MrY>Os9i ! R A@($I$(e!,c/bĻ~s]w:N&a,>ؖUal*y(:P"DJUUfhr>8i(4Gq1&$lˈ*!K)󸴄X.pyEL cv$dygeh$?-ߺqt;EJf9|ً"qtA9'@[Zj\u\Ya6?;㾏i ( _4Qu.])]7L2 Ac!hD$ 0˴$8HS33KR(q.j5imMTD_9:b~իkNӝ󎎎l^]]}mT*e),/+I]IP6f {~%*s3)  IDWVXM2M11] 5W9)EdfI$a&Iq$Ų ׻oi^/BiH r)ϡ!F*˙eBA.j^_7 Ӳ t]Si6Ql6HSo$DE M3MuZnw:MCu2E䌉b(F#qɲ_YYi v{4hXeY1MuRPKKΎT,B˻]$ mۯ t8obyaZ[nzpXh6w0 q(X_~yloO'ʹ)կ.^K,J1"b5 EP;nyu5L#dz=J)2qRĀs gjTYŢ8D׉?qE"F)%$4=ˊ RfɉuzJ:(&W58._~+_9;;}:Ng"J)" ŅGTgtudYvtttpV~B3дZMWVYXA;80[-e0 YPeVei}]:?KWq}c!NY(qQ*"4UOU%Mǧ;wEq1V(DD.DQtCd 恜H,'JZng|J7sۅPUI.']W׮eKKIZt:M@iJ.+KKƆzY?cXVŲtM[E:2O*{Ji$Ç%I./Urp M& c&hZڵ7nܸyK4$ @JsIUM~ǖe'rnjZ!_Z^nnZժZ,]G]GIdS㄀$QLӢ4~v|LMF0I*A4]#X״}kˢv0pΟɋD WdY^JE X 䝦iǭVލxz$* @0]lgGٱm;厎c:IPdb>"2.I-| E,x0 Gs󺇇V $IjZaU___GXi + L*ey꫕kJGGk(LsP U5 ٔS/iۊeiV,ZQ. C(][[!pH'1GQ mYH8Dؾx|tt4كfgKr|_^6R - u EO1k6fSmä{x: 8T z3 l+WQ.0diq<ϋHH"u]u?ъS?Ç|7ell8_R^јN|8 ecQۦ,sٝ;w>$gg_98X ~om LwO9;Dr9_,T*%J#mD$%AQi^DJ(ڈL cx,8<$mllT*Y#L !jjXkZ*Z s9t]4 E|2 Z&;>fN:ө$jzy\*$ImRaǧ݋y_ _!~&Aoo=zZfggN YE~8M@<2rK~V[][$1N`HE3lV5 Ʌ>M &&JB?~8۷߿EVx|>, |e%wjekkqNOiEӔ_j5t I,%:ut!R$P$P{=i0cN7)d,|rr2Lٙ4R.U)!eIRam+MѐOO$l 3"QUTF+ Y^v#0S2ᐬcib,,C"H>oIFd2Hua4MT*z ;nWvd>J$^,f4v>pn *ݻir7so6(҂ ;%ƞ,h9T̥DvZhqS9G$eUUt- 4 OS.)ō2JY9kdY<&pٙB",oeênr c J;uGꪘp(2MN壨ZYFd4 4 5Me+M9fY/4죏>S{!H 4`O0n? e;FHI#DC%@rO+v[o%K4IgHx$IE}"J $eιkkkʝlΝ|XZ*T]=91z=6iXA5 QODQZ./$ m˅|4,JtP xC0 #өz\9RJ)!i$ 2WZ>V\ш t:4NU~N~?T%JISTw @ĜǏmqNSDIQBaRei=ϊDժgFV^.]s·Y169Xii21"am&x4IgqhtÝ<-g"<IϧS>nv:d8W!(jmj !&*>G`H/=Fϝ#KU]3Q4M;w=}<.OlJ%jULSc0 l6 [^{xLJ$};6 C1ȗqI}$ ms9AIFdN)Odөѯ fZͲ,Et(EMۜsEAɕJN4Q>?+Wt{[]]][[K40ب,/ta(GruO 1LSMzvlvn߶ݳEi"ƈL\nZX*: v?P8˂XP(EWZeQ:3#یŌ,D,,H>o#YT,&|> ԅaxNDUB'̦(tc>N' iLBQWϾM5X[k!},MK\7w읞J^+ˢ4˲R8qpiB>eE"/2',O9e9˲f9:½=y^z{"RDi3ME\.AYQ MK_ʾDxb-t:aB~_cc)ywqBׅRdh2ejĴ]f??~9V%I"bCOI_6(Ag3>$p~{rJRHiz||a'Iyۯ׿?S4YQ1ƞѢNDZiο/ CAlp8遲A$0Lij_Z*ز> ÔRaжai)JE/]vx\ 4=vB-H%D)e4MD@D )O.Fe6l< fQØ1"R]UuN2FyyFDm{<o"ːen+R.}("A!0PR |> :Q5 C`b!墝˥iʵkg%XWX6gh4L&TyEV4M'i*es-K.bg"ϧ}a[[֜rdp]ޭT\NN!M9p}-KcRZB Y|l<z~igcK'6Y|}_p ՖOy$yiK׮B4M>i~,|Q((} Ĵ^vv!^|YD" *P :(PJ(ǢE:t)N) EFycH B_:1Syߪu8mðբY,i|\veUQ0$L/ \qe%"Ƕ߅ MnyL$IY$y%6d)tAI c Lܤ4I|T bQ〢 (@I!ݲd@QCYE !rq*++V&&%' c,<ҢW)-cYR 0E6W!+<~g.)ȹ2u^,zM IJm\FYl;wGVOS\E8O8s><@Q%IsPLՊcmRrJ0q Vky6cq%XQ$mnln+Dž?$B')OȝLu\ ѓip Br90NZ~nI9$VrY-ڃW0lDZ]W,Iu\t#ʶ-;}I%YF`Emۆa3 cqj'dO1Q,x8) 8'1IS1lѴ,EGKhii!!TPTUE,bT!ϗ*bۥFh=CR,ʾO!{)DbWVDF1!K˕z\(bQq'M\;>滻1$$MCS #ΧEH%QmQږ$` 2Ǹmۖ(AD5ZD9R%DARD#|E,7 t+LBH2!b0lNMWSBv.KӐsӂ@~iiۆ')B"˚j& ?b`Q#چj<7 f~A ޛHrdgfgZYMR$Dߖ Bk8366(M]**+++r> gTVMٺE ,w7;f|;!a !ISmK5 $v^J=)'(ce*:o9eL$bFQM-Pl8dL(SBBKΡZ TBTJ_4,6 %˜/Q"m[0Mi2ZfA`31U;QpbQJS!,Bi ¦_Sgggd7+@D/[!DQz )s$XUY6!+|6V۠޵Z-co6eV#@Q$*IQUf3˲X,("8@)2%s8|E~X2,yY"撄q!1!4EMe0 Iu˲G)c1"!(*(ɲ@y-P5MӎcVYa@9Q4].l\oXSUc9c$1%M)$aD c ixe)AuɹR76ڻ+WM0HxY$A@E"uI]XYF|FHDHBH%De0dו\W. RTX,4E#YƦd V!={m4qs],AE(09O"β agJSE<ҢٜhP]O,8(y^"$IEA `0!|qLGQQXu(UtGYY/yieEQH} ((d2ђ"2Ʋ(Z+֖dY8IxaYӃ&,, 1cT aaQeVH(iʶmZV4a`T ԰`F=yӧ$$AA3 G%;EXkfsXؖ|>0 -IRUgWE{jP IDAT,۶\eDi/H8 RN)$(40yn,$}zxAq=\ei n%g(1b$y"cAu[,+,燇^<#vJ)5Y `y.湄PPqPQ_0 CEFe p(4~k5jI2] @ 4V&"y Bfy!ӧOo޼$IEy[8d2Ea3F$$Ӳ,㗲qDq:FQ͹"jKqQlvׯu]1ggfaIl(MiFCu@]Dj6eӔ8bFĪ9,cMÚL;}e24-w]yaxvHA@s9XdBsYT<-isl>?::\àL0ƔbAnVPujGTT$Tr1FCgϞOO'OpNCn\WEyLTm[ C,KE!mݸaj`S>s'bN(0!UŲMbQqL*K9I$@dYTUɶZMmi(˸q<\ٌ쌝x8\FѲ,??=mB3C* Ywbd3I8Փ'_K]CNc KC^ JY"Q9[szCp\c=l6x1&fnFO&X˲0!iɄ(.(ZZr ( MZM(ϡ"@9,_j5l b۶^vfV>~9EQ KWd& Qc>$[,E<,&s>Jdssuݢ^#LcE˕.)E͸"΅Zn/OKq ;i8Q5!IC)*AniYof!aҭ-!eDiܸHgh8d_.صg1H/E$ z$DUE ;בbMêD"(XAsXшO& h{,CrΑ +4-i ]_G=?Hoݺ%x:iB"HB? k߹lEJ24n1B)2,VÚ8$)VBX$!MCҔO|:eYEJ(}EQ666jڬ]"\EN)_jgúL+nrsIGQĘy,ΣGdR-P$BC(W,˽MV"1&$!)ll,C}c6Cߪ*Ap) 4lY:vTZ Wc< CxN&^,2^ DIolWf%Օ@s&@0GH흝vvEQv1$=Au]Nw:’dc Srp$-c11s cc!u^ ' jd۶ dxpONxY^WAa<(3MRYU I>'O\vwmZE_㏝Sz!"'!l0)'/M/6BM>~oooC4Kӄ.ILغ("UEeY1ko>|hL&8&d ߧ3(YW&UU$ԣI>!IJa}6b,$J*KJ(klv$P\!**c|>;9a( A0j{SU5Z-4(<@bLXXf%n! w76ggaX z_'+$IrqȮV+ q9N$?AK>8CFWWLAHuQF]UfSQUBHIî]Kc(LQ,sIK4 g%邠erF>8(Яe<C4eG@{MHFu|ˊHvt,ˍ YǞmY﹄Ês!:g@<.JHAP9\aG)>B˒k"I^lm {{!n6Ipz=7\JY.$ IBXUQYbUE-eFy| \`,=9!|r}w:kD :VUt~Ύq2/5'a,f3uo߾-QEiƭcX.˹,TeM+ (rTphyTį;rcXHXշ_l͌qI1{A0kC4MѲP-Mm|)Ϸ{ap,K=) P2\\l6[>squg'cUTM3M`(Krrj52ҴyI'e~W:21k6kzQTmyJ$)qCp}QO|_ǘ޾-4 8~뭷]-޹۳(\]l7ܲPq߿.Dކm.o(|4Mc,C(@T|l6fSv]4]>r?"GǏ>$^I)+K"$yqQ$0EqQu<9Ewnhq#d29??/˲n홳YfB_4ƔbQD,Cy~F]SAp]MnE]$8H*Vj]G&vlKp(2(`Vouq?zTI: f4EQx\ǥa亞0t*%5h<&b6Íi8n/2"ER`@_OŽQvpND B4M_N3L>xlrAtj"B`QQ0Pΰ뒍 j [-2+$M}KI*L3h4p-K* w(50NEq+[o-}?<=Ν;PZ$IVuyOOOtdY- ) q8Fs*Kee,|U\p0v$6 "h8IQ$ee"I E+_.oݼyZEB>Y67Fł/#*"nad0H}2DE dY,;:b'',σ'Dv<~v+G ={駟f~SJƨ`&ö͞pxqe Ʋa˲\.cCeY,nDz} IBf -IXUpl.6Ml۲F7Ze4  dBcX8NsNScJ4{޾}_~Gt*Ţ,/(s_~Qe)\8XDYrqTeXx5M4YUEǡS><碈âlPA+_~SZ1BZI5@um6I%5CjbKd\ H򜚦hۊmgg矓yz,ϓE!ؽ^R*nl64gHI⮋wwey9Ǚq<` Xn z|aEEQ xtT,`@QTQvvV,yKsd`a0Ĭ͔* BHQMM##$\L;BIk0DK}qEPVT9u_mEI$. [DM5M 'O}l2Ylm`JaI6ծ pyZǎ w:uA9a<Qi,v9B4y;w !AF8qz( ٓ'$N k./إrbjLQȲLXA$L&1UU9ߔM{8y .U c")ˤ,㲄DŽ:g!,uFcXnmeeُo!w0N5 + ~x蜜8ʲKr9X^L0 =9Gx}LEe)Tz|ea;;%! C%JRڀ jbb8d n^Fi)W43C^(ER-_PkMs\uvuΝW^}x<<Ç t HtXJL֖L:?o bq<>ߏx۷Fml(7nHyl8l Byz"j(!T,+:H Ӵ@ȲKJ+/ IGO&Z^n\fP<`/Yŭ-7#Y{iԆu] ]QQA{|4==FQĘ8Q쫪&auϕ}Kt4^+GA_Qf !lnjw׮}>)xuo6*<]݇R(|yr]WUU4<P_eW_'YFO?B?c,q[.x3F>})?:BIg$h8T#Ta(ʲFe 5A4ͲNc&TII( .˲ b?ϝz[El1%$BKsAm?mooy1VC+u @v߲,#ur.~K6i1#:!L1q9Zb Z=(W\4^/_yvph4_O2uB,Q(Exnyr 5lۆjpdY\Bl2AڠI ((^Gzښ}y7.aABM"!dooU,}eD|k9?>fOGG< yYK%UH18?Cwn^w]k{Woݲ,kt:Cuyzr |^{ۿ=]׽~͛7_yUZY`%IP'GQTm7RY"702t`qt]C㜗[.h;AniZЉQQ(SDQT}2T"* < yA<:,RX,NGJ7Fu۶aҼythY?Sp_Mt}+o/ydYl&ٜۤgMݹS[I؂B4Mje=ssYV}~, CcQ>xpxs{G?}ݿb?v藞Kq! virBq|6f3Ml\.45iyw@罽=woOn?;< l{`8sk0{w}5YQ֏>@Ŋ169Ƹ^SJONNcVk0\X֓~? li_{70,KkE\я~, > B%@l08 b6]49\&I)&-ʒDQ>I, W^a aDAW(J98O9WA cSQ-5.&n4ȕ+AȲm+=t|[V0Is~~+Wn߾ $I0\Ww[h~(|׮] ~,]q666@s.R j$,T _5 3c$\=TÀ3TQQ 8[Fz> uk[34ʕeWm ¢^J*@r澚KP. tN!:蘹 {(,{{/8ÜCEH@(g˲,"ƴ\],(m6Ǫ21ys~TBU%s}ߟL&,*bZ۳ oy6AE( :@顮 e7Wb!T];;Kd>Ca:wիK_WGR"sJ)CZ !eīHZf0*#\߀ןNAE }lmۍFqqbYaxj=Mӳ s"`P***ˊ$jĘ!*˳2Dž'E|t#Tr^s1˜2&aL5 ;vmgyk3V3I ò,_]8Bu;P"Ex<ne7 j說.!$MS]>_ZxWiV=AkG_jExPUk*Ck~ZP}w UXмV~ sLӄv4a=@jS8LEAо CaAk۶8p'H ʲ\,i^ IRtX.I҅ cT4< "0E~ TD PEͦM77lgOfyYN8}a ³Nbv uGzej!)pk\u`P$"c+\;|Ae,C@ YCP%e"S/@T.zk+2uEJ`Q~6zP]vi}L\vכbzDz}J{kv]RhHqEEYXa>&;eYYNCM4B4JM+uagGّҔܿh4.l-'h<>>~7׭_s~1@,j6lLkUג`S՚&t  `l6AIӷ 5 Wຊ8q\[c#cx N:>Oۥͬ2?ؐ@>?chlr,WҎ\~t]/j`j1ƊiWX(˨۵kݮJ E,Y(bqy|\惁urfv(! R䭖ݮe>=:*t\j0BO (|gwT+f ]xtU Y+Шڑᵯ2Mj~e0RpeVjrJ+B#', /UV1JhP4'n0I PQ}=s`uói$ 7f+`=Wx/ hPQR*꺴Xg4UEuj4mW|^FɉyvffQN,!*mlYV0Sw~3A@q,z:ө6?MӜs^DȽ^?w>!t֭wZQXAj聉B j_7tju}el)z;j\:*Wx_癫KzΤ\OV(rXȹ((I 40 hW@0@m6$]$ɦ1yXt*i'}Qk>?nݼ?iBkPo 'zJ]狥_ ۶2 Ò1g{[ ~?2ͲbuB0!1Y#IH c,S$ $U}}ooP3v^Ʉ߿w^_ՍW_Tyl6#V/7EuVJx@6~㝛7矟2$>>w~o{wgW=2ug?e׮=(u׽{^q65, CB/^~|*y^mzZv2|珧_g>zj<Vm{隖e(*?}|vV,>Mh+CU`h4s੸{_tȮ(mnr&>;;o N4}Ւ$K2˄(D3Q|@v-,۶m[x^Lh\N|Ӏ? ea4[״hcpx1dmۮ$˾}ιeY$zǟ|bhZFCuƵW |1g 1`{WUyiZt:NorAƿ;1cxa384W@౲,!mP^tH800}[kn~mBF>F-a\.opѧof%]`!Qh8ds o. 0M,˒$ak;6E*_Kn=#<gh103>Ex i]Hh p)'[_$ה8@BYy#*IENDB`log4r-1.1.10/doc/dev/0000755000004100000410000000000011702744173014202 5ustar www-datawww-datalog4r-1.1.10/doc/dev/things-to-do0000644000004100000410000000044311702744173016442 0ustar www-datawww-data* Add gem generation to the automated build process * Rewrite the RDoc in third person (no "you"s) and be more formal * Warn of any remaining parameters from XML and YAML in the Configurators * Refactor YamlConfigurator and Configurator a bit: XML shouldn't sound like the prefered option log4r-1.1.10/doc/dev/README.developers0000644000004100000410000000327411702744173017237 0ustar www-datawww-dataThis document introduces interested developers to log4r development. It also reminds us how things work here. :-) RubyForge Site -------------- Log4r is hosted on RubyForge. It was hosted on SourceForge up to 1.0.5. Project Full Name: Log4r Project Unix Name: log4r CVS Server: cvs.log4r.rubyforge.org Shell/Web Server: log4r.rubyforge.org Path to web pages: /var/www/gforge-projects/log4r/ HTML manual and site -------------------- This is pieced together with a homebrewed content-template system. doc/content has the actual contents, which are just three lines of metadata and a bunch of s that are incorporated into a template. The only template is doc/templates/main.html which is universal. To test the changes, run bin/makedoc.rb directly and check the results in doc/index.html. Testing RDoc ------------ Either run bin/makerdoc.rb directly or, cd lib/ rdoc --op /tmp/rdoc --template kilmer --main log4r.rb Automated Builds ---------------- The build system is automated and relies on CVS and ruby. There are three main things that go on during build: 1) bin/makedist.rb checks out a build to prepare for distribution and calls other build scripts, then assembles the distribution into tgz and zip balls 2) HTML manual is constructed by bin/makehtml.rb, called from makedist.rb 3) RDoc is constructed by bin/makerdoc.rb, called from makedist.rb All system variables and configurable options are in bin/devconfig.rb. Essentially, the only thing that needs to be done to build packages for distribution is, ruby makedist.rb The results are one tarball, one zip file of the same, and one documentation tarball ready to be placed on the log4r home page. log4r-1.1.10/doc/dev/checklist0000644000004100000410000000114711702744173016101 0ustar www-datawww-dataRelease checklist: * DON'T FORGET: change install.rb when new lib/ files are added * Update the log4r.gemspec * Update the changelog * Update the README * Change any INSTALL instructions * Update the manuals and HTML * Modify what should not appear in the release (bin/prune.rb) * Run makedist.rb and check the integrity of the resulting files - Test installs - Run the unit tests (cd tests; ruby testall.rb) - Run all the examples - Browse the docs Who to Tell: * RubyGems distribution (to upload gem) * ruby-talk mailing list * RAA * RubyForge news * RubyForge email notification of new file releases log4r-1.1.10/doc/templates/0000755000004100000410000000000011702744173015422 5ustar www-datawww-datalog4r-1.1.10/doc/templates/main.html0000644000004100000410000000657711702744173017253 0ustar www-datawww-data

 
 
 

log4r-1.1.10/examples/0000755000004100000410000000000011702744173014475 5ustar www-datawww-datalog4r-1.1.10/examples/README0000644000004100000410000000143511702744173015360 0ustar www-datawww-dataThe examples are: 1. outofthebox.rb - How to get started with minimal setup 2. simpleconfig.rb - Using Log4r casually 3. moderateconfig.rb - A more sophisticated config 4. xmlconfig.rb and moderate.xml - XML configuration example based on #3 5. rrsetup.rb and rrconfig.xml - A real example (or used to be ;-) 6. logserver.rb and logclient.rb - Remote logging example 7. fileroll.rb - Using RollingFileOutputter 8. yaml.rb and log4r_yaml.yaml - YAML configuration example The output will go to screen and to files in the directory logs/. Note to RubyGems users: The syntax to require log4r as a gem is as follows: require 'rubygems' require_gem 'log4r' Obviously, the examples will need to be modified to follow this. log4r-1.1.10/examples/ancestors.rb0000644000004100000410000000276011702744173017030 0ustar www-datawww-data$: << File.join("..","lib") # This file demonstrates how inheritence works in log4r # require 'rubygems' require 'log4r' include Log4r Logger.global.level = ALL formatter = PatternFormatter.new(:pattern => "%l - %m - %c") StdoutOutputter.new('console', :formatter => formatter) # By default, the root logger is the top ancestor to the # immediate descendants # However, any descendants below the top ancestors will # have the ancestor as their RootLogger, which dictates # (among other things) the lowest level of log messages Logger.new('grandparent', FATAL).add('console') Logger.new('grandparent::parent', DEBUG) Logger.new('grandparent::parent::child', DEBUG) def do_logging(log) puts "--" log.debug "This is debug" log.info "This is info" log.warn "This is warn" log.error "This is error" log.fatal "This is fatal" end # This logger is configured to log at FATAL, and it does do_logging Logger['grandparent'] # This logger is configured to log at DEBUG level, but it logs # at FATAL because grandparent is now the RootLogger for parent do_logging Logger['grandparent::parent'] # 'child' logger is configured to log at DEBUG level, but it logs # at FATAL because of grandparent do_logging Logger['grandparent::parent::child'] Logger['grandparent'].level = DEBUG # Now that the grandparent's level is set to DEBUG, the child # will log at that level do_logging Logger['grandparent::parent::child'] Logger['grandparent'].level = OFF puts "off?" do_logging Logger['grandparent::parent::child'] log4r-1.1.10/examples/rrsetup.rb0000644000004100000410000000211111702744173016521 0ustar www-datawww-data# This is a real config file used by a game that I'm working on # The XML config file is called rrconfig.xml $: << File.join('..','lib') require 'log4r' require 'log4r/configurator' include Log4r # How to format component data - low noise class CompFormatter < Formatter def format(event) buff = event.name + "> " if event.data.kind_of?(String) then buff += event.data else buff += event.data.inspect end return buff + "\n" end end # Set the logpath. Eventually, this will be determined from the environment. Configurator['logpath'] = './logs' Configurator.load_xml_file('rrconfig.xml') # the rest is an example Robot = {"name"=>"twonky", "row"=>"3", "col"=>"4"} def do_logging(log) log.comp3 Robot log.comp2 Robot log.comp1 Robot log.data "this is a piece of data".split log.debug "debugging" log.info "a piece of info" log.warn "Danger, Will Robinson, danger!" log.error "I dropped my Wookie! :(" log.fatal "kaboom!" end Logger.each_logger {|logger| do_logging(logger)} # you can see the results onscreen and in logs/game.log # logs/data.log and logs/component.log log4r-1.1.10/examples/rdoc-gen0000644000004100000410000000006711702744173016121 0ustar www-datawww-datardoc --exclude *CVS* --exclude .*patch --exclude diff log4r-1.1.10/examples/syslogcustom.rb0000644000004100000410000000257211702744173017603 0ustar www-datawww-data# Suppose we don't like having 5 levels named DEBUG, INFO, etc. # Suppose we'd rather use 3 levels named Foo, Bar, and Baz. # Suppose we'd like to use these with syslog # Log4r allows you to rename the levels and their corresponding methods # in a painless way and then map those to corrisponding syslog levels # or have them all default to LOG_INFO # This file provides an example $: << '../lib' require 'log4r' require 'log4r/configurator' require 'log4r/formatter/patternformatter' require 'log4r/outputter/syslogoutputter' require 'syslog' include Log4r include Syslog::Constants # This is how we specify our levels Configurator.custom_levels "Foo", "Bar", "Baz" l = Logger.new('custom levels') slp = PatternFormatter.new( :pattern => '{%p} {%h} {%d} {%l} {%C} {%m}', :date_method => 'usec' ) sl = SyslogOutputter.new( 'sysloggertest', { :logopt => LOG_CONS | LOG_PID | LOG_PERROR, :facility => LOG_LOCAL7, :formatter => slp } ) sl.map_levels_by_name_to_syslog( { "Foo" => "DEBUG", "Bar" => "INFO", "Baz" => "ALERT" } ) l.add sl l.level = Foo puts l.foo? l.foo "This is foo" puts l.bar? l.bar "this is bar" puts l.baz? l.baz "this is baz" puts "Now change to Baz" l.level = Baz puts l.foo? l.foo {"This is foo"} puts l.bar? l.bar {"this is bar"} puts l.baz? l.baz {"this is baz"} l4r = Logger.new('log4r') l4r.add Log4r::Outputter.stderr Log4r::SyslogOutputter.new 'test' log4r-1.1.10/examples/logclient.rb0000644000004100000410000000157511702744173017012 0ustar www-datawww-data# How to use RemoteOutputter. See logserver.rb first. $: << File.join('..','lib') require 'log4r' require 'log4r/outputter/remoteoutputter' include Log4r Logger.new('log4r').add 'stdout' # to see what's going on inside RemoteOutputter.new 'remote', # make a RemoteOutputter :uri=>'tcpromp://localhost:9999', # where our LogServer is :buffsize=>10 # buffer 10 before sending to LogServer Logger.new('client').add('remote') # give 'remote' to a 'client' Logger # we're done with setup, now let's log def log(l) l.debug "debugging" l.info "a piece of info" l.warn "Danger, Will Robinson, danger!" l.error "I dropped by Wookie! :(" l.fatal "kaboom!" end 5.times { log(Logger['client']) } # do a bunch of logging Logger['client'].info "Bye Bye from client!" Outputter['remote'].flush # flush the RemoteOutputter log4r-1.1.10/examples/logserver.rb0000644000004100000410000000101111702744173017023 0ustar www-datawww-data# How to use LogServer $: << File.join('..','lib') require 'log4r' require 'log4r/configurator' # XML configuration is simple enough to embed here xml = %( stdout ) Log4r::Logger.new('log4r').add 'stdout' # to see what's going on inside Log4r::Configurator.load_xml_string xml # load it up sleep # now run logclient.rb on another terminal log4r-1.1.10/examples/fileroll.rb0000644000004100000410000000164011702744173016633 0ustar www-datawww-data# How to use RollingFileOutputter $: << "../lib" require 'log4r' include Log4r puts "this will take a while" # example of log file being split by time constraint 'maxtime' config = { "filename" => "logs/TestTime.log", "maxtime" => 10, "trunc" => true } timeLog = Logger.new 'WbExplorer' timeLog.outputters = RollingFileOutputter.new("WbExplorer", config) timeLog.level = DEBUG # log something once a second for 100 seconds 100.times { |t| timeLog.info "blah #{t}" sleep(1.0) } # example of log file being split by space constraint 'maxsize' config = { "filename" => "logs/TestSize.log", "maxsize" => 16000, "trunc" => true } sizeLog = Logger.new 'WbExplorer' sizeLog.outputters = RollingFileOutputter.new("WbExplorer", config) sizeLog.level = DEBUG # log a large number of times 100000.times { |t| sizeLog.info "blah #{t}" } puts "done! check the two sets of log files in logs/ (TestTime and TestSize)" log4r-1.1.10/examples/gmail.yaml0000644000004100000410000000423411702744173016455 0ustar www-datawww-data purpose : Test Mailing to Gmail description: Provides configuration info for login to email servers via STARTTLS, e.g. gmail.com say : gmail is nice --- # *** YAML2LOG4R *** log4r_config: # define all pre config ... pre_config: custom_levels: - DEB - INF - PRT - WRN - ERR - FAT global: level: DEB root : level: DEB parameters: - name : x value : aaa - name : y value : bbb # define all loggers ... loggers: - name : mylogger level : DEB additive : 'false' trace : 'false' outputters: - stderr - logfile - email - name : yourlogger level : INF outputters: - stderr - logfile # define all outputters (incl. formatters) outputters: - type : StderrOutputter name : stderr level : DEB only_at : - INF - WRN - FAT formatter: date_pattern: '%y%m%d %H:%M:%S' pattern : '%d %l: %m ' type : PatternFormatter - type : DateFileOutputter name : logfile level : DEB date_pattern: '%Y%m%d' trunc : 'false' dirname : "#{HOME}/logs" formatter : date_pattern: '%y%m%d %H:%M:%S' pattern : '%d %l: %m' type : PatternFormatter - type : EmailOutputter name : email level : FAT tls : 'true' domain : gmail.com server : smtp.gmail.com port : '587' subject : 'Message from testing:' from : INSERT_YOUR_FROM_ADDRESS to : INSERT_YOUR_TO_ADDRESS acct : INSERT_YOUR_GMAIL_ACCOUNTNAME passwd : INSERT_YOUR_GMAIL_PASSWORD authtype : plain immediate_at: FAT formatfirst : 'true' formatter : date_pattern: '%y%m%d %H:%M:%S' pattern : '%d %l: %m' type : PatternFormatter --- purpose : TestB description: This is the last YAML doc say : Bye log4r-1.1.10/examples/xmlconfig.rb0000644000004100000410000000110211702744173017002 0ustar www-datawww-data# This is like moderateconfig.rb, but using an XML config # please look at moderate.xml $: << '../lib' require 'log4r' require 'log4r/configurator' include Log4r # set any runtime XML variables Configurator['logpath'] = './logs' # Load up the config file Configurator.load_xml_file('./moderate.xml') # now repeat what moderateconfig.rb does def do_logging(log) log.debug "debugging" log.info "a piece of info" log.warn "Danger, Will Robinson, danger!" log.error "I dropped my Wookie! :(" log.fatal "kaboom!" end Logger.each_logger{|logger| do_logging(logger) } # stop here log4r-1.1.10/examples/rrconfig.xml0000644000004100000410000000536011702744173017034 0ustar www-datawww-data COMP3, COMP2, COMP1, DATA, DEBUG, INFO, WARN, ERROR, FATAL #{logpath}/game.log #{logpath}/data.log #{logpath}/component.log gameout, gamedata, console componentout console log4r-1.1.10/examples/simpleconfig.rb0000644000004100000410000000256111702744173017505 0ustar www-datawww-data# Simple configuration example. # Where we configure just one logger and make it log to a file and stdout. # add the path to log4r if it isn't installed in a ruby path $: << File.join('..','lib') require "log4r" # First things first, get the root logger and set its level to WARN. # This makes the global level WARN. Later on, we can turn off all logging # by setting it to OFF right here (or dynamically if you prefer) Log4r::Logger.root.level = Log4r::WARN # Remember: By specifying a level, we are saying "Include this level and # anything worse." So in this case, we're logging WARN, ERROR and FATAL # create a logger log = Log4r::Logger.new("simpleconf") # We want to log to $stderr and a file ./tmp.log # Create an outputter for $stderr. It defaults to the root level WARN Log4r::StderrOutputter.new 'console' # for the file, we want to log only FATAL and ERROR and don't trunc Log4r::FileOutputter.new('logfile', :filename=>'logs/simple.log', :trunc=>false, :level=>Log4r::FATAL) # add the outputters (this method accepts outputter names or references) log.add('console','logfile') # Now let's try it out: log.debug "debugging" log.info "a piece of info" log.warn "Danger, Will Robinson, danger!" log.error "I dropped my Wookie! :(" log.fatal "kaboom!" # now run this and compare output to ./tmp.log log4r-1.1.10/examples/outofthebox.rb0000644000004100000410000000113611702744173017371 0ustar www-datawww-data# Here's how to start using log4r right away $: << File.join('..','lib') # path if log4r not installed require "log4r" Log = Log4r::Logger.new("outofthebox") # create a logger Log.add Log4r::Outputter.stderr # which logs to stdout # do some logging def do_logging Log.debug "debugging" Log.info "a piece of info" Log.warn "Danger, Will Robinson, danger!" Log.error "I dropped my Wookie! :(" Log.fatal "kaboom!" end do_logging # now let's filter anything below WARN level (DEBUG and INFO) puts "-= Changing level to WARN =-" Log.level = Log4r::WARN do_logging log4r-1.1.10/examples/yaml.rb0000644000004100000410000000171211702744173015765 0ustar www-datawww-data# Log4r can be configured using YAML. This example uses log4r_yaml.yaml $: << File.join('..','lib') # path if log4r is not installed require 'log4r' require 'log4r/yamlconfigurator' # we use various outputters, so require them, otherwise config chokes require 'log4r/outputter/datefileoutputter' require 'log4r/outputter/emailoutputter' require 'log4r/outputter/scribeoutputter' cfg = Log4r::YamlConfigurator # shorthand cfg['HOME'] = '.' # the only parameter in the YAML, our HOME directory # load the YAML file with this cfg.load_yaml_file('log4r_yaml.yaml') # Method to log each of the custom levels def do_logging(log) log.deb "This is DEB" log.inf "This is INF" log.prt "This is PRT" log.wrn "This is WRN" log.err "This is ERR" log.fat "This is FAT" end # turn off the email outputter Log4r::Outputter['email'].level = Log4r::OFF # the other two outputters log to stderr and a timestamped file in ./logs do_logging( Log4r::Logger['mylogger']) log4r-1.1.10/examples/filelog.rb0000644000004100000410000000126111702744173016443 0ustar www-datawww-data# Here's how to start using log4r right away $: << File.join('..','lib') # path if log4r not installed require "log4r" Log = Log4r::Logger.new("filelog") # create a logger # add FileOutputter Log.add Log4r::FileOutputter.new( "filelog", {:filename=>"file.log"} ) # See book keeping logger events iLog = Log4r::Logger.new("log4r") iLog.add Log4r::Outputter.stderr # do some logging def do_logging Log.debug "debugging" Log.info "a piece of info" Log.warn "Danger, Will Robinson, danger!" Log.error "I dropped my Wookie! :(" Log.fatal "kaboom!" end do_logging # now let's filter anything below WARN level (DEBUG and INFO) Log.level = Log4r::WARN do_logging log4r-1.1.10/examples/customlevels.rb0000644000004100000410000000133411702744173017550 0ustar www-datawww-data# Suppose we don't like having 5 levels named DEBUG, INFO, etc. # Suppose we'd rather use 3 levels named Foo, Bar, and Baz. # Log4r allows you to rename the levels and their corresponding methods # in a painless way. This file provides and example $: << '../lib' require 'log4r' require 'log4r/configurator' include Log4r # This is how we specify our levels Configurator.custom_levels "Foo", "Bar", "Baz" l = Logger.new('custom levels') l.add StdoutOutputter.new('console') l.level = Foo puts l.foo? l.foo "This is foo" puts l.bar? l.bar "this is bar" puts l.baz? l.baz "this is baz" puts "Now change to Baz" l.level = Baz puts l.foo? l.foo {"This is foo"} puts l.bar? l.bar {"this is bar"} puts l.baz? l.baz {"this is baz"} log4r-1.1.10/examples/gmail.rb0000644000004100000410000000164011702744173016114 0ustar www-datawww-data# Log4r can be configured using YAML to email using STARTTLS. This example uses gmail.yaml $: << File.join('..','lib') # path if log4r is not installed require 'log4r' require 'log4r/yamlconfigurator' # we use various outputters, so require them, otherwise config chokes require 'log4r/outputter/datefileoutputter' require 'log4r/outputter/emailoutputter' include Log4r cfg = YamlConfigurator # shorthand cfg['HOME'] = '.' # the only parameter in the YAML, our HOME directory # load the YAML file with this cfg.load_yaml_file('gmail.yaml') # Method to log each of the custom levels def do_logging(log) log.deb "This is DEB" log.inf "This is INF" log.prt "This is PRT" log.wrn "This is WRN" log.err "This is ERR" log.fat "This is FAT" end # turn off the email outputter Outputter['email'].level = WRN # the other two outputters log to stderr and a timestamped file in ./logs do_logging( Logger['mylogger']) log4r-1.1.10/examples/myformatter.rb0000644000004100000410000000121311702744173017370 0ustar www-datawww-data# try out a custom formatter $: << '../lib' require "log4r" class MyFormatter < Log4r::Formatter def format(event) buff = "The level is #{event.level} and has " buff += "name '#{Log4r::LNAMES[event.level]}'\n" buff += "The logger is '#{event.name}' " buff += "and the data type is #{event.data.class}\n" buff += "Let's inspect the data:\n" buff += event.data.inspect + "\n" buff += "We were called at #{event.tracer[0]}\n\n" end end log = Log4r::Logger.new('custom formatter') log.trace = true log.add Log4r::StdoutOutputter.new('stdout', :formatter=>MyFormatter) log.info [1, 2, 3, 4] log.error "A log statement" log4r-1.1.10/examples/chainsaw_settings.xml0000644000004100000410000000047311702744173020740 0ustar www-datawww-data log4r-1.1.10/examples/log4r_yaml.yaml0000644000004100000410000000421411702744173017433 0ustar www-datawww-data purpose : TestA description: This is the 1st YAML doc say : Hi --- # *** YAML2LOG4R *** log4r_config: # define all pre config ... pre_config: custom_levels: - DEB - INF - PRT - WRN - ERR - FAT global: level: DEB root : level: DEB parameters: - name : x value : aaa - name : y value : bbb # define all loggers ... loggers: - name : mylogger level : DEB additive : 'false' trace : 'false' outputters: - stderr - logfile - email - scribe - name : yourlogger level : INF outputters: - stderr - logfile - scribe # define all outputters (incl. formatters) outputters: - type : StderrOutputter name : stderr level : DEB only_at : - INF - WRN - FAT formatter: date_pattern: '%y%m%d %H:%M:%S' pattern : '%d %l: %m ' type : PatternFormatter - type : DateFileOutputter name : logfile level : DEB date_pattern: '%Y%m%d' trunc : 'false' dirname : "#{HOME}/logs" formatter : date_pattern: '%y%m%d %H:%M:%S' pattern : '%d %l: %m' type : PatternFormatter - type : EmailOutputter name : email level : FAT server : localhost subject : 'Message from #{PN}:' from : test@localhost to : anhu@localhost immediate_at: FAT formatfirst : 'true' formatter : date_pattern: '%y%m%d %H:%M:%S' pattern : '%d %l: %m' type : PatternFormatter - type : ScribeOutputter name : scribe level : DEB host : "127.0.0.1" port : "9090" formatter : date_pattern: '%y%m%d %H:%M:%S' pattern : '%d %l: %m' type : PatternFormatter --- purpose : TestB description: This is the last YAML doc say : Bye log4r-1.1.10/examples/moderateconfig.rb0000644000004100000410000000460611702744173020016 0ustar www-datawww-data# Now, for something more complicted # Let's pretend this is the global config file for our app $: << File.join('..','lib') require "log4r" include Log4r # include Log4r to make things simple Logger.root.level = DEBUG # global level DEBUG # suppose we want to have loggers for a Server and a Client class # furthermore, we want the client gui to have its own logger. (You'll want # one logger per class or so.) # When the loggers are created, they are stored in a repository for further # retreival at any point using a hash method call: Logger['name'] # server is stable, so only log ERROR and FATAL Logger.new("server", ERROR) # let's say we don't need the DEBUG junk for client logs Logger.new("client", INFO) # but we're still debugging the gui debugger = Logger.new("client::gui", DEBUG) debugger.trace = true # we want to see where the log method was called # Guilog is a child of client. In this case, any log events to the gui # logger will also be logged to the client outputters. We can change # that behavior by setting guilogger's 'additive' to false, but not yet. # let's create the outputters FileOutputter.new('server', :filename=>'logs/server.log', :trunc => false) FileOutputter.new('client', :filename=>'logs/client.log') FileOutputter.new('gui', :filename=>'logs/guidebug.log') # additionally, we want ERROR and FATAL messages to go to stderr StderrOutputter.new('console', :level=>ERROR) # add the outputters Logger['server'].add 'server', 'console' Logger['client'].add 'client', 'console' Logger['client::gui'].add 'gui' # gui will also write to client's outputters # That's it for config. Now let's use the loggers: def do_logging(log) log.debug "debugging" log.info "a piece of info" log.warn "Danger, Will Robinson, danger!" log.error "I dropped my Wookie! :(" log.fatal "kaboom!" end Logger.each_logger{|logger| do_logging(logger) } # You can dynamically change levels and turn off tracing: Logger['client'].level = OFF Logger['client::gui'].trace = false puts 'Only server should show Dynamic Change onscreen:' Logger.each_logger{|logger| logger.fatal "Dynamic change." } # logs/client.log file should not show "Dynamic change." # logs/guidebug.log should not show the trace at "Dynamic change." # we can also set our outputter to log only specified levels: Outputter['console'].only_at ERROR puts "Should only see ERROR next:" do_logging Logger['server'] log4r-1.1.10/examples/moderate.xml0000644000004100000410000000174311702744173017024 0ustar www-datawww-data #{serverlog} false DEBUG gui log4r-1.1.10/tests/0000755000004100000410000000000011702744173014021 5ustar www-datawww-datalog4r-1.1.10/tests/testbase.rb0000644000004100000410000000433411702744173016164 0ustar www-datawww-datarequire 'test_helper' class TestBase < TestCase include Log4r # check that LNAMES loads properly (it uses an eval to load) def test_default_levels Logger.root # doing this loads the default levels assert_equal(ALL,0) assert_equal(DEBUG,1) assert_equal(INFO,2) assert_equal(WARN,3) assert_equal(ERROR,4) assert_equal(FATAL,5) assert_equal(OFF,6) assert_equal(LEVELS, 7) assert_equal(LNAMES.size, 7) end # check bad input and bounds for validate_level def test_validate_level 7.times{|i| assert_nothing_raised {Log4rTools.validate_level(i)} } assert_raise(ArgumentError) {Log4rTools.validate_level(-1)} assert_raise(ArgumentError) {Log4rTools.validate_level(LEVELS)} assert_raise(ArgumentError) {Log4rTools.validate_level(String)} assert_raise(ArgumentError) {Log4rTools.validate_level("bogus")} end # decode_bool turns a string 'true' into true and so on def test_decode_bool # when the key is a symbol :data assert(Log4rTools.decode_bool({:data=> 'true'} ,:data,false) == true) assert(Log4rTools.decode_bool({:data=> true} ,:data,false) == true) assert(Log4rTools.decode_bool({:data=> 'false'} ,:data,true) == false) assert(Log4rTools.decode_bool({:data=> false} ,:data,true) == false) assert(Log4rTools.decode_bool({:data=> nil} ,:data,true) == true) assert(Log4rTools.decode_bool({:data=> nil} ,:data,false) == false) assert(Log4rTools.decode_bool({:data=> String} ,:data,true) == true) assert(Log4rTools.decode_bool({:data=> String} ,:data,false) == false) # now the key is a string 'data' assert(Log4rTools.decode_bool({'data'=> 'true'} ,:data,false) == true) assert(Log4rTools.decode_bool({'data'=> true} ,:data,false) == true) assert(Log4rTools.decode_bool({'data'=> 'false'} ,:data,true) == false) assert(Log4rTools.decode_bool({'data'=> false} ,:data,true) == false) assert(Log4rTools.decode_bool({'data'=> nil} ,:data,true) == true) assert(Log4rTools.decode_bool({'data'=> nil} ,:data,false) == false) assert(Log4rTools.decode_bool({'data'=> String} ,:data,true) == true) assert(Log4rTools.decode_bool({'data'=> String} ,:data,false) == false) end end log4r-1.1.10/tests/README0000644000004100000410000000107211702744173014701 0ustar www-datawww-dataThe unit tests are currently out of date. The examples actually provide a decent test suite for log4r. But the unit tests are still very important because of bounds-checking and a quicker turnaround for bug discovery. The unit files need to be converted to the new 'test/unit' paradigm. Because Log4r dynamically defines constants according to user preferences, the unit testing can't all be done in one instance of ruby. It is planned to use popen to run each test that needs a clean ruby instance. The logs/ directory is where these tests dump generated log files. log4r-1.1.10/tests/testformatter.rb0000644000004100000410000000177311702744173017261 0ustar www-datawww-datarequire 'test_helper' class TestFormatter < TestCase include Log4r def test_creation assert_nothing_raised { Formatter.new.format(3) } assert_nothing_raised { DefaultFormatter.new } assert_kind_of(Formatter, DefaultFormatter.new) end def test_simple_formatter sf = SimpleFormatter.new f = Logger.new('simple formatter') event = LogEvent.new(0, f, nil, "some data") assert_match(sf.format(event), /simple formatter/) end def test_basic_formatter b = BasicFormatter.new f = Logger.new('fake formatter') event = LogEvent.new(0, f, caller, "fake formatter") event2 = LogEvent.new(0, f, nil, "fake formatter") # this checks for tracing assert_match(b.format(event), /in/) assert_not_match(b.format(event2), /in/) e = ArgumentError.new("argerror") e.set_backtrace ['backtrace'] event3 = LogEvent.new(0, f, nil, e) assert_match(b.format(event3), /ArgumentError/) assert_match(b.format(LogEvent.new(0,f,nil,[1,2,3])), /Array/) end end log4r-1.1.10/tests/testxmlconf.rb0000644000004100000410000000211311702744173016711 0ustar www-datawww-datarequire 'test_helper' One=<<-EOX Foo EOX Two=<<-EOX EOX Three=<<-EOX Foo EOX # must be run independently class TestXmlConf < TestCase include Log4r def test_load1 Configurator.load_xml_string(One) assert_nothing_raised{ assert(Foo == 1) assert(Logger.global.level == ALL) } end def test_load2 Configurator.load_xml_string(Two) assert_nothing_raised{ assert(Logger.global.level == DEBUG) } end def test_load3 Configurator.load_xml_string(Three) assert_nothing_raised{ assert(Foo == 1) assert(Logger.global.level == Foo) } end def test_load4 assert_nothing_raised { Configurator['logpath'] = '.' Configurator.load_xml_file "xml/testconf.xml" a = Logger['first::second'] a.bing "what the heck" } end end log4r-1.1.10/tests/testchainsaw.rb0000644000004100000410000000166111702744173017047 0ustar www-datawww-datarequire 'test_helper' include Log4r log4r = Logger.new 'log4r' log4r.trace = true log4r.outputters = StdoutOutputter.new 'log4r' log4r.level = ALL formatter = Log4jXmlFormatter.new outputter = UDPOutputter.new 'udp', :hostname => "localhost", :port => 8071 outputter.formatter = formatter mylog = Logger.new 'mylog' mylog.trace = true mylog.outputters = [outputter] # Log4r::Formatter throws when formatting # an excpetion with a nil backtrace (line 73). def get_exception(msg) begin raise msg rescue Exception => e e end end NDC.push "saw test" MDC.put "clientip", %q{10.33.33.33} def do_log(log) log.debug "This is a message with level DEBUG" log.info "This is a message with level INFO" log.warn "This is a message with level WARN" log.error "This is a message with level ERROR" log.fatal "This is a message with level FATAL" log.fatal get_exception( "This is an exception" ) end do_log(mylog) log4r-1.1.10/tests/testall.rb0000644000004100000410000000026711702744173016023 0ustar www-datawww-datarequire 'test_helper' # because constants are dynamically defined, some tests need to # be opened in a fresh instance of Ruby, hence the popens IO.popen("date") { |f| puts f.gets } log4r-1.1.10/tests/testcustom.rb0000644000004100000410000000155511702744173016566 0ustar www-datawww-datarequire 'test_helper' # tests the customization of Log4r levels class TestCustom < TestCase include Log4r def test_validation assert_raise(TypeError) { Configurator.custom_levels "lowercase" } assert_raise(TypeError) { Configurator.custom_levels "With space" } end def test_create assert_nothing_raised { Configurator.custom_levels "Foo", "Bar", "Baz" } assert_nothing_raised { Configurator.custom_levels } assert_nothing_raised { Configurator.custom_levels "Bogus", "Levels" } end # def test_methods # l = Logger.new 'custom1' # assert_respond_to(l, :foo) # assert_respond_to(l, :foo?) # assert_respond_to(l, :bar) # assert_respond_to(l, :bar?) # assert_respond_to(l, :baz) # assert_respond_to(l, :baz?) # assert_nothing_raised { Bar } # assert_nothing_raised { Baz } # assert_nothing_raised { Foo } # end end log4r-1.1.10/tests/test_helper.rb0000644000004100000410000000046611702744173016672 0ustar www-datawww-data$:.unshift(File.dirname(__FILE__)) require "test/unit" require 'log4r' require 'log4r/configurator' require 'log4r/staticlogger' require 'log4r/formatter/log4jxmlformatter' require 'log4r/outputter/udpoutputter' require 'log4r/outputter/consoleoutputters' require 'log4r/yamlconfigurator' include Test::Unit log4r-1.1.10/tests/testyaml_arrays.yaml0000644000004100000410000000110611702744173020126 0ustar www-datawww-datalog4r_config: # define all loggers ... loggers: - name : mylogger level : INFO additive : 'false' trace : 'false' outputters: - testyaml # define all outputters (incl. formatters) outputters: - type : TestYamlOutputter name : testyaml level : INFO array_param: - fred@foo.com - barney@foo.com - 'wilma@#{CUSTOM_DOMAIN}' formatter: date_pattern: '%y%m%d %H:%M:%S' pattern : '%d %l: %m ' type : PatternFormatter log4r-1.1.10/tests/testMDC.rb0000644000004100000410000000231211702744173015647 0ustar www-datawww-datarequire 'test_helper' class TestMDC < TestCase include Log4r def test_multithread_copy Log4r::MDC.put("user","colbygk") t = Thread.new("test first copy") do |name| assert(Log4r::MDC.get("user") == "colbygk", "Did not get back expected value, '#{MDC.get("user")}'") Log4r::MDC.put("user","unique") assert(Log4r::MDC.get("user") == "unique", "Did not get back expected value, '#{MDC.get("user")}'") end t.join assert(Log4r::MDC.get("user") == "colbygk", "Did not get back expected value, '#{MDC.get("user")}'") end def test_MDCoutput Log4r::MDC.put(:user, "symbol") Log4r::MDC.put("string", "string") Log4r::MDC.put(5, "number") l = Logger.new 'test' o = StdoutOutputter.new 'test' l.add o assert_nothing_raised { f = PatternFormatter.new :pattern=> "%l user: %X{:user} %X{strng} %X{5}" Outputter['test'].formatter = f l.debug "And this?" l.info "How's this?" l.error "and a really freaking huge line which we hope will be trimmed?" e = ArgumentError.new("something barfed") e.set_backtrace Array.new(5, "trace junk at thisfile.rb 154") l.fatal e l.info [1, 3, 5] } end end log4r-1.1.10/tests/testthreads.rb0000644000004100000410000000150111702744173016675 0ustar www-datawww-data# $Id$ # Test guts sent in by chetreddy bug #27184 # # Note: this test won't always catch a threading problem, as it # relies on a brute force approach. NUM_THREADS can be increased # to stress the system longer and therefore increasing the chance # of exposing a threading issue, however, it is not a definitive # test. # require 'test_helper' class TestThreads < TestCase include Log4r NUMTHREADS = 1000 def test_threads assert_nothing_raised do (0..NUMTHREADS).map do |i| Thread.new do Thread.current[:logger] = Log4r::Logger.new "Hello #{i}" Thread.current[:logger].outputters = [StdoutOutputter.new("log4r#{i}")] Thread.current[:logger].outputters.each { |j| j.flush } Thread.current.exit() end end.each do |thr| thr.join end end end end log4r-1.1.10/tests/testconf.xml0000644000004100000410000000214711702744173016374 0ustar www-datawww-data Foo, Bar,Baz, Bing [%l] %d %t - %m Foo %d %c %l> %m #{datem} %H:%S #{logpath}/junk/foo.log true Foo, Bar, Bing true SO, SE, F, stdout, stderr log4r-1.1.10/tests/testNDC.rb0000644000004100000410000000116711702744173015657 0ustar www-datawww-datarequire 'test_helper' class TestNDC < TestCase include Log4r def test_ndc_remove_push NDC.remove() NDC.push("ndc") assert(Log4r::NDC.get() == "ndc", "Expected 'ndc' got '#{NDC.get()}'" ) NDC.push("ndc") assert(Log4r::NDC.get() == "ndc ndc", "Expected 'ndc ndc' got '#{NDC.get()}'" ) end def test_ndc_remove_push_clone_and_inherit NDC.remove() NDC.push("ndc") NDC.push("ndc") a = NDC.clone_stack() NDC.remove() assert(NDC.get() == "", "Expected '' got '#{NDC.get()}'" ) NDC.inherit(a) assert(NDC.get() == "ndc ndc", "Expected 'ndc ndc' got '#{NDC.get()}'" ) end end log4r-1.1.10/tests/testpatternformatter.rb0000644000004100000410000000413111702744173020646 0ustar www-datawww-datarequire 'test_helper' class TestPatternFormatter < TestCase include Log4r def test_pattern l = Logger.new 'test::this::that' l.trace = true o = StdoutOutputter.new 'test' l.add o assert_nothing_raised { f = PatternFormatter.new :pattern=> "'%t' T-'%T' %d %6l [%C]%c %% %-40.30M" #:date_pattern=> "%Y" #:date_method => :usec Outputter['test'].formatter = f l.debug "And this?" l.info "How's this?" l.error "and a really freaking huge line which we hope will be trimmed?" e = ArgumentError.new("something barfed") e.set_backtrace Array.new(5, "trace junk at thisfile.rb 154") l.fatal e l.info [1, 3, 5] } end def test_ndc l = Logger.new 'test::this::that::other' l.trace = true o = StdoutOutputter.new 'testy' l.add o f = PatternFormatter.new :pattern=> "%d %6l [%C]%c {%x} %% %-40.30M" #:date_pattern=> "%Y" #:date_method => :usec Outputter['testy'].formatter = f l.info "no NDC" NDC.push("start") l.info "start NDC" NDC.push("finish") l.info "start finish NDC" NDC.pop() l.info "start NDC" NDC.remove() l.info "no NDC" end def test_gdc l = Logger.new 'test::this::that::other' l.trace = true o = StdoutOutputter.new 'testy' l.add o f = PatternFormatter.new :pattern=> "%d %6l [%C]%c {%g} %% %-40.30M" #:date_pattern=> "%Y" #:date_method => :usec Outputter['testy'].formatter = f l.info "GDC default" GDC.set("non-default") l.info "GDC non-default" end def test_mdc l = Logger.new 'test::this::that::other' l.trace = true o = StdoutOutputter.new 'testy' l.add o f = PatternFormatter.new :pattern=> "%d %6l [%C]%c {%X{user}} %% %-40.30M" #:date_pattern=> "%Y" #:date_method => :usec Outputter['testy'].formatter = f l.info "no user" MDC.put("user","colbygk") l.info "user colbygk" end end log4r-1.1.10/tests/testoutputter.rb0000644000004100000410000001216211702744173017323 0ustar www-datawww-data# encoding: utf-8 require 'test_helper' class TestOutputter < TestCase include Log4r def test_validation assert_raise(ArgumentError) { Outputter.new } assert_raise(ArgumentError) { Outputter.new 'fonda', :level=>-10} assert_raise(TypeError) { Outputter.new 'fonda', :formatter=>-10} end def test_io assert_nothing_raised { IOOutputter.new('foo3', $stdout) IOOutputter.new('foo4', $stderr) } f = File.new("junk/tmpx.log", "w") o = IOOutputter.new('asdf', f) o.close assert(f.closed? == true) assert(o.level == OFF) end def test_repository assert( Outputter['foo3'].class == IOOutputter ) assert( Outputter['foo4'].class == IOOutputter ) assert( Outputter['asdf'].class == IOOutputter ) end def test_validation_and_creation assert_nothing_raised { StdoutOutputter.new('out', 'level'=>DEBUG) FileOutputter.new('file', 'filename'=>'junk/test', :trunc=>true) } a = StdoutOutputter.new 'out2' assert(a.level == Logger.root.level) assert(a.formatter.class == DefaultFormatter) b = StdoutOutputter.new('ook', :level => DEBUG, :formatter => Formatter) assert(b.level == DEBUG) assert(b.formatter.class == Formatter) c = StdoutOutputter.new('akk', :formatter => Formatter) assert(c.level == Logger.root.level) assert(c.formatter.class == Formatter) c = StderrOutputter.new('iikk', :level => OFF) assert(c.level == OFF) assert(c.formatter.class == DefaultFormatter) o = StderrOutputter.new 'ik' assert_nothing_raised(TypeError) { o.formatter = DefaultFormatter } assert(o.formatter.class == DefaultFormatter) end # test the resource= bounds def test_boundaries o = StderrOutputter.new('ak', :formatter => Formatter) assert_raise(TypeError) { o.formatter = nil } assert_raise(TypeError) { o.formatter = String } assert_raise(TypeError) { o.formatter = "bogus" } assert_raise(TypeError) { o.formatter = -3 } # the formatter should be preserved assert(o.formatter.class == Formatter) end def test_file assert_raise(TypeError) { FileOutputter.new 'f' } assert_raise(TypeError) { FileOutputter.new('fa', :filename => DEBUG) } assert_raise(TypeError) { FileOutputter.new('fo', :filename => nil) } assert_nothing_raised { FileOutputter.new('fi', :filename => './junk/tmp') FileOutputter.new('fum', :filename=>'./junk/tmp', :trunc => "true") } fo = FileOutputter.new('food', :filename => './junk/tmp', :trunc => false) assert(fo.trunc == false) assert(fo.filename == './junk/tmp') assert(fo.closed? == false) fo.close assert(fo.closed? == true) assert(fo.level == OFF) end # test the dynamic definition of outputter log messages def test_log_methods o = StderrOutputter.new('so1', :level => WARN ) # test to see if all of the methods are defined for mname in LNAMES next if mname == 'OFF' || mname == 'ALL' assert_respond_to(o, mname.downcase.to_sym, "Test respond to #{mname.to_s}") end return # cuz the rest is borked # we rely on BasicFormatter's inability to reference a nil Logger to test # the log methods. Everything from WARN to FATAL should choke. event = LogEvent.new(nil, nil, nil, nil) assert_nothing_raised { o.debug event } assert_nothing_raised { o.info event } assert_raise(NameError) { o.warn event } assert_raise(NameError) { o.error event } assert_raise(NameError) { o.fatal event } # now let's dynamically change the level and repeat o.level = ERROR assert_nothing_raised { o.debug event} assert_nothing_raised { o.info event} assert_nothing_raised { o.warn event} assert_raise(NameError) { o.error event} assert_raise(NameError) { o.fatal event} end def test_only_at_validation o = StdoutOutputter.new 'so2' assert_raise(ArgumentError) { o.only_at } assert_raise(ArgumentError) { o.only_at ALL } assert_raise(TypeError) { o.only_at OFF } assert_nothing_raised { o.only_at DEBUG, ERROR } return # cuz the rest is borked # test the methods as before event = LogEvent.new(nil,nil,nil,nil) assert_raise(NameError) { o.debug event} assert_raise(NameError) { o.error event} assert_nothing_raised { o.warn event} assert_nothing_raised { o.info event} assert_nothing_raised { o.fatal event} end if defined?( Encoding ) # tests that files are opened in binary mode def test_file_encoding Encoding.default_internal = Encoding::UTF_8 File.open( './junk/tmp2', 'w' ) { |f| f.write( 'scheiß encoding' ) } fenc = FileOutputter.new('fenc', :filename => './junk/tmp2') event = LogEvent.new(1, Logger.root, nil, 'scheiß encoding'.force_encoding('ASCII-8BIT')) assert_nothing_raised(Encoding::UndefinedConversionError) do fenc.debug event end end end def broken_test_threading class << self def log_work o = StdoutOutputter.new 'so2' assert_nothing_raised { o.only_at DEBUG, ERROR } Thread.current().exit() end def log_thread_start t = Thread.new(log_work) t.join end end ts = Thread.new(log_thread_start) ts.join end end log4r-1.1.10/tests/testyaml_injection.yaml0000644000004100000410000000100211702744173020602 0ustar www-datawww-datalog4r_config: # define all loggers ... loggers: - name : mylogger level : INFO additive : 'false' trace : 'false' outputters: - stderr # define all outputters (incl. formatters) outputters: - type : StderrOutputter name : stderr level : INFO crash : "'; raise Exception #" formatter: date_pattern: '%y%m%d %H:%M:%S' pattern : '%d %l: %m ' type : PatternFormatter log4r-1.1.10/tests/testyaml.rb0000644000004100000410000000206511702744173016213 0ustar www-datawww-datarequire 'test_helper' # Define a custom outputter that allows arrays in configuration hash module Log4r class TestYamlOutputter < Outputter # expose array parameter attr_reader :array_param def initialize(name, hash = {}) @array_param = hash['array_param'] end end end class TestYaml < TestCase include Log4r def setup @cfg = YamlConfigurator # shorthand @cfg['CUSTOM_DOMAIN'] = 'bar.com' end def test_injection assert_nothing_raised("Exception injected") do @cfg.load_yaml_file(File.join(File.dirname(__FILE__),'testyaml_injection.yaml')) end end def test_arrays assert_nothing_raised("Parser couldn't handle arrays in YAML") do @cfg.load_yaml_file(File.join(File.dirname(__FILE__),'testyaml_arrays.yaml')) end log = Logger['mylogger'] assert_instance_of(Array, log.outputters.first.array_param, 'Array not loaded properly from YAML') assert_equal('wilma@bar.com', log.outputters.first.array_param[2], '#{}-style parameter interpolation doesn\'t work properly in arrays') end end log4r-1.1.10/tests/testGDC.rb0000644000004100000410000000120511702744173015641 0ustar www-datawww-datarequire 'test_helper' class TestGDC < TestCase include Log4r def test_gdc_default assert(GDC.get() == "testGDC.rb", "Expected 'testGDC.rb' got '#{GDC.get()}'" ) end def test_gdc_set assert_nothing_raised() { GDC.set("testGDCset") } assert(GDC.get() == "testGDCset", "Expected 'testGDCset' got '#{GDC.get()}'" ) end def test_gdc_threaded assert_nothing_raised() { GDC.set("testGDCset") } t = Thread.new("test GDC thread") do |name| assert_raise(RuntimeError) { GDC.set("somethingelse") } end t.join assert(GDC.get() == "testGDCset", "Expected 'testGDCset' got '#{GDC.get()}'" ) end end log4r-1.1.10/tests/testlogger.rb0000644000004100000410000001461211702744173016531 0ustar www-datawww-datarequire 'test_helper' class MyFormatter1 < Log4r::Formatter def format(event) return "MyFormatter1\n" end end class MyFormatter2 < Log4r::Formatter def format(event) return "MyFormatter2\n" end end class TestLogger < TestCase include Log4r def test_root l1 = Logger.root l2 = Logger['root'] l3 = Logger.global assert(l1 == l2, "RootLogger wasn't singleton!") assert(l1 == l3) assert(l1.is_root? == true, "is_root? not working") assert(l1.parent == nil, "Root's parent wasn't nil!") end def test_validation assert_raise(ArgumentError) { Logger.new } assert_nothing_raised { Logger.new('validate', nil) } end def test_all_off l = Logger.new("create_method") l.level = WARN assert(l.debug? == false) assert(l.info? == false) assert(l.warn? == true) assert(l.error? == true) assert(l.fatal? == true) assert(l.off? == false) assert(l.all? == false) l.level = OFF assert(l.off? == true) assert(l.all? == false) l.level = ALL assert(l.off? == false) assert(l.all? == true) end def test_add_outputters StdoutOutputter.new('fake1') StdoutOutputter.new('fake2') a = Logger.new("add") assert_raise(TypeError) { a.add 'bogus' } assert_raise(TypeError) { a.add Class } assert_raise(TypeError) { a.add 'fake1', Class } assert_nothing_raised { a.add 'fake1', 'fake2' } end def test_repository assert_raise(NameError) { Logger.get('bogusbogus') } assert_nothing_raised { Logger['bogusbogus'] } end def test_heiarchy a = Logger.new("a") a.additive = true assert(a.name == "a", "name wasn't set properly") assert(a.path == "", "path wasn't set properly") assert(a.level == Logger.root.level, "didn't inherit root's level") assert(a.parent == Logger.root) a.level = WARN b = Logger.new("a::b") assert(b.name == "b", "name wasn't set properly") assert(b.path == "a", "path wasn't set properly") assert(b.level == a.level, "didn't inherit parent's level") assert(b.parent == a, "parent wasn't what is expected") c = Logger.new("a::b::c") assert(Logger["a::b::c"] == c) assert(c.name == "c", "name wasn't set properly") assert(c.path == "a::b", "path wasn't set properly") assert(c.level == b.level, "didn't inherit parent's level") assert(c.parent == b, "parent wasn't what is expected") d = Logger.new("a::d") assert(Logger["a::d"] == d) assert(d.name == "d", "name wasn't set properly") assert(d.path == "a", "path wasn't set properly") assert(d.level == a.level, "didn't inherit parent's level") assert(d.parent == a, "parent wasn't what is expected") assert_raise(ArgumentError) { Logger.new("::a") } end def test_undefined_parents a = Logger.new 'has::no::real::parents::me' assert(a.parent == Logger.root) b = Logger.new 'has::no::real::parents::me::child' assert(b.parent == a) c = Logger.new 'has::no::real::parents::metoo' assert(c.parent == Logger.root) p = Logger.new 'has::no::real::parents' assert(p.parent == Logger.root) assert(a.parent == p) assert(b.parent == a) assert(c.parent == p) Logger.each{|fullname, logger| if logger != a and logger != c assert(logger.parent != p) end } end def test_levels l = Logger.new("levels", WARN) assert(l.level == WARN, "level wasn't changed") assert(l.fatal? == true) assert(l.error? == true) assert(l.warn? == true) assert(l.info? == false) assert(l.debug? == false) l.debug "debug message should NOT show up" l.info "info message should NOT show up" l.warn "warn messge should show up. 3 total" l.error "error messge should show up. 3 total" l.fatal "fatal messge should show up. 3 total" l.level = ERROR assert(l.level == ERROR, "level wasn't changed") assert(l.fatal? == true) assert(l.error? == true) assert(l.warn? == false) assert(l.info? == false) assert(l.debug? == false) l.debug "debug message should NOT show up" l.info "info message should NOT show up" l.warn "warn messge should NOT show up." l.error "error messge should show up. 2 total" l.fatal "fatal messge should show up. 2 total" l.level = WARN end def test_log_blocks l = Logger.new 'logblocks' l.level = WARN l.add(Outputter.stdout) assert_nothing_raised { l.debug { puts "should not show up"; "LOGBLOCKS" } l.fatal { puts "should show up"; "LOGBLOCKS" } l.fatal { nil } l.fatal {} } end def test_heiarchial_logging a = Logger.new("one") a.add(StdoutOutputter.new 'so1') b = Logger.new("one::two") b.add(StdoutOutputter.new 'so2') c = Logger.new("one::two::three") c.add(StdoutOutputter.new 'so3') d = Logger.new("one::two::three::four") d.add(StdoutOutputter.new 'so4') d.additive = false e = Logger.new("one::two::three::four::five") e.add(StdoutOutputter.new 'so5') a.fatal "statement from a should show up once" b.fatal "statement from b should show up twice" c.fatal "statement from c should show up thrice" d.fatal "statement from d should show up once" e.fatal "statement from e should show up twice" end def test_multi_outs f1 = FileOutputter.new('f1', :filename => "./junk/tmp1.log", :level=>ALL) f2 = FileOutputter.new('f2', :filename => "./junk/tmp2.log", :level=>DEBUG) f3 = FileOutputter.new('f3', :filename => "./junk/tmp3.log", :level=>ERROR) f4 = FileOutputter.new('f4', :filename => "./junk/tmp4.log", :level=>FATAL) l = Logger.new("multi") l.add(f1, f3, f4) a = Logger.new("multi::multi2") a.level = ERROR a.add(f2, f4) l.debug "debug test_multi_outputters" l.info "info test_multi_outputters" l.warn "warn test_multi_outputters" l.error "error test_multi_outputters" l.fatal "fatal test_multi_outputters" a.debug "debug test_multi_outputters" a.info "info test_multi_outputters" a.warn "warn test_multi_outputters" a.error "error test_multi_outputters" a.fatal "fatal test_multi_outputters" f1.close; f2.close; f3.close; f4.close end def test_custom_formatter l = Logger.new('custom_formatter') o = StdoutOutputter.new('formatter'=>MyFormatter1.new) l.add o l.error "try myformatter1" l.fatal "try myformatter1" o.formatter = MyFormatter2.new l.error "try formatter2" l.fatal "try formatter2" end end log4r-1.1.10/metadata.yml0000644000004100000410000001164611702744173015172 0ustar www-datawww-data--- !ruby/object:Gem::Specification name: log4r version: !ruby/object:Gem::Version hash: 7 prerelease: segments: - 1 - 1 - 10 version: 1.1.10 platform: ruby authors: - Colby Gutierrez-Kraybill autorequire: bindir: bin cert_chain: [] date: 2012-01-02 00:00:00 Z dependencies: - !ruby/object:Gem::Dependency name: bundler prerelease: false requirement: &id001 !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 23 segments: - 1 - 0 - 0 version: 1.0.0 type: :development version_requirements: *id001 - !ruby/object:Gem::Dependency name: rake prerelease: false requirement: &id002 !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version hash: 49 segments: - 0 - 8 - 7 version: 0.8.7 type: :development version_requirements: *id002 description: "See also: http://logging.apache.org/log4j" email: colby@astro.berkeley.edu executables: [] extensions: [] extra_rdoc_files: [] files: - doc/content/contact.html - doc/content/contribute.html - doc/content/index.html - doc/content/license.html - doc/content/manual.html - doc/dev/checklist - doc/dev/README.developers - doc/dev/things-to-do - doc/images/log4r-logo.png - doc/images/logo2.png - doc/log4r.css - doc/rdoc-log4r.css - doc/templates/main.html - examples/ancestors.rb - examples/chainsaw_settings.xml - examples/customlevels.rb - examples/filelog.rb - examples/fileroll.rb - examples/gmail.rb - examples/gmail.yaml - examples/log4r_yaml.yaml - examples/logclient.rb - examples/logserver.rb - examples/moderate.xml - examples/moderateconfig.rb - examples/myformatter.rb - examples/outofthebox.rb - examples/rdoc-gen - examples/README - examples/rrconfig.xml - examples/rrsetup.rb - examples/simpleconfig.rb - examples/syslogcustom.rb - examples/xmlconfig.rb - examples/yaml.rb - lib/log4r/base.rb - lib/log4r/config.rb - lib/log4r/configurator.rb - lib/log4r/formatter/formatter.rb - lib/log4r/formatter/log4jxmlformatter.rb - lib/log4r/formatter/patternformatter.rb - lib/log4r/GDC.rb - lib/log4r/lib/drbloader.rb - lib/log4r/lib/xmlloader.rb - lib/log4r/logevent.rb - lib/log4r/logger.rb - lib/log4r/loggerfactory.rb - lib/log4r/logserver.rb - lib/log4r/MDC.rb - lib/log4r/NDC.rb - lib/log4r/outputter/consoleoutputters.rb - lib/log4r/outputter/datefileoutputter.rb - lib/log4r/outputter/emailoutputter.rb - lib/log4r/outputter/fileoutputter.rb - lib/log4r/outputter/iooutputter.rb - lib/log4r/outputter/outputter.rb - lib/log4r/outputter/outputterfactory.rb - lib/log4r/outputter/remoteoutputter.rb - lib/log4r/outputter/rollingfileoutputter.rb - lib/log4r/outputter/scribeoutputter.rb - lib/log4r/outputter/staticoutputter.rb - lib/log4r/outputter/syslogoutputter.rb - lib/log4r/outputter/udpoutputter.rb - lib/log4r/rdoc/configurator - lib/log4r/rdoc/emailoutputter - lib/log4r/rdoc/formatter - lib/log4r/rdoc/GDC - lib/log4r/rdoc/log4jxmlformatter - lib/log4r/rdoc/log4r - lib/log4r/rdoc/logger - lib/log4r/rdoc/logserver - lib/log4r/rdoc/MDC - lib/log4r/rdoc/NDC - lib/log4r/rdoc/outputter - lib/log4r/rdoc/patternformatter - lib/log4r/rdoc/scribeoutputter - lib/log4r/rdoc/syslogoutputter - lib/log4r/rdoc/win32eventoutputter - lib/log4r/rdoc/yamlconfigurator - lib/log4r/repository.rb - lib/log4r/staticlogger.rb - lib/log4r/version.rb - lib/log4r/yamlconfigurator.rb - lib/log4r.rb - tests/README - tests/test_helper.rb - tests/testall.rb - tests/testbase.rb - tests/testchainsaw.rb - tests/testconf.xml - tests/testcustom.rb - tests/testformatter.rb - tests/testGDC.rb - tests/testlogger.rb - tests/testMDC.rb - tests/testNDC.rb - tests/testoutputter.rb - tests/testpatternformatter.rb - tests/testthreads.rb - tests/testxmlconf.rb - tests/testyaml.rb - tests/testyaml_arrays.yaml - tests/testyaml_injection.yaml homepage: http://log4r.rubyforge.org licenses: [] post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" requirements: [] rubyforge_project: rubygems_version: 1.8.8 signing_key: specification_version: 3 summary: Log4r, logging framework for ruby test_files: - tests/README - tests/test_helper.rb - tests/testall.rb - tests/testbase.rb - tests/testchainsaw.rb - tests/testconf.xml - tests/testcustom.rb - tests/testformatter.rb - tests/testGDC.rb - tests/testlogger.rb - tests/testMDC.rb - tests/testNDC.rb - tests/testoutputter.rb - tests/testpatternformatter.rb - tests/testthreads.rb - tests/testxmlconf.rb - tests/testyaml.rb - tests/testyaml_arrays.yaml - tests/testyaml_injection.yaml log4r-1.1.10/lib/0000755000004100000410000000000011702744173013425 5ustar www-datawww-datalog4r-1.1.10/lib/log4r/0000755000004100000410000000000011702744173014454 5ustar www-datawww-datalog4r-1.1.10/lib/log4r/repository.rb0000644000004100000410000000454211702744173017225 0ustar www-datawww-data# :nodoc: # Version:: $Id$ # # Using Thread.exclusive seems to be more efficient than using # a class wide instance of Sync.synchronize in ruby 1.8.6 - Colby # # Using Sync.synchronize, 5000 iterations: # real 3m55.493s user 3m45.557s sys 0m3.478s # # Using Thread.exclusive, 5000 iterations: # real 2m35.859s user 2m33.951s sys 0m1.224s # require 'monitor' require "singleton" module Log4r class Logger # The repository stores a Hash of loggers keyed to their fullnames and # provides a few functions to reduce the code bloat in log4r/logger.rb. # This class is supposed to be transparent to end users, hence it is # a class within Logger. If anyone knows how to make this private, # let me know. class Repository # :nodoc: extend MonitorMixin include Singleton attr_reader :loggers def initialize @loggers = Hash.new end def self.[](fullname) self.synchronize do instance.loggers[fullname] end # exclusive end def self.[]=(fullname, logger) self.synchronize do instance.loggers[fullname] = logger end # exclusive end # Retrieves all children of a parent def self.all_children(parent) # children have the parent name + delimiter in their fullname daddy = parent.name + Private::Config::LoggerPathDelimiter self.synchronize do for fullname, logger in instance.loggers yield logger if parent.is_root? || fullname =~ /#{daddy}/ end end # exclusive end # when new loggers are introduced, they may get inserted into # an existing inheritance tree. this method # updates the children of a logger to link their new parent def self.reassign_any_children(parent) self.synchronize do for fullname, logger in instance.loggers next if logger.is_root? logger.parent = parent if logger.path =~ /^#{parent.fullname}$/ end end # exclusive end # looks for the first defined logger in a child's path # or nil if none found (which will then be rootlogger) def self.find_ancestor(path) arr = path.split Log4rConfig::LoggerPathDelimiter logger = nil self.synchronize do while arr.size > 0 do logger = Repository[arr.join(Log4rConfig::LoggerPathDelimiter)] break unless logger.nil? arr.pop end end # exclusive logger end end # class Repository end # class Logger end # Module Log4r log4r-1.1.10/lib/log4r/version.rb0000644000004100000410000000013411702744173016464 0ustar www-datawww-datamodule Log4r Log4rVersion = [1, 1, 10].join '.' # deprecate? VERSION = Log4rVersion end log4r-1.1.10/lib/log4r/outputter/0000755000004100000410000000000011702744173016527 5ustar www-datawww-datalog4r-1.1.10/lib/log4r/outputter/fileoutputter.rb0000644000004100000410000000304311702744173021767 0ustar www-datawww-data# :nodoc: # Version:: $Id$ require "log4r/outputter/iooutputter" require "log4r/staticlogger" module Log4r # Convenience wrapper for File. Additional hash arguments are: # # [:filename] Name of the file to log to. # [:trunc] Truncate the file? class FileOutputter < IOOutputter attr_reader :trunc, :filename def initialize(_name, hash={}) super(_name, nil, hash) @trunc = Log4rTools.decode_bool(hash, :trunc, false) _filename = (hash[:filename] or hash['filename']) @create = Log4rTools.decode_bool(hash, :create, true) if _filename.class != String raise TypeError, "Argument 'filename' must be a String", caller end # file validation if FileTest.exist?( _filename ) if not FileTest.file?( _filename ) raise StandardError, "'#{_filename}' is not a regular file", caller elsif not FileTest.writable?( _filename ) raise StandardError, "'#{_filename}' is not writable!", caller end else # ensure directory is writable dir = File.dirname( _filename ) if not FileTest.writable?( dir ) raise StandardError, "'#{dir}' is not writable!" end end @filename = _filename if ( @create == true ) then @out = File.new(@filename, (@trunc ? "wb" : "ab")) Logger.log_internal { "FileOutputter '#{@name}' writing to #{@filename}" } else Logger.log_internal { "FileOutputter '#{@name}' called with :create == false, #{@filename}" } end end end end log4r-1.1.10/lib/log4r/outputter/staticoutputter.rb0000644000004100000410000000142311702744173022337 0ustar www-datawww-data# :nodoc: module Log4r class Outputter < Monitor # Retrieve an outputter. def self.[](name) out = @@outputters[name] if out.nil? return case name when 'stdout' then StdoutOutputter.new 'stdout' when 'stderr' then StderrOutputter.new 'stderr' else nil end end out end def self.stdout; Outputter['stdout'] end def self.stderr; Outputter['stderr'] end # Set an outputter. def self.[]=(name, outputter) @@outputters[name] = outputter end # Yields each outputter's name and reference. def self.each @@outputters.each {|name, outputter| yield name, outputter} end def self.each_outputter @@outputters.each_value {|outputter| yield outputter} end end end log4r-1.1.10/lib/log4r/outputter/udpoutputter.rb0000644000004100000410000000201611702744173021637 0ustar www-datawww-data# :include: ../rdoc/outputter # # == Other Info # # Version:: $Id$ # Author:: Leon Torres require "log4r/outputter/outputter" require 'log4r/staticlogger' require "socket" module Log4r class UDPOutputter < Outputter attr_reader :host, :port attr_accessor :udpsock def initialize(_name, hash={}) super(_name, hash) @host = (hash[:hostname] or hash["hostname"]) @port = (hash[:port] or hash["port"]) begin Logger.log_internal { "UDPOutputter will send to #{@host}:#{@port}" } @udpsock = UDPSocket.new @udpsock.connect( @host, @port ) rescue Exception => e Logger.log_internal(ERROR) { "UDPOutputter failed to create UDP socket: #{e}" } Logger.log_internal {e} self.level = OFF raise e end end ####### private ####### def write(data) @udpsock.send(data, 0) rescue Exception => e Logger.log_internal(ERROR) { "UDPOutputter failed to send data to #{@host}:#{@port}, #{e}" } end end end log4r-1.1.10/lib/log4r/outputter/syslogoutputter.rb0000644000004100000410000001016111702744173022367 0ustar www-datawww-data# :include: ../rdoc/syslogoutputter # # Version:: $Id$ # Author:: Steve Lumos # Author:: Leon Torres require 'log4r/formatter/formatter' require 'log4r/outputter/outputter' require 'log4r/configurator' require 'syslog' module Log4r SYSLOGNAMES = Hash.new class SyslogOutputter < Outputter include Syslog::Constants # maps default log4r levels to syslog priorities (logevents never see ALL and OFF) # SYSLOG Levels are: # "DEBUG" => Syslog::LOG_DEBUG # "INFO" => Syslog::LOG_INFO # "NOTICE" => Syslog::LOG_NOTICE # "WARN" => Syslog::LOG_WARN # "ERROR" => Syslog::LOG_ERROR # "FATAL" => Syslog::LOG_FATAL # "ALERT" => Syslog::LOG_ALERT # "EMERG" => Syslog::LOG_EMERG SYSLOG_LEVELS_MAP = { "DEBUG" => LOG_DEBUG, "INFO" => LOG_INFO, "NOTICE" => LOG_NOTICE, # by default NOTICE is not in log4r "WARN" => LOG_WARNING, "ERROR" => LOG_ERR, "FATAL" => LOG_CRIT, "ALERT" => LOG_ALERT, # by default ALERT is not in log4r "EMERG" => LOG_EMERG, # by default EMERG is not in log4r } # mapping from Log4r default levels to syslog, by string name # "DEBUG" => "DEBUG" # "INFO" => "INFO" # "WARN" => "WARN" # "ERROR" => "ERROR" # "FATAL" => "FATAL" SYSLOG_LOG4R_MAP = { "DEBUG" => "DEBUG", "INFO" => "INFO", "WARN" => "WARN", "ERROR" => "ERROR", "FATAL" => "FATAL" # "NOTICE" => "INFO", # by default NOTICE is not in log4r # "ALERT" => "FATAL", # by default ALERT is not in log4r # "EMERG" => "FATAL" # by default EMERG is not in log4r } @levels_map = SYSLOG_LOG4R_MAP # There are 3 hash arguments # # [:ident] syslog ident, defaults to _name # [:logopt] syslog logopt, defaults to LOG_PID | LOG_CONS # [:facility] syslog facility, defaults to LOG_USER def initialize(_name, hash={}) super(_name, hash) ident = (hash[:ident] or hash['ident'] or _name) logopt = (hash[:logopt] or hash['logopt'] or LOG_PID | LOG_CONS).to_i facility = (hash[:facility] or hash['facility'] or LOG_USER).to_i map_levels_by_name_to_syslog() if ( Syslog.opened? ) then Logger.log_internal { "Syslog already initialized, to alter, " + "you must close first"} end @syslog = ( Syslog.opened? ) ? Syslog : Syslog.open(ident, logopt, facility) end def closed? return !@syslog.opened? end def close @syslog.close unless @syslog.nil? @level = OFF OutputterFactory.create_methods(self) Logger.log_internal {"Outputter '#{@name}' closed Syslog and set to OFF"} end # A single hash argument that maps custom names to syslog names # # [levels_map] A map that will create a linkage between levels # in a hash and underlying syslog levels. # By default, these are direct mapping of the log4r # levels (e.g. "DEBUG" => "DEBUG") # If you have defined your own custom levels, you # should provide this underlying mapping, otherwise # all messages will be mapped to the underlying syslog # level of INFO by default. # e.g. # You have created custom levels called: # Configurator.custom_levels "HIGH", "MEDIUM", "LOW" # To map these to 'equivilent' syslog levels, after instantiatin # a syslogoutputter: # SyslogOutputter.map_levels_by_name_to_syslog( # { "HIGH" => "ALERT", "MEDIUM" => "WARN", "LOW" => "INFO" } # ) def map_levels_by_name_to_syslog( lmap = SYSLOG_LOG4R_MAP ) @levels_map = lmap end def get_levels_map() return @levels_map end private def canonical_log(logevent) pri = SYSLOG_LEVELS_MAP[@levels_map[LNAMES[logevent.level]]] rescue pri = LOG_INFO o = format(logevent) if o.kind_of? Exception then msg = "#{o.class} at (#{o.backtrace[0]}): #{o.message}" elsif o.respond_to? :to_str then msg = o.to_str else msg = o.inspect end @syslog.log(pri, '%s', msg) end end end log4r-1.1.10/lib/log4r/outputter/scribeoutputter.rb0000644000004100000410000000167211702744173022325 0ustar www-datawww-data# :nodoc: # Version:: $Id$ require "log4r/outputter/outputter" require "rubygems" require "scribe" module Log4r class ScribeOutputter < Outputter attr_reader :host, :port, :category def initialize(_name, hash={}) super(_name, hash) @host = (hash[:host] or hash[:host] or 'localhost') @port = (hash[:port] or hash[:port] or '1463') @category = (hash[:category] or hash[:category] or 'default') @client = Scribe.new("#{@host}:#{@port}", category=@category, add_newlines=false) end private def write(data) begin @client.log(data.strip, @category) rescue ScribeThrift::Client::TransportException => e Logger.log_internal(-2) { "Caught TransportException, is the scribe server alive?" } rescue ThriftClient::NoServersAvailable => e Logger.log_internal(-2) { "No scribe servers are available!" } end end end end log4r-1.1.10/lib/log4r/outputter/remoteoutputter.rb0000644000004100000410000000147211702744173022347 0ustar www-datawww-data# :nodoc: require 'log4r/lib/drbloader' require 'log4r/outputter/outputter' module Log4r # See log4r/logserver.rb class RemoteOutputter < Outputter def initialize(_name, hash={}) super(_name, hash) @uri = (hash[:uri] or hash['uri']) @buffsize = (hash[:buffsize] or hash['buffsize'] or 1).to_i @buff = [] connect end if HAVE_ROMP include ROMPClient else def initialize(*args) raise RuntimeError, "LogServer not supported. ROMP is required", caller end end # Call flush to send any remaining LogEvents to the remote server. def flush synch { send_buffer } end private def canonical_log(logevent) synch { @buff.push logevent send_buffer if @buff.size >= @buffsize } end end end log4r-1.1.10/lib/log4r/outputter/rollingfileoutputter.rb0000644000004100000410000002266711702744173023373 0ustar www-datawww-data # :nodoc: # Version:: $Id: rollingfileoutputter.rb,v 1.2 2009/09/29 18:13:13 colbygk Exp $ require "log4r/outputter/fileoutputter" require "log4r/staticlogger" require 'fileutils' module Log4r # RollingFileOutputter - subclass of FileOutputter that rolls files on size # or time. So, given a filename of "error.log", the first log file will be "error000001.log". # When its check condition is exceeded, it'll create and log to "error000002.log", etc. # # Additional hash arguments are: # # [:maxsize] Maximum size of the file in bytes. # [:maxtime] Maximum age of the file in seconds. # [:max_backups] Maxium number of prior log files to maintain. If max_backups is a positive number, # then each time a roll happens, RollingFileOutputter will delete the oldest backup log files in excess # of this number (if any). So, if max_backups is 10, then a maximum of 11 files will be maintained (the current # log, plus 10 backups). If max_backups is 0, no backups will be kept. If it is negative (the default), # there will be no limit on the number of files created. Note that the sequence numbers will continue to escalate; # old sequence numbers are not reused. # [:trunc] If true, deletes ALL existing log files (based on :filename) upon initialization, # and the sequence numbering will start over at 000001. Otherwise continues logging where it left off # last time (i.e. either to the file with the highest sequence number, or a new file, as appropriate). class RollingFileOutputter < FileOutputter attr_reader :current_sequence_number, :maxsize, :maxtime, :start_time, :max_backups def initialize(_name, hash={}) super( _name, hash.merge({:create => false}) ) if hash.has_key?(:maxsize) || hash.has_key?('maxsize') _maxsize = (hash[:maxsize] or hash['maxsize']).to_i if _maxsize.class != Fixnum raise TypeError, "Argument 'maxsize' must be an Fixnum", caller end if _maxsize == 0 raise TypeError, "Argument 'maxsize' must be > 0", caller end @maxsize = _maxsize end if hash.has_key?(:maxtime) || hash.has_key?('maxtime') _maxtime = (hash[:maxtime] or hash['maxtime']).to_i if _maxtime.class != Fixnum raise TypeError, "Argument 'maxtime' must be an Fixnum", caller end if _maxtime == 0 raise TypeError, "Argument 'maxtime' must be > 0", caller end @maxtime = _maxtime end if hash.has_key?(:max_backups) || hash.has_key?('max_backups') _max_backups = (hash[:max_backups] or hash['max_backups']).to_i if _max_backups.class != Fixnum raise TypeError, "Argument 'max_backups' must be an Fixnum", caller end @max_backups = _max_backups else @max_backups = -1 end # @filename starts out as the file (including path) provided by the user, e.g. "\usr\logs\error.log". # It will get assigned the current log file (including sequence number) # @log_dir is the directory in which we'll log, e.g. "\usr\logs" # @file_extension is the file's extension (if any) including any period, e.g. ".log" # @core_file_name is the part of the log file's name, sans sequence digits or extension, e.g. "error" @log_dir = File.dirname(@filename) @file_extension = File.extname(@filename) # Note: the File API doc comment states that this doesn't include the period, but its examples and behavior do include it. We'll depend on the latter. @core_file_name = File.basename(@filename, @file_extension) if (@trunc) purge_log_files(0) end @current_sequence_number = get_current_sequence_number() makeNewFilename # Now @filename points to a properly sequenced filename, which may or may not yet exist. open_log_file('a') # Note: it's possible we're already in excess of our time or size constraint for the current file; # no worries -- if a new file needs to be started, it'll happen during the write() call. end ####### private ####### # Delete all but the latest number_to_keep log files. def purge_log_files(number_to_keep) Dir.chdir(@log_dir) do # Make a list of the log files to delete. Start with all of the matching log files... glob = "#{@core_file_name}[0-9][0-9][0-9][0-9][0-9][0-9]#{@file_extension}" files = Dir.glob(glob) # ... if there are fewer than our threshold, just return... if (files.size() <= number_to_keep ) # Logger.log_internal {"No log files need purging."} return end # ...then remove those that we want to keep (i.e. the most recent #{number_to_keep} files). files.sort!().slice!(-number_to_keep, number_to_keep) # Delete the files. We use force (rm_f), so in case any files can't be deleted (e.g. someone's got one # open in an editor), we'll swallow the error and keep going. FileUtils.rm_f(files) Logger.log_internal { "Purged #{files.length} log files: #{files}" } end end # Get the highest existing log file sequence number, or 1 if there are no existing log files. def get_current_sequence_number() max_seq_no = 0 Dir.foreach(@log_dir) do |child| if child =~ /^#{@core_file_name}(\d+)#{@file_extension}$/ seq_no = $1.to_i if (seq_no > max_seq_no) max_seq_no = seq_no end end end return [max_seq_no, 1].max end # perform the write def write(data) # we have to keep track of the file size ourselves - File.size doesn't # seem to report the correct size when the size changes rapidly @datasize += data.size + 1 # the 1 is for newline roll if requiresRoll super end # Constructs a new filename from the @current_sequence_number, @core_file_name, and @file_extension, # and assigns it to @filename def makeNewFilename # note use of hard coded 6 digit sequence width - is this enough files? padded_seq_no = "0" * (6 - @current_sequence_number.to_s.length) + @current_sequence_number.to_s newbase = "#{@core_file_name}#{padded_seq_no}#{@file_extension}" @filename = File.join(@log_dir, newbase) end # Open @filename with the given mode: # 'a' - appends to the end of the file if it exists; otherwise creates it. # 'w' - truncates the file to zero length if it exists, otherwise creates it. # Re-initializes @datasize and @startime appropriately. def open_log_file(mode) # It appears that if a file has been recently deleted then recreated, calls like # File.ctime can return the erstwhile creation time. File.size? can similarly return # old information. So instead of simply doing ctime and size checks after File.new, we # do slightly more complicated checks beforehand: if (mode == 'w' || !File.exists?(@filename)) @start_time = Time.now() @datasize = 0 else @start_time = File.ctime(@filename) @datasize = File.size?(@filename) || 0 # File.size? returns nil even if the file exists but is empty; we convert it to 0. end @out = File.new(@filename, mode) Logger.log_internal {"File #{@filename} opened with mode #{mode}"} end # does the file require a roll? def requiresRoll if !@maxsize.nil? && @datasize > @maxsize Logger.log_internal { "Rolling because #{@filename} (#{@datasize} bytes) has exceded the maxsize limit (#{@maxsize} bytes)." } return true end if !@maxtime.nil? && (Time.now - @start_time) > @maxtime Logger.log_internal { "Rolling because #{@filename} (created: #{@start_time}) has exceded the maxtime age (#{@maxtime} seconds)." } return true end false end # roll the file def roll begin # If @baseFilename == @filename, then this method is about to # try to close out a file that is not actually opened because # fileoutputter has been called with the parameter roll=true # TODO: Is this check valid any more? I suspect not. Am commenting out...: #if ( @baseFilename != @filename ) then @out.close #end rescue Logger.log_internal { "RollingFileOutputter '#{@name}' could not close #{@filename}" } end # Prepare the next file. (Note: if max_backups is zero, we can skip this; we'll # just overwrite the existing log file) if (@max_backups != 0) @current_sequence_number += 1 makeNewFilename end open_log_file('w') # purge any excess log files (unless max_backups is negative, which means don't purge). if (@max_backups >= 0) purge_log_files(@max_backups + 1) end end end end # this can be found in examples/fileroll.rb as well if __FILE__ == $0 require 'log4r' include Log4r timeLog = Logger.new 'WbExplorer' timeLog.outputters = RollingFileOutputter.new("WbExplorer", { "filename" => "TestTime.log", "maxtime" => 10, "trunc" => true }) timeLog.level = DEBUG 100.times { |t| timeLog.info "blah #{t}" sleep(1.0) } sizeLog = Logger.new 'WbExplorer' sizeLog.outputters = RollingFileOutputter.new("WbExplorer", { "filename" => "TestSize.log", "maxsize" => 16000, "trunc" => true }) sizeLog.level = DEBUG 10000.times { |t| sizeLog.info "blah #{t}" } end log4r-1.1.10/lib/log4r/outputter/outputter.rb0000644000004100000410000000756311702744173021142 0ustar www-datawww-data# :include: ../rdoc/outputter # # == Other Info # # Version:: $Id$ # Author:: Leon Torres require "thread" require "log4r/outputter/outputterfactory" require "log4r/formatter/formatter" require "log4r/staticlogger" require 'monitor' module Log4r class Outputter < Monitor attr_reader :name, :level, :formatter @@outputters = Hash.new # An Outputter needs a name. RootLogger will be loaded if not already # done. The hash arguments are as follows: # # [:level] Logger level. Optional, defaults to root level # [:formatter] A Formatter. Defaults to DefaultFormatter def initialize(_name, hash={}) super() if _name.nil? raise ArgumentError, "Bad arguments. Name and IO expected.", caller end @name = _name validate_hash(hash) @@outputters[@name] = self end # dynamically change the level def level=(_level) Log4rTools.validate_level(_level) @level = _level OutputterFactory.create_methods(self) Logger.log_internal {"Outputter '#{@name}' level is #{LNAMES[_level]}"} end # Set the levels to log. All others will be ignored def only_at(*levels) raise ArgumentError, "Gimme some levels!", caller if levels.empty? raise ArgumentError, "Can't log only_at ALL", caller if levels.include? ALL levels.each {|level| Log4rTools.validate_level(level)} @level = levels.sort.first OutputterFactory.create_methods self, levels Logger.log_internal { "Outputter '#{@name}' writes only on " +\ levels.collect{|l| LNAMES[l]}.join(", ") } end # Dynamically change the formatter. You can just specify a Class # object and the formatter will invoke +new+ or +instance+ # on it as appropriate. def formatter=(_formatter) if _formatter.kind_of?(Formatter) @formatter = _formatter elsif _formatter.kind_of?(Class) and _formatter <= Formatter if _formatter.respond_to? :instance @formatter = _formatter.instance else @formatter = _formatter.new end else raise TypeError, "Argument was not a Formatter!", caller end Logger.log_internal {"Outputter '#{@name}' using #{@formatter.class}"} end # Call flush to force an outputter to write out any buffered # log events. Similar to IO#flush, so use in a similar fashion. def flush end ######### protected ######### # Validates the common hash arguments. For now, that would be # +:level+, +:formatter+ and the string equivalents def validate_hash(hash) # default to root level and DefaultFormatter if hash.empty? self.level = Logger.root.level @formatter = DefaultFormatter.new return end self.level = (hash[:level] or hash['level'] or Logger.root.level) self.formatter = (hash[:formatter] or hash['formatter'] or DefaultFormatter.new) end ####### private ####### # This method handles all log events passed to a typical Outputter. # Overload this to change the overall behavior of an outputter. Make # sure that the new behavior is thread safe. def canonical_log(logevent) synch { write(format(logevent)) } end # Common method to format data. All it does is call the resident # formatter's format method. If a different formatting behavior is # needed, then overload this method. def format(logevent) # @formatter is guaranteed to be DefaultFormatter if no Formatter # was specified @formatter.format(logevent) end # Abstract method to actually write the data to a destination. # Custom outputters should overload this to specify how the # formatted data should be written and to where. def write(data) end def synch; synchronize { yield } end end end log4r-1.1.10/lib/log4r/outputter/datefileoutputter.rb0000644000004100000410000000641511702744173022633 0ustar www-datawww-data# = DateFileOutputter # # Subclass of FileOutputter that changes the log file daily. When a new # day begins, a new file is created with the date included in the name. # # == Usage # # df_out = DateFileOutputter.new('name', # :dirname="/tmp", :date_pattern=>"%m-%d" # ) # # == Rate of Change # # A new logfile is created whenever the current time as formatted by the date # pattern no longer matches the previous time. (This is a simple String # comparison.) So, in order to change the frequency of the rollover, just # alter the date pattern to match how fast the files should be generated. # For instance, to generate files by the minute, # # df_out.date_pattern = "%M" # # This causes the following files to show up one minute apart, asuming the # script starts at the 4th minute of the hour: # # file_04.rb # file_05.rb # file_06.rb # ... # # The only limitation of this approach is that the precise time cannot be # recorded as the smallest time interval equals the rollover period for this # system. require "log4r/outputter/fileoutputter" require "log4r/staticlogger" module Log4r # Additional hash arguments are: # # [:dirname] Directory of the log file # [:date_pattern] Time.strftime format string (default is "%Y-%m-%d") class DateFileOutputter < FileOutputter DEFAULT_DATE_FMT = "%Y-%m-%d" def initialize(_name, hash={}) @DatePattern = (hash[:date_pattern] or hash['date_pattern'] or DEFAULT_DATE_FMT) @DateStamp = Time.now.strftime( @DatePattern); _dirname = (hash[:dirname] or hash['dirname']) # hash[:dirname] masks hash[:filename] if _dirname if not FileTest.directory?( _dirname) raise StandardError, "'#{_dirname}' must be a valid directory", caller end end _filename = (hash[:filename] or hash['filename']) if _filename.nil? @filebase = File.basename( $0, '.rb') + ".log" else @filebase = File.basename((hash[:filename] or hash['filename'] or "")) end # Get rid of the 'nil' in the path path = [_dirname, @filebase.sub(/(\.\w*)$/, "_#{@DateStamp}" + '\1')].compact hash[:filename] = hash['filename'] = File.join(path) super(_name, hash) end ####### private ####### # perform the write def write(data) change if requiresChange super end # construct a new filename from the DateStamp def makeNewFilename @DateStamp = Time.now.strftime( @DatePattern); @filename = File.join(File.dirname(@filename), @filebase.sub(/(\.\w*)$/, "_#{@DateStamp}" + '\1')) end # does the file require a change? def requiresChange _DateStamp = Time.now.strftime( @DatePattern); if not _DateStamp == @DateStamp @DateStamp = _DateStamp return true end false end # change the file def change begin @out.close rescue Logger.log_internal { "DateFileOutputter '#{@name}' could not close #{@filename}" } end makeNewFilename @out = File.new(@filename, (@trunc ? "w" : "a")) Logger.log_internal { "DateFileOutputter '#{@name}' now writing to #{@filename}" } end end end log4r-1.1.10/lib/log4r/outputter/outputterfactory.rb0000644000004100000410000000315611702744173022524 0ustar www-datawww-data# :nodoc: # Version: $Id$ require "log4r/base" require "log4r/repository" require "log4r/logger" require 'monitor' module Log4r class Outputter < Monitor class OutputterFactory #:nodoc: include Singleton # handles two cases: logging above a level (no second arg specified) # or logging a set of levels (passed into the second argument) def self.create_methods(out, levels=nil) Logger.root # force levels to be loaded # first, undefine all the log levels for mname in LNAMES undefine_log(mname.downcase, out) end if not levels.nil? and levels.include? OFF raise TypeError, "Can't log only_at OFF", caller[1..-1] end return out if out.level == OFF if levels.nil? # then define the log methods for lev >= outlev for lev in out.level...LEVELS define_log(LNAMES[lev].downcase, lev, out) end else # define the logs only for assigned levels for lev in levels define_log(LNAMES[lev].downcase, lev, out) end end return out end # we need to synch the actual write/format for thread safteyness def self.define_log(mname, level, out) return if mname == 'off' || mname == 'all' mstr = %- def out.#{mname}(logevent) canonical_log(logevent) end - module_eval mstr end def self.undefine_log(mname, out) return if mname == 'off' || mname == 'all' mstr = "def out.#{mname}(logevent); end" module_eval mstr end end end end log4r-1.1.10/lib/log4r/outputter/consoleoutputters.rb0000644000004100000410000000060311702744173022674 0ustar www-datawww-data# :nodoc: require "log4r/outputter/iooutputter" module Log4r # Same as IOOutputter(name, $stdout) class StdoutOutputter < IOOutputter def initialize(_name, hash={}) super(_name, $stdout, hash) end end # Same as IOOutputter(name, $stderr) class StderrOutputter < IOOutputter def initialize(_name, hash={}) super(_name, $stderr, hash) end end end log4r-1.1.10/lib/log4r/outputter/iooutputter.rb0000644000004100000410000000245511702744173021465 0ustar www-datawww-data# :nodoc: require "log4r/outputter/outputter" require "log4r/staticlogger" module Log4r ## # IO Outputter invokes print then flush on the wrapped IO # object. If the IO stream dies, IOOutputter sets itself to OFF # and the system continues on its merry way. # # To find out why an IO stream died, create a logger named 'log4r' # and look at the output. class IOOutputter < Outputter # IOOutputter needs an IO object to write to. def initialize(_name, _out, hash={}) super(_name, hash) @out = _out end def closed? @out.closed? end # Close the IO and sets level to OFF def close @out.close unless @out.nil? @level = OFF OutputterFactory.create_methods(self) Logger.log_internal {"Outputter '#{@name}' closed IO and set to OFF"} end ####### private ####### # perform the write def write(data) begin @out.print data @out.flush rescue IOError => ioe # recover from this instead of crash Logger.log_internal {"IOError in Outputter '#{@name}'!"} Logger.log_internal {ioe} close rescue NameError => ne Logger.log_internal {"Outputter '#{@name}' IO is #{@out.class}!"} Logger.log_internal {ne} close end end end end log4r-1.1.10/lib/log4r/outputter/emailoutputter.rb0000644000004100000410000001002711702744173022137 0ustar www-datawww-data# :include: ../rdoc/emailoutputter require 'log4r/outputter/outputter' require 'log4r/staticlogger' require 'net/smtp' module Log4r class EmailOutputter < Outputter attr_reader :server, :port, :domain, :acct, :authtype, :subject, :tls def initialize(_name, hash={}) super(_name, hash) validate(hash) @buff = [] begin Logger.log_internal { "EmailOutputter '#{@name}' running SMTP client on #{@server}:#{@port}" } rescue Exception => e Logger.log_internal(-2) { "EmailOutputter '#{@name}' failed to start SMTP client!" } Logger.log_internal {e} self.level = OFF raise e end end # send out an email with the current buffer def flush synch { send_mail } Logger.log_internal {"Flushed EmailOutputter '#{@name}'"} end private def validate(hash) @buffsize = (hash[:buffsize] or hash['buffsize'] or 100).to_i @formatfirst = Log4rTools.decode_bool(hash, :formatfirst, false) decode_immediate_at(hash) validate_smtp_params(hash) end def decode_immediate_at(hash) @immediate = Hash.new _at = (hash[:immediate_at] or hash['immediate_at']) return if _at.nil? Log4rTools.comma_split(_at).each {|lname| level = LNAMES.index(lname) if level.nil? Logger.log_internal(-2) do "EmailOutputter: skipping bad immediate_at level name '#{lname}'" end next end @immediate[level] = true } end def validate_smtp_params(hash) @from = (hash[:from] or hash['from']) raise ArgumentError, "Must specify from address" if @from.nil? _to = (hash[:to] or hash['to'] or "") @to = Log4rTools.comma_split(_to) raise ArgumentError, "Must specify recepients" if @to.empty? @server = (hash[:server] or hash['server'] or 'localhost') @port = (hash[:port] or hash['port'] or 25).to_i @domain = (hash[:domain] or hash['domain'] or ENV['HOSTNAME']) @acct = (hash[:acct] or hash['acct']) @passwd = (hash[:passwd] or hash['passwd']) @authtype = (hash[:authtype] or hash['authtype'] or :cram_md5).to_s.to_sym @subject = (hash[:subject] or hash['subject'] or "Message of #{$0}") @tls = (hash[:tls] or hash['tls'] or nil) @params = [@server, @port, @domain, @acct, @passwd, @authtype] end def canonical_log(event) synch { @buff.push case @formatfirst when true then @formatter.format event else event end send_mail if @buff.size >= @buffsize or @immediate[event.level] } end def send_mail msg = case @formatfirst when true then @buff.join else @buff.collect{|e| @formatter.format e}.join end ### build a mail header for RFC 822 rfc822msg = "From: #{@from}\n" + "To: #{@to}\n" + "Subject: #{@subject}\n" + "Date: #{Time.now.strftime( "%a, %d %b %Y %H:%M:%S %z %Z")}\n" + "Message-Id: <#{"%.8f" % Time.now.to_f}@#{@domain}>\n\n" + "#{msg}" ### send email begin smtp = Net::SMTP.new( @server, @port ) if ( @tls ) # >1.8.7 has smtp_tls built in, 1.8.6 requires smtp_tls if RUBY_VERSION < "1.8.7" then begin require 'rubygems' require 'smtp_tls' smtp.enable_starttls if smtp.respond_to?(:enable_starttls) rescue LoadError => e Logger.log_internal(-2) { "EmailOutputter '#{@name}' unable to load smtp_tls, needed to support TLS on Ruby versions < 1.8.7" } raise e end else # RUBY_VERSION >= 1.8.7 smtp.enable_starttls_auto if smtp.respond_to?(:enable_starttls_auto) end end # if @tls smtp.start(@domain, @acct, @passwd, @authtype) do |s| s.send_message(rfc822msg, @from, @to) end rescue Exception => e Logger.log_internal(-2) { "EmailOutputter '#{@name}' couldn't send email!" } Logger.log_internal {e} self.level = OFF raise e ensure @buff.clear end # begin end # def send_mail end # class EmailOutputter end # module Log4r log4r-1.1.10/lib/log4r/base.rb0000644000004100000410000000443511702744173015721 0ustar www-datawww-data# :nodoc: require "log4r/config" module Log4r ALL = 0 LNAMES = ['ALL'] # Defines the log levels of the Log4r module at runtime. It is given # either the default level spec (when root logger is created) or the # user-specified level spec (when Logger.custom_levels is called). # # The last constant defined by this method is OFF. Other level-sensitive # parts of the code check to see if OFF is defined before deciding what # to do. The typical action would be to force the creation of RootLogger # so that the custom levels get loaded and business can proceed as usual. # # For purposes of formatting, a constant named MaxLevelLength is defined # in this method. It stores the max level name string size. def Log4r.define_levels(*levels) #:nodoc: return if const_defined? :OFF for i in 0...levels.size name = levels[i].to_s module_eval "#{name} = #{i} + 1; LNAMES.push '#{name}'" end module_eval %{ LNAMES.push 'OFF' LEVELS = LNAMES.size OFF = LEVELS - 1 MaxLevelLength = Log4rTools.max_level_str_size } end # Some common functions class Log4rTools # Raises ArgumentError if level argument is an invalid level. Depth # specifies how many trace entries to remove. def self.validate_level(level, depth=0) unless valid_level?(level) raise ArgumentError, "Log level must be in 0..#{LEVELS}", caller[1..-(depth + 1)] end end def self.valid_level?(lev) not lev.nil? and lev.kind_of?(Numeric) and lev >= ALL and lev <= OFF end def self.max_level_str_size #:nodoc: size = 0 LNAMES.each {|i| size = i.length if i.length > size} size end # Shortcut for decoding 'true', 'false', true, false or nil into a bool # from a hash parameter. E.g., it looks for true/false values for # the keys 'symbol' and :symbol. def self.decode_bool(hash, symbol, default) data = hash[symbol] data = hash[symbol.to_s] if data.nil? return case data when 'true',true then true when 'false',false then false else default end end # Splits comma-delimited lists with arbitrary \s padding def self.comma_split(string) string.split(/\s*,\s*/).collect {|s| s.strip} end end end log4r-1.1.10/lib/log4r/logserver.rb0000644000004100000410000000124411702744173017012 0ustar www-datawww-data# :include: rdoc/logserver require 'log4r/logger' require 'log4r/lib/drbloader' module Log4r # See log4r/logserver.rb class LogServer < Logger attr_reader :uri # A valid ROMP uri must be specified. def initialize(_fullname, _uri, _level=nil, _additive=true, _trace=false, &accept) super(_fullname, _level, _additive, _trace) @uri = _uri start_server(_uri, accept) Logger.log_internal {"LogServer started at #{@uri}"} end if HAVE_ROMP include ROMPServer else def initialize(*args) raise RuntimeError, "LogServer not supported. ROMP is required", caller end end end end log4r-1.1.10/lib/log4r/configurator.rb0000644000004100000410000001512411702744173017506 0ustar www-datawww-data# :include: rdoc/configurator # # == Other Info # # Version:: $Id$ require "log4r/logger" require "log4r/outputter/staticoutputter" require "log4r/lib/xmlloader" require "log4r/logserver" require "log4r/outputter/remoteoutputter" # TODO: catch unparsed parameters #{FOO} and die module Log4r # Gets raised when Configurator encounters bad XML. class ConfigError < Exception end # See log4r/configurator.rb class Configurator include REXML if HAVE_REXML @@params = Hash.new # Get a parameter's value def self.[](param); @@params[param] end # Define a parameter with a value def self.[]=(param, value); @@params[param] = value end # Sets the custom levels. This method accepts symbols or strings. # # Configurator.custom_levels('My', 'Custom', :Levels) # # Alternatively, you can specify custom levels in XML: # # # # # My, Custom, Levels # # ... def self.custom_levels(*levels) return Logger.root if levels.size == 0 for i in 0...levels.size name = levels[i].to_s if name =~ /\s/ or name !~ /^[A-Z]/ raise TypeError, "#{name} is not a valid Ruby Constant name", caller end end Log4r.define_levels *levels end # Given a filename, loads the XML configuration for Log4r. def self.load_xml_file(filename) detect_rexml actual_load Document.new(File.new(filename)) end # You can load a String XML configuration instead of a file. def self.load_xml_string(string) detect_rexml actual_load Document.new(string) end ####### private ####### def self.detect_rexml unless HAVE_REXML raise LoadError, "Need REXML to load XML configuration", caller[1..-1] end end def self.actual_load(doc) confignode = doc.elements['//log4r_config'] if confignode.nil? raise ConfigError, " element not defined", caller[1..-1] end decode_xml(confignode) end def self.decode_xml(doc) decode_pre_config(doc.elements['pre_config']) doc.elements.each('outputter') {|e| decode_outputter(e)} doc.elements.each('logger') {|e| decode_logger(e)} doc.elements.each('logserver') {|e| decode_logserver(e)} end def self.decode_pre_config(e) return Logger.root if e.nil? decode_custom_levels(e.elements['custom_levels']) global_config(e.elements['global']) global_config(e.elements['root']) decode_parameters(e.elements['parameters']) e.elements.each('parameter') {|p| decode_parameter(p)} end def self.decode_custom_levels(e) return Logger.root if e.nil? or e.text.nil? begin custom_levels *Log4rTools.comma_split(e.text) rescue TypeError => te raise ConfigError, te.message, caller[1..-4] end end def self.global_config(e) return if e.nil? globlev = e.value_of 'level' return if globlev.nil? lev = LNAMES.index(globlev) # find value in LNAMES Log4rTools.validate_level(lev, 4) # choke on bad level Logger.global.level = lev end def self.decode_parameters(e) e.elements.each{|p| @@params[p.name] = p.text} unless e.nil? end def self.decode_parameter(e) @@params[e.value_of('name')] = e.value_of 'value' end def self.decode_outputter(e) # fields name = e.value_of 'name' type = e.value_of 'type' level = e.value_of 'level' only_at = e.value_of 'only_at' # validation raise ConfigError, "Outputter missing name", caller[1..-3] if name.nil? raise ConfigError, "Outputter missing type", caller[1..-3] if type.nil? Log4rTools.validate_level(LNAMES.index(level)) unless level.nil? only_levels = [] unless only_at.nil? for lev in Log4rTools.comma_split(only_at) alev = LNAMES.index(lev) Log4rTools.validate_level(alev, 3) only_levels.push alev end end formatter = decode_formatter(e.elements['formatter']) # build the eval string buff = "Outputter[name] = #{type}.new name" buff += ",:level=>#{LNAMES.index(level)}" unless level.nil? buff += ",:formatter=>formatter" unless formatter.nil? params = decode_hash_params(e) buff += "," + params.join(',') if params.size > 0 begin eval buff rescue Exception => ae raise ConfigError, "Problem creating outputter: #{ae.message}", caller[1..-3] end Outputter[name].only_at *only_levels if only_levels.size > 0 Outputter[name] end def self.decode_formatter(e) return nil if e.nil? type = e.value_of 'type' raise ConfigError, "Formatter missing type", caller[1..-4] if type.nil? buff = "#{type}.new " + decode_hash_params(e).join(',') begin return eval(buff) rescue Exception => ae raise ConfigError, "Problem creating outputter: #{ae.message}", caller[1..-4] end end ExcludeParams = %w{formatter level name type} # Does the fancy parameter to hash argument transformation def self.decode_hash_params(e) buff = [] e.attributes.each_attribute {|p| next if ExcludeParams.include? p.name buff << ":" + p.name + "=>" + paramsub(p.value) } e.elements.each {|p| next if ExcludeParams.include? p.name buff << ":" + p.name + "=>" + paramsub(p.text) } buff end # Substitues any #{foo} in the XML with Parameter['foo'] def self.paramsub(str) return nil if str.nil? @@params.each {|param, value| str.sub! '#{'+param+'}', value} "'" + str + "'" end def self.decode_logger(e) l = Logger.new e.value_of('name') decode_logger_common(l, e) end def self.decode_logserver(e) return unless HAVE_REXML name = e.value_of 'name' uri = e.value_of 'uri' l = LogServer.new name, uri decode_logger_common(l, e) end def self.decode_logger_common(l, e) level = e.value_of 'level' additive = e.value_of 'additive' trace = e.value_of 'trace' l.level = LNAMES.index(level) unless level.nil? l.additive = additive unless additive.nil? l.trace = trace unless trace.nil? # and now for outputters outs = e.value_of 'outputters' Log4rTools.comma_split(outs).each {|n| l.add n.strip} unless outs.nil? e.elements.each('outputter') {|e| name = (e.value_of 'name' or e.text) l.add Outputter[name] } end end end log4r-1.1.10/lib/log4r/MDC.rb0000644000004100000410000000265111702744173015410 0ustar www-datawww-data# :include: rdoc/MDC # # == Other Info # # Version:: $Id$ # Author:: Colby Gutierrez-Kraybill require 'monitor' module Log4r MDCNAME = "log4rMDC" MDCNAMEMAXDEPTH = "log4rMDCMAXDEPTH" $globalMDCLock = Monitor.new # See log4r/MDC.rb class MDC < Monitor private_class_method :new def self.check_thread_instance() # need to interlock here, so that if # another thread is entering this section # of code before the main thread does, # then the main thread copy of the MDC # is setup before then attempting to clone # it off if ( Thread.current[MDCNAME] == nil ) then $globalMDCLock.synchronize do if ( Thread.main[MDCNAME] == nil ) then Thread.main[MDCNAME] = Hash.new end if ( Thread.current != Thread.main ) then Thread.current[MDCNAME] = Hash.new Thread.main[MDCNAME].each{ |k,v| Thread.current[MDCNAME][k] = v } end end end end def self.get( a_key ) self.check_thread_instance() Thread.current[MDCNAME].fetch(a_key, ""); end def self.get_context() self.check_thread_instance() return Thread.current[MDCNAME].clone end def self.put( a_key, a_value ) self.check_thread_instance() Thread.current[MDCNAME][a_key] = a_value end def self.remove( a_key ) self.check_thread_instance() Thread.current[MDCNAME].delete( a_key ) end end end log4r-1.1.10/lib/log4r/yamlconfigurator.rb0000644000004100000410000001274311702744173020375 0ustar www-datawww-data# :include: rdoc/yamlconfigurator # # == Other Info # # Version: $Id$ require "log4r/logger" require "log4r/outputter/staticoutputter" require "log4r/logserver" require "log4r/outputter/remoteoutputter" require 'yaml' module Log4r # Gets raised when Configurator encounters bad YAML. class ConfigError < Exception end # See log4r/yamlconfigurator.rb class YamlConfigurator @@params = Hash.new # Get a parameter's value def self.[](param); @@params[param] end # Define a parameter with a value def self.[]=(param, value); @@params[param] = value end def self.custom_levels( levels) return Logger.root if levels.size == 0 for i in 0...levels.size name = levels[i].to_s if name =~ /\s/ or name !~ /^[A-Z]/ raise TypeError, "#{name} is not a valid Ruby Constant name", caller end end Log4r.define_levels *levels end # Given a filename, loads the YAML configuration for Log4r. def self.load_yaml_file( filename) actual_load( File.open( filename)) end # You can load a String YAML configuration instead of a file. def self.load_yaml_string( string) actual_load( string) end ####### private ####### def self.actual_load( yaml_docs) log4r_config = nil YAML.load_documents( yaml_docs){ |doc| doc.has_key?( 'log4r_config') and log4r_config = doc['log4r_config'] and break } if log4r_config.nil? raise ConfigError, "Key 'log4r_config:' not defined in yaml documents", caller[1..-1] end decode_yaml( log4r_config) end def self.decode_yaml( cfg) decode_pre_config( cfg['pre_config']) cfg['outputters'].each{ |op| decode_outputter( op)} cfg['loggers'].each{ |lo| decode_logger( lo)} cfg['logserver'].each{ |lo| decode_logserver( lo)} unless cfg['logserver'].nil? end def self.decode_pre_config( pre) return Logger.root if pre.nil? decode_custom_levels( pre['custom_levels']) global_config( pre['global']) global_config( pre['root']) decode_parameters( pre['parameters']) end def self.decode_custom_levels( levels) return Logger.root if levels.nil? begin custom_levels( levels) rescue TypeError => te raise ConfigError, te.message, caller[1..-4] end end def self.global_config( e) return if e.nil? globlev = e['level'] return if globlev.nil? lev = LNAMES.index(globlev) # find value in LNAMES Log4rTools.validate_level(lev, 4) # choke on bad level Logger.global.level = lev end def self.decode_parameters( params) params.each{ |p| @@params[p['name']] = p['value']} unless params.nil? end def self.decode_outputter( op) # fields name = op['name'] type = op['type'] level = op['level'] only_at = op['only_at'] # validation raise ConfigError, "Outputter missing name", caller[1..-3] if name.nil? raise ConfigError, "Outputter missing type", caller[1..-3] if type.nil? Log4rTools.validate_level(LNAMES.index(level)) unless level.nil? only_levels = [] unless only_at.nil? for lev in only_at alev = LNAMES.index(lev) Log4rTools.validate_level(alev, 3) only_levels.push alev end end formatter = decode_formatter( op['formatter']) opts = {} opts[:level] = LNAMES.index(level) unless level.nil? opts[:formatter] = formatter unless formatter.nil? opts.merge!(decode_hash_params(op)) begin Outputter[name] = Log4r.const_get(type).new name, opts rescue Exception => ae raise ConfigError, "Problem creating outputter: #{ae.message}", caller[1..-3] end Outputter[name].only_at( *only_levels) if only_levels.size > 0 Outputter[name] end def self.decode_formatter( fo) return nil if fo.nil? type = fo['type'] raise ConfigError, "Formatter missing type", caller[1..-4] if type.nil? begin return Log4r.const_get(type).new(decode_hash_params(fo)) rescue Exception => ae raise ConfigError, "Problem creating outputter: #{ae.message}", caller[1..-4] end end ExcludeParams = %w{formatter level name type only_at} # Does the fancy parameter to hash argument transformation def self.decode_hash_params(ph) case ph when Hash ph.inject({}){|a,(k,v)| a[k] = self.decode_hash_params(v); a} when Array ph.map{|v| self.decode_hash_params(v)} when String self.paramsub(ph) else ph end end # Substitues any #{foo} in the YAML with Parameter['foo'] def self.paramsub(str) @@params.each {|param, value| str = str.sub("\#{#{param}}", value) } str end def self.decode_logger( lo) l = Logger.new lo['name'] decode_logger_common( l, lo) end def self.decode_logserver( lo) name = lo['name'] uri = lo['uri'] l = LogServer.new name, uri decode_logger_common(l, lo) end def self.decode_logger_common( l, lo) level = lo['level'] additive = lo['additive'] trace = lo['trace'] l.level = LNAMES.index( level) unless level.nil? l.additive = additive unless additive.nil? l.trace = trace unless trace.nil? # and now for outputters outs = lo['outputters'] outs.each {|n| l.add n.strip} unless outs.nil? end end end log4r-1.1.10/lib/log4r/loggerfactory.rb0000644000004100000410000000503411702744173017652 0ustar www-datawww-data# :nodoc: # Version:: $Id$ require "log4r/base" require "log4r/repository" require 'log4r/logevent' module Log4r class Logger class LoggerFactory #:nodoc: # we want to log iff root.lev <= lev && logger.lev <= lev # BTW, root is guaranteed to be defined by this point def self.define_methods(logger) return if logger.is_root? undefine_methods(logger) globlev = Repository['root'].level return if logger.level == OFF or globlev == OFF toggle_methods(globlev, logger) end # set logging methods to null defaults def self.undefine_methods(logger) for lname in LNAMES next if lname == 'OFF'|| lname == 'ALL' unset_log(logger, lname) set_false(logger, lname) end set_false(logger, 'all') set_true(logger, 'off') end # toggle methods >= globlev that are also >= level def self.toggle_methods(globlev, logger) for lev in globlev...LEVELS # satisfies >= globlev next if lev < logger.level # satisfies >= level next if LNAMES[lev] == 'OFF' next if LNAMES[lev] == 'ALL' set_log(logger, LNAMES[lev]) set_true(logger, LNAMES[lev]) end if logger.level == ALL set_true(logger, 'all') end if logger.level != OFF && globlev != OFF set_false(logger, 'off') end end # And now, the weird dynamic method definitions! :) def self.unset_log(logger, lname) mstr="def logger.#{lname.downcase}(data=nil, propagated=false); end" module_eval mstr end # Logger logging methods are defined here. def self.set_log(logger, lname) # invoke caller iff the logger invoked is tracing tracercall = (logger.trace ? "caller" : "nil") # maybe pass parent a logevent. second arg is the switch if logger.additive && !logger.parent.is_root? parentcall = "@parent.#{lname.downcase}(event, true)" end mstr = %- def logger.#{lname.downcase}(data=nil, propagated=false) if propagated then event = data else data = yield if block_given? event = LogEvent.new(#{lname}, self, #{tracercall}, data) end @outputters.each {|o| o.#{lname.downcase}(event) } #{parentcall} end - module_eval mstr end def self.set_false(logger, lname) module_eval "def logger.#{lname.downcase}?; false end" end def self.set_true(logger, lname) module_eval "def logger.#{lname.downcase}?; true end" end end end end log4r-1.1.10/lib/log4r/staticlogger.rb0000644000004100000410000000261311702744173017472 0ustar www-datawww-data# :nodoc: module Log4r class Logger # Returns the root logger. Identical to Logger.global def self.root; return RootLogger.instance end # Returns the root logger. Identical to Logger.root def self.global; return root end # Get a logger with a fullname from the repository or nil if logger # wasn't found. def self.[](_fullname) # forces creation of RootLogger if it doesn't exist yet. return RootLogger.instance if _fullname=='root' or _fullname=='global' Repository[_fullname] end # Like Logger[] except that it raises NameError if Logger wasn't found. def self.get(_fullname) logger = self[_fullname] if logger.nil? raise NameError, "Logger '#{_fullname}' not found.", caller end logger end # Yields fullname and logger for every logger in the system. def self.each for fullname, logger in Repository.instance.loggers yield fullname, logger end end def self.each_logger Repository.instance.loggers.each_value {|logger| yield logger} end # Internal logging for Log4r components. Accepts only blocks. # To see such log events, create a logger named 'log4r' and give # it an outputter. def self.log_internal(level=1) internal = Logger['log4r'] return if internal.nil? internal.send(LNAMES[level].downcase, yield) end end end log4r-1.1.10/lib/log4r/rdoc/0000755000004100000410000000000011702744173015403 5ustar www-datawww-datalog4r-1.1.10/lib/log4r/rdoc/GDC0000644000004100000410000000076711702744173015735 0ustar www-datawww-data= GDC The GDC class implements a copy of the Global Diagnostic Context, which is not part of the Apache Log4j library, as of this writing (10 Jan 2009). The GDC is like the NDC and MDC classes, only it is global to the application (see NDC and MDC for details on those classes). The GDC is local to the main thread, and any new threads will return the value of the current GDC set in the main thread. Only the main thread can set the GDC, any other threads that attempt to will raise an exception. log4r-1.1.10/lib/log4r/rdoc/MDC0000644000004100000410000000120411702744173015726 0ustar www-datawww-data= MDC The MDC class implements a copy of the Mapped Diagnostic Context, which is part of the Apache Log4j library. See the NDC documentation for more details. MDCs are much like NDCs, but instead of a stack context it uses a map for holding this information. This allows for selection of information out of the map when the log message is being created. MDCs are thread safe, and are unique to each thread. An important difference between MDCs in Log4r vs Log4j is that they only inherit from the main thread. Ruby treats all new threads as being the children of the main thread, even if they are started from a thread that is not main. log4r-1.1.10/lib/log4r/rdoc/emailoutputter0000644000004100000410000000666111702744173020422 0ustar www-datawww-data= EmailOutputter This is an experimental class that sends a number of formatted log events as an RFC 822 email. It should work fine if Net:SMTP doesn't cause any problems. Just in case, create a logger named 'log4r' and give it an outputter to see the logging statements made by this class. If it fails to send email, it will set itself to OFF and stop logging. In order to use it, require 'log4r/outputter/emailoutputter' == SMTP Configuration All arguments to Net::SMTP.start are supported. Pass them as hash parameters to +new+. The to field is specified as a comma-delimited list of emails (padded with \s* if desired). An example: email_out = EmailOutputter.new 'email_out', :server=>'localhost', :port=>25, :domain=>'somewhere.com', :from=>'me@foo.bar', :to=>'them@foo.bar, me@foo.bar, bozo@clown.net', :subject=>'Log Report' == LogEvent Buffer EmailOutputter stores log messages in a buffer. When the buffer reaches a certain number, the buffsize, it will send an email containing the contents of the buffer. The default +buffsize+ is 100. To set +buffsize+, email_out.buffsize = 1000 # set the buffsize to 1000 == Flush To Send Email Flushing an EmailOutputter will mail out all the remaining LogEvents. This is convenient for systems that encapsulate the shutdown process. It's a good idea to do this for all outputters, Outputter.each_outputter {|o| o.flush} Alternatively, one can invoke flush on the outputter directly, email_out.flush It's also a good idea to notify the recepient of the email that the system is shutting down. Before flushing, log a message to the owner of this outputter, log_with_email_out.info "The system is shutting down at #{Time.now}" == Format When? LogEvents may either be formatted as they come in or as the email is being composed. To do the former, specify a value of +true+ to the hash parameter +formatfirst+. The default is to format during email composition. email_out.formatfirst = true # format as soon as LogEvents are received == Immediate Notification EmailOutputter can be configured to flush and send the email whenever the logger sees a certain log priority. Use the +immediate_at+ hash parameter and specify the levels as a comma-delimited list (like an XML element). To trigger an email on FATAL and ERROR, email_out.immediate_at = "FATAL, ERROR" == Example A security logger sends email to several folks, buffering up to 25 log events and sending immediates on CRIT and WARN EmailOutputter.new 'security', :to => 'bob@secure.net, frank@secure.net', :buffsize => 25, :immediate_at => 'WARN, CRIT' == XML Configuration See log4r/configurator.rb for details. Here's an example: WARN, CRIT localhost me@secure.net bob@secure.net, frank@secure.net ... == To Do This class could use some sophistication, in particular a means to compress the logs, a way to set the subject dynamically (probably via a block method), and a time trigger. When the time trigger is introduced, a +buffsize+ of 0 should mean ignore +buffsize+ to determine when to send the email. log4r-1.1.10/lib/log4r/rdoc/outputter0000644000004100000410000000652611702744173017412 0ustar www-datawww-data= Outputters An Outputter is a logging destination with a particular way to format data. It has a level threshold and a flexible level mask. Outputters must have names. == Level Threshold Outputters have their own level thresholds that default to root level. They will not write any log events with a rank less than their threshold. == Level Mask Alternatively, an Outputter can be told to log specific levels only: o = StdoutOutputter.new 'console' o.only_at DEBUG, FATAL # only DEBUG and FATAL get written == Outputter Repository When outputters are created, they store themselves in an Outputter repository similar to the Logger repository. StdoutOutputter.new 'console' => Create 'console' outputter Outputter['console'] => Get it back from the stash. == Formatter An outputter has a format defined by its Formatter. If no Formatter is specified, DefaultFormatter will be used. == Outputter is Abstract The basic Outputter class is both abstract and a null object. == Interesting Outputters * log4r/outputter/syslogoutputter.rb - Logs to syslog * log4r/outputter/emailoutputter.rb - Email logs * log4r/logserver.rb - For remote logging == Subclasses * Log4r::IOOutputter - for any IO object * Log4r::StdoutOutputter - $stdout * Log4r::StderrOutputter - $stderr * Log4r::FileOutputter - log to a file * Log4r::RollingFileOutputter - log to a file and split it as it grows * Log4r::SyslogOutputter - logs to syslog * Log4r::EmailOutputter - email logs * Log4r::RemoteOutputter - for remote logging == Default Outputters Two outputters named 'stdout' and 'stderr' are created automatically at the root level. They are nice shortcuts. Outputter['stdout'] => 'stdout' Outputter['stderr'] => 'stderr' Outputter.stdout => 'stdout' Outputter.stderr => 'stderr' == Configuring Outputters must have names and receive hash arguments. The parameter name for the hash args can be either a symbol or a string. All defined outputters accept :level and :formatter arguments. For arguments specific to a convenience Outputter, please look at the class description. The level threshold, the levels to log at (only_at) and formatter can be changed dynamically using the = methods. As a collective example of all this, here are various ways to set up an IOOutputter: IOOutputter.new ExoticIO.new 'exotic', 'level' => WARN, :formatter => MyFormatter.new # an equivalent way: o = IOOutputter.new ExoticIO.new 'exotic' o.level = WARN o.formatter = MyFormatter # we can specify just the class o.only_at = THIS, THAT == XML Configuration Specify outputters as children of : DEBUG, INFO FileOutputter #{logpath}/file.log false ... As explained in log4r/configurator.rb, the hash arguments you would normally pass to new are specified as XML parameters. It is given an IO object to write to, a Formatter to call, and, optionally, levels to write at. Outputters invoke print then flush on the wrapped IO object. If the IO chokes, the Outputter will close the IO and set its level to OFF. log4r-1.1.10/lib/log4r/rdoc/logger0000644000004100000410000001254411702744173016613 0ustar www-datawww-data= Loggers Loggers provide the interface for logging in Log4r. To create a logger, first come up with a name for it. Good choices include the name of the class using it, a service name, or the name of the file. To create a logger named 'mylog': Logger.new('mylog') After creating a logger, it is stashed in a repository. The logger may be retrieved at any time: Logger['mylog'] # get mylog back It will return nil if the logger is not found. Alternatively, if an Exception is desired when a nonexistant logger is referenced, the Logger#get command can be used: Logger.get('boguslog') # raises NameError if it doesn't exist == Manipulating a Logger's Outputters Loggers start out with no outputters. They can be added using the Logger#add method or set directly by modifying the Loggers#outputters array: mylog = Logger['mylog'] # assume we've created Outputters out1 through out4 mylog.outputters = out1, out2 mylog.add(out3, out4) mylog.each_outputter {|o| o.flush} # assume out5 through out7 have names 'out5' through 'out7' resp. mylog.outputters = 'out5', 'out6' mylog.add('out7') mylog.remove('out5','out7') Please see log4r/outputter/outputter.rb and Log4r::Outputter for more about outputters. == Logging Methods To log something at a certain priority, use the logging method named after the lowercased priority level name: mylog.warn "This is a message with priority WARN" mylog.fatal "A FATAL message" Blocks can also be logged: mylog.warn {"This is also a message with priority WARN"} mylog.debug do # some complicated string magic return result end The primary difference is that the block doesn't get called unless the Logger can log at that level. It is useful for doing computationaly expensive things at a log event. == Query Methods To ask Log4r whether it is capable of logging a certain level: mylog.warn? # are we logging WARN? mylog.fatal? # how about FATAL? Query methods and blocks accomplish the same thing: mylog.warn "don't evaluate unless WARN is on" if mylog.warn? mylog.warn {"don't evaluate unless WARN is on"} == What About the Special Levels? ALL and OFF can be querried, but not logged: log.off? # true iff level is OFF log.all? # true iff level is ALL log.all "Try to log" => Method not defined. (NameError) == Custom Levels and Method Names Suppose we've set up Log4r with the custom levels: Foo < Bar < Baz As one might expect, the logging methods are named after them: log.bar "something" # log at custom level Bar log.bar? # are we logging at level Bar? = Logger Inheritance Normally, when a logger is created, its parent is set to RootLogger. If a Logger's level isn't specified at creation, it will inherit the level of its parent. To specify an ancestors of a logger besides RootLogger, include the names of the ancestors in order of ancestry and delimited by Log4r::Log4rConfig::LoggerPathDelimiter. For example, if the delimiter is the default ::, our logger is 'me' and its ancestors are 'cain', 'grandpa', and 'pa', we create the logger like so: Logger.new('cain::grandpa::pa::me') This string is split into three compontents which can be used by a Formatter to avoid parsing the name: Logger#fullname:: The whole enchilada: 'cain::grandpa::pa::me' Logger#name:: Just 'me' To get this logger back from the repository, Logger['cain::grandpa::pa::me'] = Outputter Additivity By default, Logger Outputters are additive. This means that a log event will also be sent to all of a logger's ancestors. To stop this behavior, set a logger's +additive+ to false. Logger['foo'].additive = false A Logger's level, additivity and trace can be changed dynamically, but this is an expensive operation as the logging methods have to be redefined. = RootLogger Log4r::RootLogger is the ancestor of all loggers. Its level defines the global logging threshold. Any loggers created after RootLogger's level is set will not log below that level. By default, RootLogger's level is set to ALL RootLogger is a singleton which gets created automaticallay. It can be retrieved at any time with Logger.root, Logger.global, Logger['root'] or Logger['global']. == Global Level Suppose we want _everything_ to ignore events less than FATAL. We can accomplish this easily: Logger.global.level = FATAL Just be sure to set this before any other Loggers or Outputters are defined. == RootLogger Does Nothing RootLogger itself behaves as if its level were permanently set to OFF, thus making it a sort of null object. = XML Configuration Please see log4r/configurator.rb for an overview of XML configuratoin. It's easy to configure a Logger in XML. The following example should be sufficient: ... false stdout stderr, dancer, doner, blitzen ... The element +outputter+ can occur multiple times, but cannot be an attribute of +logger+. That is, it is not an XML directive. However, the element +outputters+ is an XML directive, as are all the others. For more examples, check the examples directory in the Log4r package. log4r-1.1.10/lib/log4r/rdoc/log4r0000644000004100000410000000575611702744173016372 0ustar www-datawww-data= #{version} Log4r API Reference Welcome to the Log4r API reference. There are two classes of reference, the file overview and the class API. They are listed under Files and Classes respectively. File overviews cover the use of the Log4r API and some implementation details, whereas class APIs detail the methods available to the various objects. The code examples in this API assume: include Log4r This file overview covers some of the major concepts in Log4r. == Log Levels Log4r provides as many levels of logging as desired. Logging levels are an ordered set of names ranked by priority. The more important a level is, the higher its priority and the more likely we want to see any data associated with it. Log4r provides many ways to filter information by level. Loggers and Outputters have a level parameter which serves as a level threshold. Any data below this threshold will be ignored by the Logger or Outputter. Additionally, Outputters can be set to mask out any particular level or collection of levels. By combining level thresholds with other Log4r features, one can direct any set of data to any destination desired in a way that is easy to visualize and configure. === Default Levels The default log levels and their priority rankings are: DEBUG < INFO < WARN < ERROR < FATAL === Custom Levels You can have as many levels as you desire, with any naming scheme. Log4r will automatically define level constants and log method names after your custom specification. Please see log4r/configurator.rb for details. === Boundary Levels There are two special levels, ALL and OFF which denote whether we are logging at all levels or at none. The priority ranks with respect to the logging levels are as follows: ALL < logging levels as defined by user < OFF Thus, setting the level to ALL will enable logging at all levels whereas OFF will turn off logging completely. == File Overviews For Loggers:: log4r/logger.rb For Outputters:: log4r/outputter/outputter.rb For Formatters:: log4r/formatter/formatter.rb For configuration:: log4r/configurator.rb == Principal Classes of Log4r * Log4r::Logger - Interface to logging * Log4r::Outputter - An output destination for a logger. * Log4r::Formatter - A means of formatting log data. * Log4r::Configurator - A means of configuring Log4r == Convenience Classes Log4r provides several convenience Outputters and Formatters. Please look at the file overviews of those classes for more details. == Remote Logging Log4r provides a way to send log events over a network. See log4r/logserver.rb for details. == What's Going on Inside? Log4r has an internal logger which records much of what goes on inside. To see the output, define a Logger named 'log4r' and give it an Outputter of some sort. It logs only at the lowest and highest priorities. That would be DEBUG and FATAL for the standard setup. It is essential to view this data when using certain classes, like Log4r::LogServer and Log4r::EmailOutputter. log4r-1.1.10/lib/log4r/rdoc/win32eventoutputter0000644000004100000410000000042011702744173021322 0ustar www-datawww-data= Win32EventOutputter THIS IS A DEVELOPMENT VERSION AND IS NOT READY FOR USE INFACT, IT MAY NEVER BE READY FOR USE, AS TRYING TO INTERACT WITH THE WIN32 EVENTLOG API REQUIRES USER INTERVENTION TO LOOKUP event_id AND category CODES THAT THIS LIBRARY CANNOT KNOW A PRIORI log4r-1.1.10/lib/log4r/rdoc/log4jxmlformatter0000644000004100000410000000122211702744173021007 0ustar www-datawww-data= Configuring Log4r with Log4r::YamlConfigurator The YamlConfigurator class allows one to set up Log4r via YAML. It is used almost exactly as Log4r::Configurator and has the same features, ycfg = YamlConfigurator # handy shorthand ycfg['foo'] = bar # replaces instances of #{foo} in the YAML with bar ycfg.load_yaml_file('foo.yaml') Ruby 1.7 and 1.8 comes with a YAML parser. Hence, YAML can be used to configure Log4r out of the box. A comprehensive example of a Log4r YAML configuration is provided in the examples directory. To use this class: require 'log4r/yamlconfigurator' Thanks to Andreas Hund for making this possible. log4r-1.1.10/lib/log4r/rdoc/NDC0000644000004100000410000000301511702744173015731 0ustar www-datawww-data= NDC The NDC class implements a copy of the Nested Diagnostic Context, which is part of the Apache Log4j library. Nested Diagnostic Contexts were derived from Neil Harrison's article on "Patterns for Logging Diagnostic Messages", part of the book "Pattern Languages of Program Design 3" edited by Martin et al. NDCs in Log4r are thread safe. NDCs in log4r are close enough to NDCs in Log4j that I include its documentation directly: ... A Nested Diagnostic Context, or NDC in short, is an instrument to distinguish interleaved log output from different sources. Log output is typically interleaved when a server handles multiple clients near-simultaneously. Interleaved log output can still be meaningful if each log entry from different contexts had a distinctive stamp. This is where NDCs come into play. Note that NDCs are managed on a per thread basis. NDC operations such as push, pop(), clear(), getDepth() and setMaxDepth(int) affect the NDC of the current thread only. NDCs of other threads remain unaffected. ... An important difference between NDCs in Log4r vs Log4j is that you do not have to called NDC.remove() when exiting a thread. This class will automatically create Thread specific storage for the current thread on the first call to any of its methods, i.e. NDC.push( "client accept" ); New threads may inherit the NDC of the parent thread by making use of the clone_stack() and inherit() methods. By default, the NDC is not inherited automatically. This is unlike MDCs, which will inherit from the main thread. log4r-1.1.10/lib/log4r/rdoc/syslogoutputter0000644000004100000410000000143711702744173020647 0ustar www-datawww-data= SyslogOutputter A SyslogOutputter transforms a Log4r::LogEvent into a call to syslog(). Since syslog has its own formatting system, log4r formatters are ignored. == Usage To use, require 'log4r/outputter/syslogoutputter' An example, require 'log4r' require 'log4r/outputter/syslogoutputter' syslog = Log4r::SyslogOutputter.new("name", 'logopt'=>#, 'facility'=>#) syslog.err("this is an ERR message") The output in /var/logs/syslog (Debian) is, Sep 3 11:43:06 tiphares sys[1603]: this is an ERR message The hash arguments +logoptions+ and +facility+ are passed to Syslog.open. The defaults are LOG_PID | LOG_CONS and LOG_USER respectively. This is a first try implementation. It works well. Please report any bugs and fixes. log4r-1.1.10/lib/log4r/rdoc/formatter0000644000004100000410000000233111702744173017330 0ustar www-datawww-data= Formatters Formatters are responsible for formatting LogEvent data. An Outputter owning a Formatter will invoke the Log4r::Formatter#format method prior to writing. == Available Formatters * Log4r::BasicFormatter - default * Log4r::PatternFormatter - most flexible. See log4r/formatter/patternformatter.rb * Log4r::SimpleFormatter - like BasicFormatter for Strings only (low noise) * Log4r::ObjectFormatter - for inspecting objects * Log4r::NullFormatter - twirls on its feet and does nothing = XML Configuration Specify the Formatter and its class (as +type+) under an directive: As explained in log4r/configurator.rb, the hash arguments you would normally pass to +new+ are specified as XML parameters. Only PatternFormatter has any of these. = Custom Formatting Building a custom Formatter is extremely easy. Just define a class that extends Formatter and override the Formatter#format method. Then give it to any interested Outputters. If you're interested in setting up your custom formatters in XML, please take a look at log4r/configurator.rb. == Data Available See Log4r::LogEvent log4r-1.1.10/lib/log4r/rdoc/scribeoutputter0000644000004100000410000000055111702744173020572 0ustar www-datawww-data= ScribeOutputter A ScribeOutputter transforms a Log4r::LogEvent into an event passed to Scribe. The user can configure the outputter with the host and port of the scribe scribe server. == Usage To use, require 'log4r' An example, require 'log4r' logger = Log4r::ScribeOutputter.new('name', '127.0.0.1', 1463) logger.debug("Hello World") log4r-1.1.10/lib/log4r/rdoc/patternformatter0000644000004100000410000001232311702744173020730 0ustar www-datawww-data= PatternFormatter PatternFormatter offers complete control over the appearance of Log4r log events without having to write custom Formatter classes. In order to take advantage of PatternFormatter, some familarity with Kernel#sprintf or the C printf function is recommended. For time formatting, please look at Time.strftime. PatternFormatter accepts three hash arguments: pattern:: Log event format string. date_pattern:: Date format string. date_method:: Time method to call (instead of using date_pattern). The pattern format string is something like "%l [%d] %80M", which resembles a pattern one would normally pass to Kernel#sprintf. However, the directives are specific to Log4r. Before we go on, let's cover some terminology. == Terminology [%] The directive identifier. Everything after this up to and including one of the directive letters defines a directive. [directive letter] Letters in the set [cCdtmMl%]. These identify what kind of data we're interested in. They are detailed below. [format directive] The numbers and assorted symbols that appears between % and a directive letter is a format directive. It is comprised of an integer specifying the field width followed optionally by a period and an integer specifying the precision. The field width is the minimum number of characters to copy from the data string while the precision is the maximum number to copy. If the field width is preceded by a - sign, the data will be left-justified. Otherwise, it is right-justified. [directive] A statement that says, "I want this data to appear with this (optional) particular format." A directive starts with a % and is followed by a format directive and terminates in a directive letter. == What the Directive Letters mean [c] Produces a logger's name. Fast. [C] Produces a logger's full name. Fast. [d] Produces the time in a format specified by date_pattern or by date_method. If neither is specified, the default will be used (ISO8601). Slow. [t] Produces the file and line number of the log event. The appearance varies by Ruby version, but it is the same output returned by Kernel#caller[0]. Slow. [m] The non-inspected log message. That is, to_s called on the object passed into a log method. Fast. [M] The message formatted by the format_object method in BasicFormatter. It will pretty-print Exceptions, print Strings and inspect everything else. Slow. [l] The name of the level. That's l as in Lambda. Fast. [%] %% just prints a %. Any formatting is probably ignored. Fast. == Examples of directives: [%d] Prints out the date according to our date_pattern or date_method. By default, it looks like this: 2001-01-12 13:15:50 [%.120m] Prints out at most 120 characters of the log message. [%15t] Prints the execution trace and pads it on the left with enough whitespace to make the whole thing 15 chars. == Pattern String A pattern string is simply a bunch of directives combined with the desired format. For instance, to show the level in brackets followed by the date and then the log message trimmed to 15 characters, we use the following pattern: "[%l] %d :: %.15m" #=> [DEBUG] 2001-01-12 13:15:50 :: This is a messa To create a PatternFormatter with this format: p = PatternFormatter.new(:pattern => "[%l] %d :: %.15m") == Formatting time To format time, do one of the following: * Specify a date_pattern * Specify what class method of Ruby's Time class to call. * Use the default format If neither date_pattern nor date_method is specified, the default date format will be used. Currently, that would be ISO8601, The date_pattern is exactly what one would pass to Time.strftime. To specify a date_pattern, pass :date_pattern=>"pattern" to PatternFormat.new. Alternatively, date_method can be specified to produce the output of a specific Time method, such as usec or to_s or any other zero argument Time method that produces a time. More precisely, the method to call will be invoked on Time.now. To specify a date_method, pass :date_method=>'methodname' (or a Symbol equivalent) to PatternFormatter.new. = XML Configuration As explained in log4r/configurator.rb, the hash arguments to PatternFormatter are XML parameters. Here's an example: usec = Performace considerations The performance impact of using a particular directive letter is noted in the What the Directives Letters mean section. The performance impact of time formatting merits special attention. If you aren't aware yet, the Time class is kind of a kludge. Time.now.usec happens to be faster than Time.now. If you're concerned about performance, please profile the various time methods and patterns. log4r-1.1.10/lib/log4r/rdoc/configurator0000644000004100000410000001623711702744173020041 0ustar www-datawww-data= Configuring Log4r with Log4r::Configurator The Configurator class allows one to set up Log4r via XML. Additionally, Configurator contains methods to configure any Log4r defaults. In particular, Configurator provides a method to customize the logging levels. Log4r is also configurable using YAML. For that, there is a class similar to Configurator called Log4r::YamlConfigurator. Please see log4r/yamlconfigurator.rb for details. REXML is required for XML configuration. Get REXML at http://www.ruby-lang.org/en/raa-list.rhtml?name=REXML To use the Configurator class, require 'log4r/configurator' == Custom Levels Suppose you want the following levels and ranks: Foo < Bar < Baz This is easily accomplished: Configurator.custom_levels('Foo', 'Bar', :Baz) The method accepts strings or symbols. However, custom levels must have names that are valid for Ruby constants. Also, custom levels should be set before anything else is done with Log4r, otherwise the default levels will be loaded. You can set custom levels in XML. That's covered in the following section. == XML Configuration If you have REXML, you can configure Log4r with XML. To do this, first write an XML configuration (which you can learn by studying this document and the examples provided in the distribution) and then load up the XML from within your program as follows: Configurator.load_xml_file('/path/to/file.xml') The Log4r XML configuration system is very flexible and powerful. In fact, it is somewhat preferable to configuring Log4r in Ruby. In order to take full advantage of this feature, there are several concepts one must know. They are covered in the following three sections. === Concept: XML Directives The expressive power of Ruby has enabled a feature I call XML directives. An XML directive is a name-value pair belonging to some element. It may be represented as an attribute (name="value") of the element, or as a child (value) of the element. Therefore, you are free to specify information about an object as either an attribute or an element. An example should clarify: Is equivalent to: value You can assume this behavior except where noted elsewhere in the API. === Concept: XML Parameters A scheme which I call XML parameters enables one to utilize the XML configuratin system for custom Outputters and Formatters. This requires no extra work on your part, so long as your objects are set up using hash arguments and can decode string values. That is, once you've written a custom Outputter, it is automatically configurable in XML without having to write any extra code. An XML parameter is analogous to a hash argument to some object's new method. Consider these hash arguments to FileOutputter: :filename => '/path/to/logs/my.log' :trunc => 'true' We can specify them in XML like this: /path/to/logs/my.log ... The name of the element/attribute is just the name of the parameter. Note that the input will be a string, thus it's wise to convert the data in from strings in any custom classes (to_i for integers, etc). Now let's suppose you have defined a custom Outputter named MyOutputter with the following additional hash args: :myarg1 => 'foo' :myarg2 => 123 Automagically, you can configure your Outputter like so: foo ... Isn't that nice? :-) === Concept: Variable Substitution To kill the need for preprocessors, Configurator provides a means of variable substitution for XML parameters at runtime. If you specify #{foo} in an XML parameter value, Configurator will replace it with the value of 'foo' in its parameter hashtable. The primary idea is that you can figure stuff out in your program, say the log path, and relay that information to the XML while it's being loaded. Secondarily, it is a way to have aliases within an XML document. There are two ways to tell Configurator about these variables. The first method we'll cover is done within a Ruby program with Configurator[]. Configurator['logpath'] = '/path/to/logs' Thereafter, any occurence of #{logpath} in each and every XML parameter will be substituted with '/path/to/logs'. For example: #{logpath}/mylog.log Becomes, /path/to/logs/mylog.log Aside from Configurator[], another way to define XML parameter variables is to define parameters under the element of an XML configuration: === Pre_config: Global Level or DEBUG Here, level is an XML directive of global. === Pre_config: Parameters Parameters are variables that will be substituted later on. Please see the Concept: Variable Substitution section above. Parameters are XML Directives, which means they can be expressed using elements or attributes. Here is an example: ... value3 value3 ... === Pre_config: Complete Example Foo,Bar, Baz /var/log/foo %l [%d] %m == Configuring Log4r Objects The XML configuration grammar for Loggers, Outputters and the like are covered in the usage guidelines for those classes. == Order Doesn't Matter You can (it is hoped) define any of the XML objects in any order desired. log4r-1.1.10/lib/log4r/rdoc/logserver0000644000004100000410000000511311702744173017336 0ustar www-datawww-data= Remote Logging Want to use Log4r over a network? No problem! A Log4r::RemoteOutputter will send its LogEvents to a Log4r::LogServer. These two classes are as easy to set up and use as the rest of Log4r. == Use ROMP There is one catch though: ROMP is required to use this service. It is a DRb-like system with superb performance and better features. Get ROMP at http://rubystuff.org/romp/ == LogServer LogServer is simply a kind of Logger which embeds a ROMP::Server. Like a normal Logger, you can give it Outputters, set its level and so on. Its logging methods are accessible over a network and are called by a RemoteOutputter on another host. === LogServer Setup Setup is easy. First, require 'log4r/logserver' The following sets up a LogServer named 'central' on localhost port 9999: LogServer.new('central', 'tcpromp://localhost:9999') We manipulate it and give it outputters as normal: serv = Logger['central'] # grab our new LogServer serv.add 'stdout' # make it log to $stdout == RemoteOutputter RemoteOutputter is simply a kind of Outputter that embeds a ROMP::Client. When RemoteOutputter gets a LogEvent, it will forward it to whatever LogServer it's connected to. In essence, RemoteOutputter behaves like a Logger that is forwarding a LogEvent to another Logger (as is done in hierarchical logging). === RemoteOutputter Setup First, require 'log4r/outputter/remoteoutputter' Unlike typical outputters, RemoteOutputter doesn't do any formatting. That's up to the LogServer's outputters. Otherwise, RemoteOutputter can be set up as usual. The ROMP uri of the LogServer must be specified. RemoteOutputter.new 'client', :uri=>'tcpromp://localhost:9999' === Using RemoteOutputter Give our new RemoteOutputter to a logger: mylog = Logger['mylog'] mylog.add 'client' Now, whenever mylog generates a LogEvent, LogServer should get a copy. Doing the following: mylog.info "This is a message from 'mylog'" Produces this output on LogServer's console: INFO mylog: This is a message from 'mylog' == XML Configuration RemoteOutputter is set up like normal Outputters. LogServer is set up like a normal Logger, but with an element name of logserver instead of logger: ... == Debugging It is recommended to set up a logger named 'log4r' on both the server and client to see what LogServer and RemoteOutputter are up to. Both of the classes use Log4r's internal logging to report any problems. See the section What's Going on Inside? in log4r.rb for more info. log4r-1.1.10/lib/log4r/rdoc/yamlconfigurator0000644000004100000410000000122111702744173020707 0ustar www-datawww-data= Configuring Log4r with Log4r::YamlConfigurator The YamlConfigurator class allows one to set up Log4r via YAML. It is used almost exactly as Log4r::Configurator and has the same features, ycfg = YamlConfigurator # handy shorthand ycfg['foo'] = bar # replaces instances of #{foo} in the YAML with bar ycfg.load_yaml_file('foo.yaml') Ruby 1.7 and 1.8 comes with a YAML parser. Hence, YAML can be used to configure Log4r out of the box. A comprehensive example of a Log4r YAML configuration is provided in the examples directory. To use this class: require 'log4r/yamlconfigurator' Thanks to Andreas Hund for making this possible. log4r-1.1.10/lib/log4r/formatter/0000755000004100000410000000000011702744173016457 5ustar www-datawww-datalog4r-1.1.10/lib/log4r/formatter/patternformatter.rb0000644000004100000410000001211311702744173022403 0ustar www-datawww-data# :include: ../rdoc/patternformatter # # == Other Info # # Version:: $Id$ require "log4r/formatter/formatter" require "log4r/GDC" require "log4r/MDC" require "log4r/NDC" module Log4r # See log4r/formatter/patternformatter.rb class PatternFormatter < BasicFormatter # Arguments to sprintf keyed to directive letters
# %c - event short name
# %C - event fullname
# %d - date
# %g - Global Diagnostic Context (GDC)
# %t - trace
# %m - message
# %h - thread name
# %p - process ID aka PID
# %M - formatted message
# %l - Level in string form
# %x - Nested Diagnostic Context (NDC)
# %X - Mapped Diagnostic Context (MDC), syntax is "%X{key}"
# %% - Insert a %
DirectiveTable = { "c" => 'event.name', "C" => 'event.fullname', "d" => 'format_date', "g" => 'Log4r::GDC.get()', "t" => '(event.tracer.nil? ? "no trace" : event.tracer[0])', "T" => '(event.tracer.nil? ? "no trace" : event.tracer[0].split(File::SEPARATOR)[-1])', "m" => 'event.data', "h" => '(Thread.current[:name] or Thread.current.to_s)', "p" => 'Process.pid.to_s', "M" => 'format_object(event.data)', "l" => 'LNAMES[event.level]', "x" => 'Log4r::NDC.get()', "X" => 'Log4r::MDC.get("DTR_REPLACE")', "%" => '"%"' } # Matches the first directive encountered and the stuff around it. # # * $1 is the stuff before directive or "" if not applicable # * $2 is the directive group or nil if there's none # * $3 is the %#.# match within directive group # * $4 is the .# match which we don't use (it's there to match properly) # * $5 is the directive letter # * $6 is the stuff after the directive or "" if not applicable # * $7 is the remainder DirectiveRegexp = /([^%]*)((%-?\d*(\.\d+)?)([cCdgtTmhpMlxX%]))?(\{.+?\})?(.*)/ # default date format ISO8601 = "%Y-%m-%d %H:%M:%S" attr_reader :pattern, :date_pattern, :date_method # Accepts the following hash arguments (either a string or a symbol): # # [pattern] A pattern format string. # [date_pattern] A Time#strftime format string. See the # Ruby Time class for details. # [+date_method+] # As an option to date_pattern, specify which # Time.now method to call. For # example, +usec+ or +to_s+. # Specify it as a String or Symbol. # # The default date format is ISO8601, which looks like this: # # yyyy-mm-dd hh:mm:ss => 2001-01-12 13:15:50 def initialize(hash={}) super(hash) @pattern = (hash['pattern'] or hash[:pattern] or nil) @date_pattern = (hash['date_pattern'] or hash[:date_pattern] or nil) @date_method = (hash['date_method'] or hash[:date_method] or nil) @date_pattern = ISO8601 if @date_pattern.nil? and @date_method.nil? PatternFormatter.create_format_methods(self) end # PatternFormatter works by dynamically defining a format method # based on the supplied pattern format. This method contains a call to # Kernel#sptrintf with arguments containing the data requested in # the pattern format. # # How is this magic accomplished? First, we visit each directive # and change the %#.# component to %#.#s. The directive letter is then # used to cull an appropriate entry from the DirectiveTable for the # sprintf argument list. After assembling the method definition, we # run module_eval on it, and voila. def PatternFormatter.create_format_methods(pf) #:nodoc: # first, define the format_date method if pf.date_method module_eval "def pf.format_date; Time.now.#{pf.date_method}; end" else module_eval <<-EOS def pf.format_date Time.now.strftime "#{pf.date_pattern}" end EOS end # and now the main format method ebuff = "def pf.format(event)\n sprintf(\"" _pattern = pf.pattern.dup args = [] # the args to sprintf which we'll append to ebuff lastly while true # work on each match in turn match = DirectiveRegexp.match _pattern ebuff << match[1] unless match[1].empty? break if match[2].nil? # deal with the directive by inserting a %#.#s where %#.# is copied # directy from the match ebuff << match[3] + "s" if ( match[5] == 'X' && match[6] != nil ) then # MDC matches, need to be able to handle String, Symbol or Number match6sub = /[\{\}\"]/ mdcmatches = match[6].match /\{(:?)(\d*)(.*)\}/ if ( mdcmatches[1] == "" && mdcmatches[2] == "" ) match6sub = /[\{\}]/ # don't remove surrounding "'s if String end args << DirectiveTable[match[5]].gsub("DTR_REPLACE", match[6]).gsub(match6sub,'') else args << DirectiveTable[match[5]] # cull the data for our argument list end break if match[7].empty? _pattern = match[7] end ebuff << '\n", ' + args.join(', ') + ")\n" ebuff << "end\n" module_eval ebuff end end end log4r-1.1.10/lib/log4r/formatter/log4jxmlformatter.rb0000644000004100000410000000342411702744173022473 0ustar www-datawww-data# :include: ../rdoc/log4jxmlformatter # # == Other Info # # Version:: $Id$ require "log4r/formatter/formatter" require "rubygems" begin require "builder" rescue LoadError puts "builder gem is required to use log4jxmlformatter, i.e. gem install builder" end module Log4r class Log4jXmlFormatter < BasicFormatter def format(logevent) logger = logevent.fullname.gsub('::', '.') timestamp = (Time.now.to_f * 1000).to_i level = LNAMES[logevent.level] message = format_object(logevent.data) exception = message if logevent.data.kind_of? Exception file, line, method = parse_caller(logevent.tracer[0]) if logevent.tracer builder = Builder::XmlMarkup.new xml = builder.log4j :event, :logger => logger, :timestamp => timestamp, :level => level, :thread => '' do |e| e.log4j :NDC, NDC.get e.log4j :message, message e.log4j :throwable, exception if exception e.log4j :locationInfo, :class => '', :method => method, :file => file, :line => line e.log4j :properties do |p| MDC.get_context.each do |key, value| p.log4j :data, :name => key, :value => value end end end xml end ####### private ####### def parse_caller(line) if /^(.+?):(\d+)(?::in `(.*)')?/ =~ line file = Regexp.last_match[1] line = Regexp.last_match[2].to_i method = Regexp.last_match[3] [file, line, method] else [] end end end end log4r-1.1.10/lib/log4r/formatter/formatter.rb0000644000004100000410000000530411702744173021011 0ustar www-datawww-data# :include: ../rdoc/formatter # # Version:: $Id$ require "singleton" require "log4r/base" module Log4r # Formatter is an abstract class and a null object class Formatter def initialize(hash={}) end # Define this method in a subclass to format data. def format(logevent) end end # SimpleFormatter produces output like this: # # WARN loggername> Danger, Will Robinson, danger! # # Does not write traces and does not inspect objects. class SimpleFormatter < Formatter def format(event) sprintf("%*s %s> %s\n", MaxLevelLength, LNAMES[event.level], event.name, event.data) end end # BasicFormatter produces output like this: # # WARN loggername: I dropped my Wookie! # # Or like this if trace is on: # # WARN loggername(file.rb at 12): Hot potato! # # Also, it will pretty-print any Exception it gets and # +inspect+ everything else. # # Hash arguments include: # # +depth+:: How many lines of the stacktrace to display. class BasicFormatter < SimpleFormatter @@basicformat = "%*s %s" def initialize(hash={}) @depth = (hash[:depth] or hash['depth'] or 7).to_i end def format(event) buff = sprintf(@@basicformat, MaxLevelLength, LNAMES[event.level], event.name) buff << (event.tracer.nil? ? "" : "(#{event.tracer[0]})") + ": " buff << format_object(event.data) + "\n" buff end # Formats data according to its class: # # String:: Prints it out as normal. # Exception:: Produces output similar to command-line exceptions. # Object:: Prints the type of object, then the output of # +inspect+. An example -- Array: [1, 2, 3] def format_object(obj) if obj.kind_of? Exception return "Caught #{obj.class}: #{obj.message}\n\t" +\ (obj.backtrace.nil? ? [] : obj.backtrace[0...@depth]).join("\n\t") elsif obj.kind_of? String return obj else # inspect the object return "#{obj.class}: #{obj.inspect}" end end end # Formats objects the same way irb does: # # loggername:foo.rb in 12> # [1, 3, 4] # loggername:foo.rb in 13> # {1=>"1"} # # Strings don't get inspected. just printed. The trace is optional. class ObjectFormatter < Formatter def format(event) buff = event.logger.name buff << (event.tracer.nil? ? "" : ":#{event.tracer[0]}") + ">\n" buff << (event.data.kind_of?(String) ? event.data : event.data.inspect) buff << "\n" end end # Outputters that don't define a Formatter will get this, which # is currently BasicFormatter class DefaultFormatter < BasicFormatter end end log4r-1.1.10/lib/log4r/GDC.rb0000644000004100000410000000142211702744173015375 0ustar www-datawww-data# :include: rdoc/GDC # # == Other Info # # Version:: $Id$ # Author:: Colby Gutierrez-Kraybill require 'monitor' module Log4r GDCNAME = "log4rGDC" $globalGDCLock = Monitor.new # See log4r/GDC.rb class GDC < Monitor private_class_method :new def self.clear() Thread.main[GDCNAME] = "" end def self.get() $globalGDCLock.synchronize do if ( Thread.main[GDCNAME] == nil ) then Thread.main[GDCNAME] = $0 end end return Thread.main[GDCNAME] end def self.set( a_name ) if ( Thread.current != Thread.main ) then raise "Can only initialize Global Diagnostic Context from Thread.main" end $globalGDCLock.synchronize do Thread.main[GDCNAME] = a_name end end end end log4r-1.1.10/lib/log4r/logger.rb0000644000004100000410000001356211702744173016267 0ustar www-datawww-data# :include: rdoc/logger # # == Other Info # # Version:: $Id$ # Author:: Leon Torres require "log4r/outputter/outputter" require "log4r/repository" require "log4r/loggerfactory" require "log4r/staticlogger" module Log4r # See log4r/logger.rb class Logger attr_reader :name, :fullname, :path, :level, :parent attr_reader :additive, :trace, :outputters # Logger requires a name. The last 3 parameters are: # # level:: Do I have a level? (Otherwise, I'll inherit my parent's) # additive:: Am I additive? # trace:: Do I record the execution trace? (slows things a wee bit) def initialize(_fullname, _level=nil, _additive=true, _trace=false) # validation raise ArgumentError, "Logger must have a name", caller if _fullname.nil? Log4rTools.validate_level(_level) unless _level.nil? validate_name(_fullname) # create the logger @fullname = _fullname @outputters = [] @additive = _additive deal_with_inheritance(_level) LoggerFactory.define_methods(self) self.trace = _trace Repository[@fullname] = self end def validate_name(_fullname) parts = _fullname.split Log4rConfig::LoggerPathDelimiter for part in parts raise ArgumentError, "Malformed path", caller[1..-1] if part.empty? end end private :validate_name # Parses name for location in heiarchy, sets the parent, and # deals with level inheritance def deal_with_inheritance(_level) mypath = @fullname.split Log4rConfig::LoggerPathDelimiter @name = mypath.pop if mypath.empty? # then root is my daddy @path = "" # This is one of the guarantees that RootLogger gets created @parent = Logger.root else @path = mypath.join(Log4rConfig::LoggerPathDelimiter) @parent = Repository.find_ancestor(@path) @parent = Logger.root if @parent.nil? end # inherit the level if no level defined if _level.nil? then @level = @parent.level else @level = _level end Repository.reassign_any_children(self) end private :deal_with_inheritance # Set the logger level dynamically. Does not affect children. def level=(_level) Log4rTools.validate_level(_level) @level = _level LoggerFactory.define_methods(self) Logger.log_internal {"Logger '#{@fullname}' set to #{LNAMES[@level]}"} @level end # Return array of defined levels. def levels LNAMES end # Set the additivity of the logger dynamically. True or false. def additive=(_additive) @additive = _additive LoggerFactory.define_methods(self) Logger.log_internal {"Logger '#{@fullname}' is additive"} @additive end # Set whether the logger traces. Can be set dynamically. Defaults # to false and understands the strings 'true' and 'false'. def trace=(_trace) @trace = case _trace when "true", true then true else false end LoggerFactory.define_methods(self) Logger.log_internal {"Logger '#{@fullname}' is tracing"} if @trace @trace end # Please don't reset the parent def parent=(parent) @parent = parent end # Set the Outputters dynamically by name or reference. Can be done any # time. def outputters=(_outputters) @outputters.clear add(*_outputters) end # Add outputters by name or by reference. Can be done any time. def add(*_outputters) for thing in _outputters o = (thing.kind_of?(Outputter) ? thing : Outputter[thing]) # some basic validation if not o.kind_of?(Outputter) raise TypeError, "Expected kind of Outputter, got #{o.class}", caller elsif o.nil? raise TypeError, "Couldn't find Outputter '#{thing}'", caller end @outputters.push o Logger.log_internal {"Added outputter '#{o.name}' to '#{@fullname}'"} end @outputters end # Remove outputters from this logger by name only. Can be done any time. def remove(*_outputters) for name in _outputters o = Outputter[name] @outputters.delete o Logger.log_internal {"Removed outputter '#{o.name}' from '#{@fullname}'"} end end def is_root?; false end def ==(other) return true if self.object_id == other.object_id end end # RootLogger should be retrieved with Logger.root or Logger.global. # It's supposed to be transparent. #-- # We must guarantee the creation of RootLogger before any other Logger # or Outputter gets their logging methods defined. There are two # guarantees in the code: # # * Logger#deal_with_inheritance - calls RootLogger.instance when # a new Logger is created without a parent. Parents must exist, therefore # RootLogger is forced to be created. # # * OutputterFactory.create_methods - Calls Logger.root first. So if # an Outputter is created, RootLogger is also created. # # When RootLogger is created, it calls # Log4r.define_levels(*Log4rConfig::LogLevels). This ensures that the # default levels are loaded if no custom ones are. class RootLogger < Logger include Singleton def initialize Log4r.define_levels(*Log4rConfig::LogLevels) # ensure levels are loaded @level = ALL @outputters = [] Repository['root'] = self Repository['global'] = self LoggerFactory.undefine_methods(self) end def is_root?; true end # Set the global level. Any loggers defined thereafter will # not log below the global level regardless of their levels. def level=(alevel); @level = alevel end # Does nothing def outputters=(foo); end # Does nothing def trace=(foo); end # Does nothing def additive=(foo); end # Does nothing def add(*foo); end # Does nothing def remove(*foo); end end end log4r-1.1.10/lib/log4r/config.rb0000644000004100000410000000026011702744173016244 0ustar www-datawww-data# :nodoc: # Version:: $Id$ module Log4r module Log4rConfig #:nodoc: LogLevels = ['DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL'] LoggerPathDelimiter = '::' end end log4r-1.1.10/lib/log4r/NDC.rb0000644000004100000410000000364111702744173015411 0ustar www-datawww-data# :include: rdoc/NDC # # == Other Info # # Version:: $Id$ # Author:: Colby Gutierrez-Kraybill module Log4r NDCNAME = "log4rNDC" NDCNAMEMAXDEPTH = "log4rNDCMAXDEPTH" NDCDEFAULTMAXDEPTH = 256 # See log4r/NDC.rb class NDC private_class_method :new def self.check_thread_instance() if ( Thread.current[NDCNAME] == nil ) then Thread.current[NDCNAME] = Array.new Thread.current[NDCNAMEMAXDEPTH] = NDCDEFAULTMAXDEPTH end end def self.clear() self.check_thread_instance() Thread.current[NDCNAME].clear end def self.clone_stack() self.check_thread_instance() return Thread.current[NDCNAME].clone end def self.get_depth() self.check_thread_instance() return Thread.current[NDCNAME].length end def self.inherit( a_stack ) if ( a_stack.class == Array ) then if ( Thread.current[NDCNAME] != nil ) then Thread.current[NDCNAME].clear Thread.current[NDCNAME] = nil end Thread.current[NDCNAME] = a_stack else raise "Expecting Array in NDC.inherit" end end def self.get() self.check_thread_instance return Thread.current[NDCNAME] * " " end def self.peek() self.check_thread_instance() return Thread.current[NDCNAME].last end def self.pop() self.check_thread_instance() return Thread.current[NDCNAME].pop end def self.push( value ) self.check_thread_instance() if ( Thread.current[NDCNAME].length < Thread.current[NDCNAMEMAXDEPTH] ) then Thread.current[NDCNAME].push( value ) end end def self.remove() self.check_thread_instance() Thread.current[NDCNAME].clear Thread.current[NDCNAMEMAXDEPTH] = nil Thread.current[NDCNAME] = nil end def self.set_max_depth( max_depth ) self.check_thread_instance() Thread.current[NDCNAMEMAXDEPTH] = max_depth end end end log4r-1.1.10/lib/log4r/lib/0000755000004100000410000000000011702744173015222 5ustar www-datawww-datalog4r-1.1.10/lib/log4r/lib/drbloader.rb0000644000004100000410000000232311702744173017505 0ustar www-datawww-data#:nodoc: module Log4r begin require 'romp' HAVE_ROMP = true rescue LoadError HAVE_ROMP = false end if HAVE_ROMP module ROMPServer #:nodoc: private def start_server(_uri, accept) @server = ROMP::Server.new(_uri, accept) # what if accept is nil? @server.bind(self, "Log4r::LogServer") end end module ROMPClient #:nodoc: private def connect begin @client = ROMP::Client.new(@uri, false) @remote_logger = @client.resolve("Log4r::LogServer") rescue Exception => e Logger.log_internal(-2) { "RemoteOutputter '#{@name}' failed to connect to #{@uri}!" } Logger.log_internal {e} self.level = OFF end end # we use propagated = true def send_buffer begin @buff.each {|levent| lname = LNAMES[levent.level].downcase @remote_logger.oneway(lname, levent, true) } rescue Exception => e Logger.log_internal(-2) {"RemoteOutputter '#{@name}' can't log!"} Logger.log_internal {e} self.level = OFF ensure @buff.clear end end end end end log4r-1.1.10/lib/log4r/lib/xmlloader.rb0000644000004100000410000000062111702744173017535 0ustar www-datawww-data#:nodoc: module Log4r begin require 'rexml/document' HAVE_REXML = true rescue LoadError HAVE_REXML = false end end if Log4r::HAVE_REXML module REXML #:nodoc: all class Element def value_of(elmt) val = attributes[elmt] if val.nil? sub = elements[elmt] val = sub.text unless sub.nil? end val end end end end log4r-1.1.10/lib/log4r/logevent.rb0000644000004100000410000000201111702744173016616 0ustar www-datawww-data# :nodoc: module Log4r ## # LogEvent wraps up all the miscellaneous data associated with a logging # statement. It gets passed around to the varied components of Log4r and # should be of interest to those creating extensions. # # Data contained: # # [level] The integer level of the log event. Use LNAMES[level] # to get the actual level name. # [tracer] The execution stack returned by caller at the # log event. It is nil if the invoked Logger's trace is false. # [data] The object that was passed into the logging method. # [name] The name of the logger that was invoked. # [fullname] The fully qualified name of the logger that was invoked. # # Note that creating timestamps is a task left to formatters. class LogEvent attr_reader :level, :tracer, :data, :name, :fullname def initialize(level, logger, tracer, data) @level, @tracer, @data = level, tracer, data @name, @fullname = logger.name, logger.fullname end end end log4r-1.1.10/lib/log4r.rb0000644000004100000410000000065511702744173015007 0ustar www-datawww-data# :include: log4r/rdoc/log4r # # == Other Info # # Author:: Leon Torres # Version:: $Id$ require 'log4r/version' require "log4r/outputter/fileoutputter" require "log4r/outputter/consoleoutputters" require "log4r/outputter/staticoutputter" require "log4r/outputter/rollingfileoutputter" require "log4r/formatter/patternformatter" require "log4r/loggerfactory" require "log4r/GDC" require "log4r/NDC" require "log4r/MDC"