Page tree

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 6 Next »

The logging system of translate5 is currently completely reworked.

The architecture is similar as the Zend Logger from Zend_Log. On investigation if Zend_Log can be used for Translate5 needs, it turned out that translate5s special needs to the logger was not implementable by just reusing / extending the Zend_Log facility. So a conceptional adoption was done.

Wording

Since not only errors are logged, instead of "Error" or "ErrorCodes" we are talking about "Event" and "EventCodes".

Basic Class Architecture

Logger itself

Debug Levels

The following levels are defined as class constants  prefixed with LEVEL_ in ZfExtended_Logger class:

  • FATAL
  • ERROR
  • WARN
  • INFO
  • DEBUG
  • TRACE

ZfExtended_Logger

  • The logger itself. Methods of that class are used to log custom messages / data and exceptions / errors.
  • A reusable default instance is located in the registry: Zend_Registry::get('logger');
  • The default instance is initialized via the Resource Plugin ZfExtended_Resource_Logger and is therefore configured from the .ini configuration system as other Zend Resources too.
    • Own instances with custom configuration can be instanced when needed
    • The default instance is also accessible via Zend getResource stuff
  • A Logger instance can have multiple writer instances which writes the received log messages to different targets - as configured.
    • One can also define additional Logger instances if needed with a different config as the default one
  • provides functions like fatal, error, warn, info, debug, trace for direct log output

  • provides a function exception to log exceptions, this is automatically invoked in the final exception handler but can also be used manually for catched exceptions, which have to be logged but should not stop the request then.


// use the default logger instance:
$logger = Zend_Registry::get('logger');
/* @var $logger ZfExtended_Logger */
$logger->info('E1234', 'This is the message for the log where {variable} can be used.', [
	'mydebugdata' => "FOOBAR can be an object or array too",
    'variable' => "This text goes into the above variable with curly braces",
]);

ZfExtended_Logger_Event

  • A container class for the event information.
  • Is used internally to communicate the event from the logger to the different writers.

Log Writers

A ZfExtended_Logger can have multiple instances of writers. The writers are responsible for filtering (according to the configuration) and writing the log message to the specific backend.

So each writer can have a different filter configuration, one can configure one writer to listen on all import errors on error level debug and send them to one address, another writer can listen to all events on level > warn to log them as usual.

ZfExtended_Logger_Writer_Abstract

Abstract class for each specific writer.

ZfExtended_Logger_Writer_Database

  • Logs the received events into the central log database table Zf_errorlog.
  • This Writer can be configured with additional writers again, which receive events only once. All repeated events are stored in the database, but for example a email is send only once.

ZfExtended_Logger_Writer_DirectMail

Sends the event directly to the configured email address. No repetition recognition of events (spam protection) is done here.

ZfExtended_Logger_Writer_ErrorLog

Writes the events to the error_log configured in PHP.

ZfExtended_Logger_Writer_ChromeLogger

Writes the events to the chrome developer toolbar JS log. The Addon "Chrome Logger" must be installed therefore in the browser.

Recommended not to be used in production environments!

editor_Logger_TaskWriter

translate5 specific writer which logs all events with a field "task" containing a editor_Models_Task instance in the extra data to a special task log table.

editor_Models_Logger_Task extending ZfExtended_Models_Entity_Abstract and editor_Models_Db_Logger_Task extending Zend_Db_Table_Abstract are used to save to and load from the task log table.

Configuration of LogWriters

The configuraton of log writers can be either done in the application.ini / installation.ini or hardcoded in PHP.

Current writer configuration in application.ini
resources.ZfExtended_Resource_Logger.writer.default.type = 'ErrorLog'
resources.ZfExtended_Resource_Logger.writer.default.level = 4 ; → warn logs only till warning

; Test config:
resources.ZfExtended_Resource_Logger.writer.mail.type = 'DirectMail'
; via the formatter define what the user gets: full debug content, or only notice and so on.
resources.ZfExtended_Resource_Logger.writer.mail.level = 2 ; → warn logs only till error
resources.ZfExtended_Resource_Logger.writer.mail.receiver[] = 'thomas@mittagqi.com'
resources.ZfExtended_Resource_Logger.writer.mail.receiver[] = 'test@mittagqi.com'

