DOCS Update documentation for separated logging interfaces

This commit is contained in:
Robbie Averill 2018-07-04 11:56:06 +12:00
parent 1cb23178ec
commit 1faf59fc54

View File

@ -4,13 +4,14 @@ summary: Trap, fire and report diagnostic logs, user exceptions, warnings and er
# Logging and Error Handling # Logging and Error Handling
SilverStripe uses Monolog for both error handling and logging. It comes with two default configurations: one for SilverStripe uses Monolog for both error handling and logging. It comes with two default configurations: one for
development environments, and another for test or live environments. On development environments, SilverStripe will logging, and another for core error handling. The core error handling implementation also comes with two default
deal harshly with any warnings or errors: a full call-stack is shown and execution stops for anything, giving you early configurations: one for development environments, and another for test or live environments. On development
warning of a potential issue to handle. environments, SilverStripe will deal harshly with any warnings or errors: a full call-stack is shown and execution
stops for anything, giving you early warning of a potential issue to handle.
## Raising errors and logging diagnostic information. ## Raising errors and logging diagnostic information.
For informational and debug logs, you can use the Logger directly. The Logger is a PSR-3 compatible LoggerInterface and For general purpose logging, you can use the Logger directly. The Logger is a PSR-3 compatible LoggerInterface and
can be accessed via the `Injector`: can be accessed via the `Injector`:
```php ```php
@ -20,13 +21,15 @@ use SilverStripe\Security\Security;
Injector::inst()->get(LoggerInterface::class)->info('User has logged in: ID #' . Security::getCurrentUser()->ID); Injector::inst()->get(LoggerInterface::class)->info('User has logged in: ID #' . Security::getCurrentUser()->ID);
Injector::inst()->get(LoggerInterface::class)->debug('Query executed: ' . $sql); Injector::inst()->get(LoggerInterface::class)->debug('Query executed: ' . $sql);
Injector::inst()->get(LoggerInterface::class)->error('Something went wrong, but let\'s continue on...');
``` ```
Although you can raise more important levels of alerts in this way, we recommend using PHP's native error systems for Although you can raise more important levels of alerts in this way, we recommend using PHP's native error systems for
these instead. these instead.
For notice-level and warning-level issues, you should use [user_error](http://www.php.net/user_error) to throw errors For notice-level and warning-level issues, you can also use [user_error](http://www.php.net/user_error) to throw errors
where appropriate. These will not halt execution but will send a message to the PHP error log. where appropriate. As with the default Logger implementation these will not halt execution, but will send a message
to the PHP error log.
```php ```php
public function delete() public function delete()
@ -48,37 +51,52 @@ public function getRelatedObject()
} }
``` ```
For errors that should halt execution, you should use Exceptions. Normally, Exceptions will halt the flow of executuion, For errors that should halt execution, you should use Exceptions. Normally, Exceptions will halt the flow of execution,
but they can be caught with a try/catch clause. but they can be caught with a try/catch clause.
```php ```php
throw new \LogicException("Query failed: " . $sql); throw new \LogicException("Query failed: " . $sql);
``` ```
### Accessing the logger via dependency injection. ### Accessing the logger via dependency injection
It can be quite verbose to call `Injector::inst()->get(LoggerInterface::class)` all the time. More importantly, It can be quite verbose to call `Injector::inst()->get(LoggerInterface::class)` all the time. More importantly,
it also means that you're coupling your code to global state, which is a bad design practise. A better it also means that you're coupling your code to global state, which is a bad design practise. A better
approach is to use depedency injection to pass the logger in for you. The [Injector](../extending/Injector) approach is to use dependency injection to pass the logger in for you. The [Injector](../extending/Injector)
can help with this. The most straightforward is to specify a `dependencies` config setting, like this: can help with this. The most straightforward is to specify a `dependencies` config setting, like this:
```php ```php
use Psr\Log\LoggerInterface;
use SilverStripe\Control\Controller; use SilverStripe\Control\Controller;
class MyController extends Controller class MyController extends Controller
{ {
private static $dependencies = [ private static $dependencies = [
'logger' => '%$Psr\Log\LoggerInterface', 'Logger' => '%$' . LoggerInterface::class,
]; ];
// This will be set automatically, as long as MyController is instantiated via Injector /**
public $logger; * This will be set automatically, as long as MyController is instantiated via Injector
*
* @var LoggerInterface
*/
protected $logger;
protected function init() protected function init()
{ {
$this->logger->debug("MyController::init() called"); $this->logger->debug("MyController::init() called");
parent::init(); parent::init();
} }
/**
* @param LoggerInterface $logger
* @return $this
*/
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
return $this;
}
} }
``` ```
@ -98,7 +116,7 @@ E_USER_ERROR if it's going to be **dangerous** or **impossible** to continue wit
## Configuring error logging ## Configuring error logging
You can configure your logging using Monolog handlers. The handlers should be provided int the `Logger.handlers` You can configure your logging using Monolog handlers. The handlers should be provided in the `Logger.handlers`
configuration setting. Below we have a couple of common examples, but Monolog comes with [many different handlers](https://github.com/Seldaek/monolog/blob/master/doc/02-handlers-formatters-processors.md#handlers) configuration setting. Below we have a couple of common examples, but Monolog comes with [many different handlers](https://github.com/Seldaek/monolog/blob/master/doc/02-handlers-formatters-processors.md#handlers)
for you to try. for you to try.
@ -150,19 +168,19 @@ The log file will be relative to the framework/ path, so "../silverstripe.log" w
### Disabling the default handler ### Disabling the default handler
You can disable a handler by removing its pushHandlers call from the calls option of the Logger service definition. You can disable a handler by removing its pushHandlers call from the calls option of the Logger service definition.
The handler key of the default handler is `DisplayErrorHandler`, so you can disable it like this: The handler key of the default handler is `pushDisplayErrorHandler`, so you can disable it like this:
```yaml ```yaml
SilverStripe\Core\Injector\Injector: SilverStripe\Core\Injector\Injector:
Psr\Log\LoggerInterface: Psr\Log\LoggerInterface.errorhandler:
calls: calls:
DisplayErrorHandler: %%remove%% pushDisplayErrorHandler: %%remove%%
``` ```
### Setting a different configuration for dev ### Setting a different configuration for dev
In order to set different logging configuration on different environment types, we rely on the environment-specific In order to set different logging configuration on different environment types, we rely on the environment-specific
configuration features that the config system proviers. For example, here we have different configuration for dev and configuration features that the config system providers. For example, here we have different configuration for dev and
non-dev. non-dev.
```yaml ```yaml
@ -172,7 +190,7 @@ Only:
environment: dev environment: dev
--- ---
SilverStripe\Core\Injector\Injector: SilverStripe\Core\Injector\Injector:
Psr\Log\LoggerInterface: Psr\Log\LoggerInterface.errorhandler:
calls: calls:
pushDisplayErrorHandler: [ pushHandler, [ %$DisplayErrorHandler ]] pushDisplayErrorHandler: [ pushHandler, [ %$DisplayErrorHandler ]]
DisplayErrorHandler: DisplayErrorHandler:
@ -188,10 +206,21 @@ Except:
environment: dev environment: dev
--- ---
SilverStripe\Core\Injector\Injector: SilverStripe\Core\Injector\Injector:
# Default logger implementation for general purpose use
Psr\Log\LoggerInterface: Psr\Log\LoggerInterface:
calls: calls:
pushFileLogHandler: [ pushHandler, [ %$LogFileHandler ]] # Save system logs to file
pushFileLogHandler: [ pushHandler, [ %$LogFileHandler ]]
# Core error handler for system use
Psr\Log\LoggerInterface.errorhandler:
calls:
# Save errors to file
pushFileLogHandler: [ pushHandler, [ %$LogFileHandler ]]
# Format and display errors in the browser/CLI
pushDisplayErrorHandler: [ pushHandler, [ %$DisplayErrorHandler ]] pushDisplayErrorHandler: [ pushHandler, [ %$DisplayErrorHandler ]]
# Custom handler to log to a file
LogFileHandler: LogFileHandler:
class: Monolog\Handler\StreamHandler class: Monolog\Handler\StreamHandler
constructor: constructor:
@ -200,12 +229,16 @@ SilverStripe\Core\Injector\Injector:
properties: properties:
Formatter: %$Monolog\Formatter\HtmlFormatter Formatter: %$Monolog\Formatter\HtmlFormatter
ContentType: text/html ContentType: text/html
# Handler for displaying errors in the browser or CLI
DisplayErrorHandler: DisplayErrorHandler:
class: SilverStripe\Logging\HTTPOutputHandler class: SilverStripe\Logging\HTTPOutputHandler
constructor: constructor:
- "error" - "error"
properties: properties:
Formatter: %$SilverStripe\Logging\DebugViewFriendlyErrorFormatter Formatter: %$SilverStripe\Logging\DebugViewFriendlyErrorFormatter
# Configuration for the "friendly" error formatter
SilverStripe\Logging\DebugViewFriendlyErrorFormatter: SilverStripe\Logging\DebugViewFriendlyErrorFormatter:
class: SilverStripe\Logging\DebugViewFriendlyErrorFormatter class: SilverStripe\Logging\DebugViewFriendlyErrorFormatter
properties: properties:
@ -214,7 +247,7 @@ SilverStripe\Core\Injector\Injector:
``` ```
<div class="info" markdown="1"> <div class="info" markdown="1">
In addition to SilverStripe-integrated logging, it is advisable to fall back to PHPs native logging functionality. A In addition to SilverStripe-integrated logging, it is advisable to fall back to PHP's native logging functionality. A
script might terminate before it reaches the SilverStripe error handling, for example in the case of a fatal error. Make script might terminate before it reaches the SilverStripe error handling, for example in the case of a fatal error. Make
sure `log_errors` and `error_log` in your PHP ini file are configured. sure `log_errors` and `error_log` in your PHP ini file are configured.
</div> </div>
@ -228,11 +261,12 @@ others.
### Replacing the logger ### Replacing the logger
Monolog comes by default with SilverStripe, but you may use another PSR-3 compliant logger, if you wish. To do this, Monolog comes by default with SilverStripe, but you may use another PSR-3 compliant logger, if you wish. To do this,
set the `Injector.Logger` configuration parameter, providing a new injector definition. For example: set the `SilverStripe\Core\Injector\Injector.Monolog\Logger` configuration parameter, providing a new injector
definition. For example:
```yaml ```yaml
SilverStripe\Core\Injector\Injector: SilverStripe\Core\Injector\Injector:
ErrorHandler: Monolog\Logger:
class: Logging\Logger class: Logging\Logger
constructor: constructor:
- 'alternative-logger' - 'alternative-logger'
@ -243,7 +277,8 @@ be ignored.
### Replacing the error handler ### Replacing the error handler
The Injector service `ErrorHandler` is responsible for initialising the error handler. By default it The Injector service `SilverStripe\Logging\ErrorHandler` is responsible for initialising the error handler. By default
it:
* Create a `SilverStripe\Logging\MonologErrorHandler` object. * Create a `SilverStripe\Logging\MonologErrorHandler` object.
* Attach the registered service `Psr\Log\LoggerInterface` to it, to start the error handler. * Attach the registered service `Psr\Log\LoggerInterface` to it, to start the error handler.
@ -255,7 +290,7 @@ another. To replace this, you should registered a new service, `ErrorHandlerLoad
```yaml ```yaml
SilverStripe\Core\Injector\Injector: SilverStripe\Core\Injector\Injector:
ErrorHandler: SilverStripe\Logging\ErrorHandler:
class: MyApp\CustomErrorHandlerLoader class: MyApp\CustomErrorHandlerLoader
``` ```