/vendor/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php |
@@ -0,0 +1,78 @@ |
<?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\Formatter; |
|
use Monolog\Logger; |
|
/** |
* Formats a log message according to the ChromePHP array format |
* |
* @author Christophe Coevoet <stof@notk.org> |
*/ |
class ChromePHPFormatter implements FormatterInterface |
{ |
/** |
* Translates Monolog log levels to Wildfire levels. |
*/ |
private $logLevels = array( |
Logger::DEBUG => 'log', |
Logger::INFO => 'info', |
Logger::NOTICE => 'info', |
Logger::WARNING => 'warn', |
Logger::ERROR => 'error', |
Logger::CRITICAL => 'error', |
Logger::ALERT => 'error', |
Logger::EMERGENCY => 'error', |
); |
|
/** |
* {@inheritdoc} |
*/ |
public function format(array $record) |
{ |
// Retrieve the line and file if set and remove them from the formatted extra |
$backtrace = 'unknown'; |
if (isset($record['extra']['file'], $record['extra']['line'])) { |
$backtrace = $record['extra']['file'].' : '.$record['extra']['line']; |
unset($record['extra']['file'], $record['extra']['line']); |
} |
|
$message = array('message' => $record['message']); |
if ($record['context']) { |
$message['context'] = $record['context']; |
} |
if ($record['extra']) { |
$message['extra'] = $record['extra']; |
} |
if (count($message) === 1) { |
$message = reset($message); |
} |
|
return array( |
$record['channel'], |
$message, |
$backtrace, |
$this->logLevels[$record['level']], |
); |
} |
|
public function formatBatch(array $records) |
{ |
$formatted = array(); |
|
foreach ($records as $record) { |
$formatted[] = $this->format($record); |
} |
|
return $formatted; |
} |
} |
/vendor/monolog/monolog/src/Monolog/Formatter/FlowdockFormatter.php |
@@ -0,0 +1,116 @@ |
<?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\Formatter; |
|
/** |
* formats the record to be used in the FlowdockHandler |
* |
* @author Dominik Liebler <liebler.dominik@gmail.com> |
*/ |
class FlowdockFormatter implements FormatterInterface |
{ |
/** |
* @var string |
*/ |
private $source; |
|
/** |
* @var string |
*/ |
private $sourceEmail; |
|
/** |
* @param string $source |
* @param string $sourceEmail |
*/ |
public function __construct($source, $sourceEmail) |
{ |
$this->source = $source; |
$this->sourceEmail = $sourceEmail; |
} |
|
/** |
* {@inheritdoc} |
*/ |
public function format(array $record) |
{ |
$tags = array( |
'#logs', |
'#' . strtolower($record['level_name']), |
'#' . $record['channel'], |
); |
|
foreach ($record['extra'] as $value) { |
$tags[] = '#' . $value; |
} |
|
$subject = sprintf( |
'in %s: %s - %s', |
$this->source, |
$record['level_name'], |
$this->getShortMessage($record['message']) |
); |
|
$record['flowdock'] = array( |
'source' => $this->source, |
'from_address' => $this->sourceEmail, |
'subject' => $subject, |
'content' => $record['message'], |
'tags' => $tags, |
'project' => $this->source, |
); |
|
return $record; |
} |
|
/** |
* {@inheritdoc} |
*/ |
public function formatBatch(array $records) |
{ |
$formatted = array(); |
|
foreach ($records as $record) { |
$formatted[] = $this->format($record); |
} |
|
return $formatted; |
} |
|
/** |
* @param string $message |
* |
* @return string |
*/ |
public function getShortMessage($message) |
{ |
static $hasMbString; |
|
if (null === $hasMbString) { |
$hasMbString = function_exists('mb_strlen'); |
} |
|
$maxLength = 45; |
|
if ($hasMbString) { |
if (mb_strlen($message, 'UTF-8') > $maxLength) { |
$message = mb_substr($message, 0, $maxLength - 4, 'UTF-8') . ' ...'; |
} |
} else { |
if (strlen($message) > $maxLength) { |
$message = substr($message, 0, $maxLength - 4) . ' ...'; |
} |
} |
|
return $message; |
} |
} |
/vendor/monolog/monolog/src/Monolog/Formatter/FluentdFormatter.php |
@@ -0,0 +1,85 @@ |
<?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\Formatter; |
|
/** |
* Class FluentdFormatter |
* |
* Serializes a log message to Fluentd unix socket protocol |
* |
* Fluentd config: |
* |
* <source> |
* type unix |
* path /var/run/td-agent/td-agent.sock |
* </source> |
* |
* Monolog setup: |
* |
* $logger = new Monolog\Logger('fluent.tag'); |
* $fluentHandler = new Monolog\Handler\SocketHandler('unix:///var/run/td-agent/td-agent.sock'); |
* $fluentHandler->setFormatter(new Monolog\Formatter\FluentdFormatter()); |
* $logger->pushHandler($fluentHandler); |
* |
* @author Andrius Putna <fordnox@gmail.com> |
*/ |
class FluentdFormatter implements FormatterInterface |
{ |
/** |
* @var bool $levelTag should message level be a part of the fluentd tag |
*/ |
protected $levelTag = false; |
|
public function __construct($levelTag = false) |
{ |
if (!function_exists('json_encode')) { |
throw new \RuntimeException('PHP\'s json extension is required to use Monolog\'s FluentdUnixFormatter'); |
} |
|
$this->levelTag = (bool) $levelTag; |
} |
|
public function isUsingLevelsInTag() |
{ |
return $this->levelTag; |
} |
|
public function format(array $record) |
{ |
$tag = $record['channel']; |
if ($this->levelTag) { |
$tag .= '.' . strtolower($record['level_name']); |
} |
|
$message = array( |
'message' => $record['message'], |
'extra' => $record['extra'], |
); |
|
if (!$this->levelTag) { |
$message['level'] = $record['level']; |
$message['level_name'] = $record['level_name']; |
} |
|
return json_encode(array($tag, $record['datetime']->getTimestamp(), $message)); |
} |
|
public function formatBatch(array $records) |
{ |
$message = ''; |
foreach ($records as $record) { |
$message .= $this->format($record); |
} |
|
return $message; |
} |
} |
/vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php |
@@ -0,0 +1,138 @@ |
<?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\Formatter; |
|
use Monolog\Logger; |
use Gelf\Message; |
|
/** |
* Serializes a log message to GELF |
* @see http://www.graylog2.org/about/gelf |
* |
* @author Matt Lehner <mlehner@gmail.com> |
*/ |
class GelfMessageFormatter extends NormalizerFormatter |
{ |
const DEFAULT_MAX_LENGTH = 32766; |
|
/** |
* @var string the name of the system for the Gelf log message |
*/ |
protected $systemName; |
|
/** |
* @var string a prefix for 'extra' fields from the Monolog record (optional) |
*/ |
protected $extraPrefix; |
|
/** |
* @var string a prefix for 'context' fields from the Monolog record (optional) |
*/ |
protected $contextPrefix; |
|
/** |
* @var int max length per field |
*/ |
protected $maxLength; |
|
/** |
* Translates Monolog log levels to Graylog2 log priorities. |
*/ |
private $logLevels = array( |
Logger::DEBUG => 7, |
Logger::INFO => 6, |
Logger::NOTICE => 5, |
Logger::WARNING => 4, |
Logger::ERROR => 3, |
Logger::CRITICAL => 2, |
Logger::ALERT => 1, |
Logger::EMERGENCY => 0, |
); |
|
public function __construct($systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_', $maxLength = null) |
{ |
parent::__construct('U.u'); |
|
$this->systemName = $systemName ?: gethostname(); |
|
$this->extraPrefix = $extraPrefix; |
$this->contextPrefix = $contextPrefix; |
$this->maxLength = is_null($maxLength) ? self::DEFAULT_MAX_LENGTH : $maxLength; |
} |
|
/** |
* {@inheritdoc} |
*/ |
public function format(array $record) |
{ |
$record = parent::format($record); |
|
if (!isset($record['datetime'], $record['message'], $record['level'])) { |
throw new \InvalidArgumentException('The record should at least contain datetime, message and level keys, '.var_export($record, true).' given'); |
} |
|
$message = new Message(); |
$message |
->setTimestamp($record['datetime']) |
->setShortMessage((string) $record['message']) |
->setHost($this->systemName) |
->setLevel($this->logLevels[$record['level']]); |
|
// message length + system name length + 200 for padding / metadata |
$len = 200 + strlen((string) $record['message']) + strlen($this->systemName); |
|
if ($len > $this->maxLength) { |
$message->setShortMessage(substr($record['message'], 0, $this->maxLength)); |
} |
|
if (isset($record['channel'])) { |
$message->setFacility($record['channel']); |
} |
if (isset($record['extra']['line'])) { |
$message->setLine($record['extra']['line']); |
unset($record['extra']['line']); |
} |
if (isset($record['extra']['file'])) { |
$message->setFile($record['extra']['file']); |
unset($record['extra']['file']); |
} |
|
foreach ($record['extra'] as $key => $val) { |
$val = is_scalar($val) || null === $val ? $val : $this->toJson($val); |
$len = strlen($this->extraPrefix . $key . $val); |
if ($len > $this->maxLength) { |
$message->setAdditional($this->extraPrefix . $key, substr($val, 0, $this->maxLength)); |
break; |
} |
$message->setAdditional($this->extraPrefix . $key, $val); |
} |
|
foreach ($record['context'] as $key => $val) { |
$val = is_scalar($val) || null === $val ? $val : $this->toJson($val); |
$len = strlen($this->contextPrefix . $key . $val); |
if ($len > $this->maxLength) { |
$message->setAdditional($this->contextPrefix . $key, substr($val, 0, $this->maxLength)); |
break; |
} |
$message->setAdditional($this->contextPrefix . $key, $val); |
} |
|
if (null === $message->getFile() && isset($record['context']['exception']['file'])) { |
if (preg_match("/^(.+):([0-9]+)$/", $record['context']['exception']['file'], $matches)) { |
$message->setFile($matches[1]); |
$message->setLine($matches[2]); |
} |
} |
|
return $message; |
} |
} |
/vendor/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php |
@@ -0,0 +1,141 @@ |
<?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\Formatter; |
|
use Monolog\Logger; |
|
/** |
* Formats incoming records into an HTML table |
* |
* This is especially useful for html email logging |
* |
* @author Tiago Brito <tlfbrito@gmail.com> |
*/ |
class HtmlFormatter extends NormalizerFormatter |
{ |
/** |
* Translates Monolog log levels to html color priorities. |
*/ |
protected $logLevels = array( |
Logger::DEBUG => '#cccccc', |
Logger::INFO => '#468847', |
Logger::NOTICE => '#3a87ad', |
Logger::WARNING => '#c09853', |
Logger::ERROR => '#f0ad4e', |
Logger::CRITICAL => '#FF7708', |
Logger::ALERT => '#C12A19', |
Logger::EMERGENCY => '#000000', |
); |
|
/** |
* @param string $dateFormat The format of the timestamp: one supported by DateTime::format |
*/ |
public function __construct($dateFormat = null) |
{ |
parent::__construct($dateFormat); |
} |
|
/** |
* Creates an HTML table row |
* |
* @param string $th Row header content |
* @param string $td Row standard cell content |
* @param bool $escapeTd false if td content must not be html escaped |
* @return string |
*/ |
protected function addRow($th, $td = ' ', $escapeTd = true) |
{ |
$th = htmlspecialchars($th, ENT_NOQUOTES, 'UTF-8'); |
if ($escapeTd) { |
$td = '<pre>'.htmlspecialchars($td, ENT_NOQUOTES, 'UTF-8').'</pre>'; |
} |
|
return "<tr style=\"padding: 4px;spacing: 0;text-align: left;\">\n<th style=\"background: #cccccc\" width=\"100px\">$th:</th>\n<td style=\"padding: 4px;spacing: 0;text-align: left;background: #eeeeee\">".$td."</td>\n</tr>"; |
} |
|
/** |
* Create a HTML h1 tag |
* |
* @param string $title Text to be in the h1 |
* @param int $level Error level |
* @return string |
*/ |
protected function addTitle($title, $level) |
{ |
$title = htmlspecialchars($title, ENT_NOQUOTES, 'UTF-8'); |
|
return '<h1 style="background: '.$this->logLevels[$level].';color: #ffffff;padding: 5px;" class="monolog-output">'.$title.'</h1>'; |
} |
|
/** |
* Formats a log record. |
* |
* @param array $record A record to format |
* @return mixed The formatted record |
*/ |
public function format(array $record) |
{ |
$output = $this->addTitle($record['level_name'], $record['level']); |
$output .= '<table cellspacing="1" width="100%" class="monolog-output">'; |
|
$output .= $this->addRow('Message', (string) $record['message']); |
$output .= $this->addRow('Time', $record['datetime']->format($this->dateFormat)); |
$output .= $this->addRow('Channel', $record['channel']); |
if ($record['context']) { |
$embeddedTable = '<table cellspacing="1" width="100%">'; |
foreach ($record['context'] as $key => $value) { |
$embeddedTable .= $this->addRow($key, $this->convertToString($value)); |
} |
$embeddedTable .= '</table>'; |
$output .= $this->addRow('Context', $embeddedTable, false); |
} |
if ($record['extra']) { |
$embeddedTable = '<table cellspacing="1" width="100%">'; |
foreach ($record['extra'] as $key => $value) { |
$embeddedTable .= $this->addRow($key, $this->convertToString($value)); |
} |
$embeddedTable .= '</table>'; |
$output .= $this->addRow('Extra', $embeddedTable, false); |
} |
|
return $output.'</table>'; |
} |
|
/** |
* Formats a set of log records. |
* |
* @param array $records A set of records to format |
* @return mixed The formatted set of records |
*/ |
public function formatBatch(array $records) |
{ |
$message = ''; |
foreach ($records as $record) { |
$message .= $this->format($record); |
} |
|
return $message; |
} |
|
protected function convertToString($data) |
{ |
if (null === $data || is_scalar($data)) { |
return (string) $data; |
} |
|
$data = $this->normalize($data); |
if (version_compare(PHP_VERSION, '5.4.0', '>=')) { |
return json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); |
} |
|
return str_replace('\\/', '/', json_encode($data)); |
} |
} |
/vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php |
@@ -0,0 +1,208 @@ |
<?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\Formatter; |
|
use Exception; |
use Throwable; |
|
/** |
* Encodes whatever record data is passed to it as json |
* |
* This can be useful to log to databases or remote APIs |
* |
* @author Jordi Boggiano <j.boggiano@seld.be> |
*/ |
class JsonFormatter extends NormalizerFormatter |
{ |
const BATCH_MODE_JSON = 1; |
const BATCH_MODE_NEWLINES = 2; |
|
protected $batchMode; |
protected $appendNewline; |
|
/** |
* @var bool |
*/ |
protected $includeStacktraces = false; |
|
/** |
* @param int $batchMode |
* @param bool $appendNewline |
*/ |
public function __construct($batchMode = self::BATCH_MODE_JSON, $appendNewline = true) |
{ |
$this->batchMode = $batchMode; |
$this->appendNewline = $appendNewline; |
} |
|
/** |
* The batch mode option configures the formatting style for |
* multiple records. By default, multiple records will be |
* formatted as a JSON-encoded array. However, for |
* compatibility with some API endpoints, alternative styles |
* are available. |
* |
* @return int |
*/ |
public function getBatchMode() |
{ |
return $this->batchMode; |
} |
|
/** |
* True if newlines are appended to every formatted record |
* |
* @return bool |
*/ |
public function isAppendingNewlines() |
{ |
return $this->appendNewline; |
} |
|
/** |
* {@inheritdoc} |
*/ |
public function format(array $record) |
{ |
return $this->toJson($this->normalize($record), true) . ($this->appendNewline ? "\n" : ''); |
} |
|
/** |
* {@inheritdoc} |
*/ |
public function formatBatch(array $records) |
{ |
switch ($this->batchMode) { |
case static::BATCH_MODE_NEWLINES: |
return $this->formatBatchNewlines($records); |
|
case static::BATCH_MODE_JSON: |
default: |
return $this->formatBatchJson($records); |
} |
} |
|
/** |
* @param bool $include |
*/ |
public function includeStacktraces($include = true) |
{ |
$this->includeStacktraces = $include; |
} |
|
/** |
* Return a JSON-encoded array of records. |
* |
* @param array $records |
* @return string |
*/ |
protected function formatBatchJson(array $records) |
{ |
return $this->toJson($this->normalize($records), true); |
} |
|
/** |
* Use new lines to separate records instead of a |
* JSON-encoded array. |
* |
* @param array $records |
* @return string |
*/ |
protected function formatBatchNewlines(array $records) |
{ |
$instance = $this; |
|
$oldNewline = $this->appendNewline; |
$this->appendNewline = false; |
array_walk($records, function (&$value, $key) use ($instance) { |
$value = $instance->format($value); |
}); |
$this->appendNewline = $oldNewline; |
|
return implode("\n", $records); |
} |
|
/** |
* Normalizes given $data. |
* |
* @param mixed $data |
* |
* @return mixed |
*/ |
protected function normalize($data) |
{ |
if (is_array($data) || $data instanceof \Traversable) { |
$normalized = array(); |
|
$count = 1; |
foreach ($data as $key => $value) { |
if ($count++ >= 1000) { |
$normalized['...'] = 'Over 1000 items, aborting normalization'; |
break; |
} |
$normalized[$key] = $this->normalize($value); |
} |
|
return $normalized; |
} |
|
if ($data instanceof Exception || $data instanceof Throwable) { |
return $this->normalizeException($data); |
} |
|
return $data; |
} |
|
/** |
* Normalizes given exception with or without its own stack trace based on |
* `includeStacktraces` property. |
* |
* @param Exception|Throwable $e |
* |
* @return array |
*/ |
protected function normalizeException($e) |
{ |
// TODO 2.0 only check for Throwable |
if (!$e instanceof Exception && !$e instanceof Throwable) { |
throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.get_class($e)); |
} |
|
$data = array( |
'class' => get_class($e), |
'message' => $e->getMessage(), |
'code' => $e->getCode(), |
'file' => $e->getFile().':'.$e->getLine(), |
); |
|
if ($this->includeStacktraces) { |
$trace = $e->getTrace(); |
foreach ($trace as $frame) { |
if (isset($frame['file'])) { |
$data['trace'][] = $frame['file'].':'.$frame['line']; |
} elseif (isset($frame['function']) && $frame['function'] === '{closure}') { |
// We should again normalize the frames, because it might contain invalid items |
$data['trace'][] = $frame['function']; |
} else { |
// We should again normalize the frames, because it might contain invalid items |
$data['trace'][] = $this->normalize($frame); |
} |
} |
} |
|
if ($previous = $e->getPrevious()) { |
$data['previous'] = $this->normalizeException($previous); |
} |
|
return $data; |
} |
} |
/vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php |
@@ -0,0 +1,179 @@ |
<?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\Formatter; |
|
/** |
* Formats incoming records into a one-line string |
* |
* This is especially useful for logging to files |
* |
* @author Jordi Boggiano <j.boggiano@seld.be> |
* @author Christophe Coevoet <stof@notk.org> |
*/ |
class LineFormatter extends NormalizerFormatter |
{ |
const SIMPLE_FORMAT = "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"; |
|
protected $format; |
protected $allowInlineLineBreaks; |
protected $ignoreEmptyContextAndExtra; |
protected $includeStacktraces; |
|
/** |
* @param string $format The format of the message |
* @param string $dateFormat The format of the timestamp: one supported by DateTime::format |
* @param bool $allowInlineLineBreaks Whether to allow inline line breaks in log entries |
* @param bool $ignoreEmptyContextAndExtra |
*/ |
public function __construct($format = null, $dateFormat = null, $allowInlineLineBreaks = false, $ignoreEmptyContextAndExtra = false) |
{ |
$this->format = $format ?: static::SIMPLE_FORMAT; |
$this->allowInlineLineBreaks = $allowInlineLineBreaks; |
$this->ignoreEmptyContextAndExtra = $ignoreEmptyContextAndExtra; |
parent::__construct($dateFormat); |
} |
|
public function includeStacktraces($include = true) |
{ |
$this->includeStacktraces = $include; |
if ($this->includeStacktraces) { |
$this->allowInlineLineBreaks = true; |
} |
} |
|
public function allowInlineLineBreaks($allow = true) |
{ |
$this->allowInlineLineBreaks = $allow; |
} |
|
public function ignoreEmptyContextAndExtra($ignore = true) |
{ |
$this->ignoreEmptyContextAndExtra = $ignore; |
} |
|
/** |
* {@inheritdoc} |
*/ |
public function format(array $record) |
{ |
$vars = parent::format($record); |
|
$output = $this->format; |
|
foreach ($vars['extra'] as $var => $val) { |
if (false !== strpos($output, '%extra.'.$var.'%')) { |
$output = str_replace('%extra.'.$var.'%', $this->stringify($val), $output); |
unset($vars['extra'][$var]); |
} |
} |
|
|
foreach ($vars['context'] as $var => $val) { |
if (false !== strpos($output, '%context.'.$var.'%')) { |
$output = str_replace('%context.'.$var.'%', $this->stringify($val), $output); |
unset($vars['context'][$var]); |
} |
} |
|
if ($this->ignoreEmptyContextAndExtra) { |
if (empty($vars['context'])) { |
unset($vars['context']); |
$output = str_replace('%context%', '', $output); |
} |
|
if (empty($vars['extra'])) { |
unset($vars['extra']); |
$output = str_replace('%extra%', '', $output); |
} |
} |
|
foreach ($vars as $var => $val) { |
if (false !== strpos($output, '%'.$var.'%')) { |
$output = str_replace('%'.$var.'%', $this->stringify($val), $output); |
} |
} |
|
// remove leftover %extra.xxx% and %context.xxx% if any |
if (false !== strpos($output, '%')) { |
$output = preg_replace('/%(?:extra|context)\..+?%/', '', $output); |
} |
|
return $output; |
} |
|
public function formatBatch(array $records) |
{ |
$message = ''; |
foreach ($records as $record) { |
$message .= $this->format($record); |
} |
|
return $message; |
} |
|
public function stringify($value) |
{ |
return $this->replaceNewlines($this->convertToString($value)); |
} |
|
protected function normalizeException($e) |
{ |
// TODO 2.0 only check for Throwable |
if (!$e instanceof \Exception && !$e instanceof \Throwable) { |
throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.get_class($e)); |
} |
|
$previousText = ''; |
if ($previous = $e->getPrevious()) { |
do { |
$previousText .= ', '.get_class($previous).'(code: '.$previous->getCode().'): '.$previous->getMessage().' at '.$previous->getFile().':'.$previous->getLine(); |
} while ($previous = $previous->getPrevious()); |
} |
|
$str = '[object] ('.get_class($e).'(code: '.$e->getCode().'): '.$e->getMessage().' at '.$e->getFile().':'.$e->getLine().$previousText.')'; |
if ($this->includeStacktraces) { |
$str .= "\n[stacktrace]\n".$e->getTraceAsString()."\n"; |
} |
|
return $str; |
} |
|
protected function convertToString($data) |
{ |
if (null === $data || is_bool($data)) { |
return var_export($data, true); |
} |
|
if (is_scalar($data)) { |
return (string) $data; |
} |
|
if (version_compare(PHP_VERSION, '5.4.0', '>=')) { |
return $this->toJson($data, true); |
} |
|
return str_replace('\\/', '/', @json_encode($data)); |
} |
|
protected function replaceNewlines($str) |
{ |
if ($this->allowInlineLineBreaks) { |
if (0 === strpos($str, '{')) { |
return str_replace(array('\r', '\n'), array("\r", "\n"), $str); |
} |
|
return $str; |
} |
|
return str_replace(array("\r\n", "\r", "\n"), ' ', $str); |
} |
} |
/vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php |
@@ -0,0 +1,166 @@ |
<?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\Formatter; |
|
/** |
* Serializes a log message to Logstash Event Format |
* |
* @see http://logstash.net/ |
* @see https://github.com/logstash/logstash/blob/master/lib/logstash/event.rb |
* |
* @author Tim Mower <timothy.mower@gmail.com> |
*/ |
class LogstashFormatter extends NormalizerFormatter |
{ |
const V0 = 0; |
const V1 = 1; |
|
/** |
* @var string the name of the system for the Logstash log message, used to fill the @source field |
*/ |
protected $systemName; |
|
/** |
* @var string an application name for the Logstash log message, used to fill the @type field |
*/ |
protected $applicationName; |
|
/** |
* @var string a prefix for 'extra' fields from the Monolog record (optional) |
*/ |
protected $extraPrefix; |
|
/** |
* @var string a prefix for 'context' fields from the Monolog record (optional) |
*/ |
protected $contextPrefix; |
|
/** |
* @var int logstash format version to use |
*/ |
protected $version; |
|
/** |
* @param string $applicationName the application that sends the data, used as the "type" field of logstash |
* @param string $systemName the system/machine name, used as the "source" field of logstash, defaults to the hostname of the machine |
* @param string $extraPrefix prefix for extra keys inside logstash "fields" |
* @param string $contextPrefix prefix for context keys inside logstash "fields", defaults to ctxt_ |
* @param int $version the logstash format version to use, defaults to 0 |
*/ |
public function __construct($applicationName, $systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_', $version = self::V0) |
{ |
// logstash requires a ISO 8601 format date with optional millisecond precision. |
parent::__construct('Y-m-d\TH:i:s.uP'); |
|
$this->systemName = $systemName ?: gethostname(); |
$this->applicationName = $applicationName; |
$this->extraPrefix = $extraPrefix; |
$this->contextPrefix = $contextPrefix; |
$this->version = $version; |
} |
|
/** |
* {@inheritdoc} |
*/ |
public function format(array $record) |
{ |
$record = parent::format($record); |
|
if ($this->version === self::V1) { |
$message = $this->formatV1($record); |
} else { |
$message = $this->formatV0($record); |
} |
|
return $this->toJson($message) . "\n"; |
} |
|
protected function formatV0(array $record) |
{ |
if (empty($record['datetime'])) { |
$record['datetime'] = gmdate('c'); |
} |
$message = array( |
'@timestamp' => $record['datetime'], |
'@source' => $this->systemName, |
'@fields' => array(), |
); |
if (isset($record['message'])) { |
$message['@message'] = $record['message']; |
} |
if (isset($record['channel'])) { |
$message['@tags'] = array($record['channel']); |
$message['@fields']['channel'] = $record['channel']; |
} |
if (isset($record['level'])) { |
$message['@fields']['level'] = $record['level']; |
} |
if ($this->applicationName) { |
$message['@type'] = $this->applicationName; |
} |
if (isset($record['extra']['server'])) { |
$message['@source_host'] = $record['extra']['server']; |
} |
if (isset($record['extra']['url'])) { |
$message['@source_path'] = $record['extra']['url']; |
} |
if (!empty($record['extra'])) { |
foreach ($record['extra'] as $key => $val) { |
$message['@fields'][$this->extraPrefix . $key] = $val; |
} |
} |
if (!empty($record['context'])) { |
foreach ($record['context'] as $key => $val) { |
$message['@fields'][$this->contextPrefix . $key] = $val; |
} |
} |
|
return $message; |
} |
|
protected function formatV1(array $record) |
{ |
if (empty($record['datetime'])) { |
$record['datetime'] = gmdate('c'); |
} |
$message = array( |
'@timestamp' => $record['datetime'], |
'@version' => 1, |
'host' => $this->systemName, |
); |
if (isset($record['message'])) { |
$message['message'] = $record['message']; |
} |
if (isset($record['channel'])) { |
$message['type'] = $record['channel']; |
$message['channel'] = $record['channel']; |
} |
if (isset($record['level_name'])) { |
$message['level'] = $record['level_name']; |
} |
if ($this->applicationName) { |
$message['type'] = $this->applicationName; |
} |
if (!empty($record['extra'])) { |
foreach ($record['extra'] as $key => $val) { |
$message[$this->extraPrefix . $key] = $val; |
} |
} |
if (!empty($record['context'])) { |
foreach ($record['context'] as $key => $val) { |
$message[$this->contextPrefix . $key] = $val; |
} |
} |
|
return $message; |
} |
} |
/vendor/monolog/monolog/src/Monolog/Formatter/MongoDBFormatter.php |
@@ -0,0 +1,105 @@ |
<?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\Formatter; |
|
/** |
* Formats a record for use with the MongoDBHandler. |
* |
* @author Florian Plattner <me@florianplattner.de> |
*/ |
class MongoDBFormatter implements FormatterInterface |
{ |
private $exceptionTraceAsString; |
private $maxNestingLevel; |
|
/** |
* @param int $maxNestingLevel 0 means infinite nesting, the $record itself is level 1, $record['context'] is 2 |
* @param bool $exceptionTraceAsString set to false to log exception traces as a sub documents instead of strings |
*/ |
public function __construct($maxNestingLevel = 3, $exceptionTraceAsString = true) |
{ |
$this->maxNestingLevel = max($maxNestingLevel, 0); |
$this->exceptionTraceAsString = (bool) $exceptionTraceAsString; |
} |
|
/** |
* {@inheritDoc} |
*/ |
public function format(array $record) |
{ |
return $this->formatArray($record); |
} |
|
/** |
* {@inheritDoc} |
*/ |
public function formatBatch(array $records) |
{ |
foreach ($records as $key => $record) { |
$records[$key] = $this->format($record); |
} |
|
return $records; |
} |
|
protected function formatArray(array $record, $nestingLevel = 0) |
{ |
if ($this->maxNestingLevel == 0 || $nestingLevel <= $this->maxNestingLevel) { |
foreach ($record as $name => $value) { |
if ($value instanceof \DateTime) { |
$record[$name] = $this->formatDate($value, $nestingLevel + 1); |
} elseif ($value instanceof \Exception) { |
$record[$name] = $this->formatException($value, $nestingLevel + 1); |
} elseif (is_array($value)) { |
$record[$name] = $this->formatArray($value, $nestingLevel + 1); |
} elseif (is_object($value)) { |
$record[$name] = $this->formatObject($value, $nestingLevel + 1); |
} |
} |
} else { |
$record = '[...]'; |
} |
|
return $record; |
} |
|
protected function formatObject($value, $nestingLevel) |
{ |
$objectVars = get_object_vars($value); |
$objectVars['class'] = get_class($value); |
|
return $this->formatArray($objectVars, $nestingLevel); |
} |
|
protected function formatException(\Exception $exception, $nestingLevel) |
{ |
$formattedException = array( |
'class' => get_class($exception), |
'message' => $exception->getMessage(), |
'code' => $exception->getCode(), |
'file' => $exception->getFile() . ':' . $exception->getLine(), |
); |
|
if ($this->exceptionTraceAsString === true) { |
$formattedException['trace'] = $exception->getTraceAsString(); |
} else { |
$formattedException['trace'] = $exception->getTrace(); |
} |
|
return $this->formatArray($formattedException, $nestingLevel); |
} |
|
protected function formatDate(\DateTime $value, $nestingLevel) |
{ |
return new \MongoDate($value->getTimestamp()); |
} |
} |
/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php |
@@ -0,0 +1,297 @@ |
<?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\Formatter; |
|
use Exception; |
|
/** |
* Normalizes incoming records to remove objects/resources so it's easier to dump to various targets |
* |
* @author Jordi Boggiano <j.boggiano@seld.be> |
*/ |
class NormalizerFormatter implements FormatterInterface |
{ |
const SIMPLE_DATE = "Y-m-d H:i:s"; |
|
protected $dateFormat; |
|
/** |
* @param string $dateFormat The format of the timestamp: one supported by DateTime::format |
*/ |
public function __construct($dateFormat = null) |
{ |
$this->dateFormat = $dateFormat ?: static::SIMPLE_DATE; |
if (!function_exists('json_encode')) { |
throw new \RuntimeException('PHP\'s json extension is required to use Monolog\'s NormalizerFormatter'); |
} |
} |
|
/** |
* {@inheritdoc} |
*/ |
public function format(array $record) |
{ |
return $this->normalize($record); |
} |
|
/** |
* {@inheritdoc} |
*/ |
public function formatBatch(array $records) |
{ |
foreach ($records as $key => $record) { |
$records[$key] = $this->format($record); |
} |
|
return $records; |
} |
|
protected function normalize($data) |
{ |
if (null === $data || is_scalar($data)) { |
if (is_float($data)) { |
if (is_infinite($data)) { |
return ($data > 0 ? '' : '-') . 'INF'; |
} |
if (is_nan($data)) { |
return 'NaN'; |
} |
} |
|
return $data; |
} |
|
if (is_array($data)) { |
$normalized = array(); |
|
$count = 1; |
foreach ($data as $key => $value) { |
if ($count++ >= 1000) { |
$normalized['...'] = 'Over 1000 items ('.count($data).' total), aborting normalization'; |
break; |
} |
$normalized[$key] = $this->normalize($value); |
} |
|
return $normalized; |
} |
|
if ($data instanceof \DateTime) { |
return $data->format($this->dateFormat); |
} |
|
if (is_object($data)) { |
// TODO 2.0 only check for Throwable |
if ($data instanceof Exception || (PHP_VERSION_ID > 70000 && $data instanceof \Throwable)) { |
return $this->normalizeException($data); |
} |
|
// non-serializable objects that implement __toString stringified |
if (method_exists($data, '__toString') && !$data instanceof \JsonSerializable) { |
$value = $data->__toString(); |
} else { |
// the rest is json-serialized in some way |
$value = $this->toJson($data, true); |
} |
|
return sprintf("[object] (%s: %s)", get_class($data), $value); |
} |
|
if (is_resource($data)) { |
return sprintf('[resource] (%s)', get_resource_type($data)); |
} |
|
return '[unknown('.gettype($data).')]'; |
} |
|
protected function normalizeException($e) |
{ |
// TODO 2.0 only check for Throwable |
if (!$e instanceof Exception && !$e instanceof \Throwable) { |
throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.get_class($e)); |
} |
|
$data = array( |
'class' => get_class($e), |
'message' => $e->getMessage(), |
'code' => $e->getCode(), |
'file' => $e->getFile().':'.$e->getLine(), |
); |
|
if ($e instanceof \SoapFault) { |
if (isset($e->faultcode)) { |
$data['faultcode'] = $e->faultcode; |
} |
|
if (isset($e->faultactor)) { |
$data['faultactor'] = $e->faultactor; |
} |
|
if (isset($e->detail)) { |
$data['detail'] = $e->detail; |
} |
} |
|
$trace = $e->getTrace(); |
foreach ($trace as $frame) { |
if (isset($frame['file'])) { |
$data['trace'][] = $frame['file'].':'.$frame['line']; |
} elseif (isset($frame['function']) && $frame['function'] === '{closure}') { |
// We should again normalize the frames, because it might contain invalid items |
$data['trace'][] = $frame['function']; |
} else { |
// We should again normalize the frames, because it might contain invalid items |
$data['trace'][] = $this->toJson($this->normalize($frame), true); |
} |
} |
|
if ($previous = $e->getPrevious()) { |
$data['previous'] = $this->normalizeException($previous); |
} |
|
return $data; |
} |
|
/** |
* Return the JSON representation of a value |
* |
* @param mixed $data |
* @param bool $ignoreErrors |
* @throws \RuntimeException if encoding fails and errors are not ignored |
* @return string |
*/ |
protected function toJson($data, $ignoreErrors = false) |
{ |
// suppress json_encode errors since it's twitchy with some inputs |
if ($ignoreErrors) { |
return @$this->jsonEncode($data); |
} |
|
$json = $this->jsonEncode($data); |
|
if ($json === false) { |
$json = $this->handleJsonError(json_last_error(), $data); |
} |
|
return $json; |
} |
|
/** |
* @param mixed $data |
* @return string JSON encoded data or null on failure |
*/ |
private function jsonEncode($data) |
{ |
if (version_compare(PHP_VERSION, '5.4.0', '>=')) { |
return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); |
} |
|
return json_encode($data); |
} |
|
/** |
* Handle a json_encode failure. |
* |
* If the failure is due to invalid string encoding, try to clean the |
* input and encode again. If the second encoding attempt fails, the |
* inital error is not encoding related or the input can't be cleaned then |
* raise a descriptive exception. |
* |
* @param int $code return code of json_last_error function |
* @param mixed $data data that was meant to be encoded |
* @throws \RuntimeException if failure can't be corrected |
* @return string JSON encoded data after error correction |
*/ |
private function handleJsonError($code, $data) |
{ |
if ($code !== JSON_ERROR_UTF8) { |
$this->throwEncodeError($code, $data); |
} |
|
if (is_string($data)) { |
$this->detectAndCleanUtf8($data); |
} elseif (is_array($data)) { |
array_walk_recursive($data, array($this, 'detectAndCleanUtf8')); |
} else { |
$this->throwEncodeError($code, $data); |
} |
|
$json = $this->jsonEncode($data); |
|
if ($json === false) { |
$this->throwEncodeError(json_last_error(), $data); |
} |
|
return $json; |
} |
|
/** |
* Throws an exception according to a given code with a customized message |
* |
* @param int $code return code of json_last_error function |
* @param mixed $data data that was meant to be encoded |
* @throws \RuntimeException |
*/ |
private function throwEncodeError($code, $data) |
{ |
switch ($code) { |
case JSON_ERROR_DEPTH: |
$msg = 'Maximum stack depth exceeded'; |
break; |
case JSON_ERROR_STATE_MISMATCH: |
$msg = 'Underflow or the modes mismatch'; |
break; |
case JSON_ERROR_CTRL_CHAR: |
$msg = 'Unexpected control character found'; |
break; |
case JSON_ERROR_UTF8: |
$msg = 'Malformed UTF-8 characters, possibly incorrectly encoded'; |
break; |
default: |
$msg = 'Unknown error'; |
} |
|
throw new \RuntimeException('JSON encoding failed: '.$msg.'. Encoding: '.var_export($data, true)); |
} |
|
/** |
* Detect invalid UTF-8 string characters and convert to valid UTF-8. |
* |
* Valid UTF-8 input will be left unmodified, but strings containing |
* invalid UTF-8 codepoints will be reencoded as UTF-8 with an assumed |
* original encoding of ISO-8859-15. This conversion may result in |
* incorrect output if the actual encoding was not ISO-8859-15, but it |
* will be clean UTF-8 output and will not rely on expensive and fragile |
* detection algorithms. |
* |
* Function converts the input in place in the passed variable so that it |
* can be used as a callback for array_walk_recursive. |
* |
* @param mixed &$data Input to check and convert if needed |
* @private |
*/ |
public function detectAndCleanUtf8(&$data) |
{ |
if (is_string($data) && !preg_match('//u', $data)) { |
$data = preg_replace_callback( |
'/[\x80-\xFF]+/', |
function ($m) { return utf8_encode($m[0]); }, |
$data |
); |
$data = str_replace( |
array('¤', '¦', '¨', '´', '¸', '¼', '½', '¾'), |
array('€', 'Š', 'š', 'Ž', 'ž', 'Œ', 'œ', 'Ÿ'), |
$data |
); |
} |
} |
} |
/vendor/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php |
@@ -0,0 +1,113 @@ |
<?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\Formatter; |
|
use Monolog\Logger; |
|
/** |
* Serializes a log message according to Wildfire's header requirements |
* |
* @author Eric Clemmons (@ericclemmons) <eric@uxdriven.com> |
* @author Christophe Coevoet <stof@notk.org> |
* @author Kirill chEbba Chebunin <iam@chebba.org> |
*/ |
class WildfireFormatter extends NormalizerFormatter |
{ |
const TABLE = 'table'; |
|
/** |
* Translates Monolog log levels to Wildfire levels. |
*/ |
private $logLevels = array( |
Logger::DEBUG => 'LOG', |
Logger::INFO => 'INFO', |
Logger::NOTICE => 'INFO', |
Logger::WARNING => 'WARN', |
Logger::ERROR => 'ERROR', |
Logger::CRITICAL => 'ERROR', |
Logger::ALERT => 'ERROR', |
Logger::EMERGENCY => 'ERROR', |
); |
|
/** |
* {@inheritdoc} |
*/ |
public function format(array $record) |
{ |
// Retrieve the line and file if set and remove them from the formatted extra |
$file = $line = ''; |
if (isset($record['extra']['file'])) { |
$file = $record['extra']['file']; |
unset($record['extra']['file']); |
} |
if (isset($record['extra']['line'])) { |
$line = $record['extra']['line']; |
unset($record['extra']['line']); |
} |
|
$record = $this->normalize($record); |
$message = array('message' => $record['message']); |
$handleError = false; |
if ($record['context']) { |
$message['context'] = $record['context']; |
$handleError = true; |
} |
if ($record['extra']) { |
$message['extra'] = $record['extra']; |
$handleError = true; |
} |
if (count($message) === 1) { |
$message = reset($message); |
} |
|
if (isset($record['context'][self::TABLE])) { |
$type = 'TABLE'; |
$label = $record['channel'] .': '. $record['message']; |
$message = $record['context'][self::TABLE]; |
} else { |
$type = $this->logLevels[$record['level']]; |
$label = $record['channel']; |
} |
|
// Create JSON object describing the appearance of the message in the console |
$json = $this->toJson(array( |
array( |
'Type' => $type, |
'File' => $file, |
'Line' => $line, |
'Label' => $label, |
), |
$message, |
), $handleError); |
|
// The message itself is a serialization of the above JSON object + it's length |
return sprintf( |
'%s|%s|', |
strlen($json), |
$json |
); |
} |
|
public function formatBatch(array $records) |
{ |
throw new \BadMethodCallException('Batch formatting does not make sense for the WildfireFormatter'); |
} |
|
protected function normalize($data) |
{ |
if (is_object($data) && !$data instanceof \DateTime) { |
return $data; |
} |
|
return parent::normalize($data); |
} |
} |