Logging and Debugging
for Neos 5 and 7
Needs technical review
This part needs a technical review to be sure that all content is correct.
Logging
Be aware, that 'Logging' is programmatically a task of the underlying Flow framework ...
System Log
A logger instance for the default System Log can be injected and used for logging quite easily:
use Psr\Log\LoggerInterface;
/**
* @var LoggerInterface
*/
protected $logger;
/**
* @param LoggerInterface $logger
* @return void
*/
public function injectLogger(LoggerInterface $logger)
{
$this->logger = $logger;
}
The various methods can then be used to log according to the level:
$message = 'Whatever you want to log';
$context = [
'anything' => 'you might need',
'but can be' => 'left empty as well'
];
$this->logger->debug(string $message, array $context);
$this->logger->info(string $message, array $context);
$this->logger->notice(string $message, array $context);
$this->logger->warning(string $message, array $context);
$this->logger->error(string $message, array $context);
$this->logger->critical(string $message, array $context);
$this->logger->alert(string $message, array $context);
In other to be able to distinguish log entries, it is wise to send the some metadata along with the log entry:
use Neos\Flow\Log\Utility\LogEnvironment;
$logger->debug(
'Some log message',
LogEnvironment::fromMethodName(__METHOD__)
);
Other logs
While logging to the System Log is easily done, and probably the most common case, you might want to log to the Security Log.
For Neos 5.x (based on Flow 6.x) this can be done using the PsrSecurityLogerInterface
– but this is deprecated as of Flow 6.0 already:
/**
* @var \Neos\Flow\Log\PsrSecurityLoggerInterface
*/
protected $securityLogger;
/**
* @param \Neos\Flow\Log\PsrSecurityLoggerInterface $securityLogger
* @return void
*/
public function injectSecurityLogger(\Neos\Flow\Log\PsrSecurityLoggerInterface $securityLogger)
{
$this->securityLogger = $securityLogger;
}
The proper, non-deprecated method for this would be the use of the logger factory:
/**
* @var \Neos\Flow\Log\PsrLoggerFactoryInterface
*/
protected $loggerFactory;
/**
* @var \Neos\Flow\Log\PsrSecurityLoggerInterface
*/
protected $securityLogger;
/**
* @param \Neos\Flow\Log\PsrLoggerFactoryInterface $loggerFactory
* @return void
*/
public function injectLoggerFactory(\Neos\Flow\Log\PsrLoggerFactoryInterface $loggerFactory)
{
$this->securityLogger = $loggerFactory->get('securityLogger');
}
Flow comes with the following loggers defined by default:
systemLogger
securityLogger
sqlLogger
i18nLogger
With Neos 7.0 (based on Flow 7.0) the PsrSystemLoggerInterface
and PsrSecurityLoggerInterface
(that were deprecated with Flow 6.0) are removed, so either use the logger factory as explained above or use virtual objects to access loggers other than for the system log:
use Neos\Flow\Annotations as Flow;
use Psr\Log\LoggerInterface;
/**
* @Flow\Inject(name="Neos.Flow:SystemLogger")
* @var LoggerInterface
*/
protected $systemLogger;
Flow comes with the following virtual logger objects defined by default:
Neos.Flow:SystemLogger
Neos.Flow:SecurityLogger
Neos.Flow:SqlLogger
Neos.Flow:I18nLogger
Defining a custom logger
While logging to the available logs is usually fine, it might be desirable to have a separate log for your application. In order to be able to log to a separate file, a custom logger must be defined.
<?php
namespace Acme\Demo\Log;
use Psr\Log\LoggerInterface;
/**
* Marker interface for my custom logger.
*
*/
interface MyLoggerInterface extends LoggerInterface
{
}
The actual logger can extend Flow's Logger and must implement MyLoggerInterface
<?php
namespace Acme\Demo\Log;
class Logger extends \Neos\Flow\Log\Psr\Logger implements MyLoggerInterface
{
}
The settings are used when the logger is injected
Acme:
Demo:
log:
myLogger:
logger: Acme\Demo\Log\Logger
backend: Neos\Flow\Log\Backend\FileBackend
backendOptions:
logFileURL: '%FLOW_PATH_DATA%Logs/My.log'
createParentDirectories: TRUE
severityThreshold: '%LOG_INFO%'
maximumLogFileSize: 1048576
logFilesToKeep: 1
In order to be able to inject to logger to your class, the constructor properties must be defined in Objects.yaml using the settings configured above
Acme\Demo\Log\MyLoggerInterface:
scope: singleton
factoryObjectName: Neos\Flow\Log\PsrLoggerFactory
factoryMethodName: get
arguments:
1:
value: 'MyLogger'
2:
setting: Acme.Demo.log.myLogger.logger
3:
setting: Acme.Demo.log.myLogger.backend
4:
setting: Acme.Demo.log.myLogger.backendOptions
Now, the logger can be injected to your class
/**
* @var \Acme\Demo\Log\MyLoggerInterface
*/
protected $logger;
/**
* @param \Acme\Demo\Log\MyLoggerInterface $myLogger
* @return void
*/
public function injectMyLogger(\Acme\Demo\Log\MyLoggerInterface $myLogger)
{
$this->logger = $myLogger;
}
Is it then available for use
$this->logger->info('My first log entry.');
The log file can be found in Data/Logs/My.log