<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[
<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[
This proposal covers a complete rewrite of Zend_Log. It addresses concernsZend Framework: Zend_Log Component Proposal
Proposed Component Name
Zend_Log
Developer Notes
http://framework.zend.com/wiki/display/ZFDEV/Zend_Log
Proposers
Mike Naberezny, with direction from Bill Karwin and Andi Gutmans
Revision
1.1 - 17 Jan 2007: Use "writer" instead of "handler" (Christopher Thompson) (wiki revision: 24)
Table of Contents
1. Overview
raised in another proposal, "Zend_Log Dynamic", and also proposes new
features requested both by the Zend team and community members.2. References
3. Component Requirements, Constraints, and Acceptance Criteria
While the log4x loggers are a popular and powerful standard, Zend has
decided to use their influence but not make a logger that is based on
them. Instead, the logger will be closer in usage to PEAR's Log package.
It must be easy to store logger instances for use with other components.
should include additional ones from the community to be included with the
package and also any specialized writers that end users might need to
write for their own needs.
(writers), and filtering log messages (filters) should be cleanly
separated into different objects. It should be simple for users to register
their own objects to perform these functions. However, the logger should
have a simple default configuration and users should not need to be aware
of these features until they are needed.
4. Dependencies on Other Framework Components
The dependencies will be determined primarily by which log writers are
developed. Possibly these will include:
- Zend_Db
- Zend_Cache
- Zend_Mail
- Zend_Http
- Zend_Exception
5. Theory of Operation
Logger
The base logging class where writers and filters can be registered.
Users will able to add new levels with a method such as
$log->addLevel($name, $level) provided the name or level does not conflict
with an existing one. The default levels will always be present and can
never be overridden (without subclassing Zend_Log).
Message can be logged with a method such as $log->log($message, $level).
It will also provide convenience methods for each level, such as
$log->warn('message');
Log Levels
Each log level will have a name and a value. The default log levels
will mimic those from syslog:
0 Emergency: system is unusable
1 Alert: action must be taken immediately
2 Critical: critical conditions
3 Error: error conditions
4 Warning: warning conditions
5 Notice: normal but significant condition
6 Informational: informational messages
7 Debug: debug-level messages
User error levels may be any number above DEBUG (7).
Filter
Loggers will have the ability to filter by level. For more sophisticated
filtering, filter objects built by users can be registered and chained.
Writer
Initially, the following log writers will be developed:
- Stream Writer (STDOUT/STDERR)
- RDBMS Writer (Zend_Db)
- File Writer
- XML File Writer
- Test Writer (mock for testing)
In the future, additional writers could be developed by the
community. Suggestions for these are:
- Rotating File Writer (Rotate Logs)
- Socket Writer (Log to TCP/IP)
- Syslog Writer (UNIX/Linux Syslog)
- NT Event Writer (Windows NT-based systems)
- Email Writer (Zend_Mail)
- HTTP Writer (Zend_Http_Client)
6. Milestones / Tasks
- Iteration 1 - Base Logger implementation
- Iteration 2 - Writer and Filter implementation
- Iteration 3 - Log writer implementation (Test, Stream, File)
- Iteration 4 - Additional writers (RDBMS, XML)
- Iteration 5 - Documentation (DocBook)
Unit tests will be written as an integral and ongoing part of the
development process so no separate iteration is needed for them.
7. Class Index
- Logger (Zend_Log)
- Writer (Zend_Log_Writer_*)
- Filter (Zend_Log_Filter_*)
- Error (Zend_Log_*Exception)
8. Use Cases
| UC-01 | Simple Usage |
|---|
| UC-02 | Using Multiple Log Writers |
|---|
| UC-03 | Custom Log Levels |
|---|
| UC-04 | Filtering for All Writers |
|---|
A filter can be added to either Zend_Log, where it will be applied
to all writers. Either a simple level or a filter object may be passed.
| UC-05 | Filtering for a Specific Writer |
|---|
| UC-06 | Use with the Registry |
|---|
The current Zend_Log implementation uses all static functions. This new
implementation has no static functions. However, for users that prefer the
old usage, similar usage can be achieved by storing a logger object in the
registry.
9. Class Skeletons
Class skeletons will not be proposed at this stage. When development begins,
behavioral requirements of the objects will be expressed as tests and the
classes will then be developed based on these requirements using TDD.
9 Comments
comments.show.hideJan 22, 2007
Darby Felton
<p>I noticed from the use cases that the names of convenience methods appear to be indeterministic. For example, a log message of <code>Zend_Log::CRITICAL</code> would correspond to an invocation of <code>Zend_Log::crit()</code>. Does this matter? User-defined log levels, however, appear to result in method names matching the level name (e.g., "foo").</p>
<p>I'm not sure I fully understand the first sentence of UC-04; perhaps a slight rephrasing would help?</p>
<p>How would I create a logger that writes messages only of a user-defined log level? For instance, let's assume that I want to write only "specialError" level messages both to a log file and to an e-mail address. Would this use case be considered in the scope of the proposal?</p>
<p>It might be reasonable to use Zend_Log for application security auditing. For example, it is often valuable to collect information about certain security violations, such as logging when users attempt to perform unauthorized operations. I could imagine providing via the Zend_Auth and Zend_Acl APIs methods to plug in Zend_Log objects for providing for an audit trail.</p>
<p>The proposal is shaping up nicely, and the approach of using use cases and test-driven development seems very appropriate to me.</p>
Jan 24, 2007
Matthew Ratzloff
<blockquote><p>How would I create a logger that writes messages only of a user-defined log level?</p></blockquote>
<p>I believe this was it:</p>
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
// add a new level
$log->addLevel('foo', 8);
// log
$log->foo('foo level message');
]]></ac:plain-text-body></ac:macro>
<p>I would caution against using arbitrarily-abbreviated log level method names like "crit()".</p>
Jan 24, 2007
Matthew Weier O'Phinney
<p>I'd like to see two additional things: (1) The constructor should take a single argument, a log adapter; this would be more convenient, and ensure no logging happens prior to logging a message. (2) I like the logLevel(), but want to make sure that the convenience methods would not change the global log level (I assume they wouldn't, but feel this should be explicit criteria).</p>
Jan 24, 2007
Bill Karwin
<ac:macro ac:name="note"><ac:parameter ac:name="title">Official Zend comment</ac:parameter><ac:rich-text-body>
<p>We have reviewed this proposal and we approve it for inclusion in the Zend Framework.</p>
<p>This represents a redesign of the existing Zend_Log class, and it is the intention to remove the old implementation in favor of this new design.</p>
<p>We have a few specific comments that we would like to see addressed in the design:</p>
<ul>
<li>We anticipate that in most cases, only one log writer would be needed. Can a single writer object be specified in the Zend_Log() constructor? This would be equivalent to adding the first writer after instantiating the Zend_Log object, but it would just make the code one line shorter.</li>
<li>It seems to make sense that there should be at least one writer, or else any messages written will go nowhere. With the current design it is possible to send messages to a Zend_Log object before adding any writers to it. What happens in this case? Is it reasonable to require at least one writer be registered, and if none are registered, the logging methods throw an exception? Or is there a legitimate use case for writing a message while having no writers registered?</li>
<li>There should be either an interface or an abstract class defined for filters, so that users know how to write their own. Also, we had wished we could see what a custom filter implementation would look like, but we understand why the class skeletons are omitted from this proposal.</li>
<li>We understand that it's traditional log4j-like functionality for filtering to restrict output to a given log level or lower level. How would one restrict output to one specific log level (other than level 0)? Can this be done with a custom filter object?</li>
</ul>
</ac:rich-text-body></ac:macro>
Feb 03, 2007
Michal Minicki
<p>Hi. I have a feature request. I have actually stumbled upon it while replying to Gavin's comment concerning my own proposal:
<a class="external-link" href="http://framework.zend.com/wiki/display/ZFPROP/Zend_Controller_Router_RegexRoute+-+Michael+Minicki">http://framework.zend.com/wiki/display/ZFPROP/Zend_Controller_Router_RegexRoute+-+Michael+Minicki</a></p>
<p>In RewriteRouter I need to log a couple of messages or a pack of data at once:</p>
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
if ($this->_log) {
$message = 'Type: ' . get_class($route) . '; ' .
'Route: ' . $route->getMatchString() . '; ' .
'Path: ' . $path . '; ' .
'Result: ' . $result;
$this->_log->debug($message);
}
]]></ac:plain-text-body></ac:macro>
<p>It gave me an idea to pass the message as an array:</p>
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
$message = array(
'Type' => get_class($route),
'Route' => $route->getMatchString(),
'Path' => $path,
'Result' => $result
);
$this->_log->debug($message);
]]></ac:plain-text-body></ac:macro>
<p>Which can then be rendered differently by different writers. </p>
<p>For example, XML writer can render it as:</p>
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
<LogItem>
<Type>Zend_Controller_Router_Route</Type>
<Route>:action/:year</Route>
<Path>users/martel</Path>
<Result>false</result>
</LogItem>
]]></ac:plain-text-body></ac:macro>
<p>While file writer could use multiline entry:</p>
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
2006-02-03 16:54 Debug:
\t Type: Zend_Controller_Router_Route
\t Route: :action/:year
\t Path: users/martel
\t Result: false
]]></ac:plain-text-body></ac:macro>
<p>And DB of course can keep it on one line separated with semicolon.</p>
<p>Hope you will like it too <ac:emoticon ac:name="wink" /></p>
Mar 12, 2007
Superbiji
<p>How about setting log format?</p>
<p>for example:<br />
$log->setFormat("%datetime <ac:link><ri:page ri:content-title="%pid" /></ac:link> %level %message");</p>
<p>by doing:<br />
$log->warning("Live support not ready");</p>
<p>should produce:<br />
2007-03-12 14:11:38 <ac:link><ri:page ri:content-title="8439" /></ac:link> WARNING Live support not ready</p>
<p>There should be predefined keyword for formatting, <br />
the most important IMHO:</p>
<p>datetime, current locale date time<br />
date,<br />
time,<br />
pid, current process ID<br />
level, current log level<br />
message, log message</p>
<p>Thanks</p>
Aug 12, 2007
Kaleb Kajero
<p>Is there an existing proposal to contribute a rotating log file writer?</p>
<p>If yes, could someone kindly point me to it?</p>
Aug 12, 2007
Bill Karwin
<p>We have had two feature requests logged in our issue tracker regarding log rotation solutions.
<a class="external-link" href="http://framework.zend.com/issues/browse/ZF-263">http://framework.zend.com/issues/browse/ZF-263</a>
<a class="external-link" href="http://framework.zend.com/issues/browse/ZF-563">http://framework.zend.com/issues/browse/ZF-563</a></p>
<p>I continue to believe that this is not appropriate to solve in a PHP class. Linux has the 'logrotate' command for this purpose.
<a class="external-link" href="http://www.linuxcommand.org/man_pages/logrotate8.html">http://www.linuxcommand.org/man_pages/logrotate8.html</a></p>
<p>Windows does not have a standard tool to do this. It needs to be done as part of restarting the HTTP server, so it cannot be a PHP solution.</p>
Aug 13, 2007
Kaleb Kajero
<p>Thanks for the prompt response, Bill.</p>
<p>First time I heard of <em>logrotate.</em> I definitely prefer that option since I'm on Linux. I agree too that it's best not to duplicate functionality if there's already a good tool that provides it.</p>
<p>P.S. I enjoyed your recent ZF Overview webinar. Even as I'm quite familiar with the content you delivered, I was all the same enwrapped by your delivery. Nice work with ZF, all-round. </p>