resources.ZfExtended_Resource_Logger.writer.mail.type = 'Database'
; via the formatter define what the user gets: full debug content, or only notice and so on.
resources.ZfExtended_Resource_Logger.writer.mail.level = 16 ; → warn logs only till error
task log writer config in application/modules/editor/configs/module.ini
resources.ZfExtended_Resource_Logger.writer.tasklog.type = 'editor_Logger_TaskWriter'
resources.ZfExtended_Resource_Logger.writer.tasklog.level = 4 ; → warn logs only till warning
;
; The TaskWriter is a editor specific writer, it logs only events containing information about a task. The events are logged in a dedicated table, accessable via the frontend. Only warnings or events more severe as warnings are written to the task log. So no notices about tasks are additionally logged.
;
In PHP just add new writters to the wanted logger instance
// use the default logger instance:
$logger = Zend_Registry::get('logger');
$logger->addWriter('name', $writerInstance);


Logging Database Tables

Currently there are two database tables receiving events:

  • Zf_errorlog via ZfExtended_Logger_Writer_Database
  • LEK_task_log via editor_Logger_TaskWriter

Whats the difference?

Zf_errorlog receives basicly ALL events, limited by the configured log level of events to be received.

LEK_task_log receives:

  • only events which contain a task in its extra data
  • only events higher as the configured log level for that writer
  • The content of that table is available via API to provide information to the tasks in the GUI
usage hint of dealing with large data
-- instead of 
select * from Zf_errorlog;
-- use for better readability:
select * from Zf_errorlog\G




Exceptions

In translate5 to less exceptions were used till now. Mostly just a ZfExtended_Exception was used.

To be more flexible in filtering on logging exceptions but also on internal exception handling with try catch more exceptions are needed.

Examples

editor_Models_Import_FileParser_Sdlxliff_Exception extends editor_Models_Import_FileParser_Exception extends ZfExtended_ErrorCodeException

In the Sdlxliff fileparser editor_Models_Import_FileParser_Sdlxliff_Exception are thrown. In general fileparser code editor_Models_Import_FileParser_Exception should be used.

Since in FileParsing many errors can happen, a fine granulated exception structure is needed. In other code places this is not the case. At least one own Exception per Plugin.

Exception Structure

Each exception contains the mapping between the used event code and the related error message string. Since we are in an exception we can talk here about errors and not generally about events.

class editor_Models_Import_FileParser_Sdlxliff_Exception extends editor_Models_Import_FileParser_Exception {
    /**
     * @var string
     */
    protected $origin = 'import.fileparser.sdlxliff';  //the origin string for hierarchical filtering
    
    static protected $localErrorCodes = [              //the error (event) codes used by that exception
        'E1000' => 'The file "{filename}" contains SDL comments which are currently not supported!',
        'E1001' => 'The opening tag "{tagName}" contains the tagId "{tagId}" which is no valid SDLXLIFF!',
        'E1003' => 'There are change Markers in the sdlxliff-file "{filename}"! Please clear them first and then try to check in the file again.',
		// [...] more mappings
    ];
}

Exception usage

if ($shitHappened && $itWasMyFault) {
	//There are change Markers in the sdlxliff-file which are not supported!        → there should be a brief comment to explain what is going wrong
    throw new editor_Models_Import_FileParser_Sdlxliff_Exception('E1003', [		 // → The exception receives just the EventCode and an array with extra data
        'task' => $this->task,
        'filename' => $this->_fileName,
    ]);
}


EventCodes

The EventCodes used in exceptions and other logging usages are defined via the ErrorCodes listed and maintained in confluence..


Use the logger facility just to log stuff

The default logger instance is generally available in the registry:

$log = Zend_Registry::get('logger');
/* @var $log ZfExtendend_Logger */
$log->error("TODO"); // logs an error
$log->logDev($data1, $data2, ...); // a convienent replacement for error_log(print_r($data, 1)); Only for development, should not be comitted!

// the WorkflowLogger - dedicated to translate5 tasks and workflow stuff - must be instanced manually:
// TODO




TODO

Exception Definition / Usage:

- Before the refactoring we had only a few Exceptions

- Now for each domain (import / export / Plugin XY) one or more Exceptions should be defined.

- Each Exception has a different domain (example: import.fileparser.sdlxliff) for filtering.

- Also the Exception carries Semantik through its type, only if needed. Example:

  Plugin_Demo_Exception > A general Exception in the Demo Plugin Scope

  Plugin_Demo_NoConnectionException > On more specific errors (no connection established) specific exceptions can be created. Why that: If we can / want to handle that exceptions differently we can do that:

    try {

        $this->foo();

    }

    catch(Plugin_Demo_NoConnectionException $e) {

        //handle the no connection error

        logger::exceptionHandled($e); //logs the exception on level debug and marks the logged Exception as Handled.

    }

    // Plugin_Demo_Exception are handled via the final handler and stops the PHP request

  • No labels