Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Table of Contents
maxLevel1

Wording

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

In the context of Exception "error" can be used, since exceptions are errors.

Basic Class Architecture

Logger itself

DebugLevels

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

LevelAs NumberUsage example
FATAL1

FATAL PHP errors, other very fatal stuff, wrong PHP version or so

ERROR2common unhandled exceptions
WARN4User locked out due multiple wrong login, A user tries to edit a task property which he is not allowed to change
INFO8user entered wrong password, wanted exceptions BadMethodCall on known non existent methods (HEAD), other known and wanted exceptions
DEBUG16debugging on a level also useful for SysAdmins, for example user logins
TRACE32tracing debugging on a level only useful for developers


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.

...

Code Block
languagephp
// 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.

...

Code Block
languagephp
titleIn PHP just add new writters to the wanted logger instance
// use the default logger instance:
$logger = Zend_Registry::get('logger');
$logger->addWriter('name', $writerInstance);

Filtering

Each writer can have an list of filter rules. See the above module.ini example. The filter rules are connected via "or", that means one of the filter rules must be valid in order that an event  is logged.

...

KeywordValid OperandsDescription
level<=
>=
=

Is used to compare with the log levels as defined at the top of this page.

The second operand must be a valid log level: "fatal", "error", "warn" etc.
Since internally the levels are integers, only numeric operators are usable.


domain=
^=
$=
*=
The domain (origin) of the event must be matched either completely, or just a part of the string, as defined by the usable string operators.
exception=
*= 
The exception equals (= operator) the given exception class name, or the current exception is a subclass of the given exception name (*= operator).



Logging Database Tables

Currently there are two database tables receiving events:

...

Code Block
languagesql
titleusage 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 different exception types 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

...

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 / Package.

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

Code Block
languagephp
class editor_Models_Import_FileParser_Sdlxliff_Exception extends editor_Models_Import_FileParser_Exception {
    /**
     * @var string
     */
    protected $domain = 'editor.import.fileparser.sdlxliff';  //the domain (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

Code Block
languagephp
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,
    ]);
}

Exception Hierarchy and way to the frontend



View file
nameError Logging Refactoring.odp
height150

Generic Exceptions

For the handling / catching of such exceptions see the section "Examples for specific Exceptions" below.

...

ExceptionHTTP CodeDescription / Idea behind
Exception
PHP Basic Exception class should never be used directly.
Can be thrown by underlying legacy code.
Zend_Exception
Zend Basic Exception class should never be used directly.
This Exception an subclasses can be thrown by underlying legacy Zend code.
ZfExtended_Exception
ZfExtended Basic Exception class should not be used directly anymore.
Should be replaced by specific exceptions.
ZfExtended_ErrorCodeException
Base class for specific exceptions, should not be thrown directly.



Exceptions with Semantic

This exceptions are used to answer errors to the API in REST full way, by transporting semantic as HTTP response code.

...

ExceptionHTTP CodeDescription / Idea behind
ZfExtended_BadMethodCallException405 Method Not AllowedMeans that the used HTTP Method is not allowed / not implemented.
So a usage makes only sense on the controller level.
ZfExtended_NotAuthenticatedException401 UnauthorizedMeans the the user is not authorized, so in the request there was no information to identify the user.
This error should redirect the user in the GUI to the login page.
ZfExtended_NotFoundException404 Not FoundIs used in application routing, is thrown when the whole requested route is not found (invalid URL).
ZfExtended_Models_Entity_NotFoundException404 Not FoundIs used if an entity can not be found (if it is loaded via an id or guid)
ZfExtended_NoAccessException
ZfExtended_Models_Entity_NoAccessException
403 Forbidden

The user (authenticated or not) is not allowed to see / manipulate the requested resource.
This can be either by missing ACLs, or missing other preconditions disallowing the request.
In difference to 422 and 409: the authenticated user is the reason why the request can not be processed.

TODO: clear the difference between both exceptions.

TODO new Unprocesseable Entity Exception
(or reuse ValidateException?)
ZfExtended_UnprocessableEntityException::createResponse
422 Unprocessable Entity

Should be used PUT/POSTed content does prevent normal processing: Wrong parameters, missing parameters.
In other words: the requested call and its data is reasonable that the request can not be processed.

ZfExtended_Models_Entity_Conflict409 ConflictShould be used if the status of the entity does prevent normal processing: The entity is locked, the entity is used/referenced in other places.
In other words: the entity it self is reasonable that the request can not be processed.

ZfExtended_VersionConflictException

409 ConflictMust only be used if entity can not be saved due a changed entity version. The classical usage of the 409 HTTP error: the entity was changed in the meantime.
ZfExtended_BadGateway
TODO implement 504 Gateway Timeout
502 Bad GatewayShould be used if our request calls internally a third party service, and the third party service or the communication with it does not work.
ZfExtended_ValidateException422 Unprocessable EntityUse this exception if the given data in the request can not be validated or contains non processable data.
ZfExtended_FileUploadException400 Bad RequestTODO, currently not used. Should be used in the context of errors with uploaded data
ZfExtended_Models_MaintenanceException503 Service UnavailableOnly usable in the context of the maintenance mode
ZfExtended_Models_Entity_Exceptions_IntegrityDuplicateKeyTODO → specific exception? No direct HTTP codeIs thrown on saving entities and the underlying DB call returns a "integrity constraint violation 1062 Duplicate entry" error:
That means an entity with such key does already exist (entities with additional unique keys, customer number or user login).
ZfExtended_Models_Entity_Exceptions_IntegrityConstraintTODO → specific exception? No direct HTTP code

Is thrown on saving/deleting entities and the underlying DB call returns one of the following "integrity constraint violation" error:

  • 1451 Cannot delete or update a parent row: a foreign key constraint fails → the to be deleted entity is used via foreign key, and may not deleted therefore.
  • 1452 Cannot add or update a child row: a foreign key constraint fails → the to be saved foreign entity does not exist (anymore)







Creation of exceptions static method createResponse

One fundamental problem for development in translate5 is that the default GUI language of translate5 is german, but most of the error messages are in english.
At some places the error message is intended to be used directly as user feedback, therefore the error message must be also in german at that place and the message must go through the internal translation mechanism before send to the user.

...

  • the default constructor, all data must be given as usual.
  • the static method getResponse which creates a new exception instance prefilled with the given error messages in the users GUI language

Examples for specific Exceptions

This exceptions are used in the case of errors in the application.

...

ExceptionDescription / Idea behind
editor_Models_Import_FileParser_Sdlxliff_ExceptionException which is thrown on the usage of the SdlXliff fileparser.
ZfExtended_Logger_ExceptionException which is thrown in the context of error logging, so if in the logging is happening an error
ZfExtended_ErrorCodeExceptionBase class for all ErrorCode based Exceptions


EventCodes

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

Domains

The domains are used to classify and therefore filter exceptions and log entries.

...

Three starting domains are defined so far: "editor" for the editor module, "core" for core code, "plugin" for plugin code.

Domain Examples:

editor.customer                 ./application/modules/editor/Controllers/CustomerController.php

...

editor.import                   ./application/modules/editor/Models/Import/Exception.php

Use the logger facility just to log stuff

The default logger instance is generally available in the registry:

Code Block
$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:

...