<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Logger</title>
</head>
<body>
<h1>Logger</h1>
<h2>Description</h2>
<p>Dumps input data to a file on disk.</p>
<p>The file location is logically related to the class or class group (from here onward named <em>calling context</em>) that invokes the module's logging functionality.</p>
<p>Note: the module is built on top of the ParamsProxy module, and therefore inherits its security model, base functionality and limitations.</p>
<h2>Features list</h2>
<ul>
<li>
<p>built-in serialization of complex input data (objects, arrays);</p>
</li>
<li>
<p>built-in <em>split</em> functionality: there can be several volumes of a given log file, based on a file size constraint;</p>
</li>
<li>
<p>built-in <em>trim</em> functionality: or, there can be a single log file that automatically trims itself from top to bottom â as new content is logged to the file â based on a file size constraint;</p>
</li>
<li>
<p>built-in optional wrapping of logged content;</p>
</li>
<li>
<p>built-in optional stamping of entries with current date and time;*</p>
</li>
<li>
<p>configurable output using templates â for log file header and entries.</p>
</li>
</ul>
<p>* via including the appropriate placeholders in the <em>entries</em> template.</p>
<h2>How it works</h2>
<p>The module is a singleton â therefor any configuration is shared system wide. </p>
<p>The module's API provides a single public method,</p>
<pre>
/**
* Writes given data on disk.
* If data is anything but a string, it is first serialized.
*/
log ($data);</pre>
<p>one would invoke like this:</p>
<pre>Logger::getInstance()->log ("FAIL: could not send email '$emailSubject' to $recipient; server responded: $error.");</pre>
<p>Upon making this call, the module will use PHP's <em>trace debug </em>feature to figure out the name of the calling class and will try to match it against a <em>context</em> definition, as stated by the module's configuration file.</p>
<p><em>Note: more on configuration file, their use, structure and location in the ParamsProxy.html document.</em></p>
<p>If the calling class isn't part of any defined context, the default <em>Main</em> context will be assumed. The string passed as argument to log will then be written into the</p>
<pre><<strong>logs directory</strong>>/<<strong>context name</strong>>/log.txt</pre>
<p>file (the file will be created if it doesn't yet exist). See also the insides about the <em>split</em> operation mode of the module.</p>
<p>The location of the <code><<strong>logs directory</strong>></code> is the parent directory of the <code><<strong>configuration directory</strong>></code> and cannot be changed. Therefore, the above could have been written as such:</p>
<pre><<strong>configuration directory</strong>>/../<<strong>context name</strong>>/log.txt</pre>
<p><em>Note: for more on the configuration folder, please consult the ParamsProxy.html document.</em></p>
<h2>XML</h2>
<p>The module is configured via its dedicated XML configuration file. The module introduces no syntax extensions to the standard defined by the ParamsProxy module.</p>
<p><em>Note: for more on the configuration files syntax, please consult the ParamsProxy.html document..</em></p>
<p>However, some values â shown in bold in the example below â are to be parsed by the module, and therefor must be entered literally.</p>
<pre>
<config for="Logger">
<param>
<type>number</type>
<name><strong>maxFileSize</strong></name>
<value>125</value>
</param>
<param>
<type>string</type>
<name><strong>operatingMode</strong></name>
<value><strong>split</strong></value>
</param>
<param>
<type>number</type>
<name><strong>wrapLimit</strong></name>
<value>80</value>
</param>
<param>
<type>string</type>
<name><strong>bannerTemplate</strong></name>
<value>
<![CDATA[
FILE: <strong>%FILE NAME%</strong> <<strong>%FILE SIZE%</strong>>
PATH: <strong>%FILE PATH%</strong>
DESCRIPTION: Log file for the <strong>%RELATED CONTEXT NAME%</strong>
STATUS: <strong>%FILE STATUS%</strong> as of <strong>%LAST MODIFIED DATE%</strong>
----------------------------------------------------------------------
]]>
</value>
</param>
<param>
<type>string</type>
<name><strong>entryTemplate</strong></name>
<value>
<![CDATA[[
<strong>%CALLING CLASS NAME%</strong> @ <strong>%Y%</strong>/<strong>%M%</strong>/<strong>%D%</strong>-<strong>%H%</strong>:<strong>%S%</strong>
<strong>%CONTENT% </strong>
]]>
</value>
</param>
<param>
<type><strong>array</strong></type>
<!-- This is a context name! There may be countless of them,
as long as each name appears only once (or else will
cause a fatal error). -->
<name>LoginOperations</name>
<value>
<!-- This is a class name! A class that appeared in one
context cannot appear in another (or else will
cause a fatal error). -->
<item>Authenticator</item>
<item>CookieManager</item>
<item>MailHandler</item>
</value>
</param>
</config>
</pre>
<p>This example uses all parameters but not all possible values. Parameters, their usage and possible values are described in the next section.</p>
<h2>Configuration</h2>
<table width="100%" border="1" cellpadding="4" cellspacing="0">
<col width="52*" />
<col width="63*" />
<col width="141*" />
<thead>
<tr valign="top">
<td><p >PARAMETER NAME</p></td>
<th> <p>POSSIBLE VALUES</p></th>
<th> <p>COMMENTS</p></th>
</tr>
</thead>
<tbody>
<tr valign="top">
<td><p>maxFileSize</p></td>
<td><p>125 to 1250</p></td>
<td><p>Ranges from a hundred to a thousand bytes â with plenty of room for additional noise introduced by templates â for the log file <em>upper size</em> limit.</p>
<p>If the log file is about to exceed its upper size limit, <em>trimming</em> or <em>splitting</em> occurs, based on the <strong>operatingMode </strong>parameter setting.</p>
<p>If omitted, defaults to 125.</p></td>
</tr>
<tr valign="top">
<td><p>operatingMode</p></td>
<td><p>one of the "trim" or "split" words, literally </p></td>
<td><p>Sets up the action to trigger when the log file is about to grow oversize due to incoming data.</p>
<p><em>Trim</em> will keep the file size the same but will alter content, by progressively deleting oldest entries until there is room for new ones.</p>
<p><em>Split</em> will keep both the file size <em>and</em> content the same, but will archive the file and will start writing to a new file instead. </p>
<p>In this documentation, archived files are currently referred to as <em>volumes</em>. Making a log file into a volume is handled behind the scene, and simply means renaming it, i.e., from "log.txt" to "log.txt.2".</p>
<p>The "log.txt.2" above means there are at least three volumes, â count starts from 1. The last (improperly named) volume is the log file currently being written, therefore its name is not altered: "log.txt".</p>
<p>If omitted, this parameter defaults to <em>trim</em>.</p></td>
</tr>
<tr valign="top">
<td><p>wrapLimit</p></td>
<td><p>80 to 240 or -1</p></td>
<td><p>The number of chars to allow per each written line of the log file. "-1" will disable the feature.</p>
<p>Wrapping line is aggressive, i.e., "middle word" splits can occur if there's no other available split point on a line (this is especially prone to happen with url-encoded links).</p>
<p>By exception, the <em>banner</em> will never be split, rather trim horizontally to the <strong>wrapLimit</strong> number of chars (see next). Wrapping is off by default.</p></td>
</tr>
<tr valign="top">
<td><p>bannerTemplate</p></td>
<td><p>any string, optionally including one or more of the following placeholders, literally, in the form of %PLACEHOLDER%:</p>
<p>"FILE PATH"</p>
<p>"FILE SIZE"</p>
<p>"FILE STATUS"</p>
<p>"LAST MODIFIED DATE"</p>
<p>"RELATED CONTEXT NAME"</p></td>
<td><p>The <em>banner </em>of a log file represents a reserved, rectangular area found at the top of the file.</p>
<p>This <em>banner</em> will always be <strong>wrapLimit</strong> columns by <em>5</em> rows (hardcoded) wide, <em>regardless of the actual size needed by the banner template or the data that will populate the template</em>.</p>
<p>If a template taller than 5 rows has been defined, it will be populated, then trimmed to 5 lines starting at the top, then applied. An ellipsis (â¦) char will be added at the end of the last line to indicate trimming.</p>
<p> If a template shorter than 5 rows has been defined, empty lines will be added to the bottom â which implies that, if no template is defined, 5 blank lines will be at the top of every log file.</p>
<p>Template content does not wrap horizontally. If the applied, i.e., <em>populated</em>, template is greater than <strong>wrapLimit</strong> chars, each line will be trimmed at <strong>wrapLimit</strong> chars and ellipsis chars will be added to indicate trimming.</p>
<p>If wrapping is disabled, the banner will be horizontally trimmed at 240 chars (the maximum wrapping value).</p>
<p>Shorter lines in the banner will be right padded with spaces to the wrapping width (or the maximum wrapping value if disabled).</p>
<p> Placeholder names are quite self-explanatory, except: </p>
<ul>
<li>
<p>"FILE STATUS": will return one of the "full", "trimmed" or "vol. no. #",<br />
where <em>full</em>, means that no split or trim operation have occurred yet, <em>trimmed</em> means the log file has been trimmed, and <em>vol</em>... means a split has been made, and the current<br />
file is the <em>n</em>th in the collection;</p>
</li>
<li>
<p>"RELATED CONTEXT NAME": is the name of the calling context, as described by the module's configuration XML file. Taking the XML snippet in the previous section as an example, it would be "LoginOperations".</p>
</li>
</ul></td>
</tr>
<tr valign="top">
<td><p>entryTemplate</p></td>
<td><p>any string, optionally including one or more of the following placeholders, literally, in the form of %PLACEHOLDER%:<br />
"Y" (for year)</p>
<p>"M" (for month)</p>
<p>"D" (for day)</p>
<p>"H" (for hour)</p>
<p>"MIN" (for minute)</p>
<p>"S" (for seconds)</p>
<p>"CALLING CLASS NAME"</p>
<p>"CONTENT"</p></td>
<td><p>Each log file is comprised by a header and several <em>entries</em>.</p>
<p>An <em>entry</em> represents the result of <em>one</em> call to the log() method (see the API section). Although entries will frequently only span one line, entries and lines mustn't be mistaken.</p>
<p>The module internally adds a non printing <strong>start-of-heading char</strong> right before any entry; the module uses this delimiter for operations that involve entry manipulation, such as the <em>trim</em> functionality. Entries are stripped from null chars before printing, should they have any.</p>
<p>A <strong>bell</strong> char is inserted after the first <strong>start-of-heading char</strong> in file, if the file has been trimmed.</p>
<p>The <strong>entryTemplate</strong> parameter controls the printed look of an entry. Unlike the banner, entries <em>do</em> wrap, and have no limitations in lines number. New lines within entries content are preserved.</p>
<p> The placeholders names are quite self-explanatory, except:</p>
<ul>
<li>
<p>"CALLING CLASS NAME": represents the class name that actually made the call to Logger::getInstance()->log (â¦). Taking the XML snippet in the previous section as example, it could be either of the "Authenticator", "CookieManager" or "MailHandler".</p>
</li>
<li>
<p>If omitted, defaults to "%CONTENT%<NL>"; If given, it must contain the CONTENT placeholder, or a fatal error will be produced.</p>
</li>
</ul></td>
</tr>
<tr valign="top">
<td><p><context> nodes</p></td>
<td><p>an array holding class names, in the form of "ClassName"</p></td>
<td><p>Any param node with a name different from all of the above is considered to be a <em>context</em> definition.</p>
<p>A context definition must be comprised of one or several unique class names and have an unique name. In other words, there cannot be several <em>contexts</em> named the same, nor can a class name appear in more than exactly one <em>context</em> definition. Failing to comply with any of the above will produce a fatal error.</p>
<p> The rationale is to group calling classes into contexts, since it is likely to be impractical to have each calling class logging into its own log file â this can be achieved, though, by specifying a context with a single class.</p>
<p>If none given, a context named "Main" is assumed, which will include all calling classes that will ever log (â¦). By exception, the "Main" context can be </p>
<p>overridden by explicitly defining a context with this name.</p></td>
</tr>
</tbody>
</table>
<h2>Known Limitations & Gotchas</h2>
<ul>
<li>
<p>The module can only be called from within a class execution context.</p>
</li>
<li>
<p>The line ending in log files will be <em>UNIX style</em>, irrespective to the host operating system or the line ending used by the <em>entries template</em> or the original line ending of the content to be logged.</p>
</li>
</ul>
</body>
</html>