FIX: Show detailed errors on CLI for live environments

API: Add HTTPOutputHandler::setCLIFormatter

Fixes https://github.com/silverstripe/silverstripe-framework/issues/6835

This provides detailed errors (but not warnings or notices) in CLI calls
on live environments.

It does this by adding a 2nd argument to our output handler,
CliFormatter. This formatter will be used when Director::is_cli() is
true.
This commit is contained in:
Sam Minnee 2017-04-24 16:38:13 +12:00
parent 5a7c6d4f60
commit 4c772c80c3
3 changed files with 65 additions and 17 deletions

View File

@ -37,8 +37,9 @@ SilverStripe\Core\Injector\Injector:
constructor: constructor:
- "error" - "error"
properties: properties:
Formatter: %$FriendlyErrorFormatter Formatter: %$SilverStripe\Logging\DebugViewFriendlyErrorFormatter
FriendlyErrorFormatter: CLIFormatter: %$SilverStripe\Logging\DetailedErrorFormatter
SilverStripe\Logging\DebugViewFriendlyErrorFormatter:
class: SilverStripe\Logging\DebugViewFriendlyErrorFormatter class: SilverStripe\Logging\DebugViewFriendlyErrorFormatter
properties: properties:
Title: "There has been an error" Title: "There has been an error"

View File

@ -107,7 +107,7 @@ To send emails, you can use Monolog's [NativeMailerHandler](https://github.com/S
- error - error
properties: properties:
ContentType: text/html ContentType: text/html
Formatter: %$SilverStripe\Framework\Logging\DetailedErrorFormatter Formatter: %$SilverStripe\Logging\DetailedErrorFormatter
The first section 4 lines passes a new handler to `Logger::pushHandler()` from the named service `MailHandler`. The The first section 4 lines passes a new handler to `Logger::pushHandler()` from the named service `MailHandler`. The
next 10 lines define what the service is. next 10 lines define what the service is.
@ -157,11 +157,12 @@ non-dev.
calls: calls:
- [ pushHandler, [ %$DisplayErrorHandler ]] - [ pushHandler, [ %$DisplayErrorHandler ]]
DisplayErrorHandler: DisplayErrorHandler:
class: SilverStripe\Framework\Logging\HTTPOutputHandler class: SilverStripe\Logging\HTTPOutputHandler
constructor: constructor:
- "notice" - "notice"
properties: properties:
Formatter: %$SilverStripe\Framework\Logging\DetailedErrorFormatter Formatter: %$SilverStripe\Logging\DetailedErrorFormatter
CLIFormatter: %$SilverStripe\Logging\DetailedErrorFormatter
--- ---
Name: live-errors Name: live-errors
Except: Except:
@ -181,13 +182,13 @@ non-dev.
Formatter: %$Monolog\Formatter\HtmlFormatter Formatter: %$Monolog\Formatter\HtmlFormatter
ContentType: text/html ContentType: text/html
DisplayErrorHandler: DisplayErrorHandler:
class: SilverStripe\Framework\Logging\HTTPOutputHandler class: SilverStripe\Logging\HTTPOutputHandler
constructor: constructor:
- "error" - "error"
properties: properties:
Formatter: %$FriendlyErrorFormatter Formatter: %$SilverStripe\Logging\DebugViewFriendlyErrorFormatter
FriendlyErrorFormatter: SilverStripe\Logging\DebugViewFriendlyErrorFormatter:
class: SilverStripe\Framework\Logging\DebugViewFriendlyErrorFormatter class: SilverStripe\Logging\DebugViewFriendlyErrorFormatter
properties: properties:
Title: "There has been an error" Title: "There has been an error"
Body: "The website server has not been able to respond to your request" Body: "The website server has not been able to respond to your request"
@ -236,21 +237,21 @@ be ignored.
### Replacing the error handler ### Replacing the error handler
The class `SilverStripe\Framework\Logging\MonologLoader` is responsible for loading performing Monolog-specific The Injector service `ErrorHandler` is responsible for initialising the error handler. By default it
configuration. It does a number of things:
* Create a `Monolog\ErrorHandler` object. * Create a `SilverStripe\Logging\MonologErrorHandler` object.
* Register the registered service `Logger` against it, to start the error handler. * Attach the registered service `Psr\Log\LoggerInterface` to it, to start the error handler.
* If `Logger` has a `pushHandler()` method, pass every object defined by `ErrorHandler.handlers` into it, one at a time.
Core.php will call `start()` on this method, to start the error handler.
This error handler is flexible enough to work with any PSR-3 logging implementation, but sometimes you will want to use This error handler is flexible enough to work with any PSR-3 logging implementation, but sometimes you will want to use
another. To replace this, you should registered a new service, `ErrorHandlerLoader`. For example: another. To replace this, you should registered a new service, `ErrorHandlerLoader`. For example:
SilverStripe\Core\Injector\Injector: SilverStripe\Core\Injector\Injector:
ErrorHandlerLoader: ErrorHandler:
class: MyApp\CustomErrorHandlerLoader class: MyApp\CustomErrorHandlerLoader
You should register something `Callable`, for example a class with an `__invoke()` method. You should register something with a `start()` method.
## Differences from SilverStripe 3 ## Differences from SilverStripe 3

View File

@ -3,8 +3,10 @@
namespace SilverStripe\Logging; namespace SilverStripe\Logging;
use SilverStripe\Control\Controller; use SilverStripe\Control\Controller;
use SilverStripe\Control\Director;
use SilverStripe\Control\HTTPResponse; use SilverStripe\Control\HTTPResponse;
use Monolog\Handler\AbstractProcessingHandler; use Monolog\Handler\AbstractProcessingHandler;
use Monolog\Formatter\FormatterInterface;
/** /**
* Output the error to the browser, with the given HTTP status code. * Output the error to the browser, with the given HTTP status code.
@ -23,6 +25,11 @@ class HTTPOutputHandler extends AbstractProcessingHandler
*/ */
private $statusCode = 500; private $statusCode = 500;
/**
* @var FormatterInterface
*/
private $cliFormatter = null;
/** /**
* Get the mime type to use when displaying this error. * Get the mime type to use when displaying this error.
* *
@ -38,7 +45,7 @@ class HTTPOutputHandler extends AbstractProcessingHandler
* Default text/html * Default text/html
* *
* @param string $contentType * @param string $contentType
* @return $this * @return HTTPOutputHandler Return $this to allow chainable calls
*/ */
public function setContentType($contentType) public function setContentType($contentType)
{ {
@ -69,6 +76,45 @@ class HTTPOutputHandler extends AbstractProcessingHandler
return $this; return $this;
} }
/**
* Set a formatter to use if Director::is_cli() is true
*
* @param $cliFormatter
* @return HTTPOutputHandler Return $this to allow chainable calls
*/
public function setCLIFormatter(FormatterInterface $cliFormatter)
{
$this->cliFormatter = $cliFormatter;
return $this;
}
/**
* Return the formatter use if Director::is_cli() is true
* If none has been set, null is returned, and the getFormatter() result will be used instead
*
* @return FormatterInterface
*/
public function getCLIFormatter()
{
return $this->cliFormatter;
}
/**
* Return the formatter to use in this case.
* May be the getCliFormatter() value if one is provided and Director::is_cli() is true.
*
* @return FormatterInterface
*/
public function getFormatter()
{
if (Director::is_cli() && ($cliFormatter = $this->getCLIFormatter())) {
return $cliFormatter;
}
return parent::getFormatter();
}
/** /**
* @param array $record * @param array $record
* @return bool * @return bool