changed log class
This commit is contained in:
@@ -20,7 +20,7 @@ class Admin extends \Espo\Core\Controllers\Base
|
||||
$result = $this->getContainer()->get('schema')->rebuild();
|
||||
} catch (\Exception $e) {
|
||||
$result = false;
|
||||
$GLOBALS['log']->add('EXCEPTION', 'Fault to rebuild database schema'.'. Details: '.$e->getMessage());
|
||||
$GLOBALS['log']->error('Fault to rebuild database schema'.'. Details: '.$e->getMessage());
|
||||
}
|
||||
|
||||
if ($result === false) {
|
||||
|
||||
@@ -20,11 +20,12 @@ class Application
|
||||
{
|
||||
$this->container = new Container();
|
||||
|
||||
$GLOBALS['log'] = $this->log = $this->container->get('log');
|
||||
$GLOBALS['log'] = $this->container->get('log');
|
||||
/*$GLOBALS['log'] = $this->container->get('logOld');
|
||||
|
||||
set_error_handler(array($this->getLog(), 'catchError'), E_ALL);
|
||||
set_exception_handler(array($this->getLog(), 'catchException'));
|
||||
|
||||
set_error_handler(array($GLOBALS['log'], 'catchError'), E_ALL);
|
||||
set_exception_handler(array($GLOBALS['log'], 'catchException'));*/
|
||||
|
||||
date_default_timezone_set('UTC');
|
||||
}
|
||||
|
||||
@@ -57,11 +58,6 @@ class Application
|
||||
return $this->container;
|
||||
}
|
||||
|
||||
public function getLog()
|
||||
{
|
||||
return $this->log;
|
||||
}
|
||||
|
||||
public function run($name = 'default')
|
||||
{
|
||||
$this->routeHooks();
|
||||
@@ -179,7 +175,7 @@ class Application
|
||||
|
||||
$method = strtolower($route['method']);
|
||||
if (!in_array($method, $crudList)) {
|
||||
$GLOBALS['log']->add('ERROR', 'Route: Method ['.$method.'] does not exist. Please check your route ['.$route['route'].']');
|
||||
$GLOBALS['log']->error('Route: Method ['.$method.'] does not exist. Please check your route ['.$route['route'].']');
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -87,16 +87,16 @@ class Container
|
||||
);
|
||||
}
|
||||
|
||||
private function loadLog()
|
||||
/*private function loadLogOld()
|
||||
{
|
||||
return new \Espo\Core\Utils\Log(
|
||||
return new \Espo\Core\Utils\LogOld(
|
||||
$this->get('fileManager'),
|
||||
$this->get('output'),
|
||||
array(
|
||||
'options' => $this->get('config')->get('logger'),
|
||||
)
|
||||
);
|
||||
}
|
||||
}*/
|
||||
|
||||
private function loadOutput()
|
||||
{
|
||||
|
||||
@@ -99,7 +99,7 @@ class CronManager
|
||||
public function run()
|
||||
{
|
||||
if (!$this->checkLastRunTime()) {
|
||||
$GLOBALS['log']->add('INFO', 'Cron Manager: Stop cron running, too frequency execution');
|
||||
$GLOBALS['log']->info('Cron Manager: Stop cron running, too frequency execution');
|
||||
return; //stop cron running, too frequency execution
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ class CronManager
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$isSuccess = false;
|
||||
$GLOBALS['log']->add('INFO', 'Failed job running, job ['.$job['id'].']. Error Details: '.$e->getMessage());
|
||||
$GLOBALS['log']->info('Failed job running, job ['.$job['id'].']. Error Details: '.$e->getMessage());
|
||||
}
|
||||
|
||||
$status = $isSuccess ? 'Success' : 'Failed';
|
||||
@@ -163,7 +163,7 @@ class CronManager
|
||||
//$nextDate = $cronExpression->getNextRunDate()->format('Y-m-d H:i:s');
|
||||
$prevDate = $cronExpression->getPreviousRunDate()->format('Y-m-d H:i:s');
|
||||
} catch (\Exception $e) {
|
||||
$GLOBALS['log']->add('Exception', 'ScheduledJob ['.$scheduledJob['id'].']: CronExpression - Impossible CRON expression ['.$scheduling.']');
|
||||
$GLOBALS['log']->error('ScheduledJob ['.$scheduledJob['id'].']: CronExpression - Impossible CRON expression ['.$scheduling.']');
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Core\Loaders;
|
||||
|
||||
use Espo\Core\Utils;
|
||||
use Monolog\Handler;
|
||||
|
||||
class Log
|
||||
{
|
||||
private $container;
|
||||
|
||||
public function __construct(\Espo\Core\Container $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
protected function getContainer()
|
||||
{
|
||||
return $this->container;
|
||||
}
|
||||
|
||||
public function load()
|
||||
{
|
||||
$config = $this->getContainer()->get('config');
|
||||
|
||||
$logConfig = $config->get('logger');
|
||||
|
||||
$log = new Utils\Log('Espo');
|
||||
$levelCode = $log->getLevelCode($logConfig['level']);
|
||||
|
||||
if ($logConfig['isRotate']) {
|
||||
$handler = new Handler\RotatingFileHandler($logConfig['path'], $logConfig['maxRotateFiles'], $levelCode);
|
||||
} else {
|
||||
$handler = new Handler\StreamHandler($logConfig['path'], $levelCode);
|
||||
}
|
||||
$log->pushHandler($handler);
|
||||
\Monolog\ErrorHandler::register($log);
|
||||
|
||||
return $log;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ class Output
|
||||
|
||||
public function processError($message = 'Error', $code = 500)
|
||||
{
|
||||
$GLOBALS['log']->add('ERROR', 'API ['.$this->getSlim()->request()->getMethod().']:'.$this->getSlim()->router()->getCurrentRoute()->getPattern().', Params:'.print_r($this->getSlim()->router()->getCurrentRoute()->getParams(), true).', InputData: '.$this->getSlim()->request()->getBody().' - '.$message);
|
||||
$GLOBALS['log']->error('API ['.$this->getSlim()->request()->getMethod().']:'.$this->getSlim()->router()->getCurrentRoute()->getPattern().', Params:'.print_r($this->getSlim()->router()->getCurrentRoute()->getParams(), true).', InputData: '.$this->getSlim()->request()->getBody().' - '.$message);
|
||||
$this->displayError($message, $code);
|
||||
|
||||
ob_clean();
|
||||
@@ -53,7 +53,7 @@ class Output
|
||||
*/
|
||||
public function displayError($text, $statusCode = 500)
|
||||
{
|
||||
$GLOBALS['log']->add('INFO', 'Display Error: '.$text.', Code: '.$statusCode.' URL: '.$_SERVER['REQUEST_URI']);
|
||||
$GLOBALS['log']->info('Display Error: '.$text.', Code: '.$statusCode.' URL: '.$_SERVER['REQUEST_URI']);
|
||||
|
||||
if (!empty( $this->slim)) {
|
||||
$this->getSlim()->response()->status($statusCode);
|
||||
@@ -61,7 +61,7 @@ class Output
|
||||
$this->getSlim()->stop();
|
||||
}
|
||||
else {
|
||||
$GLOBALS['log']->add('INFO', 'Could not get Slim instance. It looks like a direct call (bypass API). URL: '.$_SERVER['REQUEST_URI']);
|
||||
$GLOBALS['log']->info('Could not get Slim instance. It looks like a direct call (bypass API). URL: '.$_SERVER['REQUEST_URI']);
|
||||
die($text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ class Auth
|
||||
|
||||
public function login($username, $password)
|
||||
{
|
||||
$GLOBALS['log']->add('DEBUG', 'AUTH: Try to authenticate');
|
||||
$GLOBALS['log']->debug('AUTH: Try to authenticate');
|
||||
|
||||
$entityManager = $this->container->get('entityManager');
|
||||
|
||||
@@ -42,7 +42,7 @@ class Auth
|
||||
if ($user instanceof \Espo\Entities\User) {
|
||||
$entityManager->setUser($user);
|
||||
$this->container->setUser($user);
|
||||
$GLOBALS['log']->add('DEBUG', 'AUTH: Result of authenticate is [true]');
|
||||
$GLOBALS['log']->debug('AUTH: Result of authenticate is [true]');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ class Config
|
||||
|
||||
$config = $this->getFileManager()->getContents($defaultConfig['configPath']);
|
||||
if (empty($config)) {
|
||||
$GLOBALS['log']->add('FATAL', 'Check syntax or permission of your '.$defaultConfig['configPath']);
|
||||
$GLOBALS['log']->emergency('Check syntax or permission of your '.$defaultConfig['configPath']);
|
||||
}
|
||||
|
||||
$this->configData = Util::merge((array) $defaultConfig, (array) $config);
|
||||
|
||||
@@ -70,14 +70,14 @@ class Converter
|
||||
*/
|
||||
public function process()
|
||||
{
|
||||
$GLOBALS['log']->add('Debug', 'Orm\Converter - Start: orm convertation');
|
||||
$GLOBALS['log']->debug('Orm\Converter - Start: orm convertation');
|
||||
|
||||
$ormMeta = $this->getOrmConverter()->process();
|
||||
|
||||
//save database meta to a file espoMetadata.php
|
||||
$result = $this->getMetadata()->setOrmMetadata($ormMeta);
|
||||
|
||||
$GLOBALS['log']->add('Debug', 'Orm\Converter - End: orm convertation, result=['.$result.']');
|
||||
$GLOBALS['log']->debug('Orm\Converter - End: orm convertation, result=['.$result.']');
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ class Converter
|
||||
foreach($entityDefs as $entityName => $entityMeta) {
|
||||
|
||||
if (empty($entityMeta)) {
|
||||
$GLOBALS['log']->add('ERROR', 'Orm\Converter:process(), Entity:'.$entityName.' - metadata cannot be converted into ORM format');
|
||||
$GLOBALS['log']->critical('Orm\Converter:process(), Entity:'.$entityName.' - metadata cannot be converted into ORM format');
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -264,7 +264,7 @@ class Converter
|
||||
{
|
||||
//set default type if exists
|
||||
if (!isset($fieldParams['type']) || empty($fieldParams['type'])) {
|
||||
$GLOBALS['log']->add('WARNING', 'Field type does not exist for '.$entityName.':'.$fieldName.'. Use default type ['.$this->defaultFieldType.']');
|
||||
$GLOBALS['log']->warning('Field type does not exist for '.$entityName.':'.$fieldName.'. Use default type ['.$this->defaultFieldType.']');
|
||||
$fieldParams['type'] = $this->defaultFieldType;
|
||||
} //END: set default type if exists
|
||||
|
||||
@@ -321,7 +321,7 @@ class Converter
|
||||
if (trim($subFieldName) == '') {
|
||||
|
||||
if (!isset($fieldTypeMeta['database'])) {
|
||||
$GLOBALS['log']->add('EXCEPTION', 'Empty field defs for ['.$entityName.':'.$fieldName.'] using "actualFields". Main field ['.$fieldName.']');
|
||||
$GLOBALS['log']->critical('Empty field defs for ['.$entityName.':'.$fieldName.'] using "actualFields". Main field ['.$fieldName.']');
|
||||
}
|
||||
|
||||
$subField['name'] = $fieldName;
|
||||
@@ -333,7 +333,7 @@ class Converter
|
||||
} else {
|
||||
|
||||
if (!isset($fieldTypeMeta['fields'][$subFieldName])) {
|
||||
$GLOBALS['log']->add('EXCEPTION', 'Empty field defs for ['.$entityName.':'.$subFieldName.'] using "actualFields". Main field ['.$fieldName.']');
|
||||
$GLOBALS['log']->critical('Empty field defs for ['.$entityName.':'.$subFieldName.'] using "actualFields". Main field ['.$fieldName.']');
|
||||
}
|
||||
|
||||
$namingType = isset($fieldTypeMeta['naming']) ? $fieldTypeMeta['naming'] : $this->defaultNaming;
|
||||
|
||||
@@ -64,7 +64,7 @@ class Converter
|
||||
|
||||
public function process(array $ormMeta, $entityDefs)
|
||||
{
|
||||
$GLOBALS['log']->add('Debug', 'Schema\Converter - Start: building schema');
|
||||
$GLOBALS['log']->debug('Schema\Converter - Start: building schema');
|
||||
|
||||
//check if exist files in "Tables" directory and merge with ormMetadata
|
||||
$ormMeta = Util::merge($ormMeta, $this->getCustomTables());
|
||||
@@ -100,7 +100,7 @@ class Converter
|
||||
|
||||
$fieldType = isset($fieldParams['dbType']) ? $fieldParams['dbType'] : $fieldParams['type'];
|
||||
if (!in_array($fieldType, $this->typeList)) {
|
||||
$GLOBALS['log']->add('DEBUG', 'Converters\Schema::process(): Field type ['.$fieldType.'] does not exist '.$entityName.':'.$fieldName);
|
||||
$GLOBALS['log']->debug('Converters\Schema::process(): Field type ['.$fieldType.'] does not exist '.$entityName.':'.$fieldName);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ class Converter
|
||||
//END: check and create columns/tables for relations
|
||||
|
||||
|
||||
$GLOBALS['log']->add('Debug', 'Schema\Converter - End: building schema');
|
||||
$GLOBALS['log']->debug('Schema\Converter - End: building schema');
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
@@ -175,11 +175,11 @@ class Schema
|
||||
$result = true;
|
||||
$connection = $this->getConnection();
|
||||
foreach ($queries as $sql) {
|
||||
$GLOBALS['log']->add('DEBUG', 'SCHEMA, Execute Query: '.$sql);
|
||||
$GLOBALS['log']->debug('SCHEMA, Execute Query: '.$sql);
|
||||
try {
|
||||
$result &= (bool) $connection->executeQuery($sql);
|
||||
} catch (\Exception $e) {
|
||||
$GLOBALS['log']->add('EXCEPTION', 'Rebuild database fault: '.$e);
|
||||
$GLOBALS['log']->alert('Rebuild database fault: '.$e);
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,7 +308,7 @@ class Manager
|
||||
$dirPermission= is_string($dirPermission) ? base_convert($dirPermission,8,10) : $dirPermission;
|
||||
|
||||
if (!mkdir($pathParts['dirname'], $dirPermission, true)) {
|
||||
$GLOBALS['log']->add('FATAL', 'Permission denied: unable to generate a folder on the server - '.$pathParts['dirname']);
|
||||
$GLOBALS['log']->critical('Permission denied: unable to generate a folder on the server - '.$pathParts['dirname']);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ class Unifier
|
||||
$decoded= Utils\Json::getArrayData($fileContent);
|
||||
|
||||
if (empty($decoded) && !is_array($decoded)) {
|
||||
$GLOBALS['log']->add('FATAL EXCEPTION', 'Syntax error or empty file - '.Utils\Util::concatPath($folderPath, $fileName));
|
||||
$GLOBALS['log']->emergency('Syntax error or empty file - '.Utils\Util::concatPath($folderPath, $fileName));
|
||||
} else {
|
||||
//Default values
|
||||
if (is_string($defaults) && !empty($defaults)) {
|
||||
|
||||
@@ -31,12 +31,10 @@ class Json
|
||||
}
|
||||
|
||||
if ($json===null) {
|
||||
$GLOBALS['log']->add('ERROR', 'Value cannot be decoded to JSON - '.print_r($value, true));
|
||||
$GLOBALS['log']->error('Value cannot be decoded to JSON - '.print_r($value, true));
|
||||
}
|
||||
|
||||
return $json;
|
||||
|
||||
//JSON_PRETTY_PRINT
|
||||
return $json;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,14 +49,10 @@ class Json
|
||||
public static function decode($json, $assoc = false, $depth = 512, $options = 0)
|
||||
{
|
||||
if (is_array($json)) {
|
||||
$GLOBALS['log']->add('WARNING', 'JSON:decode() - JSON cannot be decoded - '.$json);
|
||||
$GLOBALS['log']->warning('JSON:decode() - JSON cannot be decoded - '.$json);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*if (strstr($json, '\\') && !strstr($json, '(\\')) {
|
||||
$json = preg_replace('/([^\\\])(\\\)([^\/\\\])/', '$1\\\\\\\$3', $json);
|
||||
} */
|
||||
|
||||
if(version_compare(phpversion(), '5.4.0', '>=')) {
|
||||
$json = json_decode($json, $assoc, $depth, $options);
|
||||
}
|
||||
@@ -69,11 +63,6 @@ class Json
|
||||
$json = json_decode($json, $assoc);
|
||||
}
|
||||
|
||||
/*if ($json===null) {
|
||||
$Log= new Utils\Log();
|
||||
$Log->add('WARNING', 'JSON:decode() - JSON string cannot be decoded - '.$json);
|
||||
}*/
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,250 +2,28 @@
|
||||
|
||||
namespace Espo\Core\Utils;
|
||||
|
||||
class Log
|
||||
class Log extends \Monolog\Logger
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string $defaultLevel - default level, uses only if level is not defined by user
|
||||
*/
|
||||
public $defaultLevel = 'INFO';
|
||||
|
||||
/**
|
||||
* @var array $errorLevels
|
||||
* @link http://www.php.net/manual/en/errorfunc.constants.php
|
||||
*/
|
||||
protected $errorLevels = array (
|
||||
'FATAL EXCEPTION' => -1,
|
||||
'EXCEPTION' => 0,
|
||||
'FATAL' => 1,
|
||||
'WARNING' => 2,
|
||||
'NOTICE' => 8,
|
||||
'ERROR' => 32767,
|
||||
'INFO' => 50000,
|
||||
'DEBUG' => 55000,
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array $phpErrorTypes
|
||||
*/
|
||||
protected $phpErrorTypes = array (
|
||||
-1 => 'FATAL EXCEPTION',
|
||||
0 => 'EXCEPTION',
|
||||
E_ERROR => 'FATAL',
|
||||
E_WARNING => 'WARNING',
|
||||
E_PARSE => 'PARSE',
|
||||
E_NOTICE => 'NOTICE',
|
||||
E_CORE_ERROR => 'CORE_ERROR',
|
||||
E_CORE_WARNING => 'CORE_WARNING',
|
||||
E_COMPILE_ERROR => 'COMPILE_ERROR',
|
||||
E_COMPILE_WARNING => 'COMPILE_WARNING',
|
||||
E_STRICT => 'STRICT',
|
||||
E_RECOVERABLE_ERROR => 'RECOVERABLE',
|
||||
E_DEPRECATED => 'DEPRECATED',
|
||||
E_USER_ERROR => 'USER_ERROR',
|
||||
E_USER_WARNING => 'USER_WARNING',
|
||||
E_USER_NOTICE => 'USER_NOTICE',
|
||||
E_USER_DEPRECATED => 'USER_DEPRECATED',
|
||||
);
|
||||
|
||||
/*
|
||||
* @var array $dieErrors - errors when should stop program execution
|
||||
*/
|
||||
protected $dieErrors = array (
|
||||
'FATAL EXCEPTION',
|
||||
'FATAL',
|
||||
);
|
||||
|
||||
|
||||
private $fileManager;
|
||||
private $output;
|
||||
private $params;
|
||||
|
||||
protected $logFilePath;
|
||||
|
||||
|
||||
public function __construct(\Espo\Core\Utils\File\Manager $fileManager, \Espo\Core\Utils\Api\Output $output, array $params)
|
||||
{
|
||||
$this->fileManager = $fileManager;
|
||||
$this->output = $output;
|
||||
$this->params = $params;
|
||||
|
||||
$this->logFilePath = Util::concatPath($params['options']['dir'], $params['options']['file']);
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected function getFileManager()
|
||||
{
|
||||
return $this->fileManager;
|
||||
}
|
||||
|
||||
protected function getOutput()
|
||||
{
|
||||
return $this->output;
|
||||
}
|
||||
|
||||
protected function getParams()
|
||||
{
|
||||
return $this->params;
|
||||
}
|
||||
protected $defaultLevelName = 'DEBUG';
|
||||
|
||||
|
||||
/**
|
||||
* Catch error and save it to the log file
|
||||
*
|
||||
* @param integer $errNo - the level of the error
|
||||
* @param string $errStr - the error message
|
||||
* @param string $errFile - the filename that the error was raised in
|
||||
* @param integer $errLine - the line number the error was raised at
|
||||
* @return bool
|
||||
*/
|
||||
function catchError($errNo, $errStr, $errFile, $errLine)
|
||||
* Get Level Code
|
||||
* @param string $level Ex. DEBUG, ...
|
||||
* @return int
|
||||
*/
|
||||
public function getLevelCode($levelName)
|
||||
{
|
||||
$errorType = $this->phpErrorTypes[$errNo];
|
||||
if (empty($errorType)) {
|
||||
$errorType = $errNo;
|
||||
}
|
||||
$errorMessage = $errStr . " - " . $errFile . ":" . $errLine;
|
||||
$levelName = strtoupper($levelName);
|
||||
|
||||
return $this->add($errorType, $errorMessage);
|
||||
}
|
||||
$levels = $this->getLevels();
|
||||
|
||||
/**
|
||||
* Catch exeption and save it to the log file
|
||||
*
|
||||
* @param integer $Exception
|
||||
* @return bool
|
||||
*/
|
||||
public function catchException($Exception)
|
||||
{
|
||||
$errNo = $Exception->getCode();
|
||||
$errorMessage = get_class($Exception).' - '.$Exception->getMessage();
|
||||
if (isset($levels[$levelName])) {
|
||||
return $levels[$levelName];
|
||||
}
|
||||
|
||||
//try to resolve the problem automatically
|
||||
/*if ($useResolver) {
|
||||
$this->getResolver()->handle($Exception);
|
||||
} */
|
||||
|
||||
$errorType= $this->phpErrorTypes[$errNo];
|
||||
if (empty($errorType)) {
|
||||
$errorType= $errNo;
|
||||
}
|
||||
|
||||
return $this->add($errorType, $errorMessage);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Saved error to the file
|
||||
*
|
||||
* @param string $text
|
||||
* @return bool
|
||||
*/
|
||||
protected function logError($text)
|
||||
{
|
||||
$text = date('Y-m-d H:i:s') . ' ' . $text;
|
||||
|
||||
$params = $this->getParams();
|
||||
return $this->getFileManager()->appendContents($this->logFilePath, $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add custom item to the log file
|
||||
*
|
||||
* @param string $errorType
|
||||
* @param string $text
|
||||
* @return bool
|
||||
*/
|
||||
public function add($errorType, $text='')
|
||||
{
|
||||
if (empty($text)) {
|
||||
$text = $errorType;
|
||||
$errorType = '';
|
||||
}
|
||||
if (!empty($errorType)){
|
||||
$errorType = mb_strtoupper($errorType);
|
||||
}
|
||||
|
||||
$text = "[".$errorType."]: ".$text."\n";
|
||||
|
||||
//CHECK Levels here
|
||||
$status = true;
|
||||
if ($this->isSave($errorType)) {
|
||||
$status = $this->logError($text);
|
||||
}
|
||||
|
||||
if (in_array($errorType, $this->dieErrors)) {
|
||||
$this->getOutput()->displayError($text, 500);
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if save the error to log file according to error level
|
||||
*
|
||||
* @param string $errorType
|
||||
* @return bool
|
||||
*/
|
||||
protected function isSave($errorType)
|
||||
{
|
||||
$params = $this->getParams();
|
||||
$configLevel= $this->getLevelValue($params['options']['level']);
|
||||
$errorLevel= $this->getLevelValue($errorType);
|
||||
|
||||
if ($configLevel >= $errorLevel) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get Level value (int) from the name
|
||||
*
|
||||
* @param string $errorName
|
||||
* @return int
|
||||
*/
|
||||
function getLevelValue($name)
|
||||
{
|
||||
if (empty($name)) {
|
||||
return $this->errorLevels[$this->defaultLevel];
|
||||
}
|
||||
|
||||
if (is_int($name)) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
$name= mb_strtoupper($name);
|
||||
$levelValue= $this->errorLevels[$this->defaultLevel];
|
||||
|
||||
//check into errorLevels
|
||||
if (array_key_exists($name, $this->errorLevels)) {
|
||||
return $this->errorLevels[$name];
|
||||
}
|
||||
|
||||
//check into phpErrorTypes
|
||||
if (in_array($name, $this->phpErrorTypes)) {
|
||||
foreach($this->phpErrorTypes as $key => $val) {
|
||||
if ($name==$val) {
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->errorLevels[$this->defaultLevel];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Level name from the int value
|
||||
*
|
||||
* @param int $intValue
|
||||
* @return string
|
||||
*/
|
||||
function getLevelName($intValue)
|
||||
{
|
||||
|
||||
}
|
||||
return $levels[$this->defaultLevelName];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ class Metadata
|
||||
{
|
||||
$data = $this->getMetadataOnly(false, $reload);
|
||||
if ($data === false) {
|
||||
$GLOBALS['log']->add('FATAL', 'Metadata:init() - metadata has not been created');
|
||||
$GLOBALS['log']->emergency('Metadata:init() - metadata has not been created');
|
||||
}
|
||||
|
||||
$this->meta = $data;
|
||||
@@ -96,7 +96,7 @@ class Metadata
|
||||
//save medatada to a cache file
|
||||
$isSaved = $this->getFileManager()->putContentsPHP($this->cacheFile, $data);
|
||||
if ($isSaved === false) {
|
||||
$GLOBALS['log']->add('FATAL', 'Metadata:init() - metadata has not been saved to a cache file');
|
||||
$GLOBALS['log']->emergency('Metadata:init() - metadata has not been saved to a cache file');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,7 +167,7 @@ class Metadata
|
||||
$data = $this->getUnifier()->unify($this->name, $this->paths, true);
|
||||
|
||||
if ($data === false) {
|
||||
$GLOBALS['log']->add('FATAL', 'Metadata:getMetadata() - metadata unite file cannot be created');
|
||||
$GLOBALS['log']->emergency('Metadata:getMetadata() - metadata unite file cannot be created');
|
||||
}
|
||||
}
|
||||
else if (file_exists($this->cacheFile)) {
|
||||
@@ -226,9 +226,8 @@ class Metadata
|
||||
public function setOrmMetadata(array $ormMeta)
|
||||
{
|
||||
$result = $this->getFileManager()->putContentsPHP($this->ormCacheFile, $ormMeta);
|
||||
if ($result == false) {
|
||||
$GLOBALS['log']->add('EXCEPTION', 'Metadata::setOrmMetadata() - Cannot save ormMetadata to a file');
|
||||
throw new \Espo\Core\Exceptions\Error();
|
||||
if ($result == false) {
|
||||
throw new \Espo\Core\Exceptions\Error('Metadata::setOrmMetadata() - Cannot save ormMetadata to a file');
|
||||
}
|
||||
|
||||
$this->ormMeta = $ormMeta;
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Core\Utils;
|
||||
|
||||
|
||||
class Resolver
|
||||
{
|
||||
protected $exceptions = array(
|
||||
'Doctrine\DBAL\DBALException' => 'DBALException',
|
||||
'ReflectionException' => 'ReflectionException',
|
||||
);
|
||||
|
||||
private $metadata;
|
||||
|
||||
|
||||
public function __construct(\Espo\Core\Utils\Metadata $metadata)
|
||||
{
|
||||
$this->metadata = $metadata;
|
||||
}
|
||||
|
||||
|
||||
protected function getMetadata()
|
||||
{
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
|
||||
public function handle($Exception)
|
||||
{
|
||||
$handler= get_class($Exception);
|
||||
$trace= $Exception->getTrace();
|
||||
$args= array();
|
||||
if (is_array($trace[0]['args'])) {
|
||||
$args= $trace[0]['args'];
|
||||
}
|
||||
|
||||
if (in_array($handler, array_keys($this->exceptions))) {
|
||||
$method= $this->exceptions[$handler];
|
||||
|
||||
$GLOBALS['log']->add('INFO', 'Try to resolve the exception - '.$handler);
|
||||
$result= false;
|
||||
try {
|
||||
$result= $this->$method($args);
|
||||
} catch(\Exception $e) {
|
||||
$GLOBALS['log']->add('INFO', 'Could not resolve the exception - '.$handler.'. Details below:');
|
||||
$GLOBALS['log']->catchException($e, false);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
protected function DBALException($args)
|
||||
{
|
||||
return $this->getMetadata()->getDoctrineConverter()->rebuildDatabase();
|
||||
}
|
||||
|
||||
protected function ReflectionException($args)
|
||||
{
|
||||
return $this->getMetadata()->getDoctrineConverter()->generateEntities($args);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -68,9 +68,8 @@ class Route
|
||||
$this->data = $this->unify();
|
||||
|
||||
$result = $this->getFileManager()->putContentsPHP($this->cacheFile, $this->data);
|
||||
if ($result == false) {
|
||||
$GLOBALS['log']->add('EXCEPTION', 'Route::init() - Cannot save Routes to a file');
|
||||
throw new \Espo\Core\Exceptions\Error();
|
||||
if ($result == false) {
|
||||
throw new \Espo\Core\Exceptions\Error('Route - Cannot save unified routes');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,7 +110,7 @@ class Route
|
||||
$content= $this->getFileManager()->getContents($routeFile);
|
||||
$arrayContent = Json::getArrayData($content);
|
||||
if (empty($arrayContent)) {
|
||||
$GLOBALS['log']->add('ERROR', 'Route::unify() - Empty file or syntax error - ['.$routeFile.']');
|
||||
$GLOBALS['log']->error('Route::unify() - Empty file or syntax error - ['.$routeFile.']');
|
||||
return $currData;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,12 +5,12 @@ return array (
|
||||
|
||||
'cachePath' => 'data/cache',
|
||||
|
||||
'languageConfig' =>
|
||||
'logger' =>
|
||||
array (
|
||||
'name' => '{lang}',
|
||||
'cachePath' => 'data/cache/application/Language',
|
||||
'corePath' => 'application/Espo/Language',
|
||||
'customPath' => 'application/Espo/Modules/{*}/Language',
|
||||
'path' => 'data/logs/espo.log',
|
||||
'level' => 'DEBUG', /*DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, EMERGENCY*/
|
||||
'isRotate' => true, /*rotate every day every logs files*/
|
||||
'maxRotateFiles' => 60, /*max number of rorate files*/
|
||||
),
|
||||
|
||||
'defaultPermissions' =>
|
||||
@@ -49,7 +49,6 @@ return array (
|
||||
'adminItems',
|
||||
'configPath',
|
||||
'cachePath',
|
||||
'languageConfig',
|
||||
'database',
|
||||
'crud',
|
||||
),
|
||||
|
||||
+2
-1
@@ -4,7 +4,8 @@
|
||||
"slim/slim": "2.*",
|
||||
"mtdowling/cron-expression": "1.0.*",
|
||||
"zendframework/zend-validator": "2.*",
|
||||
"zendframework/zend-mail": "2.*"
|
||||
"zendframework/zend-mail": "2.*",
|
||||
"monolog/monolog": "1.*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
|
||||
Generated
+144
-37
@@ -3,7 +3,7 @@
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
|
||||
],
|
||||
"hash": "878029eeb6e84ef1ad4f900e1823a0b8",
|
||||
"hash": "c4c250c119f9692633b36265cd867581",
|
||||
"packages": [
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
@@ -153,16 +153,16 @@
|
||||
},
|
||||
{
|
||||
"name": "doctrine/collections",
|
||||
"version": "v1.1",
|
||||
"version": "v1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/collections.git",
|
||||
"reference": "560f29c39cfcfbcd210e5d549d993a39d898b04b"
|
||||
"reference": "b99c5c46c87126201899afe88ec490a25eedd6a2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/collections/zipball/560f29c39cfcfbcd210e5d549d993a39d898b04b",
|
||||
"reference": "560f29c39cfcfbcd210e5d549d993a39d898b04b",
|
||||
"url": "https://api.github.com/repos/doctrine/collections/zipball/b99c5c46c87126201899afe88ec490a25eedd6a2",
|
||||
"reference": "b99c5c46c87126201899afe88ec490a25eedd6a2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -171,7 +171,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.1.x-dev"
|
||||
"dev-master": "1.2.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -217,7 +217,7 @@
|
||||
"collections",
|
||||
"iterator"
|
||||
],
|
||||
"time": "2013-03-07 12:15:54"
|
||||
"time": "2014-02-03 23:07:43"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/common",
|
||||
@@ -476,6 +476,73 @@
|
||||
],
|
||||
"time": "2013-01-12 18:59:04"
|
||||
},
|
||||
{
|
||||
"name": "monolog/monolog",
|
||||
"version": "1.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Seldaek/monolog.git",
|
||||
"reference": "6225b22de9dcf36546be3a0b2fa8e3d986153f57"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/6225b22de9dcf36546be3a0b2fa8e3d986153f57",
|
||||
"reference": "6225b22de9dcf36546be3a0b2fa8e3d986153f57",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0",
|
||||
"psr/log": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"aws/aws-sdk-php": "~2.4.8",
|
||||
"doctrine/couchdb": "dev-master",
|
||||
"mlehner/gelf-php": "1.0.*",
|
||||
"phpunit/phpunit": "~3.7.0",
|
||||
"raven/raven": "0.5.*",
|
||||
"ruflin/elastica": "0.90.*"
|
||||
},
|
||||
"suggest": {
|
||||
"aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
|
||||
"doctrine/couchdb": "Allow sending log messages to a CouchDB server",
|
||||
"ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
|
||||
"ext-mongo": "Allow sending log messages to a MongoDB server",
|
||||
"mlehner/gelf-php": "Allow sending log messages to a GrayLog2 server",
|
||||
"raven/raven": "Allow sending log messages to a Sentry server",
|
||||
"ruflin/elastica": "Allow sending log messages to an Elastic Search server"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.7.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Monolog": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jordi Boggiano",
|
||||
"email": "j.boggiano@seld.be",
|
||||
"homepage": "http://seld.be",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Sends your logs to files, sockets, inboxes, databases and various web services",
|
||||
"homepage": "http://github.com/Seldaek/monolog",
|
||||
"keywords": [
|
||||
"log",
|
||||
"logging",
|
||||
"psr-3"
|
||||
],
|
||||
"time": "2013-11-14 19:48:31"
|
||||
},
|
||||
{
|
||||
"name": "mtdowling/cron-expression",
|
||||
"version": "v1.0.3",
|
||||
@@ -518,17 +585,55 @@
|
||||
"time": "2013-11-23 19:48:39"
|
||||
},
|
||||
{
|
||||
"name": "slim/slim",
|
||||
"version": "2.4.0",
|
||||
"name": "psr/log",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/codeguy/Slim.git",
|
||||
"reference": "ff7d7148848fa4f45712984d7b91ac3cbced586b"
|
||||
"url": "https://github.com/php-fig/log.git",
|
||||
"reference": "fe0936ee26643249e916849d48e3a51d5f5e278b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/codeguy/Slim/zipball/ff7d7148848fa4f45712984d7b91ac3cbced586b",
|
||||
"reference": "ff7d7148848fa4f45712984d7b91ac3cbced586b",
|
||||
"url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b",
|
||||
"reference": "fe0936ee26643249e916849d48e3a51d5f5e278b",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Psr\\Log\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "http://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for logging libraries",
|
||||
"keywords": [
|
||||
"log",
|
||||
"psr",
|
||||
"psr-3"
|
||||
],
|
||||
"time": "2012-12-21 11:40:51"
|
||||
},
|
||||
{
|
||||
"name": "slim/slim",
|
||||
"version": "2.4.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/codeguy/Slim.git",
|
||||
"reference": "3a2ac723f17b5d81607287ff28575d38b9fbc70e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/codeguy/Slim/zipball/3a2ac723f17b5d81607287ff28575d38b9fbc70e",
|
||||
"reference": "3a2ac723f17b5d81607287ff28575d38b9fbc70e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -561,7 +666,7 @@
|
||||
"rest",
|
||||
"router"
|
||||
],
|
||||
"time": "2013-11-29 20:33:36"
|
||||
"time": "2014-02-16 18:18:25"
|
||||
},
|
||||
{
|
||||
"name": "zendframework/zend-crypt",
|
||||
@@ -927,22 +1032,22 @@
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "1.2.13",
|
||||
"version": "1.2.15",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "466e7cd2554b4e264c9e3f31216d25ac0e5f3d94"
|
||||
"reference": "6ba4ed2895d538a039d5d5866edc4ec0424c7852"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/466e7cd2554b4e264c9e3f31216d25ac0e5f3d94",
|
||||
"reference": "466e7cd2554b4e264c9e3f31216d25ac0e5f3d94",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6ba4ed2895d538a039d5d5866edc4ec0424c7852",
|
||||
"reference": "6ba4ed2895d538a039d5d5866edc4ec0424c7852",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"phpunit/php-file-iterator": ">=1.3.0@stable",
|
||||
"phpunit/php-text-template": ">=1.1.1@stable",
|
||||
"phpunit/php-text-template": ">=1.2.0@stable",
|
||||
"phpunit/php-token-stream": ">=1.1.3@stable"
|
||||
},
|
||||
"require-dev": {
|
||||
@@ -984,7 +1089,7 @@
|
||||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2013-09-10 08:14:32"
|
||||
"time": "2014-02-03 07:44:47"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
@@ -1033,16 +1138,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-text-template",
|
||||
"version": "1.1.4",
|
||||
"version": "1.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/sebastianbergmann/php-text-template.git",
|
||||
"reference": "1.1.4"
|
||||
"url": "https://github.com/sebastianbergmann/php-text-template.git",
|
||||
"reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://github.com/sebastianbergmann/php-text-template/zipball/1.1.4",
|
||||
"reference": "1.1.4",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a",
|
||||
"reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1073,7 +1178,7 @@
|
||||
"keywords": [
|
||||
"template"
|
||||
],
|
||||
"time": "2012-10-31 11:15:28"
|
||||
"time": "2014-01-30 17:20:04"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-timer",
|
||||
@@ -1171,16 +1276,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "3.7.29",
|
||||
"version": "3.7.31",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "faeb2d9f15dc83830d2db5e4c67acf1d68c9b5ac"
|
||||
"reference": "d24e9877331039582497052cc3c4d9f465b88210"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/faeb2d9f15dc83830d2db5e4c67acf1d68c9b5ac",
|
||||
"reference": "faeb2d9f15dc83830d2db5e4c67acf1d68c9b5ac",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d24e9877331039582497052cc3c4d9f465b88210",
|
||||
"reference": "d24e9877331039582497052cc3c4d9f465b88210",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1241,7 +1346,7 @@
|
||||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2014-01-15 06:46:38"
|
||||
"time": "2014-02-03 07:46:27"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit-mock-objects",
|
||||
@@ -1294,17 +1399,17 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v2.4.1",
|
||||
"version": "v2.4.2",
|
||||
"target-dir": "Symfony/Component/Yaml",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Yaml.git",
|
||||
"reference": "4e1a237fc48145fae114b96458d799746ad89aa0"
|
||||
"reference": "bb6ddaf8956139d1b8c360b4b713ed0138e876b3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Yaml/zipball/4e1a237fc48145fae114b96458d799746ad89aa0",
|
||||
"reference": "4e1a237fc48145fae114b96458d799746ad89aa0",
|
||||
"url": "https://api.github.com/repos/symfony/Yaml/zipball/bb6ddaf8956139d1b8c360b4b713ed0138e876b3",
|
||||
"reference": "bb6ddaf8956139d1b8c360b4b713ed0138e876b3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1328,7 +1433,9 @@
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
"email": "fabien@symfony.com",
|
||||
"homepage": "http://fabien.potencier.org",
|
||||
"role": "Lead Developer"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
@@ -1337,7 +1444,7 @@
|
||||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "http://symfony.com",
|
||||
"time": "2013-12-28 08:12:03"
|
||||
"time": "2014-01-07 13:28:54"
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
|
||||
Regular → Executable
BIN
Binary file not shown.
Vendored
+1
-1
@@ -4,4 +4,4 @@
|
||||
|
||||
require_once __DIR__ . '/composer' . '/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInit2d878a0f509f5555709d4ce72e116d30::getLoader();
|
||||
return ComposerAutoloaderInit838748678582ba23758384df47dd5301::getLoader();
|
||||
|
||||
Vendored
+11
-1
@@ -266,7 +266,7 @@ class ClassLoader
|
||||
public function loadClass($class)
|
||||
{
|
||||
if ($file = $this->findFile($class)) {
|
||||
include $file;
|
||||
includeFile($file);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -352,3 +352,13 @@ class ClassLoader
|
||||
return $this->classMap[$class] = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope isolated include.
|
||||
*
|
||||
* Prevents access to $this/self from included files.
|
||||
*/
|
||||
function includeFile($file)
|
||||
{
|
||||
include $file;
|
||||
}
|
||||
|
||||
+2
@@ -17,6 +17,8 @@ return array(
|
||||
'Zend\\Crypt\\' => array($vendorDir . '/zendframework/zend-crypt'),
|
||||
'Symfony\\Component\\Yaml\\' => array($vendorDir . '/symfony/yaml'),
|
||||
'Slim' => array($vendorDir . '/slim/slim'),
|
||||
'Psr\\Log\\' => array($vendorDir . '/psr/log'),
|
||||
'Monolog' => array($vendorDir . '/monolog/monolog/src'),
|
||||
'Doctrine\\DBAL\\' => array($vendorDir . '/doctrine/dbal/lib'),
|
||||
'Doctrine\\Common\\Lexer\\' => array($vendorDir . '/doctrine/lexer/lib'),
|
||||
'Doctrine\\Common\\Inflector\\' => array($vendorDir . '/doctrine/inflector/lib'),
|
||||
|
||||
Vendored
+8
-3
@@ -2,7 +2,7 @@
|
||||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInit2d878a0f509f5555709d4ce72e116d30
|
||||
class ComposerAutoloaderInit838748678582ba23758384df47dd5301
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
@@ -19,9 +19,9 @@ class ComposerAutoloaderInit2d878a0f509f5555709d4ce72e116d30
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInit2d878a0f509f5555709d4ce72e116d30', 'loadClassLoader'), true, true);
|
||||
spl_autoload_register(array('ComposerAutoloaderInit838748678582ba23758384df47dd5301', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit2d878a0f509f5555709d4ce72e116d30', 'loadClassLoader'));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit838748678582ba23758384df47dd5301', 'loadClassLoader'));
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
@@ -50,3 +50,8 @@ class ComposerAutoloaderInit2d878a0f509f5555709d4ce72e116d30
|
||||
return $loader;
|
||||
}
|
||||
}
|
||||
|
||||
function composerRequire838748678582ba23758384df47dd5301($file)
|
||||
{
|
||||
require $file;
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -6,11 +6,11 @@ $vendorDir = dirname(dirname(__FILE__));
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
||||
return array(
|
||||
$vendorDir . '/phpunit/php-text-template',
|
||||
$vendorDir . '/phpunit/phpunit-mock-objects',
|
||||
$vendorDir . '/phpunit/php-timer',
|
||||
$vendorDir . '/phpunit/php-token-stream',
|
||||
$vendorDir . '/phpunit/php-file-iterator',
|
||||
$vendorDir . '/phpunit/php-text-template',
|
||||
$vendorDir . '/phpunit/php-code-coverage',
|
||||
$vendorDir . '/phpunit/phpunit',
|
||||
$vendorDir . '/symfony/yaml',
|
||||
|
||||
Vendored
+463
-352
@@ -1,50 +1,4 @@
|
||||
[
|
||||
{
|
||||
"name": "phpunit/php-text-template",
|
||||
"version": "1.1.4",
|
||||
"version_normalized": "1.1.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/sebastianbergmann/php-text-template.git",
|
||||
"reference": "1.1.4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://github.com/sebastianbergmann/php-text-template/zipball/1.1.4",
|
||||
"reference": "1.1.4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"time": "2012-10-31 11:15:28",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"Text/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"include-path": [
|
||||
""
|
||||
],
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sb@sebastian-bergmann.de",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "Simple template engine.",
|
||||
"homepage": "https://github.com/sebastianbergmann/php-text-template/",
|
||||
"keywords": [
|
||||
"template"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit-mock-objects",
|
||||
"version": "1.2.3",
|
||||
@@ -270,76 +224,6 @@
|
||||
"parser"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "doctrine/collections",
|
||||
"version": "v1.1",
|
||||
"version_normalized": "1.1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/collections.git",
|
||||
"reference": "560f29c39cfcfbcd210e5d549d993a39d898b04b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/collections/zipball/560f29c39cfcfbcd210e5d549d993a39d898b04b",
|
||||
"reference": "560f29c39cfcfbcd210e5d549d993a39d898b04b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.2"
|
||||
},
|
||||
"time": "2013-03-07 12:15:54",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.1.x-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Doctrine\\Common\\Collections\\": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com",
|
||||
"homepage": "http://www.jwage.com/",
|
||||
"role": "Creator"
|
||||
},
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com",
|
||||
"homepage": "http://www.instaclick.com"
|
||||
},
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de"
|
||||
},
|
||||
{
|
||||
"name": "Johannes Schmitt",
|
||||
"email": "schmittjoh@gmail.com",
|
||||
"homepage": "http://jmsyst.com",
|
||||
"role": "Developer of wrapped JMSSerializerBundle"
|
||||
}
|
||||
],
|
||||
"description": "Collections Abstraction library",
|
||||
"homepage": "http://www.doctrine-project.org",
|
||||
"keywords": [
|
||||
"array",
|
||||
"collections",
|
||||
"iterator"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "doctrine/cache",
|
||||
"version": "v1.3.0",
|
||||
@@ -658,242 +542,6 @@
|
||||
"iterator"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "1.2.13",
|
||||
"version_normalized": "1.2.13.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "466e7cd2554b4e264c9e3f31216d25ac0e5f3d94"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/466e7cd2554b4e264c9e3f31216d25ac0e5f3d94",
|
||||
"reference": "466e7cd2554b4e264c9e3f31216d25ac0e5f3d94",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"phpunit/php-file-iterator": ">=1.3.0@stable",
|
||||
"phpunit/php-text-template": ">=1.1.1@stable",
|
||||
"phpunit/php-token-stream": ">=1.1.3@stable"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "3.7.*@dev"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-dom": "*",
|
||||
"ext-xdebug": ">=2.0.5"
|
||||
},
|
||||
"time": "2013-09-10 08:14:32",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.2.x-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"PHP/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"include-path": [
|
||||
""
|
||||
],
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sb@sebastian-bergmann.de",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
|
||||
"homepage": "https://github.com/sebastianbergmann/php-code-coverage",
|
||||
"keywords": [
|
||||
"coverage",
|
||||
"testing",
|
||||
"xunit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "slim/slim",
|
||||
"version": "2.4.0",
|
||||
"version_normalized": "2.4.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/codeguy/Slim.git",
|
||||
"reference": "ff7d7148848fa4f45712984d7b91ac3cbced586b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/codeguy/Slim/zipball/ff7d7148848fa4f45712984d7b91ac3cbced586b",
|
||||
"reference": "ff7d7148848fa4f45712984d7b91ac3cbced586b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mcrypt": "Required for HTTP cookie encryption"
|
||||
},
|
||||
"time": "2013-11-29 20:33:36",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Slim": "."
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Josh Lockhart",
|
||||
"email": "info@joshlockhart.com",
|
||||
"homepage": "http://www.joshlockhart.com/"
|
||||
}
|
||||
],
|
||||
"description": "Slim Framework, a PHP micro framework",
|
||||
"homepage": "http://github.com/codeguy/Slim",
|
||||
"keywords": [
|
||||
"microframework",
|
||||
"rest",
|
||||
"router"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v2.4.1",
|
||||
"version_normalized": "2.4.1.0",
|
||||
"target-dir": "Symfony/Component/Yaml",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Yaml.git",
|
||||
"reference": "4e1a237fc48145fae114b96458d799746ad89aa0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Yaml/zipball/4e1a237fc48145fae114b96458d799746ad89aa0",
|
||||
"reference": "4e1a237fc48145fae114b96458d799746ad89aa0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"time": "2013-12-28 08:12:03",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.4-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Symfony\\Component\\Yaml\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "http://symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "3.7.29",
|
||||
"version_normalized": "3.7.29.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "faeb2d9f15dc83830d2db5e4c67acf1d68c9b5ac"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/faeb2d9f15dc83830d2db5e4c67acf1d68c9b5ac",
|
||||
"reference": "faeb2d9f15dc83830d2db5e4c67acf1d68c9b5ac",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"ext-pcre": "*",
|
||||
"ext-reflection": "*",
|
||||
"ext-spl": "*",
|
||||
"php": ">=5.3.3",
|
||||
"phpunit/php-code-coverage": "~1.2.1",
|
||||
"phpunit/php-file-iterator": ">=1.3.1",
|
||||
"phpunit/php-text-template": ">=1.1.1",
|
||||
"phpunit/php-timer": ">=1.0.4",
|
||||
"phpunit/phpunit-mock-objects": "~1.2.0",
|
||||
"symfony/yaml": "~2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"pear-pear/pear": "1.9.4"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-json": "*",
|
||||
"ext-simplexml": "*",
|
||||
"ext-tokenizer": "*",
|
||||
"phpunit/php-invoker": ">=1.1.0,<1.2.0"
|
||||
},
|
||||
"time": "2014-01-15 06:46:38",
|
||||
"bin": [
|
||||
"composer/bin/phpunit"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.7.x-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"PHPUnit/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"include-path": [
|
||||
"",
|
||||
"../../symfony/yaml/"
|
||||
],
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "The PHP Unit Testing framework.",
|
||||
"homepage": "http://www.phpunit.de/",
|
||||
"keywords": [
|
||||
"phpunit",
|
||||
"testing",
|
||||
"xunit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "doctrine/dbal",
|
||||
"version": "v2.4.2",
|
||||
@@ -1380,5 +1028,468 @@
|
||||
"cron",
|
||||
"schedule"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "slim/slim",
|
||||
"version": "2.4.2",
|
||||
"version_normalized": "2.4.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/codeguy/Slim.git",
|
||||
"reference": "3a2ac723f17b5d81607287ff28575d38b9fbc70e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/codeguy/Slim/zipball/3a2ac723f17b5d81607287ff28575d38b9fbc70e",
|
||||
"reference": "3a2ac723f17b5d81607287ff28575d38b9fbc70e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mcrypt": "Required for HTTP cookie encryption"
|
||||
},
|
||||
"time": "2014-02-16 18:18:25",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Slim": "."
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Josh Lockhart",
|
||||
"email": "info@joshlockhart.com",
|
||||
"homepage": "http://www.joshlockhart.com/"
|
||||
}
|
||||
],
|
||||
"description": "Slim Framework, a PHP micro framework",
|
||||
"homepage": "http://github.com/codeguy/Slim",
|
||||
"keywords": [
|
||||
"microframework",
|
||||
"rest",
|
||||
"router"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v2.4.2",
|
||||
"version_normalized": "2.4.2.0",
|
||||
"target-dir": "Symfony/Component/Yaml",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Yaml.git",
|
||||
"reference": "bb6ddaf8956139d1b8c360b4b713ed0138e876b3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Yaml/zipball/bb6ddaf8956139d1b8c360b4b713ed0138e876b3",
|
||||
"reference": "bb6ddaf8956139d1b8c360b4b713ed0138e876b3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"time": "2014-01-07 13:28:54",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.4-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Symfony\\Component\\Yaml\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com",
|
||||
"homepage": "http://fabien.potencier.org",
|
||||
"role": "Lead Developer"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "http://symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-text-template",
|
||||
"version": "1.2.0",
|
||||
"version_normalized": "1.2.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-text-template.git",
|
||||
"reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a",
|
||||
"reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"time": "2014-01-30 17:20:04",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"Text/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"include-path": [
|
||||
""
|
||||
],
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sb@sebastian-bergmann.de",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "Simple template engine.",
|
||||
"homepage": "https://github.com/sebastianbergmann/php-text-template/",
|
||||
"keywords": [
|
||||
"template"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "1.2.15",
|
||||
"version_normalized": "1.2.15.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "6ba4ed2895d538a039d5d5866edc4ec0424c7852"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6ba4ed2895d538a039d5d5866edc4ec0424c7852",
|
||||
"reference": "6ba4ed2895d538a039d5d5866edc4ec0424c7852",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"phpunit/php-file-iterator": ">=1.3.0@stable",
|
||||
"phpunit/php-text-template": ">=1.2.0@stable",
|
||||
"phpunit/php-token-stream": ">=1.1.3@stable"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "3.7.*@dev"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-dom": "*",
|
||||
"ext-xdebug": ">=2.0.5"
|
||||
},
|
||||
"time": "2014-02-03 07:44:47",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.2.x-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"PHP/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"include-path": [
|
||||
""
|
||||
],
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sb@sebastian-bergmann.de",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
|
||||
"homepage": "https://github.com/sebastianbergmann/php-code-coverage",
|
||||
"keywords": [
|
||||
"coverage",
|
||||
"testing",
|
||||
"xunit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "3.7.31",
|
||||
"version_normalized": "3.7.31.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "d24e9877331039582497052cc3c4d9f465b88210"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d24e9877331039582497052cc3c4d9f465b88210",
|
||||
"reference": "d24e9877331039582497052cc3c4d9f465b88210",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"ext-pcre": "*",
|
||||
"ext-reflection": "*",
|
||||
"ext-spl": "*",
|
||||
"php": ">=5.3.3",
|
||||
"phpunit/php-code-coverage": "~1.2.1",
|
||||
"phpunit/php-file-iterator": ">=1.3.1",
|
||||
"phpunit/php-text-template": ">=1.1.1",
|
||||
"phpunit/php-timer": ">=1.0.4",
|
||||
"phpunit/phpunit-mock-objects": "~1.2.0",
|
||||
"symfony/yaml": "~2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"pear-pear/pear": "1.9.4"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-json": "*",
|
||||
"ext-simplexml": "*",
|
||||
"ext-tokenizer": "*",
|
||||
"phpunit/php-invoker": ">=1.1.0,<1.2.0"
|
||||
},
|
||||
"time": "2014-02-03 07:46:27",
|
||||
"bin": [
|
||||
"composer/bin/phpunit"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.7.x-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"PHPUnit/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"include-path": [
|
||||
"",
|
||||
"../../symfony/yaml/"
|
||||
],
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "The PHP Unit Testing framework.",
|
||||
"homepage": "http://www.phpunit.de/",
|
||||
"keywords": [
|
||||
"phpunit",
|
||||
"testing",
|
||||
"xunit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "doctrine/collections",
|
||||
"version": "v1.2",
|
||||
"version_normalized": "1.2.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/collections.git",
|
||||
"reference": "b99c5c46c87126201899afe88ec490a25eedd6a2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/collections/zipball/b99c5c46c87126201899afe88ec490a25eedd6a2",
|
||||
"reference": "b99c5c46c87126201899afe88ec490a25eedd6a2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.2"
|
||||
},
|
||||
"time": "2014-02-03 23:07:43",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.2.x-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Doctrine\\Common\\Collections\\": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com",
|
||||
"homepage": "http://www.jwage.com/",
|
||||
"role": "Creator"
|
||||
},
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com",
|
||||
"homepage": "http://www.instaclick.com"
|
||||
},
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de"
|
||||
},
|
||||
{
|
||||
"name": "Johannes Schmitt",
|
||||
"email": "schmittjoh@gmail.com",
|
||||
"homepage": "http://jmsyst.com",
|
||||
"role": "Developer of wrapped JMSSerializerBundle"
|
||||
}
|
||||
],
|
||||
"description": "Collections Abstraction library",
|
||||
"homepage": "http://www.doctrine-project.org",
|
||||
"keywords": [
|
||||
"array",
|
||||
"collections",
|
||||
"iterator"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "psr/log",
|
||||
"version": "1.0.0",
|
||||
"version_normalized": "1.0.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/log.git",
|
||||
"reference": "fe0936ee26643249e916849d48e3a51d5f5e278b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b",
|
||||
"reference": "fe0936ee26643249e916849d48e3a51d5f5e278b",
|
||||
"shasum": ""
|
||||
},
|
||||
"time": "2012-12-21 11:40:51",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Psr\\Log\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "http://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for logging libraries",
|
||||
"keywords": [
|
||||
"log",
|
||||
"psr",
|
||||
"psr-3"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "monolog/monolog",
|
||||
"version": "1.7.0",
|
||||
"version_normalized": "1.7.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Seldaek/monolog.git",
|
||||
"reference": "6225b22de9dcf36546be3a0b2fa8e3d986153f57"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/6225b22de9dcf36546be3a0b2fa8e3d986153f57",
|
||||
"reference": "6225b22de9dcf36546be3a0b2fa8e3d986153f57",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0",
|
||||
"psr/log": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"aws/aws-sdk-php": "~2.4.8",
|
||||
"doctrine/couchdb": "dev-master",
|
||||
"mlehner/gelf-php": "1.0.*",
|
||||
"phpunit/phpunit": "~3.7.0",
|
||||
"raven/raven": "0.5.*",
|
||||
"ruflin/elastica": "0.90.*"
|
||||
},
|
||||
"suggest": {
|
||||
"aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
|
||||
"doctrine/couchdb": "Allow sending log messages to a CouchDB server",
|
||||
"ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
|
||||
"ext-mongo": "Allow sending log messages to a MongoDB server",
|
||||
"mlehner/gelf-php": "Allow sending log messages to a GrayLog2 server",
|
||||
"raven/raven": "Allow sending log messages to a Sentry server",
|
||||
"ruflin/elastica": "Allow sending log messages to an Elastic Search server"
|
||||
},
|
||||
"time": "2013-11-14 19:48:31",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.7.x-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Monolog": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jordi Boggiano",
|
||||
"email": "j.boggiano@seld.be",
|
||||
"homepage": "http://seld.be",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Sends your logs to files, sockets, inboxes, databases and various web services",
|
||||
"homepage": "http://github.com/Seldaek/monolog",
|
||||
"keywords": [
|
||||
"log",
|
||||
"logging",
|
||||
"psr-3"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ php:
|
||||
- 5.3
|
||||
- 5.4
|
||||
- 5.5
|
||||
- hhvm
|
||||
|
||||
before_script:
|
||||
- composer --prefer-source --dev install
|
||||
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2006-2013 Doctrine Project
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+14
@@ -1,3 +1,17 @@
|
||||
# Doctrine Collections
|
||||
|
||||
Collections Abstraction library
|
||||
|
||||
## Changelog
|
||||
|
||||
### v1.2
|
||||
|
||||
* Add a new ``AbstractLazyCollection``
|
||||
|
||||
### v1.1
|
||||
|
||||
* Deprecated ``Comparison::IS``, because it's only there for SQL semantics.
|
||||
These are fixed in the ORM instead.
|
||||
* Add ``Comparison::CONTAINS`` to perform partial string matches:
|
||||
|
||||
$criteria->andWhere($criteria->expr()->contains('property', 'Foo'));
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.1.x-dev"
|
||||
"dev-master": "1.2.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+343
@@ -0,0 +1,343 @@
|
||||
<?php
|
||||
/*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the MIT license. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\Common\Collections;
|
||||
|
||||
use Closure;
|
||||
|
||||
/**
|
||||
* Lazy collection that is backed by a concrete collection
|
||||
*
|
||||
* @author Michaël Gallego <mic.gallego@gmail.com>
|
||||
* @since 1.2
|
||||
*/
|
||||
abstract class AbstractLazyCollection implements Collection
|
||||
{
|
||||
/**
|
||||
* The backed collection to use
|
||||
*
|
||||
* @var Collection
|
||||
*/
|
||||
protected $collection;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $initialized = false;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function add($element)
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->add($element);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->initialize();
|
||||
$this->collection->clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function contains($element)
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->contains($element);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function isEmpty()
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function remove($key)
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->remove($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function removeElement($element)
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->removeElement($element);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function containsKey($key)
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->containsKey($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function get($key)
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getKeys()
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->getKeys();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getValues()
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->getValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function set($key, $value)
|
||||
{
|
||||
$this->initialize();
|
||||
$this->collection->set($key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function first()
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function last()
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->last();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->key();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->current();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->next();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function exists(Closure $p)
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->exists($p);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function filter(Closure $p)
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->filter($p);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function forAll(Closure $p)
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->forAll($p);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function map(Closure $func)
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->map($func);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function partition(Closure $p)
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->partition($p);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function indexOf($element)
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->indexOf($element);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function slice($offset, $length = null)
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->slice($offset, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->getIterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->offsetExists($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->collection->offsetGet($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
$this->initialize();
|
||||
$this->collection->offsetSet($offset, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
$this->initialize();
|
||||
$this->collection->offsetUnset($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the lazy collection already initialized?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isInitialized()
|
||||
{
|
||||
return $this->initialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the collection
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
if (!$this->initialized) {
|
||||
$this->doInitialize();
|
||||
$this->initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the initialization logic
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function doInitialize();
|
||||
}
|
||||
@@ -203,9 +203,8 @@ interface Collection extends Countable, IteratorAggregate, ArrayAccess
|
||||
function filter(Closure $p);
|
||||
|
||||
/**
|
||||
* Applies the given predicate p to all elements of this collection,
|
||||
* returning true, if the predicate yields true for all elements.
|
||||
*
|
||||
* Tests whether the given predicate p holds for all elements of this collection.
|
||||
*
|
||||
* @param Closure $p The predicate.
|
||||
*
|
||||
* @return boolean TRUE, if the predicate yields TRUE for all elements, FALSE otherwise.
|
||||
|
||||
Vendored
+5
-2
@@ -42,6 +42,10 @@ class ClosureExpressionVisitor extends ExpressionVisitor
|
||||
*/
|
||||
public static function getObjectFieldValue($object, $field)
|
||||
{
|
||||
if (is_array($object)) {
|
||||
return $object[$field];
|
||||
}
|
||||
|
||||
$accessors = array('get', 'is');
|
||||
|
||||
foreach ($accessors as $accessor) {
|
||||
@@ -61,7 +65,7 @@ class ClosureExpressionVisitor extends ExpressionVisitor
|
||||
return $object->$accessor();
|
||||
}
|
||||
|
||||
if ($object instanceof \ArrayAccess || is_array($object)) {
|
||||
if ($object instanceof \ArrayAccess) {
|
||||
return $object[$field];
|
||||
}
|
||||
|
||||
@@ -107,7 +111,6 @@ class ClosureExpressionVisitor extends ExpressionVisitor
|
||||
|
||||
switch ($comparison->getOperator()) {
|
||||
case Comparison::EQ:
|
||||
case Comparison::IS:
|
||||
return function ($object) use ($field, $value) {
|
||||
return ClosureExpressionVisitor::getObjectFieldValue($object, $field) === $value;
|
||||
};
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ class Comparison implements Expression
|
||||
const LTE = '<=';
|
||||
const GT = '>';
|
||||
const GTE = '>=';
|
||||
const IS = 'IS';
|
||||
const IS = '='; // no difference with EQ
|
||||
const IN = 'IN';
|
||||
const NIN = 'NIN';
|
||||
const CONTAINS = 'CONTAINS';
|
||||
|
||||
+5
-1
@@ -26,6 +26,10 @@ use Doctrine\Common\Collections\Expr\Value;
|
||||
/**
|
||||
* Builder for Expressions in the {@link Selectable} interface.
|
||||
*
|
||||
* Important Notice for interoperable code: You have to use scalar
|
||||
* values only for comparisons, otherwise the behavior of the comparision
|
||||
* may be different between implementations (Array vs ORM vs ODM).
|
||||
*
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @since 2.3
|
||||
*/
|
||||
@@ -124,7 +128,7 @@ class ExpressionBuilder
|
||||
*/
|
||||
public function isNull($field)
|
||||
{
|
||||
return new Comparison($field, Comparison::IS, new Value(null));
|
||||
return new Comparison($field, Comparison::EQ, new Value(null));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Vendored
+20
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\Common\Collections;
|
||||
|
||||
use Doctrine\Tests\LazyArrayCollection;
|
||||
|
||||
class AbstractLazyCollectionTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testLazyCollection()
|
||||
{
|
||||
$collection = new LazyArrayCollection();
|
||||
|
||||
$this->assertFalse($collection->isInitialized());
|
||||
$this->assertCount(3, $collection);
|
||||
|
||||
$collection->add('bar');
|
||||
$this->assertTrue($collection->isInitialized());
|
||||
$this->assertCount(4, $collection);
|
||||
}
|
||||
}
|
||||
Vendored
+1
-1
@@ -108,7 +108,7 @@ class ExpressionBuilderTest extends \PHPUnit_Framework_TestCase
|
||||
$expr = $this->builder->isNull("a");
|
||||
|
||||
$this->assertInstanceOf("Doctrine\Common\Collections\Expr\Comparison", $expr);
|
||||
$this->assertEquals(Comparison::IS, $expr->getOperator());
|
||||
$this->assertEquals(Comparison::EQ, $expr->getOperator());
|
||||
}
|
||||
|
||||
public function testContains()
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests;
|
||||
|
||||
use Doctrine\Common\Collections\AbstractLazyCollection;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
|
||||
/**
|
||||
* Simple lazy collection that used an ArrayCollection as backed collection
|
||||
*/
|
||||
class LazyArrayCollection extends AbstractLazyCollection
|
||||
{
|
||||
/**
|
||||
* Do the initialization logic
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function doInitialize()
|
||||
{
|
||||
$this->collection = new ArrayCollection(array('a', 'b', 'c'));
|
||||
}
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
### 1.7.0 (2013-11-14)
|
||||
|
||||
* Added ElasticSearchHandler to send logs to an Elastic Search server
|
||||
* Added DynamoDbHandler and ScalarFormatter to send logs to Amazon's Dynamo DB
|
||||
* Added SyslogUdpHandler to send logs to a remote syslogd server
|
||||
* Added LogglyHandler to send logs to a Loggly account
|
||||
* Added $level to IntrospectionProcessor so it only adds backtraces when needed
|
||||
* Added $version to LogstashFormatter to allow using the new v1 Logstash format
|
||||
* Added $appName to NewRelicHandler
|
||||
* Added configuration of Pushover notification retries/expiry
|
||||
* Added $maxColumnWidth to NativeMailerHandler to change the 70 chars default
|
||||
* Added chainability to most setters for all handlers
|
||||
* Fixed RavenHandler batch processing so it takes the message from the record with highest priority
|
||||
* Fixed HipChatHandler batch processing so it sends all messages at once
|
||||
* Fixed issues with eAccelerator
|
||||
* Fixed and improved many small things
|
||||
|
||||
### 1.6.0 (2013-07-29)
|
||||
|
||||
* Added HipChatHandler to send logs to a HipChat chat room
|
||||
* Added ErrorLogHandler to send logs to PHP's error_log function
|
||||
* Added NewRelicHandler to send logs to NewRelic's service
|
||||
* Added Monolog\ErrorHandler helper class to register a Logger as exception/error/fatal handler
|
||||
* Added ChannelLevelActivationStrategy for the FingersCrossedHandler to customize levels by channel
|
||||
* Added stack traces output when normalizing exceptions (json output & co)
|
||||
* Added Monolog\Logger::API constant (currently 1)
|
||||
* Added support for ChromePHP's v4.0 extension
|
||||
* Added support for message priorities in PushoverHandler, see $highPriorityLevel and $emergencyLevel
|
||||
* Added support for sending messages to multiple users at once with the PushoverHandler
|
||||
* Fixed RavenHandler's support for batch sending of messages (when behind a Buffer or FingersCrossedHandler)
|
||||
* Fixed normalization of Traversables with very large data sets, only the first 1000 items are shown now
|
||||
* Fixed issue in RotatingFileHandler when an open_basedir restriction is active
|
||||
* Fixed minor issues in RavenHandler and bumped the API to Raven 0.5.0
|
||||
* Fixed SyslogHandler issue when many were used concurrently with different facilities
|
||||
|
||||
### 1.5.0 (2013-04-23)
|
||||
|
||||
* Added ProcessIdProcessor to inject the PID in log records
|
||||
* Added UidProcessor to inject a unique identifier to all log records of one request/run
|
||||
* Added support for previous exceptions in the LineFormatter exception serialization
|
||||
* Added Monolog\Logger::getLevels() to get all available levels
|
||||
* Fixed ChromePHPHandler so it avoids sending headers larger than Chrome can handle
|
||||
|
||||
### 1.4.1 (2013-04-01)
|
||||
|
||||
* Fixed exception formatting in the LineFormatter to be more minimalistic
|
||||
* Fixed RavenHandler's handling of context/extra data, requires Raven client >0.1.0
|
||||
* Fixed log rotation in RotatingFileHandler to work with long running scripts spanning multiple days
|
||||
* Fixed WebProcessor array access so it checks for data presence
|
||||
* Fixed Buffer, Group and FingersCrossed handlers to make use of their processors
|
||||
|
||||
### 1.4.0 (2013-02-13)
|
||||
|
||||
* Added RedisHandler to log to Redis via the Predis library or the phpredis extension
|
||||
* Added ZendMonitorHandler to log to the Zend Server monitor
|
||||
* Added the possibility to pass arrays of handlers and processors directly in the Logger constructor
|
||||
* Added `$useSSL` option to the PushoverHandler which is enabled by default
|
||||
* Fixed ChromePHPHandler and FirePHPHandler issue when multiple instances are used simultaneously
|
||||
* Fixed header injection capability in the NativeMailHandler
|
||||
|
||||
### 1.3.1 (2013-01-11)
|
||||
|
||||
* Fixed LogstashFormatter to be usable with stream handlers
|
||||
* Fixed GelfMessageFormatter levels on Windows
|
||||
|
||||
### 1.3.0 (2013-01-08)
|
||||
|
||||
* Added PSR-3 compliance, the `Monolog\Logger` class is now an instance of `Psr\Log\LoggerInterface`
|
||||
* Added PsrLogMessageProcessor that you can selectively enable for full PSR-3 compliance
|
||||
* Added LogstashFormatter (combine with SocketHandler or StreamHandler to send logs to Logstash)
|
||||
* Added PushoverHandler to send mobile notifications
|
||||
* Added CouchDBHandler and DoctrineCouchDBHandler
|
||||
* Added RavenHandler to send data to Sentry servers
|
||||
* Added support for the new MongoClient class in MongoDBHandler
|
||||
* Added microsecond precision to log records' timestamps
|
||||
* Added `$flushOnOverflow` param to BufferHandler to flush by batches instead of losing
|
||||
the oldest entries
|
||||
* Fixed normalization of objects with cyclic references
|
||||
|
||||
### 1.2.1 (2012-08-29)
|
||||
|
||||
* Added new $logopts arg to SyslogHandler to provide custom openlog options
|
||||
* Fixed fatal error in SyslogHandler
|
||||
|
||||
### 1.2.0 (2012-08-18)
|
||||
|
||||
* Added AmqpHandler (for use with AMQP servers)
|
||||
* Added CubeHandler
|
||||
* Added NativeMailerHandler::addHeader() to send custom headers in mails
|
||||
* Added the possibility to specify more than one recipient in NativeMailerHandler
|
||||
* Added the possibility to specify float timeouts in SocketHandler
|
||||
* Added NOTICE and EMERGENCY levels to conform with RFC 5424
|
||||
* Fixed the log records to use the php default timezone instead of UTC
|
||||
* Fixed BufferHandler not being flushed properly on PHP fatal errors
|
||||
* Fixed normalization of exotic resource types
|
||||
* Fixed the default format of the SyslogHandler to avoid duplicating datetimes in syslog
|
||||
|
||||
### 1.1.0 (2012-04-23)
|
||||
|
||||
* Added Monolog\Logger::isHandling() to check if a handler will
|
||||
handle the given log level
|
||||
* Added ChromePHPHandler
|
||||
* Added MongoDBHandler
|
||||
* Added GelfHandler (for use with Graylog2 servers)
|
||||
* Added SocketHandler (for use with syslog-ng for example)
|
||||
* Added NormalizerFormatter
|
||||
* Added the possibility to change the activation strategy of the FingersCrossedHandler
|
||||
* Added possibility to show microseconds in logs
|
||||
* Added `server` and `referer` to WebProcessor output
|
||||
|
||||
### 1.0.2 (2011-10-24)
|
||||
|
||||
* Fixed bug in IE with large response headers and FirePHPHandler
|
||||
|
||||
### 1.0.1 (2011-08-25)
|
||||
|
||||
* Added MemoryPeakUsageProcessor and MemoryUsageProcessor
|
||||
* Added Monolog\Logger::getName() to get a logger's channel name
|
||||
|
||||
### 1.0.0 (2011-07-06)
|
||||
|
||||
* Added IntrospectionProcessor to get info from where the logger was called
|
||||
* Fixed WebProcessor in CLI
|
||||
|
||||
### 1.0.0-RC1 (2011-07-01)
|
||||
|
||||
* Initial release
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
Copyright (c) Jordi Boggiano
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
Vendored
+252
@@ -0,0 +1,252 @@
|
||||
Monolog - Logging for PHP 5.3+ [](http://travis-ci.org/Seldaek/monolog)
|
||||
==============================
|
||||
|
||||
[](https://packagist.org/packages/monolog/monolog)
|
||||
[](https://packagist.org/packages/monolog/monolog)
|
||||
|
||||
|
||||
Monolog sends your logs to files, sockets, inboxes, databases and various
|
||||
web services. See the complete list of handlers below. Special handlers
|
||||
allow you to build advanced logging strategies.
|
||||
|
||||
This library implements the [PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md)
|
||||
interface that you can type-hint against in your own libraries to keep
|
||||
a maximum of interoperability. You can also use it in your applications to
|
||||
make sure you can always use another compatible logger at a later time.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\Handler\StreamHandler;
|
||||
|
||||
// create a log channel
|
||||
$log = new Logger('name');
|
||||
$log->pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING));
|
||||
|
||||
// add records to the log
|
||||
$log->addWarning('Foo');
|
||||
$log->addError('Bar');
|
||||
```
|
||||
|
||||
Core Concepts
|
||||
-------------
|
||||
|
||||
Every `Logger` instance has a channel (name) and a stack of handlers. Whenever
|
||||
you add a record to the logger, it traverses the handler stack. Each handler
|
||||
decides whether it handled fully the record, and if so, the propagation of the
|
||||
record ends there.
|
||||
|
||||
This allows for flexible logging setups, for example having a `StreamHandler` at
|
||||
the bottom of the stack that will log anything to disk, and on top of that add
|
||||
a `MailHandler` that will send emails only when an error message is logged.
|
||||
Handlers also have a `$bubble` property which defines whether they block the
|
||||
record or not if they handled it. In this example, setting the `MailHandler`'s
|
||||
`$bubble` argument to false means that records handled by the `MailHandler` will
|
||||
not propagate to the `StreamHandler` anymore.
|
||||
|
||||
You can create many `Logger`s, each defining a channel (e.g.: db, request,
|
||||
router, ..) and each of them combining various handlers, which can be shared
|
||||
or not. The channel is reflected in the logs and allows you to easily see or
|
||||
filter records.
|
||||
|
||||
Each Handler also has a Formatter, a default one with settings that make sense
|
||||
will be created if you don't set one. The formatters normalize and format
|
||||
incoming records so that they can be used by the handlers to output useful
|
||||
information.
|
||||
|
||||
Custom severity levels are not available. Only the eight
|
||||
[RFC 5424](http://tools.ietf.org/html/rfc5424) levels (debug, info, notice,
|
||||
warning, error, critical, alert, emergency) are present for basic filtering
|
||||
purposes, but for sorting and other use cases that would require
|
||||
flexibility, you should add Processors to the Logger that can add extra
|
||||
information (tags, user ip, ..) to the records before they are handled.
|
||||
|
||||
Log Levels
|
||||
----------
|
||||
|
||||
Monolog supports the logging levels described by [RFC 5424](http://tools.ietf.org/html/rfc5424).
|
||||
|
||||
- **DEBUG** (100): Detailed debug information.
|
||||
|
||||
- **INFO** (200): Interesting events. Examples: User logs in, SQL logs.
|
||||
|
||||
- **NOTICE** (250): Normal but significant events.
|
||||
|
||||
- **WARNING** (300): Exceptional occurrences that are not errors. Examples:
|
||||
Use of deprecated APIs, poor use of an API, undesirable things that are not
|
||||
necessarily wrong.
|
||||
|
||||
- **ERROR** (400): Runtime errors that do not require immediate action but
|
||||
should typically be logged and monitored.
|
||||
|
||||
- **CRITICAL** (500): Critical conditions. Example: Application component
|
||||
unavailable, unexpected exception.
|
||||
|
||||
- **ALERT** (550): Action must be taken immediately. Example: Entire website
|
||||
down, database unavailable, etc. This should trigger the SMS alerts and wake
|
||||
you up.
|
||||
|
||||
- **EMERGENCY** (600): Emergency: system is unusable.
|
||||
|
||||
Docs
|
||||
====
|
||||
|
||||
**See the `doc` directory for more detailed documentation.
|
||||
The following is only a list of all parts that come with Monolog.**
|
||||
|
||||
Handlers
|
||||
--------
|
||||
|
||||
### Log to files and syslog
|
||||
|
||||
- _StreamHandler_: Logs records into any PHP stream, use this for log files.
|
||||
- _RotatingFileHandler_: Logs records to a file and creates one logfile per day.
|
||||
It will also delete files older than `$maxFiles`. You should use
|
||||
[logrotate](http://linuxcommand.org/man_pages/logrotate8.html) for high profile
|
||||
setups though, this is just meant as a quick and dirty solution.
|
||||
- _SyslogHandler_: Logs records to the syslog.
|
||||
- _ErrorLogHandler_: Logs records to PHP's
|
||||
[`error_log()`](http://docs.php.net/manual/en/function.error-log.php) function.
|
||||
|
||||
### Send alerts and emails
|
||||
|
||||
- _NativeMailerHandler_: Sends emails using PHP's
|
||||
[`mail()`](http://php.net/manual/en/function.mail.php) function.
|
||||
- _SwiftMailerHandler_: Sends emails using a [`Swift_Mailer`](http://swiftmailer.org/) instance.
|
||||
- _PushoverHandler_: Sends mobile notifications via the [Pushover](https://www.pushover.net/) API.
|
||||
- _HipChatHandler_: Logs records to a [HipChat](http://hipchat.com) chat room using its API.
|
||||
|
||||
### Log specific servers and networked logging
|
||||
|
||||
- _SocketHandler_: Logs records to [sockets](http://php.net/fsockopen), use this
|
||||
for UNIX and TCP sockets. See an [example](https://github.com/Seldaek/monolog/blob/master/doc/sockets.md).
|
||||
- _AmqpHandler_: Logs records to an [amqp](http://www.amqp.org/) compatible
|
||||
server. Requires the [php-amqp](http://pecl.php.net/package/amqp) extension (1.0+).
|
||||
- _GelfHandler_: Logs records to a [Graylog2](http://www.graylog2.org) server.
|
||||
- _CubeHandler_: Logs records to a [Cube](http://square.github.com/cube/) server.
|
||||
- _RavenHandler_: Logs records to a [Sentry](http://getsentry.com/) server using
|
||||
[raven](https://packagist.org/packages/raven/raven).
|
||||
- _ZendMonitorHandler_: Logs records to the Zend Monitor present in Zend Server.
|
||||
- _NewRelicHandler_: Logs records to a [NewRelic](http://newrelic.com/) application.
|
||||
- _LogglyHandler_: Logs records to a [Loggly](http://www.loggly.com/) account.
|
||||
- _SyslogUdpHandler_: Logs records to a remote [Syslogd](http://www.rsyslog.com/) server.
|
||||
|
||||
### Logging in development
|
||||
|
||||
- _FirePHPHandler_: Handler for [FirePHP](http://www.firephp.org/), providing
|
||||
inline `console` messages within [FireBug](http://getfirebug.com/).
|
||||
- _ChromePHPHandler_: Handler for [ChromePHP](http://www.chromephp.com/), providing
|
||||
inline `console` messages within Chrome.
|
||||
|
||||
### Log to databases
|
||||
|
||||
- _RedisHandler_: Logs records to a [redis](http://redis.io) server.
|
||||
- _MongoDBHandler_: Handler to write records in MongoDB via a
|
||||
[Mongo](http://pecl.php.net/package/mongo) extension connection.
|
||||
- _CouchDBHandler_: Logs records to a CouchDB server.
|
||||
- _DoctrineCouchDBHandler_: Logs records to a CouchDB server via the Doctrine CouchDB ODM.
|
||||
- _ElasticSearchHandler_: Logs records to an Elastic Search server.
|
||||
- _DynamoDbHandler_: Logs records to a DynamoDB table with the [AWS SDK](https://github.com/aws/aws-sdk-php).
|
||||
|
||||
### Wrappers / Special Handlers
|
||||
|
||||
- _FingersCrossedHandler_: A very interesting wrapper. It takes a logger as
|
||||
parameter and will accumulate log records of all levels until a record
|
||||
exceeds the defined severity level. At which point it delivers all records,
|
||||
including those of lower severity, to the handler it wraps. This means that
|
||||
until an error actually happens you will not see anything in your logs, but
|
||||
when it happens you will have the full information, including debug and info
|
||||
records. This provides you with all the information you need, but only when
|
||||
you need it.
|
||||
- _NullHandler_: Any record it can handle will be thrown away. This can be used
|
||||
to put on top of an existing handler stack to disable it temporarily.
|
||||
- _BufferHandler_: This handler will buffer all the log records it receives
|
||||
until `close()` is called at which point it will call `handleBatch()` on the
|
||||
handler it wraps with all the log messages at once. This is very useful to
|
||||
send an email with all records at once for example instead of having one mail
|
||||
for every log record.
|
||||
- _GroupHandler_: This handler groups other handlers. Every record received is
|
||||
sent to all the handlers it is configured with.
|
||||
- _TestHandler_: Used for testing, it records everything that is sent to it and
|
||||
has accessors to read out the information.
|
||||
|
||||
Formatters
|
||||
----------
|
||||
|
||||
- _LineFormatter_: Formats a log record into a one-line string.
|
||||
- _NormalizerFormatter_: Normalizes objects/resources down to strings so a record can easily be serialized/encoded.
|
||||
- _ScalarFormatter_: Used to format log records into an associative array of scalar values.
|
||||
- _JsonFormatter_: Encodes a log record into json.
|
||||
- _WildfireFormatter_: Used to format log records into the Wildfire/FirePHP protocol, only useful for the FirePHPHandler.
|
||||
- _ChromePHPFormatter_: Used to format log records into the ChromePHP format, only useful for the ChromePHPHandler.
|
||||
- _GelfFormatter_: Used to format log records into Gelf message instances, only useful for the GelfHandler.
|
||||
- _LogstashFormatter_: Used to format log records into [logstash](http://logstash.net/) event json, useful for any handler listed under inputs [here](http://logstash.net/docs/1.1.5/).
|
||||
- _ElasticaFormatter_: Used to format log records into an Elastica\Document object, only useful for the ElasticSearchHandler.
|
||||
|
||||
Processors
|
||||
----------
|
||||
|
||||
- _IntrospectionProcessor_: Adds the line/file/class/method from which the log call originated.
|
||||
- _WebProcessor_: Adds the current request URI, request method and client IP to a log record.
|
||||
- _MemoryUsageProcessor_: Adds the current memory usage to a log record.
|
||||
- _MemoryPeakUsageProcessor_: Adds the peak memory usage to a log record.
|
||||
- _ProcessIdProcessor_: Adds the process id to a log record.
|
||||
- _UidProcessor_: Adds a unique identifier to a log record.
|
||||
|
||||
Utilities
|
||||
---------
|
||||
|
||||
- _ErrorHandler_: The `Monolog\ErrorHandler` class allows you to easily register
|
||||
a Logger instance as an exception handler, error handler or fatal error handler.
|
||||
- _ErrorLevelActivationStrategy_: Activates a FingersCrossedHandler when a certain log
|
||||
level is reached.
|
||||
- _ChannelLevelActivationStrategy_: Activates a FingersCrossedHandler when a certain
|
||||
log level is reached, depending on which channel received the log record.
|
||||
|
||||
About
|
||||
=====
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
- Any flavor of PHP 5.3 or above should do
|
||||
- [optional] PHPUnit 3.5+ to execute the test suite (phpunit --version)
|
||||
|
||||
Submitting bugs and feature requests
|
||||
------------------------------------
|
||||
|
||||
Bugs and feature request are tracked on [GitHub](https://github.com/Seldaek/monolog/issues)
|
||||
|
||||
Frameworks Integration
|
||||
----------------------
|
||||
|
||||
- Frameworks and libraries using [PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md)
|
||||
can be used very easily with Monolog since it implements the interface.
|
||||
- [Symfony2](http://symfony.com) comes out of the box with Monolog.
|
||||
- [Silex](http://silex.sensiolabs.org/) comes out of the box with Monolog.
|
||||
- [Laravel 4](http://laravel.com/) comes out of the box with Monolog.
|
||||
- [PPI](http://www.ppi.io/) comes out of the box with Monolog.
|
||||
- [CakePHP](http://cakephp.org/) is usable with Monolog via the [cakephp-monolog](https://github.com/jadb/cakephp-monolog) plugin.
|
||||
- [Slim](http://www.slimframework.com/) is usable with Monolog via the [Slim-Monolog](https://github.com/Flynsarmy/Slim-Monolog) log writer.
|
||||
- [XOOPS 2.6](http://xoops.org/) comes out of the box with Monolog.
|
||||
|
||||
Author
|
||||
------
|
||||
|
||||
Jordi Boggiano - <j.boggiano@seld.be> - <http://twitter.com/seldaek><br />
|
||||
See also the list of [contributors](https://github.com/Seldaek/monolog/contributors) which participated in this project.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
Monolog is licensed under the MIT License - see the `LICENSE` file for details
|
||||
|
||||
Acknowledgements
|
||||
----------------
|
||||
|
||||
This library is heavily inspired by Python's [Logbook](http://packages.python.org/Logbook/)
|
||||
library, although most concepts have been adjusted to fit to the PHP world.
|
||||
Vendored
+44
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "monolog/monolog",
|
||||
"description": "Sends your logs to files, sockets, inboxes, databases and various web services",
|
||||
"keywords": ["log", "logging", "psr-3"],
|
||||
"homepage": "http://github.com/Seldaek/monolog",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jordi Boggiano",
|
||||
"email": "j.boggiano@seld.be",
|
||||
"homepage": "http://seld.be"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.3.0",
|
||||
"psr/log": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~3.7.0",
|
||||
"mlehner/gelf-php": "1.0.*",
|
||||
"raven/raven": "0.5.*",
|
||||
"ruflin/elastica": "0.90.*",
|
||||
"doctrine/couchdb": "dev-master",
|
||||
"aws/aws-sdk-php": "~2.4.8"
|
||||
},
|
||||
"suggest": {
|
||||
"mlehner/gelf-php": "Allow sending log messages to a GrayLog2 server",
|
||||
"raven/raven": "Allow sending log messages to a Sentry server",
|
||||
"doctrine/couchdb": "Allow sending log messages to a CouchDB server",
|
||||
"ruflin/elastica": "Allow sending log messages to an Elastic Search server",
|
||||
"ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
|
||||
"ext-mongo": "Allow sending log messages to a MongoDB server",
|
||||
"aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {"Monolog": "src/"}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.7.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
Extending Monolog
|
||||
=================
|
||||
|
||||
Monolog is fully extensible, allowing you to adapt your logger to your needs.
|
||||
|
||||
Writing your own handler
|
||||
------------------------
|
||||
|
||||
Monolog provides many built-in handlers. But if the one you need does not
|
||||
exist, you can write it and use it in your logger. The only requirement is
|
||||
to implement `Monolog\Handler\HandlerInterface`.
|
||||
|
||||
Let's write a PDOHandler to log records to a database. We will extend the
|
||||
abstract class provided by Monolog to keep things DRY.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\Handler\AbstractProcessingHandler;
|
||||
|
||||
class PDOHandler extends AbstractProcessingHandler
|
||||
{
|
||||
private $initialized = false;
|
||||
private $pdo;
|
||||
private $statement;
|
||||
|
||||
public function __construct(PDO $pdo, $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
$this->pdo = $pdo;
|
||||
parent::__construct($level, $bubble);
|
||||
}
|
||||
|
||||
protected function write(array $record)
|
||||
{
|
||||
if (!$this->initialized) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
$this->statement->execute(array(
|
||||
'channel' => $record['channel'],
|
||||
'level' => $record['level'],
|
||||
'message' => $record['formatted'],
|
||||
'time' => $record['datetime']->format('U'),
|
||||
));
|
||||
}
|
||||
|
||||
private function initialize()
|
||||
{
|
||||
$this->pdo->exec(
|
||||
'CREATE TABLE IF NOT EXISTS monolog '
|
||||
.'(channel VARCHAR(255), level INTEGER, message LONGTEXT, time INTEGER UNSIGNED)'
|
||||
);
|
||||
$this->statement = $this->pdo->prepare(
|
||||
'INSERT INTO monolog (channel, level, message, time) VALUES (:channel, :level, :message, :time)'
|
||||
);
|
||||
|
||||
$this->initialized = true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can now use this handler in your logger:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
$logger->pushHandler(new PDOHandler(new PDO('sqlite:logs.sqlite'));
|
||||
|
||||
// You can now use your logger
|
||||
$logger->addInfo('My logger is now ready');
|
||||
```
|
||||
|
||||
The `Monolog\Handler\AbstractProcessingHandler` class provides most of the
|
||||
logic needed for the handler, including the use of processors and the formatting
|
||||
of the record (which is why we use ``$record['formatted']`` instead of ``$record['message']``).
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
Sockets Handler
|
||||
===============
|
||||
|
||||
This handler allows you to write your logs to sockets using [fsockopen](http://php.net/fsockopen)
|
||||
or [pfsockopen](http://php.net/pfsockopen).
|
||||
|
||||
Persistent sockets are mainly useful in web environments where you gain some performance not closing/opening
|
||||
the connections between requests.
|
||||
|
||||
Basic Example
|
||||
-------------
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\Handler\SocketHandler;
|
||||
|
||||
// Create the logger
|
||||
$logger = new Logger('my_logger');
|
||||
|
||||
// Create the handler
|
||||
$handler = new SocketHandler('unix:///var/log/httpd_app_log.socket');
|
||||
$handler->setPersistent(true);
|
||||
|
||||
// Now add the handler
|
||||
$logger->pushHandler($handler, Logger::DEBUG);
|
||||
|
||||
// You can now use your logger
|
||||
$logger->addInfo('My logger is now ready');
|
||||
|
||||
```
|
||||
|
||||
In this example, using syslog-ng, you should see the log on the log server:
|
||||
|
||||
cweb1 [2012-02-26 00:12:03] my_logger.INFO: My logger is now ready [] []
|
||||
|
||||
Vendored
+162
@@ -0,0 +1,162 @@
|
||||
Using Monolog
|
||||
=============
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Monolog is available on Packagist ([monolog/monolog](http://packagist.org/packages/monolog/monolog))
|
||||
and as such installable via [Composer](http://getcomposer.org/).
|
||||
|
||||
```bash
|
||||
php composer.phar require monolog/monolog '~1.4'
|
||||
```
|
||||
|
||||
If you do not use Composer, you can grab the code from GitHub, and use any
|
||||
PSR-0 compatible autoloader (e.g. the [Symfony2 ClassLoader component](https://github.com/symfony/ClassLoader))
|
||||
to load Monolog classes.
|
||||
|
||||
Configuring a logger
|
||||
--------------------
|
||||
|
||||
Here is a basic setup to log to a file and to firephp on the DEBUG level:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\Handler\StreamHandler;
|
||||
use Monolog\Handler\FirePHPHandler;
|
||||
|
||||
// Create the logger
|
||||
$logger = new Logger('my_logger');
|
||||
// Now add some handlers
|
||||
$logger->pushHandler(new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG));
|
||||
$logger->pushHandler(new FirePHPHandler());
|
||||
|
||||
// You can now use your logger
|
||||
$logger->addInfo('My logger is now ready');
|
||||
```
|
||||
|
||||
Let's explain it. The first step is to create the logger instance which will
|
||||
be used in your code. The argument is a channel name, which is useful when
|
||||
you use several loggers (see below for more details about it).
|
||||
|
||||
The logger itself does not know how to handle a record. It delegates it to
|
||||
some handlers. The code above registers two handlers in the stack to allow
|
||||
handling records in two different ways.
|
||||
|
||||
Note that the FirePHPHandler is called first as it is added on top of the
|
||||
stack. This allows you to temporarily add a logger with bubbling disabled if
|
||||
you want to override other configured loggers.
|
||||
|
||||
Adding extra data in the records
|
||||
--------------------------------
|
||||
|
||||
Monolog provides two different ways to add extra informations along the simple
|
||||
textual message.
|
||||
|
||||
### Using the logging context
|
||||
|
||||
The first way is the context, allowing to pass an array of data along the
|
||||
record:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
$logger->addInfo('Adding a new user', array('username' => 'Seldaek'));
|
||||
```
|
||||
|
||||
Simple handlers (like the StreamHandler for instance) will simply format
|
||||
the array to a string but richer handlers can take advantage of the context
|
||||
(FirePHP is able to display arrays in pretty way for instance).
|
||||
|
||||
### Using processors
|
||||
|
||||
The second way is to add extra data for all records by using a processor.
|
||||
Processors can be any callable. They will get the record as parameter and
|
||||
must return it after having eventually changed the `extra` part of it. Let's
|
||||
write a processor adding some dummy data in the record:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
$logger->pushProcessor(function ($record) {
|
||||
$record['extra']['dummy'] = 'Hello world!';
|
||||
|
||||
return $record;
|
||||
});
|
||||
```
|
||||
|
||||
Monolog provides some built-in processors that can be used in your project.
|
||||
Look at the [README file](https://github.com/Seldaek/monolog/blob/master/README.mdown) for the list.
|
||||
|
||||
> Tip: processors can also be registered on a specific handler instead of
|
||||
the logger to apply only for this handler.
|
||||
|
||||
Leveraging channels
|
||||
-------------------
|
||||
|
||||
Channels are a great way to identify to which part of the application a record
|
||||
is related. This is useful in big applications (and is leveraged by
|
||||
MonologBundle in Symfony2).
|
||||
|
||||
Picture two loggers sharing a handler that writes to a single log file.
|
||||
Channels would allow you to identify the logger that issued every record.
|
||||
You can easily grep through the log files filtering this or that channel.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\Handler\StreamHandler;
|
||||
use Monolog\Handler\FirePHPHandler;
|
||||
|
||||
// Create some handlers
|
||||
$stream = new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG);
|
||||
$firephp = new FirePHPHandler();
|
||||
|
||||
// Create the main logger of the app
|
||||
$logger = new Logger('my_logger');
|
||||
$logger->pushHandler($stream);
|
||||
$logger->pushHandler($firephp);
|
||||
|
||||
// Create a logger for the security-related stuff with a different channel
|
||||
$securityLogger = new Logger('security');
|
||||
$securityLogger->pushHandler($stream);
|
||||
$securityLogger->pushHandler($firephp);
|
||||
```
|
||||
|
||||
Customizing log format
|
||||
----------------------
|
||||
|
||||
In Monolog it's easy to customize the format of the logs written into files,
|
||||
sockets, mails, databases and other handlers. Most of the handlers use the
|
||||
|
||||
```php
|
||||
$record['formatted']
|
||||
```
|
||||
|
||||
value to be automatically put into the log device. This value depends on the
|
||||
formatter settings. You can choose between predefined formatter classes or
|
||||
write your own (e.g. a multiline text file for human-readable output).
|
||||
|
||||
To configure a predefined formatter class, just set it as the handler's field:
|
||||
|
||||
```php
|
||||
// the default date format is "Y-m-d H:i:s"
|
||||
$dateFormat = "Y n j, g:i a";
|
||||
// the default output format is "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"
|
||||
$output = "%datetime% > %level_name% > %message% %context% %extra%\n";
|
||||
// finally, create a formatter
|
||||
$formatter = new LineFormatter($output, $dateFormat);
|
||||
|
||||
// Create a handler
|
||||
$stream = new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG);
|
||||
$stream->setFormatter($formatter);
|
||||
// bind it to a logger object
|
||||
$securityLogger = new Logger('security');
|
||||
$securityLogger->pushHandler($stream);
|
||||
```
|
||||
|
||||
You may also reuse the same formatter between multiple handlers and share those
|
||||
handlers between multiple loggers.
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<phpunit bootstrap="tests/bootstrap.php" colors="true">
|
||||
<testsuites>
|
||||
<testsuite name="Monolog Test Suite">
|
||||
<directory>tests/Monolog/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">src/Monolog/</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
||||
+208
@@ -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;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
|
||||
/**
|
||||
* Monolog error handler
|
||||
*
|
||||
* A facility to enable logging of runtime errors, exceptions and fatal errors.
|
||||
*
|
||||
* Quick setup: <code>ErrorHandler::register($logger);</code>
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class ErrorHandler
|
||||
{
|
||||
private $logger;
|
||||
|
||||
private $previousExceptionHandler;
|
||||
private $uncaughtExceptionLevel;
|
||||
|
||||
private $previousErrorHandler;
|
||||
private $errorLevelMap;
|
||||
|
||||
private $fatalLevel;
|
||||
private $reservedMemory;
|
||||
private static $fatalErrors = array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR);
|
||||
|
||||
public function __construct(LoggerInterface $logger)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new ErrorHandler for a given Logger
|
||||
*
|
||||
* By default it will handle errors, exceptions and fatal errors
|
||||
*
|
||||
* @param LoggerInterface $logger
|
||||
* @param array|false $errorLevelMap an array of E_* constant to LogLevel::* constant mapping, or false to disable error handling
|
||||
* @param int|false $exceptionLevel a LogLevel::* constant, or false to disable exception handling
|
||||
* @param int|false $fatalLevel a LogLevel::* constant, or false to disable fatal error handling
|
||||
* @return ErrorHandler
|
||||
*/
|
||||
public static function register(LoggerInterface $logger, $errorLevelMap = array(), $exceptionLevel = null, $fatalLevel = null)
|
||||
{
|
||||
$handler = new static($logger);
|
||||
if ($errorLevelMap !== false) {
|
||||
$handler->registerErrorHandler($errorLevelMap);
|
||||
}
|
||||
if ($exceptionLevel !== false) {
|
||||
$handler->registerExceptionHandler($exceptionLevel);
|
||||
}
|
||||
if ($fatalLevel !== false) {
|
||||
$handler->registerFatalHandler($fatalLevel);
|
||||
}
|
||||
|
||||
return $handler;
|
||||
}
|
||||
|
||||
public function registerExceptionHandler($level = null, $callPrevious = true)
|
||||
{
|
||||
$prev = set_exception_handler(array($this, 'handleException'));
|
||||
$this->uncaughtExceptionLevel = $level;
|
||||
if ($callPrevious && $prev) {
|
||||
$this->previousExceptionHandler = $prev;
|
||||
}
|
||||
}
|
||||
|
||||
public function registerErrorHandler(array $levelMap = array(), $callPrevious = true, $errorTypes = -1)
|
||||
{
|
||||
$prev = set_error_handler(array($this, 'handleError'), $errorTypes);
|
||||
$this->errorLevelMap = array_replace($this->defaultErrorLevelMap(), $levelMap);
|
||||
if ($callPrevious) {
|
||||
$this->previousErrorHandler = $prev ?: true;
|
||||
}
|
||||
}
|
||||
|
||||
public function registerFatalHandler($level = null, $reservedMemorySize = 20)
|
||||
{
|
||||
register_shutdown_function(array($this, 'handleFatalError'));
|
||||
|
||||
$this->reservedMemory = str_repeat(' ', 1024 * $reservedMemorySize);
|
||||
$this->fatalLevel = $level;
|
||||
}
|
||||
|
||||
protected function defaultErrorLevelMap()
|
||||
{
|
||||
return array(
|
||||
E_ERROR => LogLevel::CRITICAL,
|
||||
E_WARNING => LogLevel::WARNING,
|
||||
E_PARSE => LogLevel::ALERT,
|
||||
E_NOTICE => LogLevel::NOTICE,
|
||||
E_CORE_ERROR => LogLevel::CRITICAL,
|
||||
E_CORE_WARNING => LogLevel::WARNING,
|
||||
E_COMPILE_ERROR => LogLevel::ALERT,
|
||||
E_COMPILE_WARNING => LogLevel::WARNING,
|
||||
E_USER_ERROR => LogLevel::ERROR,
|
||||
E_USER_WARNING => LogLevel::WARNING,
|
||||
E_USER_NOTICE => LogLevel::NOTICE,
|
||||
E_STRICT => LogLevel::NOTICE,
|
||||
E_RECOVERABLE_ERROR => LogLevel::ERROR,
|
||||
E_DEPRECATED => LogLevel::NOTICE,
|
||||
E_USER_DEPRECATED => LogLevel::NOTICE,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function handleException(\Exception $e)
|
||||
{
|
||||
$this->logger->log(
|
||||
$this->uncaughtExceptionLevel === null ? LogLevel::ERROR : $this->uncaughtExceptionLevel,
|
||||
'Uncaught exception',
|
||||
array('exception' => $e)
|
||||
);
|
||||
|
||||
if ($this->previousExceptionHandler) {
|
||||
call_user_func($this->previousExceptionHandler, $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function handleError($code, $message, $file = '', $line = 0, $context = array())
|
||||
{
|
||||
if (!(error_reporting() & $code)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$level = isset($this->errorLevelMap[$code]) ? $this->errorLevelMap[$code] : LogLevel::CRITICAL;
|
||||
$this->logger->log($level, self::codeToString($code).': '.$message, array('file' => $file, 'line' => $line));
|
||||
|
||||
if ($this->previousErrorHandler === true) {
|
||||
return false;
|
||||
} elseif ($this->previousErrorHandler) {
|
||||
return call_user_func($this->previousErrorHandler, $code, $message, $file, $line, $context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function handleFatalError()
|
||||
{
|
||||
$this->reservedMemory = null;
|
||||
|
||||
$lastError = error_get_last();
|
||||
if ($lastError && in_array($lastError['type'], self::$fatalErrors)) {
|
||||
$this->logger->log(
|
||||
$this->fatalLevel === null ? LogLevel::ALERT : $this->fatalLevel,
|
||||
'Fatal Error ('.self::codeToString($lastError['type']).'): '.$lastError['message'],
|
||||
array('file' => $lastError['file'], 'line' => $lastError['line'])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static function codeToString($code)
|
||||
{
|
||||
switch ($code) {
|
||||
case E_ERROR:
|
||||
return 'E_ERROR';
|
||||
case E_WARNING:
|
||||
return 'E_WARNING';
|
||||
case E_PARSE:
|
||||
return 'E_PARSE';
|
||||
case E_NOTICE:
|
||||
return 'E_NOTICE';
|
||||
case E_CORE_ERROR:
|
||||
return 'E_CORE_ERROR';
|
||||
case E_CORE_WARNING:
|
||||
return 'E_CORE_WARNING';
|
||||
case E_COMPILE_ERROR:
|
||||
return 'E_COMPILE_ERROR';
|
||||
case E_COMPILE_WARNING:
|
||||
return 'E_COMPILE_WARNING';
|
||||
case E_USER_ERROR:
|
||||
return 'E_USER_ERROR';
|
||||
case E_USER_WARNING:
|
||||
return 'E_USER_WARNING';
|
||||
case E_USER_NOTICE:
|
||||
return 'E_USER_NOTICE';
|
||||
case E_STRICT:
|
||||
return 'E_STRICT';
|
||||
case E_RECOVERABLE_ERROR:
|
||||
return 'E_RECOVERABLE_ERROR';
|
||||
case E_DEPRECATED:
|
||||
return 'E_DEPRECATED';
|
||||
case E_USER_DEPRECATED:
|
||||
return 'E_USER_DEPRECATED';
|
||||
}
|
||||
|
||||
return 'Unknown PHP error';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?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']) && isset($record['extra']['line'])) {
|
||||
$backtrace = $record['extra']['file'].' : '.$record['extra']['line'];
|
||||
unset($record['extra']['file']);
|
||||
unset($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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
use Elastica\Document;
|
||||
|
||||
/**
|
||||
* Format a log message into an Elastica Document
|
||||
*
|
||||
* @author Jelle Vink <jelle.vink@gmail.com>
|
||||
*/
|
||||
class ElasticaFormatter extends NormalizerFormatter
|
||||
{
|
||||
/**
|
||||
* @var string Elastic search index name
|
||||
*/
|
||||
protected $index;
|
||||
|
||||
/**
|
||||
* @var string Elastic search document type
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* @param string $index Elastic Search index name
|
||||
* @param string $type Elastic Search document type
|
||||
*/
|
||||
public function __construct($index, $type)
|
||||
{
|
||||
parent::__construct(\DateTime::ISO8601);
|
||||
$this->index = $index;
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function format(array $record)
|
||||
{
|
||||
$record = parent::format($record);
|
||||
return $this->getDocument($record);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter index
|
||||
* @return string
|
||||
*/
|
||||
public function getIndex()
|
||||
{
|
||||
return $this->index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter type
|
||||
* @return string
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a log message into an Elastica Document
|
||||
*
|
||||
* @param array $record Log message
|
||||
* @return Document
|
||||
*/
|
||||
protected function getDocument($record)
|
||||
{
|
||||
$document = new Document();
|
||||
$document->setData($record);
|
||||
$document->setType($this->type);
|
||||
$document->setIndex($this->index);
|
||||
return $document;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Interface for formatters
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
interface FormatterInterface
|
||||
{
|
||||
/**
|
||||
* Formats a log record.
|
||||
*
|
||||
* @param array $record A record to format
|
||||
* @return mixed The formatted record
|
||||
*/
|
||||
public function format(array $record);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
<?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
|
||||
{
|
||||
/**
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* 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_')
|
||||
{
|
||||
parent::__construct('U.u');
|
||||
|
||||
$this->systemName = $systemName ?: gethostname();
|
||||
|
||||
$this->extraPrefix = $extraPrefix;
|
||||
$this->contextPrefix = $contextPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function format(array $record)
|
||||
{
|
||||
$record = parent::format($record);
|
||||
$message = new Message();
|
||||
$message
|
||||
->setTimestamp($record['datetime'])
|
||||
->setShortMessage((string) $record['message'])
|
||||
->setFacility($record['channel'])
|
||||
->setHost($this->systemName)
|
||||
->setLine(isset($record['extra']['line']) ? $record['extra']['line'] : null)
|
||||
->setFile(isset($record['extra']['file']) ? $record['extra']['file'] : null)
|
||||
->setLevel($this->logLevels[$record['level']]);
|
||||
|
||||
// Do not duplicate these values in the additional fields
|
||||
unset($record['extra']['line']);
|
||||
unset($record['extra']['file']);
|
||||
|
||||
foreach ($record['extra'] as $key => $val) {
|
||||
$message->setAdditional($this->extraPrefix . $key, is_scalar($val) ? $val : $this->toJson($val));
|
||||
}
|
||||
|
||||
foreach ($record['context'] as $key => $val) {
|
||||
$message->setAdditional($this->contextPrefix . $key, is_scalar($val) ? $val : $this->toJson($val));
|
||||
}
|
||||
|
||||
if (null === $message->getFile() && isset($record['context']['exception'])) {
|
||||
if (preg_match("/^(.+):([0-9]+)$/", $record['context']['exception']['file'], $matches)) {
|
||||
$message->setFile($matches[1]);
|
||||
$message->setLine($matches[2]);
|
||||
}
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* 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 implements FormatterInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function format(array $record)
|
||||
{
|
||||
return json_encode($record);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formatBatch(array $records)
|
||||
{
|
||||
return json_encode($records);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* @param string $format The format of the message
|
||||
* @param string $dateFormat The format of the timestamp: one supported by DateTime::format
|
||||
*/
|
||||
public function __construct($format = null, $dateFormat = null)
|
||||
{
|
||||
$this->format = $format ?: static::SIMPLE_FORMAT;
|
||||
parent::__construct($dateFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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->convertToString($val), $output);
|
||||
unset($vars['extra'][$var]);
|
||||
}
|
||||
}
|
||||
foreach ($vars as $var => $val) {
|
||||
if (false !== strpos($output, '%'.$var.'%')) {
|
||||
$output = str_replace('%'.$var.'%', $this->convertToString($val), $output);
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function formatBatch(array $records)
|
||||
{
|
||||
$message = '';
|
||||
foreach ($records as $record) {
|
||||
$message .= $this->format($record);
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
protected function normalize($data)
|
||||
{
|
||||
if (is_bool($data) || is_null($data)) {
|
||||
return var_export($data, true);
|
||||
}
|
||||
|
||||
if ($data instanceof \Exception) {
|
||||
$previousText = '';
|
||||
if ($previous = $data->getPrevious()) {
|
||||
do {
|
||||
$previousText .= ', '.get_class($previous).': '.$previous->getMessage().' at '.$previous->getFile().':'.$previous->getLine();
|
||||
} while ($previous = $previous->getPrevious());
|
||||
}
|
||||
|
||||
return '[object] ('.get_class($data).': '.$data->getMessage().' at '.$data->getFile().':'.$data->getLine().$previousText.')';
|
||||
}
|
||||
|
||||
return parent::normalize($data);
|
||||
}
|
||||
|
||||
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 $this->toJson($data, true);
|
||||
}
|
||||
|
||||
return str_replace('\\/', '/', @json_encode($data));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
<?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 integer 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_
|
||||
*/
|
||||
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)
|
||||
{
|
||||
$message = array(
|
||||
'@timestamp' => $record['datetime'],
|
||||
'@message' => $record['message'],
|
||||
'@tags' => array($record['channel']),
|
||||
'@source' => $this->systemName,
|
||||
'@fields' => array(
|
||||
'channel' => $record['channel'],
|
||||
'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'];
|
||||
}
|
||||
foreach ($record['extra'] as $key => $val) {
|
||||
$message['@fields'][$this->extraPrefix . $key] = $val;
|
||||
}
|
||||
|
||||
foreach ($record['context'] as $key => $val) {
|
||||
$message['@fields'][$this->contextPrefix . $key] = $val;
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
protected function formatV1(array $record)
|
||||
{
|
||||
$message = array(
|
||||
'@timestamp' => $record['datetime'],
|
||||
'@version' => 1,
|
||||
'message' => $record['message'],
|
||||
'host' => $this->systemName,
|
||||
'type' => $record['channel'],
|
||||
'channel' => $record['channel'],
|
||||
'level' => $record['level_name']
|
||||
);
|
||||
|
||||
if ($this->applicationName) {
|
||||
$message['type'] = $this->applicationName;
|
||||
}
|
||||
|
||||
foreach ($record['extra'] as $key => $val) {
|
||||
$message[$this->extraPrefix . $key] = $val;
|
||||
}
|
||||
|
||||
foreach ($record['context'] as $key => $val) {
|
||||
$message[$this->contextPrefix . $key] = $val;
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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)) {
|
||||
return $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 \DateTime) {
|
||||
return $data->format($this->dateFormat);
|
||||
}
|
||||
|
||||
if (is_object($data)) {
|
||||
if ($data instanceof Exception) {
|
||||
return $this->normalizeException($data);
|
||||
}
|
||||
|
||||
return sprintf("[object] (%s: %s)", get_class($data), $this->toJson($data, true));
|
||||
}
|
||||
|
||||
if (is_resource($data)) {
|
||||
return '[resource]';
|
||||
}
|
||||
|
||||
return '[unknown('.gettype($data).')]';
|
||||
}
|
||||
|
||||
protected function normalizeException(Exception $e)
|
||||
{
|
||||
$data = array(
|
||||
'class' => get_class($e),
|
||||
'message' => $e->getMessage(),
|
||||
'file' => $e->getFile().':'.$e->getLine(),
|
||||
);
|
||||
|
||||
$trace = $e->getTrace();
|
||||
array_shift($trace);
|
||||
foreach ($trace as $frame) {
|
||||
if (isset($frame['file'])) {
|
||||
$data['trace'][] = $frame['file'].':'.$frame['line'];
|
||||
} else {
|
||||
$data['trace'][] = json_encode($frame);
|
||||
}
|
||||
}
|
||||
|
||||
if ($previous = $e->getPrevious()) {
|
||||
$data['previous'] = $this->normalizeException($previous);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function toJson($data, $ignoreErrors = false)
|
||||
{
|
||||
// suppress json_encode errors since it's twitchy with some inputs
|
||||
if ($ignoreErrors) {
|
||||
if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
|
||||
return @json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
return @json_encode($data);
|
||||
}
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
|
||||
return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
return json_encode($data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?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\Formatter\NormalizerFormatter;
|
||||
|
||||
/**
|
||||
* Formats data into an associative array of scalar values.
|
||||
* Objects and arrays will be JSON encoded.
|
||||
*
|
||||
* @author Andrew Lawson <adlawson@gmail.com>
|
||||
*/
|
||||
class ScalarFormatter extends NormalizerFormatter
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function format(array $record)
|
||||
{
|
||||
foreach ($record as $key => $value) {
|
||||
$record[$key] = $this->normalizeValue($value);
|
||||
}
|
||||
|
||||
return $record;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
*/
|
||||
protected function normalizeValue($value)
|
||||
{
|
||||
$normalized = $this->normalize($value);
|
||||
|
||||
if (is_array($normalized) || is_object($normalized)) {
|
||||
return $this->toJson($normalized, true);
|
||||
}
|
||||
|
||||
return $normalized;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?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
|
||||
{
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
// Create JSON object describing the appearance of the message in the console
|
||||
$json = $this->toJson(array(
|
||||
array(
|
||||
'Type' => $this->logLevels[$record['level']],
|
||||
'File' => $file,
|
||||
'Line' => $line,
|
||||
'Label' => $record['channel'],
|
||||
),
|
||||
$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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
<?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;
|
||||
use Monolog\Formatter\FormatterInterface;
|
||||
use Monolog\Formatter\LineFormatter;
|
||||
|
||||
/**
|
||||
* Base Handler class providing the Handler structure
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
abstract class AbstractHandler implements HandlerInterface
|
||||
{
|
||||
protected $level = Logger::DEBUG;
|
||||
protected $bubble = true;
|
||||
|
||||
/**
|
||||
* @var FormatterInterface
|
||||
*/
|
||||
protected $formatter;
|
||||
protected $processors = array();
|
||||
|
||||
/**
|
||||
* @param integer $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
|
||||
*/
|
||||
public function __construct($level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
$this->level = $level;
|
||||
$this->bubble = $bubble;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isHandling(array $record)
|
||||
{
|
||||
return $record['level'] >= $this->level;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handleBatch(array $records)
|
||||
{
|
||||
foreach ($records as $record) {
|
||||
$this->handle($record);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the handler.
|
||||
*
|
||||
* This will be called automatically when the object is destroyed
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function pushProcessor($callback)
|
||||
{
|
||||
if (!is_callable($callback)) {
|
||||
throw new \InvalidArgumentException('Processors must be valid callables (callback or object with an __invoke method), '.var_export($callback, true).' given');
|
||||
}
|
||||
array_unshift($this->processors, $callback);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function popProcessor()
|
||||
{
|
||||
if (!$this->processors) {
|
||||
throw new \LogicException('You tried to pop from an empty processor stack.');
|
||||
}
|
||||
|
||||
return array_shift($this->processors);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setFormatter(FormatterInterface $formatter)
|
||||
{
|
||||
$this->formatter = $formatter;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormatter()
|
||||
{
|
||||
if (!$this->formatter) {
|
||||
$this->formatter = $this->getDefaultFormatter();
|
||||
}
|
||||
|
||||
return $this->formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets minimum logging level at which this handler will be triggered.
|
||||
*
|
||||
* @param integer $level
|
||||
* @return self
|
||||
*/
|
||||
public function setLevel($level)
|
||||
{
|
||||
$this->level = $level;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets minimum logging level at which this handler will be triggered.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getLevel()
|
||||
{
|
||||
return $this->level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bubbling behavior.
|
||||
*
|
||||
* @param Boolean $bubble true means that this handler allows bubbling.
|
||||
* false means that bubbling is not permitted.
|
||||
* @return self
|
||||
*/
|
||||
public function setBubble($bubble)
|
||||
{
|
||||
$this->bubble = $bubble;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the bubbling behavior.
|
||||
*
|
||||
* @return Boolean true means that this handler allows bubbling.
|
||||
* false means that bubbling is not permitted.
|
||||
*/
|
||||
public function getBubble()
|
||||
{
|
||||
return $this->bubble;
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
try {
|
||||
$this->close();
|
||||
} catch (\Exception $e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default formatter.
|
||||
*
|
||||
* @return FormatterInterface
|
||||
*/
|
||||
protected function getDefaultFormatter()
|
||||
{
|
||||
return new LineFormatter();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Base Handler class providing the Handler structure
|
||||
*
|
||||
* Classes extending it should (in most cases) only implement write($record)
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @author Christophe Coevoet <stof@notk.org>
|
||||
*/
|
||||
abstract class AbstractProcessingHandler extends AbstractHandler
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handle(array $record)
|
||||
{
|
||||
if (!$this->isHandling($record)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$record = $this->processRecord($record);
|
||||
|
||||
$record['formatted'] = $this->getFormatter()->format($record);
|
||||
|
||||
$this->write($record);
|
||||
|
||||
return false === $this->bubble;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the record down to the log of the implementing handler
|
||||
*
|
||||
* @param array $record
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function write(array $record);
|
||||
|
||||
/**
|
||||
* Processes a record.
|
||||
*
|
||||
* @param array $record
|
||||
* @return array
|
||||
*/
|
||||
protected function processRecord(array $record)
|
||||
{
|
||||
if ($this->processors) {
|
||||
foreach ($this->processors as $processor) {
|
||||
$record = call_user_func($processor, $record);
|
||||
}
|
||||
}
|
||||
|
||||
return $record;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
<?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;
|
||||
use Monolog\Formatter\LineFormatter;
|
||||
|
||||
/**
|
||||
* Common syslog functionality
|
||||
*/
|
||||
abstract class AbstractSyslogHandler extends AbstractProcessingHandler
|
||||
{
|
||||
protected $facility;
|
||||
|
||||
/**
|
||||
* Translates Monolog log levels to syslog log priorities.
|
||||
*/
|
||||
protected $logLevels = array(
|
||||
Logger::DEBUG => LOG_DEBUG,
|
||||
Logger::INFO => LOG_INFO,
|
||||
Logger::NOTICE => LOG_NOTICE,
|
||||
Logger::WARNING => LOG_WARNING,
|
||||
Logger::ERROR => LOG_ERR,
|
||||
Logger::CRITICAL => LOG_CRIT,
|
||||
Logger::ALERT => LOG_ALERT,
|
||||
Logger::EMERGENCY => LOG_EMERG,
|
||||
);
|
||||
|
||||
/**
|
||||
* List of valid log facility names.
|
||||
*/
|
||||
protected $facilities = array(
|
||||
'auth' => LOG_AUTH,
|
||||
'authpriv' => LOG_AUTHPRIV,
|
||||
'cron' => LOG_CRON,
|
||||
'daemon' => LOG_DAEMON,
|
||||
'kern' => LOG_KERN,
|
||||
'lpr' => LOG_LPR,
|
||||
'mail' => LOG_MAIL,
|
||||
'news' => LOG_NEWS,
|
||||
'syslog' => LOG_SYSLOG,
|
||||
'user' => LOG_USER,
|
||||
'uucp' => LOG_UUCP,
|
||||
);
|
||||
|
||||
/**
|
||||
* @param mixed $facility
|
||||
* @param integer $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
|
||||
*/
|
||||
public function __construct($facility = LOG_USER, $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
parent::__construct($level, $bubble);
|
||||
|
||||
if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
|
||||
$this->facilities['local0'] = LOG_LOCAL0;
|
||||
$this->facilities['local1'] = LOG_LOCAL1;
|
||||
$this->facilities['local2'] = LOG_LOCAL2;
|
||||
$this->facilities['local3'] = LOG_LOCAL3;
|
||||
$this->facilities['local4'] = LOG_LOCAL4;
|
||||
$this->facilities['local5'] = LOG_LOCAL5;
|
||||
$this->facilities['local6'] = LOG_LOCAL6;
|
||||
$this->facilities['local7'] = LOG_LOCAL7;
|
||||
}
|
||||
|
||||
// convert textual description of facility to syslog constant
|
||||
if (array_key_exists(strtolower($facility), $this->facilities)) {
|
||||
$facility = $this->facilities[strtolower($facility)];
|
||||
} elseif (!in_array($facility, array_values($this->facilities), true)) {
|
||||
throw new \UnexpectedValueException('Unknown facility value "'.$facility.'" given');
|
||||
}
|
||||
|
||||
$this->facility = $facility;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getDefaultFormatter()
|
||||
{
|
||||
return new LineFormatter('%channel%.%level_name%: %message% %context% %extra%');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?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;
|
||||
use Monolog\Formatter\JsonFormatter;
|
||||
|
||||
class AmqpHandler extends AbstractProcessingHandler
|
||||
{
|
||||
/**
|
||||
* @var \AMQPExchange $exchange
|
||||
*/
|
||||
protected $exchange;
|
||||
|
||||
/**
|
||||
* @param \AMQPExchange $exchange AMQP exchange, ready for use
|
||||
* @param string $exchangeName
|
||||
* @param int $level
|
||||
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
|
||||
*/
|
||||
public function __construct(\AMQPExchange $exchange, $exchangeName = 'log', $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
$this->exchange = $exchange;
|
||||
$this->exchange->setName($exchangeName);
|
||||
|
||||
parent::__construct($level, $bubble);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function write(array $record)
|
||||
{
|
||||
$data = $record["formatted"];
|
||||
|
||||
$routingKey = sprintf(
|
||||
'%s.%s',
|
||||
substr($record['level_name'], 0, 4),
|
||||
$record['channel']
|
||||
);
|
||||
|
||||
$this->exchange->publish(
|
||||
$data,
|
||||
strtolower($routingKey),
|
||||
0,
|
||||
array(
|
||||
'delivery_mode' => 2,
|
||||
'Content-type' => 'application/json'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function getDefaultFormatter()
|
||||
{
|
||||
return new JsonFormatter();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Buffers all records until closing the handler and then pass them as batch.
|
||||
*
|
||||
* This is useful for a MailHandler to send only one mail per request instead of
|
||||
* sending one per log message.
|
||||
*
|
||||
* @author Christophe Coevoet <stof@notk.org>
|
||||
*/
|
||||
class BufferHandler extends AbstractHandler
|
||||
{
|
||||
protected $handler;
|
||||
protected $bufferSize = 0;
|
||||
protected $bufferLimit;
|
||||
protected $flushOnOverflow;
|
||||
protected $buffer = array();
|
||||
|
||||
/**
|
||||
* @param HandlerInterface $handler Handler.
|
||||
* @param integer $bufferLimit How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
|
||||
* @param integer $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 Boolean $flushOnOverflow If true, the buffer is flushed when the max size has been reached, by default oldest entries are discarded
|
||||
*/
|
||||
public function __construct(HandlerInterface $handler, $bufferLimit = 0, $level = Logger::DEBUG, $bubble = true, $flushOnOverflow = false)
|
||||
{
|
||||
parent::__construct($level, $bubble);
|
||||
$this->handler = $handler;
|
||||
$this->bufferLimit = (int) $bufferLimit;
|
||||
$this->flushOnOverflow = $flushOnOverflow;
|
||||
|
||||
// __destructor() doesn't get called on Fatal errors
|
||||
register_shutdown_function(array($this, 'close'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handle(array $record)
|
||||
{
|
||||
if ($record['level'] < $this->level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->bufferLimit > 0 && $this->bufferSize === $this->bufferLimit) {
|
||||
if ($this->flushOnOverflow) {
|
||||
$this->flush();
|
||||
} else {
|
||||
array_shift($this->buffer);
|
||||
$this->bufferSize--;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->processors) {
|
||||
foreach ($this->processors as $processor) {
|
||||
$record = call_user_func($processor, $record);
|
||||
}
|
||||
}
|
||||
|
||||
$this->buffer[] = $record;
|
||||
$this->bufferSize++;
|
||||
|
||||
return false === $this->bubble;
|
||||
}
|
||||
|
||||
public function flush()
|
||||
{
|
||||
if ($this->bufferSize === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->handler->handleBatch($this->buffer);
|
||||
$this->bufferSize = 0;
|
||||
$this->buffer = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
$this->flush();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
<?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\Formatter\ChromePHPFormatter;
|
||||
use Monolog\Logger;
|
||||
|
||||
/**
|
||||
* Handler sending logs to the ChromePHP extension (http://www.chromephp.com/)
|
||||
*
|
||||
* @author Christophe Coevoet <stof@notk.org>
|
||||
*/
|
||||
class ChromePHPHandler extends AbstractProcessingHandler
|
||||
{
|
||||
/**
|
||||
* Version of the extension
|
||||
*/
|
||||
const VERSION = '4.0';
|
||||
|
||||
/**
|
||||
* Header name
|
||||
*/
|
||||
const HEADER_NAME = 'X-ChromeLogger-Data';
|
||||
|
||||
protected static $initialized = false;
|
||||
|
||||
/**
|
||||
* Tracks whether we sent too much data
|
||||
*
|
||||
* Chrome limits the headers to 256KB, so when we sent 240KB we stop sending
|
||||
*
|
||||
* @var Boolean
|
||||
*/
|
||||
protected static $overflowed = false;
|
||||
|
||||
protected static $json = array(
|
||||
'version' => self::VERSION,
|
||||
'columns' => array('label', 'log', 'backtrace', 'type'),
|
||||
'rows' => array(),
|
||||
);
|
||||
|
||||
protected static $sendHeaders = true;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handleBatch(array $records)
|
||||
{
|
||||
$messages = array();
|
||||
|
||||
foreach ($records as $record) {
|
||||
if ($record['level'] < $this->level) {
|
||||
continue;
|
||||
}
|
||||
$messages[] = $this->processRecord($record);
|
||||
}
|
||||
|
||||
if (!empty($messages)) {
|
||||
$messages = $this->getFormatter()->formatBatch($messages);
|
||||
self::$json['rows'] = array_merge(self::$json['rows'], $messages);
|
||||
$this->send();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function getDefaultFormatter()
|
||||
{
|
||||
return new ChromePHPFormatter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates & sends header for a record
|
||||
*
|
||||
* @see sendHeader()
|
||||
* @see send()
|
||||
* @param array $record
|
||||
*/
|
||||
protected function write(array $record)
|
||||
{
|
||||
self::$json['rows'][] = $record['formatted'];
|
||||
|
||||
$this->send();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the log header
|
||||
*
|
||||
* @see sendHeader()
|
||||
*/
|
||||
protected function send()
|
||||
{
|
||||
if (self::$overflowed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self::$initialized) {
|
||||
self::$sendHeaders = $this->headersAccepted();
|
||||
self::$json['request_uri'] = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
|
||||
|
||||
self::$initialized = true;
|
||||
}
|
||||
|
||||
$json = @json_encode(self::$json);
|
||||
$data = base64_encode(utf8_encode($json));
|
||||
if (strlen($data) > 240*1024) {
|
||||
self::$overflowed = true;
|
||||
|
||||
$record = array(
|
||||
'message' => 'Incomplete logs, chrome header size limit reached',
|
||||
'context' => array(),
|
||||
'level' => Logger::WARNING,
|
||||
'level_name' => Logger::getLevelName(Logger::WARNING),
|
||||
'channel' => 'monolog',
|
||||
'datetime' => new \DateTime(),
|
||||
'extra' => array(),
|
||||
);
|
||||
self::$json['rows'][count(self::$json['rows']) - 1] = $this->getFormatter()->format($record);
|
||||
$json = @json_encode(self::$json);
|
||||
$data = base64_encode(utf8_encode($json));
|
||||
}
|
||||
|
||||
$this->sendHeader(self::HEADER_NAME, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send header string to the client
|
||||
*
|
||||
* @param string $header
|
||||
* @param string $content
|
||||
*/
|
||||
protected function sendHeader($header, $content)
|
||||
{
|
||||
if (!headers_sent() && self::$sendHeaders) {
|
||||
header(sprintf('%s: %s', $header, $content));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if the headers are accepted by the current user agent
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
protected function headersAccepted()
|
||||
{
|
||||
return !isset($_SERVER['HTTP_USER_AGENT'])
|
||||
|| preg_match('{\bChrome/\d+[\.\d+]*\b}', $_SERVER['HTTP_USER_AGENT']);
|
||||
}
|
||||
|
||||
/**
|
||||
* BC getter for the sendHeaders property that has been made static
|
||||
*/
|
||||
public function __get($property)
|
||||
{
|
||||
if ('sendHeaders' !== $property) {
|
||||
throw new \InvalidArgumentException('Undefined property '.$property);
|
||||
}
|
||||
|
||||
return static::$sendHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* BC setter for the sendHeaders property that has been made static
|
||||
*/
|
||||
public function __set($property, $value)
|
||||
{
|
||||
if ('sendHeaders' !== $property) {
|
||||
throw new \InvalidArgumentException('Undefined property '.$property);
|
||||
}
|
||||
|
||||
static::$sendHeaders = $value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?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\Formatter\JsonFormatter;
|
||||
use Monolog\Logger;
|
||||
|
||||
/**
|
||||
* CouchDB handler
|
||||
*
|
||||
* @author Markus Bachmann <markus.bachmann@bachi.biz>
|
||||
*/
|
||||
class CouchDBHandler extends AbstractProcessingHandler
|
||||
{
|
||||
private $options;
|
||||
|
||||
public function __construct(array $options = array(), $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
$this->options = array_merge(array(
|
||||
'host' => 'localhost',
|
||||
'port' => 5984,
|
||||
'dbname' => 'logger',
|
||||
'username' => null,
|
||||
'password' => null,
|
||||
), $options);
|
||||
|
||||
parent::__construct($level, $bubble);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function write(array $record)
|
||||
{
|
||||
$basicAuth = null;
|
||||
if ($this->options['username']) {
|
||||
$basicAuth = sprintf('%s:%s@', $this->options['username'], $this->options['password']);
|
||||
}
|
||||
|
||||
$url = 'http://'.$basicAuth.$this->options['host'].':'.$this->options['port'].'/'.$this->options['dbname'];
|
||||
$context = stream_context_create(array(
|
||||
'http' => array(
|
||||
'method' => 'POST',
|
||||
'content' => $record['formatted'],
|
||||
'ignore_errors' => true,
|
||||
'max_redirects' => 0,
|
||||
'header' => 'Content-type: application/json',
|
||||
)
|
||||
));
|
||||
|
||||
if (false === @file_get_contents($url, null, $context)) {
|
||||
throw new \RuntimeException(sprintf('Could not connect to %s', $url));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function getDefaultFormatter()
|
||||
{
|
||||
return new JsonFormatter();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Logs to Cube.
|
||||
*
|
||||
* @link http://square.github.com/cube/
|
||||
* @author Wan Chen <kami@kamisama.me>
|
||||
*/
|
||||
class CubeHandler extends AbstractProcessingHandler
|
||||
{
|
||||
private $udpConnection = null;
|
||||
private $httpConnection = null;
|
||||
private $scheme = null;
|
||||
private $host = null;
|
||||
private $port = null;
|
||||
private $acceptedSchemes = array('http', 'udp');
|
||||
|
||||
/**
|
||||
* Create a Cube handler
|
||||
*
|
||||
* @throws UnexpectedValueException when given url is not a valid url.
|
||||
* A valid url must consists of three parts : protocol://host:port
|
||||
* Only valid protocol used by Cube are http and udp
|
||||
*/
|
||||
public function __construct($url, $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
$urlInfos = parse_url($url);
|
||||
|
||||
if (!isset($urlInfos['scheme']) || !isset($urlInfos['host']) || !isset($urlInfos['port'])) {
|
||||
throw new \UnexpectedValueException('URL "'.$url.'" is not valid');
|
||||
}
|
||||
|
||||
if (!in_array($urlInfos['scheme'], $this->acceptedSchemes)) {
|
||||
throw new \UnexpectedValueException(
|
||||
'Invalid protocol (' . $urlInfos['scheme'] . ').'
|
||||
. ' Valid options are ' . implode(', ', $this->acceptedSchemes));
|
||||
}
|
||||
|
||||
$this->scheme = $urlInfos['scheme'];
|
||||
$this->host = $urlInfos['host'];
|
||||
$this->port = $urlInfos['port'];
|
||||
|
||||
parent::__construct($level, $bubble);
|
||||
}
|
||||
|
||||
/**
|
||||
* Establish a connection to an UDP socket
|
||||
*
|
||||
* @throws LogicException when unable to connect to the socket
|
||||
*/
|
||||
protected function connectUdp()
|
||||
{
|
||||
if (!extension_loaded('sockets')) {
|
||||
throw new MissingExtensionException('The sockets extension is required to use udp URLs with the CubeHandler');
|
||||
}
|
||||
|
||||
$this->udpConnection = socket_create(AF_INET, SOCK_DGRAM, 0);
|
||||
if (!$this->udpConnection) {
|
||||
throw new \LogicException('Unable to create a socket');
|
||||
}
|
||||
|
||||
if (!socket_connect($this->udpConnection, $this->host, $this->port)) {
|
||||
throw new \LogicException('Unable to connect to the socket at ' . $this->host . ':' . $this->port);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Establish a connection to a http server
|
||||
*/
|
||||
protected function connectHttp()
|
||||
{
|
||||
if (!extension_loaded('curl')) {
|
||||
throw new \LogicException('The curl extension is needed to use http URLs with the CubeHandler');
|
||||
}
|
||||
|
||||
$this->httpConnection = curl_init('http://'.$this->host.':'.$this->port.'/1.0/event/put');
|
||||
|
||||
if (!$this->httpConnection) {
|
||||
throw new \LogicException('Unable to connect to ' . $this->host . ':' . $this->port);
|
||||
}
|
||||
|
||||
curl_setopt($this->httpConnection, CURLOPT_CUSTOMREQUEST, "POST");
|
||||
curl_setopt($this->httpConnection, CURLOPT_RETURNTRANSFER, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function write(array $record)
|
||||
{
|
||||
$date = $record['datetime'];
|
||||
|
||||
$data = array('time' => $date->format('Y-m-d\TH:i:s.uO'));
|
||||
unset($record['datetime']);
|
||||
|
||||
if (isset($record['context']['type'])) {
|
||||
$data['type'] = $record['context']['type'];
|
||||
unset($record['context']['type']);
|
||||
} else {
|
||||
$data['type'] = $record['channel'];
|
||||
}
|
||||
|
||||
$data['data'] = $record['context'];
|
||||
$data['data']['level'] = $record['level'];
|
||||
|
||||
$this->{'write'.$this->scheme}(json_encode($data));
|
||||
}
|
||||
|
||||
private function writeUdp($data)
|
||||
{
|
||||
if (!$this->udpConnection) {
|
||||
$this->connectUdp();
|
||||
}
|
||||
|
||||
socket_send($this->udpConnection, $data, strlen($data), 0);
|
||||
}
|
||||
|
||||
private function writeHttp($data)
|
||||
{
|
||||
if (!$this->httpConnection) {
|
||||
$this->connectHttp();
|
||||
}
|
||||
|
||||
curl_setopt($this->httpConnection, CURLOPT_POSTFIELDS, '['.$data.']');
|
||||
curl_setopt($this->httpConnection, CURLOPT_HTTPHEADER, array(
|
||||
'Content-Type: application/json',
|
||||
'Content-Length: ' . strlen('['.$data.']'))
|
||||
);
|
||||
|
||||
return curl_exec($this->httpConnection);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?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;
|
||||
use Monolog\Formatter\NormalizerFormatter;
|
||||
use Doctrine\CouchDB\CouchDBClient;
|
||||
|
||||
/**
|
||||
* CouchDB handler for Doctrine CouchDB ODM
|
||||
*
|
||||
* @author Markus Bachmann <markus.bachmann@bachi.biz>
|
||||
*/
|
||||
class DoctrineCouchDBHandler extends AbstractProcessingHandler
|
||||
{
|
||||
private $client;
|
||||
|
||||
public function __construct(CouchDBClient $client, $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
$this->client = $client;
|
||||
parent::__construct($level, $bubble);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function write(array $record)
|
||||
{
|
||||
$this->client->postDocument($record['formatted']);
|
||||
}
|
||||
|
||||
protected function getDefaultFormatter()
|
||||
{
|
||||
return new NormalizerFormatter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?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 Aws\Common\Aws;
|
||||
use Aws\DynamoDb\DynamoDbClient;
|
||||
use Monolog\Formatter\ScalarFormatter;
|
||||
use Monolog\Handler\AbstractProcessingHandler;
|
||||
use Monolog\Logger;
|
||||
|
||||
/**
|
||||
* Amazon DynamoDB handler (http://aws.amazon.com/dynamodb/)
|
||||
*
|
||||
* @link https://github.com/aws/aws-sdk-php/
|
||||
* @author Andrew Lawson <adlawson@gmail.com>
|
||||
*/
|
||||
class DynamoDbHandler extends AbstractProcessingHandler
|
||||
{
|
||||
const DATE_FORMAT = 'Y-m-d\TH:i:s.uO';
|
||||
|
||||
/**
|
||||
* @var DynamoDbClient
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table;
|
||||
|
||||
/**
|
||||
* @param DynamoDbClient $client
|
||||
* @param string $table
|
||||
* @param integer $level
|
||||
* @param boolean $bubble
|
||||
*/
|
||||
public function __construct(DynamoDbClient $client, $table, $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
if (!defined('Aws\Common\Aws::VERSION') || version_compare('3.0', Aws::VERSION, '<=')) {
|
||||
throw new \RuntimeException('The DynamoDbHandler is only known to work with the AWS SDK 2.x releases');
|
||||
}
|
||||
|
||||
$this->client = $client;
|
||||
$this->table = $table;
|
||||
|
||||
parent::__construct($level, $bubble);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function write(array $record)
|
||||
{
|
||||
$filtered = $this->filterEmptyFields($record['formatted']);
|
||||
$formatted = $this->client->formatAttributes($filtered);
|
||||
|
||||
$this->client->putItem(array(
|
||||
'TableName' => $this->table,
|
||||
'Item' => $formatted
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $record
|
||||
* @return array
|
||||
*/
|
||||
protected function filterEmptyFields(array $record)
|
||||
{
|
||||
return array_filter($record, function($value) {
|
||||
return !empty($value) || false === $value || 0 === $value;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getDefaultFormatter()
|
||||
{
|
||||
return new ScalarFormatter(self::DATE_FORMAT);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
<?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\Formatter\FormatterInterface;
|
||||
use Monolog\Formatter\ElasticaFormatter;
|
||||
use Monolog\Logger;
|
||||
use Elastica\Client;
|
||||
use Elastica\Exception\ExceptionInterface;
|
||||
|
||||
/**
|
||||
* Elastic Search handler
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* $client = new \Elastica\Client();
|
||||
* $options = array(
|
||||
* 'index' => 'elastic_index_name',
|
||||
* 'type' => 'elastic_doc_type',
|
||||
* );
|
||||
* $handler = new ElasticSearchHandler($client, $options);
|
||||
* $log = new Logger('application');
|
||||
* $log->pushHandler($handler);
|
||||
*
|
||||
* @author Jelle Vink <jelle.vink@gmail.com>
|
||||
*/
|
||||
class ElasticSearchHandler extends AbstractProcessingHandler
|
||||
{
|
||||
/**
|
||||
* @var Client
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* @var array Handler config options
|
||||
*/
|
||||
protected $options = array();
|
||||
|
||||
/**
|
||||
* @param Client $client Elastica Client object
|
||||
* @param array $options Handler configuration
|
||||
* @param integer $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
|
||||
*/
|
||||
public function __construct(Client $client, array $options = array(), $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
parent::__construct($level, $bubble);
|
||||
$this->client = $client;
|
||||
$this->options = array_merge(
|
||||
array(
|
||||
'index' => 'monolog', // Elastic index name
|
||||
'type' => 'record', // Elastic document type
|
||||
'ignore_error' => false, // Suppress Elastica exceptions
|
||||
),
|
||||
$options
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function write(array $record)
|
||||
{
|
||||
$this->bulkSend(array($record['formatted']));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setFormatter(FormatterInterface $formatter)
|
||||
{
|
||||
if ($formatter instanceof ElasticaFormatter) {
|
||||
return parent::setFormatter($formatter);
|
||||
}
|
||||
throw new \InvalidArgumentException('ElasticSearchHandler is only compatible with ElasticaFormatter');
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter options
|
||||
* @return array
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function getDefaultFormatter()
|
||||
{
|
||||
return new ElasticaFormatter($this->options['index'], $this->options['type']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handleBatch(array $records)
|
||||
{
|
||||
$documents = $this->getFormatter()->formatBatch($records);
|
||||
$this->bulkSend($documents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use Elasticsearch bulk API to send list of documents
|
||||
* @param array $documents
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function bulkSend(array $documents)
|
||||
{
|
||||
try {
|
||||
$this->client->addDocuments($documents);
|
||||
} catch (ExceptionInterface $e) {
|
||||
if (!$this->options['ignore_error']) {
|
||||
throw new \RuntimeException("Error sending messages to Elasticsearch", 0, $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?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 PHP error_log() handler.
|
||||
*
|
||||
* @author Elan Ruusamäe <glen@delfi.ee>
|
||||
*/
|
||||
class ErrorLogHandler extends AbstractProcessingHandler
|
||||
{
|
||||
const OPERATING_SYSTEM = 0;
|
||||
const SAPI = 4;
|
||||
|
||||
protected $messageType;
|
||||
|
||||
/**
|
||||
* @param integer $messageType Says where the error should go.
|
||||
* @param integer $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
|
||||
*/
|
||||
public function __construct($messageType = self::OPERATING_SYSTEM, $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
parent::__construct($level, $bubble);
|
||||
|
||||
if (false === in_array($messageType, self::getAvailableTypes())) {
|
||||
$message = sprintf('The given message type "%s" is not supported', print_r($messageType, true));
|
||||
throw new \InvalidArgumentException($message);
|
||||
}
|
||||
|
||||
$this->messageType = $messageType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array With all available types
|
||||
*/
|
||||
public static function getAvailableTypes()
|
||||
{
|
||||
return array(
|
||||
self::OPERATING_SYSTEM,
|
||||
self::SAPI,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function write(array $record)
|
||||
{
|
||||
error_log((string) $record['formatted'], $this->messageType);
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
<?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\FingersCrossed;
|
||||
|
||||
/**
|
||||
* Interface for activation strategies for the FingersCrossedHandler.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
interface ActivationStrategyInterface
|
||||
{
|
||||
/**
|
||||
* Returns whether the given record activates the handler.
|
||||
*
|
||||
* @param array $record
|
||||
* @return Boolean
|
||||
*/
|
||||
public function isHandlerActivated(array $record);
|
||||
}
|
||||
Vendored
+57
@@ -0,0 +1,57 @@
|
||||
<?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\FingersCrossed;
|
||||
|
||||
/**
|
||||
* Channel and Error level based monolog activation strategy. Allows to trigger activation
|
||||
* based on level per channel. e.g. trigger activation on level 'ERROR' by default, except
|
||||
* for records of the 'sql' channel; those should trigger activation on level 'WARN'.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* <code>
|
||||
* $activationStrategy = new ChannelLevelActivationStrategy(
|
||||
* Logger::CRITICAL,
|
||||
* array(
|
||||
* 'request' => Logger::ALERT,
|
||||
* 'sensitive' => Logger::ERROR,
|
||||
* )
|
||||
* );
|
||||
* $handler = new FingersCrossedHandler(new StreamHandler('php://stderr'), $activationStrategy);
|
||||
* </code>
|
||||
*
|
||||
* @author Mike Meessen <netmikey@gmail.com>
|
||||
*/
|
||||
class ChannelLevelActivationStrategy implements ActivationStrategyInterface
|
||||
{
|
||||
private $defaultActionLevel;
|
||||
private $channelToActionLevel;
|
||||
|
||||
/**
|
||||
* @param int $defaultActionLevel The default action level to be used if the record's category doesn't match any
|
||||
* @param array $categoryToActionLevel An array that maps channel names to action levels.
|
||||
*/
|
||||
public function __construct($defaultActionLevel, $channelToActionLevel = array())
|
||||
{
|
||||
$this->defaultActionLevel = $defaultActionLevel;
|
||||
$this->channelToActionLevel = $channelToActionLevel;
|
||||
}
|
||||
|
||||
public function isHandlerActivated(array $record)
|
||||
{
|
||||
if (isset($this->channelToActionLevel[$record['channel']])) {
|
||||
return $record['level'] >= $this->channelToActionLevel[$record['channel']];
|
||||
}
|
||||
|
||||
return $record['level'] >= $this->defaultActionLevel;
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
<?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\FingersCrossed;
|
||||
|
||||
/**
|
||||
* Error level based activation strategy.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ErrorLevelActivationStrategy implements ActivationStrategyInterface
|
||||
{
|
||||
private $actionLevel;
|
||||
|
||||
public function __construct($actionLevel)
|
||||
{
|
||||
$this->actionLevel = $actionLevel;
|
||||
}
|
||||
|
||||
public function isHandlerActivated(array $record)
|
||||
{
|
||||
return $record['level'] >= $this->actionLevel;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
<?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\Handler\FingersCrossed\ErrorLevelActivationStrategy;
|
||||
use Monolog\Handler\FingersCrossed\ActivationStrategyInterface;
|
||||
use Monolog\Logger;
|
||||
|
||||
/**
|
||||
* Buffers all records until a certain level is reached
|
||||
*
|
||||
* The advantage of this approach is that you don't get any clutter in your log files.
|
||||
* Only requests which actually trigger an error (or whatever your actionLevel is) will be
|
||||
* in the logs, but they will contain all records, not only those above the level threshold.
|
||||
*
|
||||
* You can find the various activation strategies in the
|
||||
* Monolog\Handler\FingersCrossed\ namespace.
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class FingersCrossedHandler extends AbstractHandler
|
||||
{
|
||||
protected $handler;
|
||||
protected $activationStrategy;
|
||||
protected $buffering = true;
|
||||
protected $bufferSize;
|
||||
protected $buffer = array();
|
||||
protected $stopBuffering;
|
||||
|
||||
/**
|
||||
* @param callable|HandlerInterface $handler Handler or factory callable($record, $fingersCrossedHandler).
|
||||
* @param int|ActivationStrategyInterface $activationStrategy Strategy which determines when this handler takes action
|
||||
* @param int $bufferSize How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
|
||||
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
|
||||
* @param Boolean $stopBuffering Whether the handler should stop buffering after being triggered (default true)
|
||||
*/
|
||||
public function __construct($handler, $activationStrategy = null, $bufferSize = 0, $bubble = true, $stopBuffering = true)
|
||||
{
|
||||
if (null === $activationStrategy) {
|
||||
$activationStrategy = new ErrorLevelActivationStrategy(Logger::WARNING);
|
||||
}
|
||||
|
||||
// convert simple int activationStrategy to an object
|
||||
if (!$activationStrategy instanceof ActivationStrategyInterface) {
|
||||
$activationStrategy = new ErrorLevelActivationStrategy($activationStrategy);
|
||||
}
|
||||
|
||||
$this->handler = $handler;
|
||||
$this->activationStrategy = $activationStrategy;
|
||||
$this->bufferSize = $bufferSize;
|
||||
$this->bubble = $bubble;
|
||||
$this->stopBuffering = $stopBuffering;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isHandling(array $record)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handle(array $record)
|
||||
{
|
||||
if ($this->processors) {
|
||||
foreach ($this->processors as $processor) {
|
||||
$record = call_user_func($processor, $record);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->buffering) {
|
||||
$this->buffer[] = $record;
|
||||
if ($this->bufferSize > 0 && count($this->buffer) > $this->bufferSize) {
|
||||
array_shift($this->buffer);
|
||||
}
|
||||
if ($this->activationStrategy->isHandlerActivated($record)) {
|
||||
if ($this->stopBuffering) {
|
||||
$this->buffering = false;
|
||||
}
|
||||
if (!$this->handler instanceof HandlerInterface) {
|
||||
if (!is_callable($this->handler)) {
|
||||
throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object");
|
||||
}
|
||||
$this->handler = call_user_func($this->handler, $record, $this);
|
||||
if (!$this->handler instanceof HandlerInterface) {
|
||||
throw new \RuntimeException("The factory callable should return a HandlerInterface");
|
||||
}
|
||||
}
|
||||
$this->handler->handleBatch($this->buffer);
|
||||
$this->buffer = array();
|
||||
}
|
||||
} else {
|
||||
$this->handler->handle($record);
|
||||
}
|
||||
|
||||
return false === $this->bubble;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the state of the handler. Stops forwarding records to the wrapped handler.
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->buffering = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
<?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\Formatter\WildfireFormatter;
|
||||
|
||||
/**
|
||||
* Simple FirePHP Handler (http://www.firephp.org/), which uses the Wildfire protocol.
|
||||
*
|
||||
* @author Eric Clemmons (@ericclemmons) <eric@uxdriven.com>
|
||||
*/
|
||||
class FirePHPHandler extends AbstractProcessingHandler
|
||||
{
|
||||
/**
|
||||
* WildFire JSON header message format
|
||||
*/
|
||||
const PROTOCOL_URI = 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2';
|
||||
|
||||
/**
|
||||
* FirePHP structure for parsing messages & their presentation
|
||||
*/
|
||||
const STRUCTURE_URI = 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1';
|
||||
|
||||
/**
|
||||
* Must reference a "known" plugin, otherwise headers won't display in FirePHP
|
||||
*/
|
||||
const PLUGIN_URI = 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3';
|
||||
|
||||
/**
|
||||
* Header prefix for Wildfire to recognize & parse headers
|
||||
*/
|
||||
const HEADER_PREFIX = 'X-Wf';
|
||||
|
||||
/**
|
||||
* Whether or not Wildfire vendor-specific headers have been generated & sent yet
|
||||
*/
|
||||
protected static $initialized = false;
|
||||
|
||||
/**
|
||||
* Shared static message index between potentially multiple handlers
|
||||
* @var int
|
||||
*/
|
||||
protected static $messageIndex = 1;
|
||||
|
||||
protected static $sendHeaders = true;
|
||||
|
||||
/**
|
||||
* Base header creation function used by init headers & record headers
|
||||
*
|
||||
* @param array $meta Wildfire Plugin, Protocol & Structure Indexes
|
||||
* @param string $message Log message
|
||||
* @return array Complete header string ready for the client as key and message as value
|
||||
*/
|
||||
protected function createHeader(array $meta, $message)
|
||||
{
|
||||
$header = sprintf('%s-%s', self::HEADER_PREFIX, join('-', $meta));
|
||||
|
||||
return array($header => $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates message header from record
|
||||
*
|
||||
* @see createHeader()
|
||||
* @param array $record
|
||||
* @return string
|
||||
*/
|
||||
protected function createRecordHeader(array $record)
|
||||
{
|
||||
// Wildfire is extensible to support multiple protocols & plugins in a single request,
|
||||
// but we're not taking advantage of that (yet), so we're using "1" for simplicity's sake.
|
||||
return $this->createHeader(
|
||||
array(1, 1, 1, self::$messageIndex++),
|
||||
$record['formatted']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function getDefaultFormatter()
|
||||
{
|
||||
return new WildfireFormatter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wildfire initialization headers to enable message parsing
|
||||
*
|
||||
* @see createHeader()
|
||||
* @see sendHeader()
|
||||
* @return array
|
||||
*/
|
||||
protected function getInitHeaders()
|
||||
{
|
||||
// Initial payload consists of required headers for Wildfire
|
||||
return array_merge(
|
||||
$this->createHeader(array('Protocol', 1), self::PROTOCOL_URI),
|
||||
$this->createHeader(array(1, 'Structure', 1), self::STRUCTURE_URI),
|
||||
$this->createHeader(array(1, 'Plugin', 1), self::PLUGIN_URI)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send header string to the client
|
||||
*
|
||||
* @param string $header
|
||||
* @param string $content
|
||||
*/
|
||||
protected function sendHeader($header, $content)
|
||||
{
|
||||
if (!headers_sent() && self::$sendHeaders) {
|
||||
header(sprintf('%s: %s', $header, $content));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates & sends header for a record, ensuring init headers have been sent prior
|
||||
*
|
||||
* @see sendHeader()
|
||||
* @see sendInitHeaders()
|
||||
* @param array $record
|
||||
*/
|
||||
protected function write(array $record)
|
||||
{
|
||||
// WildFire-specific headers must be sent prior to any messages
|
||||
if (!self::$initialized) {
|
||||
self::$sendHeaders = $this->headersAccepted();
|
||||
|
||||
foreach ($this->getInitHeaders() as $header => $content) {
|
||||
$this->sendHeader($header, $content);
|
||||
}
|
||||
|
||||
self::$initialized = true;
|
||||
}
|
||||
|
||||
$header = $this->createRecordHeader($record);
|
||||
$this->sendHeader(key($header), current($header));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if the headers are accepted by the current user agent
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
protected function headersAccepted()
|
||||
{
|
||||
return !isset($_SERVER['HTTP_USER_AGENT'])
|
||||
|| preg_match('{\bFirePHP/\d+\.\d+\b}', $_SERVER['HTTP_USER_AGENT'])
|
||||
|| isset($_SERVER['HTTP_X_FIREPHP_VERSION']);
|
||||
}
|
||||
|
||||
/**
|
||||
* BC getter for the sendHeaders property that has been made static
|
||||
*/
|
||||
public function __get($property)
|
||||
{
|
||||
if ('sendHeaders' !== $property) {
|
||||
throw new \InvalidArgumentException('Undefined property '.$property);
|
||||
}
|
||||
|
||||
return static::$sendHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* BC setter for the sendHeaders property that has been made static
|
||||
*/
|
||||
public function __set($property, $value)
|
||||
{
|
||||
if ('sendHeaders' !== $property) {
|
||||
throw new \InvalidArgumentException('Undefined property '.$property);
|
||||
}
|
||||
|
||||
static::$sendHeaders = $value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?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 Gelf\IMessagePublisher;
|
||||
use Monolog\Logger;
|
||||
use Monolog\Handler\AbstractProcessingHandler;
|
||||
use Monolog\Formatter\GelfMessageFormatter;
|
||||
|
||||
/**
|
||||
* Handler to send messages to a Graylog2 (http://www.graylog2.org) server
|
||||
*
|
||||
* @author Matt Lehner <mlehner@gmail.com>
|
||||
*/
|
||||
class GelfHandler extends AbstractProcessingHandler
|
||||
{
|
||||
/**
|
||||
* @var Gelf\IMessagePublisher the publisher object that sends the message to the server
|
||||
*/
|
||||
protected $publisher;
|
||||
|
||||
/**
|
||||
* @param Gelf\IMessagePublisher $publisher a publisher object
|
||||
* @param integer $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
|
||||
*/
|
||||
public function __construct(IMessagePublisher $publisher, $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
parent::__construct($level, $bubble);
|
||||
|
||||
$this->publisher = $publisher;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
$this->publisher = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function write(array $record)
|
||||
{
|
||||
$this->publisher->publish($record['formatted']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function getDefaultFormatter()
|
||||
{
|
||||
return new GelfMessageFormatter();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Forwards records to multiple handlers
|
||||
*
|
||||
* @author Lenar Lõhmus <lenar@city.ee>
|
||||
*/
|
||||
class GroupHandler extends AbstractHandler
|
||||
{
|
||||
protected $handlers;
|
||||
|
||||
/**
|
||||
* @param array $handlers Array of Handlers.
|
||||
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
|
||||
*/
|
||||
public function __construct(array $handlers, $bubble = true)
|
||||
{
|
||||
foreach ($handlers as $handler) {
|
||||
if (!$handler instanceof HandlerInterface) {
|
||||
throw new \InvalidArgumentException('The first argument of the GroupHandler must be an array of HandlerInterface instances.');
|
||||
}
|
||||
}
|
||||
|
||||
$this->handlers = $handlers;
|
||||
$this->bubble = $bubble;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isHandling(array $record)
|
||||
{
|
||||
foreach ($this->handlers as $handler) {
|
||||
if ($handler->isHandling($record)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handle(array $record)
|
||||
{
|
||||
if ($this->processors) {
|
||||
foreach ($this->processors as $processor) {
|
||||
$record = call_user_func($processor, $record);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->handlers as $handler) {
|
||||
$handler->handle($record);
|
||||
}
|
||||
|
||||
return false === $this->bubble;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handleBatch(array $records)
|
||||
{
|
||||
foreach ($this->handlers as $handler) {
|
||||
$handler->handleBatch($records);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?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\Formatter\FormatterInterface;
|
||||
|
||||
/**
|
||||
* Interface that all Monolog Handlers must implement
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
interface HandlerInterface
|
||||
{
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param array $record
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function isHandling(array $record);
|
||||
|
||||
/**
|
||||
* Handles a record.
|
||||
*
|
||||
* All records may be passed to this method, and the handler should discard
|
||||
* those that it does not want to handle.
|
||||
*
|
||||
* The return value of this function controls the bubbling process of the handler stack.
|
||||
* Unless the bubbling is interrupted (by returning true), the Logger class will keep on
|
||||
* calling further handlers in the stack with a given log record.
|
||||
*
|
||||
* @param array $record The record to handle
|
||||
* @return Boolean true means that this handler handled the record, and that bubbling is not permitted.
|
||||
* false means the record was either not processed or that this handler allows bubbling.
|
||||
*/
|
||||
public function handle(array $record);
|
||||
|
||||
/**
|
||||
* Handles a set of records at once.
|
||||
*
|
||||
* @param array $records The records to handle (an array of record arrays)
|
||||
*/
|
||||
public function handleBatch(array $records);
|
||||
|
||||
/**
|
||||
* Adds a processor in the stack.
|
||||
*
|
||||
* @param callable $callback
|
||||
* @return self
|
||||
*/
|
||||
public function pushProcessor($callback);
|
||||
|
||||
/**
|
||||
* Removes the processor on top of the stack and returns it.
|
||||
*
|
||||
* @return callable
|
||||
*/
|
||||
public function popProcessor();
|
||||
|
||||
/**
|
||||
* Sets the formatter.
|
||||
*
|
||||
* @param FormatterInterface $formatter
|
||||
* @return self
|
||||
*/
|
||||
public function setFormatter(FormatterInterface $formatter);
|
||||
|
||||
/**
|
||||
* Gets the formatter.
|
||||
*
|
||||
* @return FormatterInterface
|
||||
*/
|
||||
public function getFormatter();
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Sends notifications through the hipchat api to a hipchat room
|
||||
*
|
||||
* Notes:
|
||||
* API token - HipChat API token
|
||||
* Room - HipChat Room Id or name, where messages are sent
|
||||
* Name - Name used to send the message (from)
|
||||
* notify - Should the message trigger a notification in the clients
|
||||
*
|
||||
* @author Rafael Dohms <rafael@doh.ms>
|
||||
* @see https://www.hipchat.com/docs/api
|
||||
*/
|
||||
class HipChatHandler extends SocketHandler
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $token;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $room;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
private $notify;
|
||||
|
||||
/**
|
||||
* @param string $token HipChat API Token
|
||||
* @param string $room The room that should be alerted of the message (Id or Name)
|
||||
* @param string $name Name used in the "from" field
|
||||
* @param bool $notify Trigger a notification in clients or not
|
||||
* @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 Boolean $useSSL Whether to connect via SSL.
|
||||
*/
|
||||
public function __construct($token, $room, $name = 'Monolog', $notify = false, $level = Logger::CRITICAL, $bubble = true, $useSSL = true)
|
||||
{
|
||||
$connectionString = $useSSL ? 'ssl://api.hipchat.com:443' : 'api.hipchat.com:80';
|
||||
parent::__construct($connectionString, $level, $bubble);
|
||||
|
||||
$this->token = $token;
|
||||
$this->name = $name;
|
||||
$this->notify = $notify;
|
||||
$this->room = $room;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param array $record
|
||||
* @return string
|
||||
*/
|
||||
protected function generateDataStream($record)
|
||||
{
|
||||
$content = $this->buildContent($record);
|
||||
|
||||
return $this->buildHeader($content) . $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the body of API call
|
||||
*
|
||||
* @param array $record
|
||||
* @return string
|
||||
*/
|
||||
private function buildContent($record)
|
||||
{
|
||||
$dataArray = array(
|
||||
'from' => $this->name,
|
||||
'room_id' => $this->room,
|
||||
'notify' => $this->notify,
|
||||
'message' => $record['formatted'],
|
||||
'message_format' => 'text',
|
||||
'color' => $this->getAlertColor($record['level']),
|
||||
);
|
||||
|
||||
return http_build_query($dataArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the header of the API Call
|
||||
*
|
||||
* @param string $content
|
||||
* @return string
|
||||
*/
|
||||
private function buildHeader($content)
|
||||
{
|
||||
$header = "POST /v1/rooms/message?format=json&auth_token=".$this->token." HTTP/1.1\r\n";
|
||||
$header .= "Host: api.hipchat.com\r\n";
|
||||
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
|
||||
$header .= "Content-Length: " . strlen($content) . "\r\n";
|
||||
$header .= "\r\n";
|
||||
|
||||
return $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns a color to each level of log records.
|
||||
*
|
||||
* @param integer $level
|
||||
* @return string
|
||||
*/
|
||||
protected function getAlertColor($level)
|
||||
{
|
||||
switch (true) {
|
||||
case $level >= Logger::ERROR:
|
||||
return 'red';
|
||||
case $level >= Logger::WARNING:
|
||||
return 'yellow';
|
||||
case $level >= Logger::INFO:
|
||||
return 'green';
|
||||
case $level == Logger::DEBUG:
|
||||
return 'gray';
|
||||
default:
|
||||
return 'yellow';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param array $record
|
||||
*/
|
||||
public function write(array $record)
|
||||
{
|
||||
parent::write($record);
|
||||
$this->closeSocket();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handleBatch(array $records)
|
||||
{
|
||||
if (count($records) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$batchRecord = $this->combineRecords($records);
|
||||
|
||||
if (!$this->isHandling($batchRecord)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->write($batchRecord);
|
||||
|
||||
return false === $this->bubble;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines multiple records into one. Error level of the combined record
|
||||
* will be the highest level from the given records. Datetime will be taken
|
||||
* from the first record.
|
||||
*
|
||||
* @param $records
|
||||
* @return array
|
||||
*/
|
||||
private function combineRecords($records)
|
||||
{
|
||||
$messages = array();
|
||||
$formattedMessages = array();
|
||||
$level = 0;
|
||||
$levelName = null;
|
||||
$datetime = null;
|
||||
|
||||
foreach ($records as $record) {
|
||||
|
||||
$record = $this->processRecord($record);
|
||||
$record['formatted'] = $this->getFormatter()->format($record);
|
||||
|
||||
$messages[] = $record['message'];
|
||||
$formattedMessages[] = $record['formatted'];
|
||||
|
||||
if ($record['level'] > $level) {
|
||||
$level = $record['level'];
|
||||
$levelName = $record['level_name'];
|
||||
}
|
||||
|
||||
if (null === $datetime) {
|
||||
$datetime = $record['datetime'];
|
||||
}
|
||||
}
|
||||
|
||||
$batchRecord = array(
|
||||
'message' => implode(PHP_EOL, $messages),
|
||||
'formatted' => implode('', $formattedMessages),
|
||||
'level' => $level,
|
||||
'level_name' => $levelName,
|
||||
'datetime' => $datetime,
|
||||
'context' => array(),
|
||||
'extra' => array(),
|
||||
);
|
||||
|
||||
return $batchRecord;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?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;
|
||||
use Monolog\Formatter\JsonFormatter;
|
||||
|
||||
/**
|
||||
* Sends errors to Loggly.
|
||||
*
|
||||
* @author Przemek Sobstel <przemek@sobstel.org>
|
||||
*/
|
||||
class LogglyHandler extends AbstractProcessingHandler
|
||||
{
|
||||
const HOST = 'logs-01.loggly.com';
|
||||
|
||||
protected $token;
|
||||
|
||||
protected $tag;
|
||||
|
||||
public function __construct($token, $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
if (!extension_loaded('curl')) {
|
||||
throw new \LogicException('The curl extension is needed to use the LogglyHandler');
|
||||
}
|
||||
|
||||
$this->token = $token;
|
||||
|
||||
parent::__construct($level, $bubble);
|
||||
}
|
||||
|
||||
public function setTag($tag)
|
||||
{
|
||||
$this->tag = $tag;
|
||||
}
|
||||
|
||||
protected function write(array $record)
|
||||
{
|
||||
$url = sprintf("http://%s/inputs/%s/", self::HOST, $this->token);
|
||||
if ($this->tag) {
|
||||
$url .= sprintf("tag/%s/", $this->tag);
|
||||
}
|
||||
|
||||
$ch = curl_init();
|
||||
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $record["formatted"]);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
|
||||
curl_exec($ch);
|
||||
curl_close($ch);
|
||||
}
|
||||
|
||||
protected function getDefaultFormatter()
|
||||
{
|
||||
return new JsonFormatter();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Base class for all mail handlers
|
||||
*
|
||||
* @author Gyula Sallai
|
||||
*/
|
||||
abstract class MailHandler extends AbstractProcessingHandler
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handleBatch(array $records)
|
||||
{
|
||||
$messages = array();
|
||||
|
||||
foreach ($records as $record) {
|
||||
if ($record['level'] < $this->level) {
|
||||
continue;
|
||||
}
|
||||
$messages[] = $this->processRecord($record);
|
||||
}
|
||||
|
||||
if (!empty($messages)) {
|
||||
$this->send((string) $this->getFormatter()->formatBatch($messages), $messages);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a mail with the given content
|
||||
*
|
||||
* @param string $content
|
||||
* @param array $records the array of log records that formed this content
|
||||
*/
|
||||
abstract protected function send($content, array $records);
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function write(array $record)
|
||||
{
|
||||
$this->send((string) $record['formatted'], array($record));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Exception can be thrown if an extension for an handler is missing
|
||||
*
|
||||
* @author Christian Bergau <cbergau86@gmail.com>
|
||||
*/
|
||||
class MissingExtensionException extends \Exception
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?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;
|
||||
use Monolog\Formatter\NormalizerFormatter;
|
||||
|
||||
/**
|
||||
* Logs to a MongoDB database.
|
||||
*
|
||||
* usage example:
|
||||
*
|
||||
* $log = new Logger('application');
|
||||
* $mongodb = new MongoDBHandler(new \Mongo("mongodb://localhost:27017"), "logs", "prod");
|
||||
* $log->pushHandler($mongodb);
|
||||
*
|
||||
* @author Thomas Tourlourat <thomas@tourlourat.com>
|
||||
*/
|
||||
class MongoDBHandler extends AbstractProcessingHandler
|
||||
{
|
||||
protected $mongoCollection;
|
||||
|
||||
public function __construct($mongo, $database, $collection, $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
if (!($mongo instanceof \MongoClient || $mongo instanceof \Mongo)) {
|
||||
throw new \InvalidArgumentException('MongoClient or Mongo instance required');
|
||||
}
|
||||
|
||||
$this->mongoCollection = $mongo->selectCollection($database, $collection);
|
||||
|
||||
parent::__construct($level, $bubble);
|
||||
}
|
||||
|
||||
protected function write(array $record)
|
||||
{
|
||||
$this->mongoCollection->save($record["formatted"]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function getDefaultFormatter()
|
||||
{
|
||||
return new NormalizerFormatter();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* NativeMailerHandler uses the mail() function to send the emails
|
||||
*
|
||||
* @author Christophe Coevoet <stof@notk.org>
|
||||
*/
|
||||
class NativeMailerHandler extends MailHandler
|
||||
{
|
||||
protected $to;
|
||||
protected $subject;
|
||||
protected $headers = array(
|
||||
'Content-type: text/plain; charset=utf-8'
|
||||
);
|
||||
protected $maxColumnWidth;
|
||||
|
||||
/**
|
||||
* @param string|array $to The receiver of the mail
|
||||
* @param string $subject The subject of the mail
|
||||
* @param string $from The sender of the mail
|
||||
* @param integer $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 $maxColumnWidth The maximum column width that the message lines will have
|
||||
*/
|
||||
public function __construct($to, $subject, $from, $level = Logger::ERROR, $bubble = true, $maxColumnWidth = 70)
|
||||
{
|
||||
parent::__construct($level, $bubble);
|
||||
$this->to = is_array($to) ? $to : array($to);
|
||||
$this->subject = $subject;
|
||||
$this->addHeader(sprintf('From: %s', $from));
|
||||
$this->maxColumnWidth = $maxColumnWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|array $headers Custom added headers
|
||||
*/
|
||||
public function addHeader($headers)
|
||||
{
|
||||
foreach ((array) $headers as $header) {
|
||||
if (strpos($header, "\n") !== false || strpos($header, "\r") !== false) {
|
||||
throw new \InvalidArgumentException('Headers can not contain newline characters for security reasons');
|
||||
}
|
||||
$this->headers[] = $header;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function send($content, array $records)
|
||||
{
|
||||
$content = wordwrap($content, $this->maxColumnWidth);
|
||||
$headers = implode("\r\n", $this->headers) . "\r\n";
|
||||
foreach ($this->to as $to) {
|
||||
mail($to, $this->subject, $content, $headers);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Class to record a log on a NewRelic application
|
||||
*
|
||||
* @see https://newrelic.com/docs/php/new-relic-for-php
|
||||
*/
|
||||
class NewRelicHandler extends AbstractProcessingHandler
|
||||
{
|
||||
/**
|
||||
* Name of the New Relic application that will receive logs from this handler.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $appName;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @param string $appName
|
||||
*/
|
||||
public function __construct($level = Logger::ERROR, $bubble = true, $appName = null)
|
||||
{
|
||||
parent::__construct($level, $bubble);
|
||||
|
||||
$this->appName = $appName;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function write(array $record)
|
||||
{
|
||||
if (!$this->isNewRelicEnabled()) {
|
||||
throw new MissingExtensionException('The newrelic PHP extension is required to use the NewRelicHandler');
|
||||
}
|
||||
|
||||
if ($appName = $this->getAppName($record['context'])) {
|
||||
$this->setNewRelicAppName($appName);
|
||||
}
|
||||
|
||||
if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Exception) {
|
||||
newrelic_notice_error($record['message'], $record['context']['exception']);
|
||||
unset($record['context']['exception']);
|
||||
} else {
|
||||
newrelic_notice_error($record['message']);
|
||||
}
|
||||
|
||||
foreach ($record['context'] as $key => $parameter) {
|
||||
newrelic_add_custom_parameter($key, $parameter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the NewRelic extension is enabled in the system.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isNewRelicEnabled()
|
||||
{
|
||||
return extension_loaded('newrelic');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the appname where this log should be sent. Each log can override the default appname, set in this
|
||||
* handler's constructor, by providing the appname in its context.
|
||||
*
|
||||
* @param array $context
|
||||
* @return null|string
|
||||
*/
|
||||
protected function getAppName(array $context)
|
||||
{
|
||||
if (isset($context['appname'])) {
|
||||
return $context['appname'];
|
||||
}
|
||||
|
||||
return $this->appName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the NewRelic application that should receive this log.
|
||||
*
|
||||
* @param string $appName
|
||||
*/
|
||||
protected function setNewRelicAppName($appName)
|
||||
{
|
||||
newrelic_set_appname($appName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Blackhole
|
||||
*
|
||||
* Any record it can handle will be thrown away. This can be used
|
||||
* to put on top of an existing stack to override it temporarily.
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class NullHandler extends AbstractHandler
|
||||
{
|
||||
/**
|
||||
* @param integer $level The minimum logging level at which this handler will be triggered
|
||||
*/
|
||||
public function __construct($level = Logger::DEBUG)
|
||||
{
|
||||
parent::__construct($level, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handle(array $record)
|
||||
{
|
||||
if ($record['level'] < $this->level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Sends notifications through the pushover api to mobile phones
|
||||
*
|
||||
* @author Sebastian Göttschkes <sebastian.goettschkes@googlemail.com>
|
||||
* @see https://www.pushover.net/api
|
||||
*/
|
||||
class PushoverHandler extends SocketHandler
|
||||
{
|
||||
private $token;
|
||||
private $users;
|
||||
private $title;
|
||||
private $user;
|
||||
private $retry;
|
||||
private $expire;
|
||||
|
||||
private $highPriorityLevel;
|
||||
private $emergencyLevel;
|
||||
|
||||
/**
|
||||
* @param string $token Pushover api token
|
||||
* @param string|array $users Pushover user id or array of ids the message will be sent to
|
||||
* @param string $title Title sent to the Pushover API
|
||||
* @param integer $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 Boolean $useSSL Whether to connect via SSL. Required when pushing messages to users that are not
|
||||
* the pushover.net app owner. OpenSSL is required for this option.
|
||||
* @param integer $highPriorityLevel The minimum logging level at which this handler will start
|
||||
* sending "high priority" requests to the Pushover API
|
||||
* @param integer $emergencyLevel The minimum logging level at which this handler will start
|
||||
* sending "emergency" requests to the Pushover API
|
||||
* @param integer $retry The retry parameter specifies how often (in seconds) the Pushover servers will send the same notification to the user.
|
||||
* @param integer $expire The expire parameter specifies how many seconds your notification will continue to be retried for (every retry seconds).
|
||||
*/
|
||||
public function __construct($token, $users, $title = null, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $highPriorityLevel = Logger::CRITICAL, $emergencyLevel = Logger::EMERGENCY, $retry = 30, $expire = 25200)
|
||||
{
|
||||
$connectionString = $useSSL ? 'ssl://api.pushover.net:443' : 'api.pushover.net:80';
|
||||
parent::__construct($connectionString, $level, $bubble);
|
||||
|
||||
$this->token = $token;
|
||||
$this->users = (array) $users;
|
||||
$this->title = $title ?: gethostname();
|
||||
$this->highPriorityLevel = $highPriorityLevel;
|
||||
$this->emergencyLevel = $emergencyLevel;
|
||||
$this->retry = $retry;
|
||||
$this->expire = $expire;
|
||||
}
|
||||
|
||||
protected function generateDataStream($record)
|
||||
{
|
||||
$content = $this->buildContent($record);
|
||||
|
||||
return $this->buildHeader($content) . $content;
|
||||
}
|
||||
|
||||
private function buildContent($record)
|
||||
{
|
||||
// Pushover has a limit of 512 characters on title and message combined.
|
||||
$maxMessageLength = 512 - strlen($this->title);
|
||||
$message = substr($record['message'], 0, $maxMessageLength);
|
||||
$timestamp = $record['datetime']->getTimestamp();
|
||||
|
||||
$dataArray = array(
|
||||
'token' => $this->token,
|
||||
'user' => $this->user,
|
||||
'message' => $message,
|
||||
'title' => $this->title,
|
||||
'timestamp' => $timestamp
|
||||
);
|
||||
|
||||
if ($record['level'] >= $this->emergencyLevel) {
|
||||
$dataArray['priority'] = 2;
|
||||
$dataArray['retry'] = $this->retry;
|
||||
$dataArray['expire'] = $this->expire;
|
||||
} elseif ($record['level'] >= $this->highPriorityLevel) {
|
||||
$dataArray['priority'] = 1;
|
||||
}
|
||||
|
||||
return http_build_query($dataArray);
|
||||
}
|
||||
|
||||
private function buildHeader($content)
|
||||
{
|
||||
$header = "POST /1/messages.json HTTP/1.1\r\n";
|
||||
$header .= "Host: api.pushover.net\r\n";
|
||||
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
|
||||
$header .= "Content-Length: " . strlen($content) . "\r\n";
|
||||
$header .= "\r\n";
|
||||
|
||||
return $header;
|
||||
}
|
||||
|
||||
public function write(array $record)
|
||||
{
|
||||
foreach ($this->users as $user) {
|
||||
$this->user = $user;
|
||||
|
||||
parent::write($record);
|
||||
$this->closeSocket();
|
||||
}
|
||||
|
||||
$this->user = null;
|
||||
}
|
||||
|
||||
public function setHighPriorityLevel($value)
|
||||
{
|
||||
$this->highPriorityLevel = $value;
|
||||
}
|
||||
|
||||
public function setEmergencyLevel($value)
|
||||
{
|
||||
$this->emergencyLevel = $value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
<?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\Formatter\LineFormatter;
|
||||
use Monolog\Formatter\FormatterInterface;
|
||||
use Monolog\Logger;
|
||||
use Monolog\Handler\AbstractProcessingHandler;
|
||||
use Raven_Client;
|
||||
|
||||
/**
|
||||
* Handler to send messages to a Sentry (https://github.com/dcramer/sentry) server
|
||||
* using raven-php (https://github.com/getsentry/raven-php)
|
||||
*
|
||||
* @author Marc Abramowitz <marc@marc-abramowitz.com>
|
||||
*/
|
||||
class RavenHandler extends AbstractProcessingHandler
|
||||
{
|
||||
/**
|
||||
* Translates Monolog log levels to Raven log levels.
|
||||
*/
|
||||
private $logLevels = array(
|
||||
Logger::DEBUG => Raven_Client::DEBUG,
|
||||
Logger::INFO => Raven_Client::INFO,
|
||||
Logger::NOTICE => Raven_Client::INFO,
|
||||
Logger::WARNING => Raven_Client::WARNING,
|
||||
Logger::ERROR => Raven_Client::ERROR,
|
||||
Logger::CRITICAL => Raven_Client::FATAL,
|
||||
Logger::ALERT => Raven_Client::FATAL,
|
||||
Logger::EMERGENCY => Raven_Client::FATAL,
|
||||
);
|
||||
|
||||
/**
|
||||
* @var Raven_Client the client object that sends the message to the server
|
||||
*/
|
||||
protected $ravenClient;
|
||||
|
||||
/**
|
||||
* @var LineFormatter The formatter to use for the logs generated via handleBatch()
|
||||
*/
|
||||
protected $batchFormatter;
|
||||
|
||||
/**
|
||||
* @param Raven_Client $ravenClient
|
||||
* @param integer $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
|
||||
*/
|
||||
public function __construct(Raven_Client $ravenClient, $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
parent::__construct($level, $bubble);
|
||||
|
||||
$this->ravenClient = $ravenClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handleBatch(array $records)
|
||||
{
|
||||
$level = $this->level;
|
||||
|
||||
// filter records based on their level
|
||||
$records = array_filter($records, function($record) use ($level) {
|
||||
return $record['level'] >= $level;
|
||||
});
|
||||
|
||||
if (!$records) {
|
||||
return;
|
||||
}
|
||||
|
||||
// the record with the highest severity is the "main" one
|
||||
$record = array_reduce($records, function($highest, $record) {
|
||||
if ($record['level'] >= $highest['level']) {
|
||||
return $record;
|
||||
}
|
||||
|
||||
return $highest;
|
||||
});
|
||||
|
||||
// the other ones are added as a context item
|
||||
$logs = array();
|
||||
foreach ($records as $r) {
|
||||
$logs[] = $this->processRecord($r);
|
||||
}
|
||||
|
||||
if ($logs) {
|
||||
$record['context']['logs'] = (string) $this->getBatchFormatter()->formatBatch($logs);
|
||||
}
|
||||
|
||||
$this->handle($record);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the formatter for the logs generated by handleBatch().
|
||||
*
|
||||
* @param FormatterInterface $formatter
|
||||
*/
|
||||
public function setBatchFormatter(FormatterInterface $formatter)
|
||||
{
|
||||
$this->batchFormatter = $formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the formatter for the logs generated by handleBatch().
|
||||
*
|
||||
* @return FormatterInterface
|
||||
*/
|
||||
public function getBatchFormatter()
|
||||
{
|
||||
if (!$this->batchFormatter) {
|
||||
$this->batchFormatter = $this->getDefaultBatchFormatter();
|
||||
}
|
||||
|
||||
return $this->batchFormatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function write(array $record)
|
||||
{
|
||||
$options = array();
|
||||
$options['level'] = $this->logLevels[$record['level']];
|
||||
if (!empty($record['context'])) {
|
||||
$options['extra']['context'] = $record['context'];
|
||||
}
|
||||
if (!empty($record['extra'])) {
|
||||
$options['extra']['extra'] = $record['extra'];
|
||||
}
|
||||
|
||||
if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Exception) {
|
||||
$options['extra']['message'] = $record['formatted'];
|
||||
$this->ravenClient->captureException($record['context']['exception'], $options);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->ravenClient->captureMessage($record['formatted'], array(), $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function getDefaultFormatter()
|
||||
{
|
||||
return new LineFormatter('[%channel%] %message%');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default formatter for the logs generated by handleBatch().
|
||||
*
|
||||
* @return FormatterInterface
|
||||
*/
|
||||
protected function getDefaultBatchFormatter()
|
||||
{
|
||||
return new LineFormatter();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?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;
|
||||
use Monolog\Formatter\LineFormatter;
|
||||
|
||||
/**
|
||||
* Logs to a Redis key using rpush
|
||||
*
|
||||
* usage example:
|
||||
*
|
||||
* $log = new Logger('application');
|
||||
* $redis = new RedisHandler(new Predis\Client("tcp://localhost:6379"), "logs", "prod");
|
||||
* $log->pushHandler($redis);
|
||||
*
|
||||
* @author Thomas Tourlourat <thomas@tourlourat.com>
|
||||
*/
|
||||
class RedisHandler extends AbstractProcessingHandler
|
||||
{
|
||||
private $redisClient;
|
||||
private $redisKey;
|
||||
|
||||
# redis instance, key to use
|
||||
public function __construct($redis, $key, $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
if (!(($redis instanceof \Predis\Client) || ($redis instanceof \Redis))) {
|
||||
throw new \InvalidArgumentException('Predis\Client or Redis instance required');
|
||||
}
|
||||
|
||||
$this->redisClient = $redis;
|
||||
$this->redisKey = $key;
|
||||
|
||||
parent::__construct($level, $bubble);
|
||||
}
|
||||
|
||||
protected function write(array $record)
|
||||
{
|
||||
$this->redisClient->rpush($this->redisKey, $record["formatted"]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function getDefaultFormatter()
|
||||
{
|
||||
return new LineFormatter();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
<?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 logs to files that are rotated every day and a limited number of files are kept.
|
||||
*
|
||||
* This rotation is only intended to be used as a workaround. Using logrotate to
|
||||
* handle the rotation is strongly encouraged when you can use it.
|
||||
*
|
||||
* @author Christophe Coevoet <stof@notk.org>
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class RotatingFileHandler extends StreamHandler
|
||||
{
|
||||
protected $filename;
|
||||
protected $maxFiles;
|
||||
protected $mustRotate;
|
||||
protected $nextRotation;
|
||||
protected $filenameFormat;
|
||||
protected $dateFormat;
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
* @param integer $maxFiles The maximal amount of files to keep (0 means unlimited)
|
||||
* @param integer $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
|
||||
*/
|
||||
public function __construct($filename, $maxFiles = 0, $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
$this->filename = $filename;
|
||||
$this->maxFiles = (int) $maxFiles;
|
||||
$this->nextRotation = new \DateTime('tomorrow');
|
||||
$this->filenameFormat = '{filename}-{date}';
|
||||
$this->dateFormat = 'Y-m-d';
|
||||
|
||||
parent::__construct($this->getTimedFilename(), $level, $bubble);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
parent::close();
|
||||
|
||||
if (true === $this->mustRotate) {
|
||||
$this->rotate();
|
||||
}
|
||||
}
|
||||
|
||||
public function setFilenameFormat($filenameFormat, $dateFormat)
|
||||
{
|
||||
$this->filenameFormat = $filenameFormat;
|
||||
$this->dateFormat = $dateFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function write(array $record)
|
||||
{
|
||||
// on the first record written, if the log is new, we should rotate (once per day)
|
||||
if (null === $this->mustRotate) {
|
||||
$this->mustRotate = !file_exists($this->url);
|
||||
}
|
||||
|
||||
if ($this->nextRotation < $record['datetime']) {
|
||||
$this->mustRotate = true;
|
||||
$this->close();
|
||||
}
|
||||
|
||||
parent::write($record);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the files.
|
||||
*/
|
||||
protected function rotate()
|
||||
{
|
||||
// update filename
|
||||
$this->url = $this->getTimedFilename();
|
||||
$this->nextRotation = new \DateTime('tomorrow');
|
||||
|
||||
// skip GC of old logs if files are unlimited
|
||||
if (0 === $this->maxFiles) {
|
||||
return;
|
||||
}
|
||||
|
||||
$logFiles = glob($this->getGlobPattern());
|
||||
if ($this->maxFiles >= count($logFiles)) {
|
||||
// no files to remove
|
||||
return;
|
||||
}
|
||||
|
||||
// Sorting the files by name to remove the older ones
|
||||
usort($logFiles, function($a, $b) {
|
||||
return strcmp($b, $a);
|
||||
});
|
||||
|
||||
foreach (array_slice($logFiles, $this->maxFiles) as $file) {
|
||||
if (is_writable($file)) {
|
||||
unlink($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function getTimedFilename()
|
||||
{
|
||||
$fileInfo = pathinfo($this->filename);
|
||||
$timedFilename = str_replace(
|
||||
array('{filename}', '{date}'),
|
||||
array($fileInfo['filename'], date($this->dateFormat)),
|
||||
$fileInfo['dirname'] . '/' . $this->filenameFormat
|
||||
);
|
||||
|
||||
if (!empty($fileInfo['extension'])) {
|
||||
$timedFilename .= '.'.$fileInfo['extension'];
|
||||
}
|
||||
|
||||
return $timedFilename;
|
||||
}
|
||||
|
||||
protected function getGlobPattern()
|
||||
{
|
||||
$fileInfo = pathinfo($this->filename);
|
||||
$glob = str_replace(
|
||||
array('{filename}', '{date}'),
|
||||
array($fileInfo['filename'], '*'),
|
||||
$fileInfo['dirname'] . '/' . $this->filenameFormat
|
||||
);
|
||||
if (!empty($fileInfo['extension'])) {
|
||||
$glob .= '.'.$fileInfo['extension'];
|
||||
}
|
||||
|
||||
return $glob;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
<?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 socket - uses fsockopen() or pfsockopen().
|
||||
*
|
||||
* @author Pablo de Leon Belloc <pablolb@gmail.com>
|
||||
* @see http://php.net/manual/en/function.fsockopen.php
|
||||
*/
|
||||
class SocketHandler extends AbstractProcessingHandler
|
||||
{
|
||||
private $connectionString;
|
||||
private $connectionTimeout;
|
||||
private $resource;
|
||||
private $timeout = 0;
|
||||
private $persistent = false;
|
||||
private $errno;
|
||||
private $errstr;
|
||||
|
||||
/**
|
||||
* @param string $connectionString Socket connection string
|
||||
* @param integer $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
|
||||
*/
|
||||
public function __construct($connectionString, $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
parent::__construct($level, $bubble);
|
||||
$this->connectionString = $connectionString;
|
||||
$this->connectionTimeout = (float) ini_get('default_socket_timeout');
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect (if necessary) and write to the socket
|
||||
*
|
||||
* @param array $record
|
||||
*
|
||||
* @throws \UnexpectedValueException
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function write(array $record)
|
||||
{
|
||||
$this->connectIfNotConnected();
|
||||
$data = $this->generateDataStream($record);
|
||||
$this->writeToSocket($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* We will not close a PersistentSocket instance so it can be reused in other requests.
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
if (!$this->isPersistent()) {
|
||||
$this->closeSocket();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close socket, if open
|
||||
*/
|
||||
public function closeSocket()
|
||||
{
|
||||
if (is_resource($this->resource)) {
|
||||
fclose($this->resource);
|
||||
$this->resource = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set socket connection to nbe persistent. It only has effect before the connection is initiated.
|
||||
*
|
||||
* @param type $boolean
|
||||
*/
|
||||
public function setPersistent($boolean)
|
||||
{
|
||||
$this->persistent = (boolean) $boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set connection timeout. Only has effect before we connect.
|
||||
*
|
||||
* @param float $seconds
|
||||
*
|
||||
* @see http://php.net/manual/en/function.fsockopen.php
|
||||
*/
|
||||
public function setConnectionTimeout($seconds)
|
||||
{
|
||||
$this->validateTimeout($seconds);
|
||||
$this->connectionTimeout = (float) $seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set write timeout. Only has effect before we connect.
|
||||
*
|
||||
* @param float $seconds
|
||||
*
|
||||
* @see http://php.net/manual/en/function.stream-set-timeout.php
|
||||
*/
|
||||
public function setTimeout($seconds)
|
||||
{
|
||||
$this->validateTimeout($seconds);
|
||||
$this->timeout = (float) $seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current connection string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getConnectionString()
|
||||
{
|
||||
return $this->connectionString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get persistent setting
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isPersistent()
|
||||
{
|
||||
return $this->persistent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current connection timeout setting
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getConnectionTimeout()
|
||||
{
|
||||
return $this->connectionTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current in-transfer timeout
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getTimeout()
|
||||
{
|
||||
return $this->timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the socket is currently available.
|
||||
*
|
||||
* UDP might appear to be connected but might fail when writing. See http://php.net/fsockopen for details.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isConnected()
|
||||
{
|
||||
return is_resource($this->resource)
|
||||
&& !feof($this->resource); // on TCP - other party can close connection.
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper to allow mocking
|
||||
*/
|
||||
protected function pfsockopen()
|
||||
{
|
||||
return @pfsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper to allow mocking
|
||||
*/
|
||||
protected function fsockopen()
|
||||
{
|
||||
return @fsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper to allow mocking
|
||||
*
|
||||
* @see http://php.net/manual/en/function.stream-set-timeout.php
|
||||
*/
|
||||
protected function streamSetTimeout()
|
||||
{
|
||||
$seconds = floor($this->timeout);
|
||||
$microseconds = round(($this->timeout - $seconds)*1e6);
|
||||
|
||||
return stream_set_timeout($this->resource, $seconds, $microseconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper to allow mocking
|
||||
*/
|
||||
protected function fwrite($data)
|
||||
{
|
||||
return @fwrite($this->resource, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper to allow mocking
|
||||
*/
|
||||
protected function streamGetMetadata()
|
||||
{
|
||||
return stream_get_meta_data($this->resource);
|
||||
}
|
||||
|
||||
private function validateTimeout($value)
|
||||
{
|
||||
$ok = filter_var($value, FILTER_VALIDATE_FLOAT);
|
||||
if ($ok === false || $value < 0) {
|
||||
throw new \InvalidArgumentException("Timeout must be 0 or a positive float (got $value)");
|
||||
}
|
||||
}
|
||||
|
||||
private function connectIfNotConnected()
|
||||
{
|
||||
if ($this->isConnected()) {
|
||||
return;
|
||||
}
|
||||
$this->connect();
|
||||
}
|
||||
|
||||
protected function generateDataStream($record)
|
||||
{
|
||||
return (string) $record['formatted'];
|
||||
}
|
||||
|
||||
private function connect()
|
||||
{
|
||||
$this->createSocketResource();
|
||||
$this->setSocketTimeout();
|
||||
}
|
||||
|
||||
private function createSocketResource()
|
||||
{
|
||||
if ($this->isPersistent()) {
|
||||
$resource = $this->pfsockopen();
|
||||
} else {
|
||||
$resource = $this->fsockopen();
|
||||
}
|
||||
if (!$resource) {
|
||||
throw new \UnexpectedValueException("Failed connecting to $this->connectionString ($this->errno: $this->errstr)");
|
||||
}
|
||||
$this->resource = $resource;
|
||||
}
|
||||
|
||||
private function setSocketTimeout()
|
||||
{
|
||||
if (!$this->streamSetTimeout()) {
|
||||
throw new \UnexpectedValueException("Failed setting timeout with stream_set_timeout()");
|
||||
}
|
||||
}
|
||||
|
||||
private function writeToSocket($data)
|
||||
{
|
||||
$length = strlen($data);
|
||||
$sent = 0;
|
||||
while ($this->isConnected() && $sent < $length) {
|
||||
if (0 == $sent) {
|
||||
$chunk = $this->fwrite($data);
|
||||
} else {
|
||||
$chunk = $this->fwrite(substr($data, $sent));
|
||||
}
|
||||
if ($chunk === false) {
|
||||
throw new \RuntimeException("Could not write to socket");
|
||||
}
|
||||
$sent += $chunk;
|
||||
$socketInfo = $this->streamGetMetadata();
|
||||
if ($socketInfo['timed_out']) {
|
||||
throw new \RuntimeException("Write timed-out");
|
||||
}
|
||||
}
|
||||
if (!$this->isConnected() && $sent < $length) {
|
||||
throw new \RuntimeException("End-of-file reached, probably we got disconnected (sent $sent of $length)");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* @param string $stream
|
||||
* @param integer $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
|
||||
*/
|
||||
public function __construct($stream, $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
parent::__construct($level, $bubble);
|
||||
if (is_resource($stream)) {
|
||||
$this->stream = $stream;
|
||||
} else {
|
||||
$this->url = $stream;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
if (is_resource($this->stream)) {
|
||||
fclose($this->stream);
|
||||
}
|
||||
$this->stream = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function write(array $record)
|
||||
{
|
||||
if (null === $this->stream) {
|
||||
if (!$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->errorMessage = null;
|
||||
set_error_handler(array($this, 'customErrorHandler'));
|
||||
$this->stream = fopen($this->url, 'a');
|
||||
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));
|
||||
}
|
||||
}
|
||||
fwrite($this->stream, (string) $record['formatted']);
|
||||
}
|
||||
|
||||
private function customErrorHandler($code, $msg) {
|
||||
$this->errorMessage = preg_replace('{^fopen\(.*?\): }', '', $msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* SwiftMailerHandler uses Swift_Mailer to send the emails
|
||||
*
|
||||
* @author Gyula Sallai
|
||||
*/
|
||||
class SwiftMailerHandler extends MailHandler
|
||||
{
|
||||
protected $mailer;
|
||||
protected $message;
|
||||
|
||||
/**
|
||||
* @param \Swift_Mailer $mailer The mailer to use
|
||||
* @param callable|\Swift_Message $message An example message for real messages, only the body will be replaced
|
||||
* @param integer $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
|
||||
*/
|
||||
public function __construct(\Swift_Mailer $mailer, $message, $level = Logger::ERROR, $bubble = true)
|
||||
{
|
||||
parent::__construct($level, $bubble);
|
||||
$this->mailer = $mailer;
|
||||
if (!$message instanceof \Swift_Message && is_callable($message)) {
|
||||
$message = call_user_func($message);
|
||||
}
|
||||
if (!$message instanceof \Swift_Message) {
|
||||
throw new \InvalidArgumentException('You must provide either a Swift_Message instance or a callable returning it');
|
||||
}
|
||||
$this->message = $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function send($content, array $records)
|
||||
{
|
||||
$message = clone $this->message;
|
||||
$message->setBody($content);
|
||||
|
||||
$this->mailer->send($message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Logs to syslog service.
|
||||
*
|
||||
* usage example:
|
||||
*
|
||||
* $log = new Logger('application');
|
||||
* $syslog = new SyslogHandler('myfacility', 'local6');
|
||||
* $formatter = new LineFormatter("%channel%.%level_name%: %message% %extra%");
|
||||
* $syslog->setFormatter($formatter);
|
||||
* $log->pushHandler($syslog);
|
||||
*
|
||||
* @author Sven Paulus <sven@karlsruhe.org>
|
||||
*/
|
||||
class SyslogHandler extends AbstractSyslogHandler
|
||||
{
|
||||
protected $ident;
|
||||
protected $logopts;
|
||||
|
||||
/**
|
||||
* @param string $ident
|
||||
* @param mixed $facility
|
||||
* @param integer $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 $logopts Option flags for the openlog() call, defaults to LOG_PID
|
||||
*/
|
||||
public function __construct($ident, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $logopts = LOG_PID)
|
||||
{
|
||||
parent::__construct($facility, $level, $bubble);
|
||||
|
||||
$this->ident = $ident;
|
||||
$this->logopts = $logopts;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
closelog();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function write(array $record)
|
||||
{
|
||||
if (!openlog($this->ident, $this->logopts, $this->facility)) {
|
||||
throw new \LogicException('Can\'t open syslog for ident "'.$this->ident.'" and facility "'.$this->facility.'"');
|
||||
}
|
||||
syslog($this->logLevels[$record['level']], (string) $record['formatted']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?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\SyslogUdp;
|
||||
|
||||
class UdpSocket
|
||||
{
|
||||
const DATAGRAM_MAX_LENGTH = 2048;
|
||||
|
||||
public function __construct($ip, $port = 514)
|
||||
{
|
||||
$this->ip = $ip;
|
||||
$this->port = $port;
|
||||
$this->socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
|
||||
}
|
||||
|
||||
public function write($line, $header = "")
|
||||
{
|
||||
$remaining = $line;
|
||||
while (!is_null($remaining)) {
|
||||
list($chunk, $remaining) = $this->splitLineIfNessesary($remaining, $header);
|
||||
$this->send($chunk);
|
||||
}
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
socket_close($this->socket);
|
||||
}
|
||||
|
||||
protected function send($chunk)
|
||||
{
|
||||
socket_sendto($this->socket, $chunk, strlen($chunk), $flags = 0, $this->ip, $this->port);
|
||||
}
|
||||
|
||||
protected function splitLineIfNessesary($line, $header)
|
||||
{
|
||||
if ($this->shouldSplitLine($line, $header)) {
|
||||
$chunkSize = self::DATAGRAM_MAX_LENGTH - strlen($header);
|
||||
$chunk = $header . substr($line, 0, $chunkSize);
|
||||
$remaining = substr($line, $chunkSize);
|
||||
} else {
|
||||
$chunk = $header . $line;
|
||||
$remaining = null;
|
||||
}
|
||||
|
||||
return array($chunk, $remaining);
|
||||
}
|
||||
|
||||
protected function shouldSplitLine($remaining, $header)
|
||||
{
|
||||
return strlen($header.$remaining) > self::DATAGRAM_MAX_LENGTH;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?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;
|
||||
use Monolog\Handler\SyslogUdp\UdpSocket;
|
||||
|
||||
/**
|
||||
* A Handler for logging to a remote syslogd server.
|
||||
*
|
||||
* @author Jesper Skovgaard Nielsen <nulpunkt@gmail.com>
|
||||
*/
|
||||
class SyslogUdpHandler extends AbstractSyslogHandler
|
||||
{
|
||||
/**
|
||||
* @param string $host
|
||||
* @param int $port
|
||||
* @param mixed $facility
|
||||
* @param integer $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
|
||||
*/
|
||||
public function __construct($host, $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
parent::__construct($facility, $level, $bubble);
|
||||
|
||||
$this->socket = new UdpSocket($host, $port ?: 514);
|
||||
}
|
||||
|
||||
protected function write(array $record)
|
||||
{
|
||||
$lines = $this->splitMessageIntoLines($record['formatted']);
|
||||
|
||||
$header = $this->makeCommonSyslogHeader($this->logLevels[$record['level']]);
|
||||
|
||||
foreach ($lines as $line) {
|
||||
$this->socket->write($line, $header);
|
||||
}
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
$this->socket->close();
|
||||
}
|
||||
|
||||
private function splitMessageIntoLines($message)
|
||||
{
|
||||
if (is_array($message)) {
|
||||
$message = implode("\n", $message);
|
||||
}
|
||||
|
||||
return preg_split('/$\R?^/m', $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make common syslog header (see rfc5424)
|
||||
*/
|
||||
private function makeCommonSyslogHeader($severity)
|
||||
{
|
||||
$priority = $severity + $this->facility;
|
||||
|
||||
return "<$priority>: ";
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject your own socket, mainly used for testing
|
||||
*/
|
||||
public function setSocket($socket)
|
||||
{
|
||||
$this->socket = $socket;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Used for testing purposes.
|
||||
*
|
||||
* It records all records and gives you access to them for verification.
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class TestHandler extends AbstractProcessingHandler
|
||||
{
|
||||
protected $records = array();
|
||||
protected $recordsByLevel = array();
|
||||
|
||||
public function getRecords()
|
||||
{
|
||||
return $this->records;
|
||||
}
|
||||
|
||||
public function hasEmergency($record)
|
||||
{
|
||||
return $this->hasRecord($record, Logger::EMERGENCY);
|
||||
}
|
||||
|
||||
public function hasAlert($record)
|
||||
{
|
||||
return $this->hasRecord($record, Logger::ALERT);
|
||||
}
|
||||
|
||||
public function hasCritical($record)
|
||||
{
|
||||
return $this->hasRecord($record, Logger::CRITICAL);
|
||||
}
|
||||
|
||||
public function hasError($record)
|
||||
{
|
||||
return $this->hasRecord($record, Logger::ERROR);
|
||||
}
|
||||
|
||||
public function hasWarning($record)
|
||||
{
|
||||
return $this->hasRecord($record, Logger::WARNING);
|
||||
}
|
||||
|
||||
public function hasNotice($record)
|
||||
{
|
||||
return $this->hasRecord($record, Logger::NOTICE);
|
||||
}
|
||||
|
||||
public function hasInfo($record)
|
||||
{
|
||||
return $this->hasRecord($record, Logger::INFO);
|
||||
}
|
||||
|
||||
public function hasDebug($record)
|
||||
{
|
||||
return $this->hasRecord($record, Logger::DEBUG);
|
||||
}
|
||||
|
||||
public function hasEmergencyRecords()
|
||||
{
|
||||
return isset($this->recordsByLevel[Logger::EMERGENCY]);
|
||||
}
|
||||
|
||||
public function hasAlertRecords()
|
||||
{
|
||||
return isset($this->recordsByLevel[Logger::ALERT]);
|
||||
}
|
||||
|
||||
public function hasCriticalRecords()
|
||||
{
|
||||
return isset($this->recordsByLevel[Logger::CRITICAL]);
|
||||
}
|
||||
|
||||
public function hasErrorRecords()
|
||||
{
|
||||
return isset($this->recordsByLevel[Logger::ERROR]);
|
||||
}
|
||||
|
||||
public function hasWarningRecords()
|
||||
{
|
||||
return isset($this->recordsByLevel[Logger::WARNING]);
|
||||
}
|
||||
|
||||
public function hasNoticeRecords()
|
||||
{
|
||||
return isset($this->recordsByLevel[Logger::NOTICE]);
|
||||
}
|
||||
|
||||
public function hasInfoRecords()
|
||||
{
|
||||
return isset($this->recordsByLevel[Logger::INFO]);
|
||||
}
|
||||
|
||||
public function hasDebugRecords()
|
||||
{
|
||||
return isset($this->recordsByLevel[Logger::DEBUG]);
|
||||
}
|
||||
|
||||
protected function hasRecord($record, $level)
|
||||
{
|
||||
if (!isset($this->recordsByLevel[$level])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_array($record)) {
|
||||
$record = $record['message'];
|
||||
}
|
||||
|
||||
foreach ($this->recordsByLevel[$level] as $rec) {
|
||||
if ($rec['message'] === $record) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function write(array $record)
|
||||
{
|
||||
$this->recordsByLevel[$record['level']][] = $record;
|
||||
$this->records[] = $record;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?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\Formatter\NormalizerFormatter;
|
||||
use Monolog\Logger;
|
||||
|
||||
/**
|
||||
* Handler sending logs to Zend Monitor
|
||||
*
|
||||
* @author Christian Bergau <cbergau86@gmail.com>
|
||||
*/
|
||||
class ZendMonitorHandler extends AbstractProcessingHandler
|
||||
{
|
||||
/**
|
||||
* Monolog level / ZendMonitor Custom Event priority map
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $levelMap = array(
|
||||
Logger::DEBUG => 1,
|
||||
Logger::INFO => 2,
|
||||
Logger::NOTICE => 3,
|
||||
Logger::WARNING => 4,
|
||||
Logger::ERROR => 5,
|
||||
Logger::CRITICAL => 6,
|
||||
Logger::ALERT => 7,
|
||||
Logger::EMERGENCY => 0,
|
||||
);
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
* @param int $level
|
||||
* @param bool $bubble
|
||||
* @throws MissingExtensionException
|
||||
*/
|
||||
public function __construct($level = Logger::DEBUG, $bubble = true)
|
||||
{
|
||||
if (!function_exists('zend_monitor_custom_event')) {
|
||||
throw new MissingExtensionException('You must have Zend Server installed in order to use this handler');
|
||||
}
|
||||
parent::__construct($level, $bubble);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function write(array $record)
|
||||
{
|
||||
$this->writeZendMonitorCustomEvent(
|
||||
$this->levelMap[$record['level']],
|
||||
$record['message'],
|
||||
$record['formatted']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a record to Zend Monitor
|
||||
*
|
||||
* @param int $level
|
||||
* @param string $message
|
||||
* @param array $formatted
|
||||
*/
|
||||
protected function writeZendMonitorCustomEvent($level, $message, $formatted)
|
||||
{
|
||||
zend_monitor_custom_event($level, $message, $formatted);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefaultFormatter()
|
||||
{
|
||||
return new NormalizerFormatter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the level map
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLevelMap()
|
||||
{
|
||||
return $this->levelMap;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user