$level
$level :
Stores to any stream resource
Can be used to store into php://stderr, remote and local files, etc.
$formatter : \Monolog\Formatter\FormatterInterface
__construct(resource|string $stream, integer $level = \Monolog\Logger::DEBUG, Boolean $bubble = true, integer|null $filePermission = null, Boolean $useLocking = false)
resource|string | $stream | |
integer | $level | The minimum logging level at which this handler will be triggered |
Boolean | $bubble | Whether the messages that are handled can bubble up the stack or not |
integer|null | $filePermission | Optional file permissions (default (0644) are only for owner read/write) |
Boolean | $useLocking | Try to lock log file before doing any writes |
If a missing directory is not buildable
If stream is not a resource or string
isHandling(array $record) : Boolean
Checks whether the given record will be handled by this handler.
This is mostly done for performance reasons, to avoid calling processors for nothing.
Handlers should still check the record levels within handle(), returning false in isHandling() is no guarantee that handle() will not be called, and isHandling() might not be called for a given record.
array | $record | Partial log record containing only a level key |
setFormatter(\Monolog\Formatter\FormatterInterface $formatter) : self
Sets the formatter.
\Monolog\Formatter\FormatterInterface | $formatter |
getFormatter() : \Monolog\Formatter\FormatterInterface
Gets the formatter.
getDefaultFormatter() : \Monolog\Formatter\FormatterInterface
Gets the default formatter.
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Logger;
/**
* Stores to any stream resource
*
* Can be used to store into php://stderr, remote and local files, etc.
*
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class StreamHandler extends AbstractProcessingHandler
{
protected $stream;
protected $url;
private $errorMessage;
protected $filePermission;
protected $useLocking;
private $dirCreated;
/**
* @param resource|string $stream
* @param int $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
* @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write)
* @param Boolean $useLocking Try to lock log file before doing any writes
*
* @throws \Exception If a missing directory is not buildable
* @throws \InvalidArgumentException If stream is not a resource or string
*/
public function __construct($stream, $level = Logger::DEBUG, $bubble = true, $filePermission = null, $useLocking = false)
{
parent::__construct($level, $bubble);
if (is_resource($stream)) {
$this->stream = $stream;
} elseif (is_string($stream)) {
$this->url = $stream;
} else {
throw new \InvalidArgumentException('A stream must either be a resource or a string.');
}
$this->filePermission = $filePermission;
$this->useLocking = $useLocking;
}
/**
* {@inheritdoc}
*/
public function close()
{
if ($this->url && is_resource($this->stream)) {
fclose($this->stream);
}
$this->stream = null;
}
/**
* Return the currently active stream if it is open
*
* @return resource|null
*/
public function getStream()
{
return $this->stream;
}
/**
* Return the stream URL if it was configured with a URL and not an active resource
*
* @return string|null
*/
public function getUrl()
{
return $this->url;
}
/**
* {@inheritdoc}
*/
protected function write(array $record)
{
if (!is_resource($this->stream)) {
if (null === $this->url || '' === $this->url) {
throw new \LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().');
}
$this->createDir();
$this->errorMessage = null;
set_error_handler(array($this, 'customErrorHandler'));
$this->stream = fopen($this->url, 'a');
if ($this->filePermission !== null) {
@chmod($this->url, $this->filePermission);
}
restore_error_handler();
if (!is_resource($this->stream)) {
$this->stream = null;
throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened: '.$this->errorMessage, $this->url));
}
}
if ($this->useLocking) {
// ignoring errors here, there's not much we can do about them
flock($this->stream, LOCK_EX);
}
$this->streamWrite($this->stream, $record);
if ($this->useLocking) {
flock($this->stream, LOCK_UN);
}
}
/**
* Write to stream
* @param resource $stream
* @param array $record
*/
protected function streamWrite($stream, array $record)
{
fwrite($stream, (string) $record['formatted']);
}
private function customErrorHandler($code, $msg)
{
$this->errorMessage = preg_replace('{^(fopen|mkdir)\(.*?\): }', '', $msg);
}
/**
* @param string $stream
*
* @return null|string
*/
private function getDirFromStream($stream)
{
$pos = strpos($stream, '://');
if ($pos === false) {
return dirname($stream);
}
if ('file://' === substr($stream, 0, 7)) {
return dirname(substr($stream, 7));
}
return;
}
private function createDir()
{
// Do not try to create dir if it has already been tried.
if ($this->dirCreated) {
return;
}
$dir = $this->getDirFromStream($this->url);
if (null !== $dir && !is_dir($dir)) {
$this->errorMessage = null;
set_error_handler(array($this, 'customErrorHandler'));
$status = mkdir($dir, 0777, true);
restore_error_handler();
if (false === $status) {
throw new \UnexpectedValueException(sprintf('There is no existing directory at "%s" and its not buildable: '.$this->errorMessage, $dir));
}
}
$this->dirCreated = true;
}
}