Logger

Description

Dumps input data to a file on disk.

The file location is logically related to the class or class group (from here onward named calling context) that invokes the module's logging functionality.

Note: the module is built on top of the ParamsProxy module, and therefore inherits its security model, base functionality and limitations.

Features list

* via including the appropriate placeholders in the entries template.

How it works

The module is a singleton – therefor any configuration is shared system wide.

The module's API provides a single public method,

 /**
 * Writes given data on disk.
 * If data is anything but a string, it is first serialized.
 */
 log ($data);

one would invoke like this:

Logger::getInstance()->log ("FAIL: could not send email '$emailSubject' to $recipient; server responded: $error.");

Upon making this call, the module will use PHP's trace debug feature to figure out the name of the calling class and will try to match it against a context definition, as stated by the module's configuration file.

Note: more on configuration file, their use, structure and location in the ParamsProxy.html document.

If the calling class isn't part of any defined context, the default Main context will be assumed. The string passed as argument to log will then be written into the

<logs directory>/<context name>/log.txt

file (the file will be created if it doesn't yet exist). See also the insides about the split operation mode of the module.

The location of the <logs directory> is the parent directory of the <configuration directory> and cannot be changed. Therefore, the above could have been written as such:

<configuration directory>/../<context name>/log.txt

Note: for more on the configuration folder, please consult the ParamsProxy.html document.

XML

The module is configured via its dedicated XML configuration file. The module introduces no syntax extensions to the standard defined by the ParamsProxy module.

Note: for more on the configuration files syntax, please consult the ParamsProxy.html document..

However, some values – shown in bold in the example below – are to be parsed by the module, and therefor must be entered literally.

    <config for="Logger">
        <param>
            <type>number</type>
            <name>maxFileSize</name>
            <value>125</value>
        </param>
        <param>
            <type>string</type>
            <name>operatingMode</name>
            <value>split</value>
        </param>
        <param>
            <type>number</type>
            <name>wrapLimit</name>
            <value>80</value>
        </param>
        <param>
            <type>string</type>
            <name>bannerTemplate</name>
    		<value>
<![CDATA[
FILE:			%FILE NAME% <%FILE SIZE%>
PATH:			%FILE PATH%
DESCRIPTION: 	Log file for the %RELATED CONTEXT NAME%
STATUS: 		%FILE STATUS% as of %LAST MODIFIED DATE%
----------------------------------------------------------------------
]]>
        	</value>
        </param>
        <param>
            <type>string</type>
            <name>entryTemplate</name>
            <value>
<![CDATA[[
%CALLING CLASS NAME% @ %Y%/%M%/%D%-%H%:%S%
%CONTENT% 
]]>
        	</value>
        </param>
        <param>
            <type>array</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>

This example uses all parameters but not all possible values. Parameters, their usage and possible values are described in the next section.

Configuration

PARAMETER NAME

POSSIBLE VALUES

COMMENTS

maxFileSize

125 to 1250

Ranges from a hundred to a thousand bytes – with plenty of room for additional noise introduced by templates – for the log file upper size limit.

If the log file is about to exceed its upper size limit, trimming or splitting occurs, based on the operatingMode parameter setting.

If omitted, defaults to 125.

operatingMode

one of the "trim" or "split" words, literally

Sets up the action to trigger when the log file is about to grow oversize due to incoming data.

Trim will keep the file size the same but will alter content, by progressively deleting oldest entries until there is room for new ones.

Split will keep both the file size and content the same, but will archive the file and will start writing to a new file instead.

In this documentation, archived files are currently referred to as volumes. 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".

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".

If omitted, this parameter defaults to trim.

wrapLimit

80 to 240 or -1

The number of chars to allow per each written line of the log file. "-1" will disable the feature.

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).

By exception, the banner will never be split, rather trim horizontally to the wrapLimit number of chars (see next). Wrapping is off by default.

bannerTemplate

any string, optionally including one or more of the following placeholders, literally, in the form of %PLACEHOLDER%:

"FILE PATH"

"FILE SIZE"

"FILE STATUS"

"LAST MODIFIED DATE"

"RELATED CONTEXT NAME"

The banner of a log file represents a reserved, rectangular area found at the top of the file.

This banner will always be wrapLimit columns by 5 rows (hardcoded) wide, regardless of the actual size needed by the banner template or the data that will populate the template.

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.

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.

Template content does not wrap horizontally. If the applied, i.e., populated, template is greater than wrapLimit chars, each line will be trimmed at wrapLimit chars and ellipsis chars will be added to indicate trimming.

If wrapping is disabled, the banner will be horizontally trimmed at 240 chars (the maximum wrapping value).

Shorter lines in the banner will be right padded with spaces to the wrapping width (or the maximum wrapping value if disabled).

Placeholder names are quite self-explanatory, except:

  • "FILE STATUS": will return one of the "full", "trimmed" or "vol. no. #",
    where full, means that no split or trim operation have occurred yet, trimmed means the log file has been trimmed, and vol... means a split has been made, and the current
    file is the nth in the collection;

  • "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".

entryTemplate

any string, optionally including one or more of the following placeholders, literally, in the form of %PLACEHOLDER%:
"Y" (for year)

"M" (for month)

"D" (for day)

"H" (for hour)

"MIN" (for minute)

"S" (for seconds)

"CALLING CLASS NAME"

"CONTENT"

Each log file is comprised by a header and several entries.

An entry represents the result of one call to the log() method (see the API section). Although entries will frequently only span one line, entries and lines mustn't be mistaken.

The module internally adds a non printing start-of-heading char right before any entry; the module uses this delimiter for operations that involve entry manipulation, such as the trim functionality. Entries are stripped from null chars before printing, should they have any.

A bell char is inserted after the first start-of-heading char in file, if the file has been trimmed.

The entryTemplate parameter controls the printed look of an entry. Unlike the banner, entries do wrap, and have no limitations in lines number. New lines within entries content are preserved.

The placeholders names are quite self-explanatory, except:

  • "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".

  • If omitted, defaults to "%CONTENT%<NL>"; If given, it must contain the CONTENT placeholder, or a fatal error will be produced.

<context> nodes

an array holding class names, in the form of "ClassName"

Any param node with a name different from all of the above is considered to be a context definition.

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 contexts named the same, nor can a class name appear in more than exactly one context definition. Failing to comply with any of the above will produce a fatal error.

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.

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

overridden by explicitly defining a context with this name.

Known Limitations & Gotchas