├── README.md ├── RResque.php ├── ResqueAutoloader.php ├── bin ├── resque └── resque-scheduler ├── composer.json └── lib ├── Credis ├── Client.php └── Cluster.php ├── Monolog ├── ErrorHandler.php ├── Formatter │ ├── ChromePHPFormatter.php │ ├── FormatterInterface.php │ ├── GelfMessageFormatter.php │ ├── JsonFormatter.php │ ├── LineFormatter.php │ ├── LogstashFormatter.php │ ├── NormalizerFormatter.php │ └── WildfireFormatter.php ├── Handler │ ├── AbstractHandler.php │ ├── AbstractProcessingHandler.php │ ├── AmqpHandler.php │ ├── BufferHandler.php │ ├── ChromePHPHandler.php │ ├── CouchDBHandler.php │ ├── CubeHandler.php │ ├── DoctrineCouchDBHandler.php │ ├── ErrorLogHandler.php │ ├── FingersCrossed │ │ ├── ActivationStrategyInterface.php │ │ ├── ChannelLevelActivationStrategy.php │ │ └── ErrorLevelActivationStrategy.php │ ├── FingersCrossedHandler.php │ ├── FirePHPHandler.php │ ├── GelfHandler.php │ ├── GroupHandler.php │ ├── HandlerInterface.php │ ├── HipChatHandler.php │ ├── MailHandler.php │ ├── MissingExtensionException.php │ ├── MongoDBHandler.php │ ├── NativeMailerHandler.php │ ├── NewRelicHandler.php │ ├── NullHandler.php │ ├── PushoverHandler.php │ ├── RavenHandler.php │ ├── RedisHandler.php │ ├── RotatingFileHandler.php │ ├── SocketHandler.php │ ├── StreamHandler.php │ ├── SwiftMailerHandler.php │ ├── SyslogHandler.php │ ├── TestHandler.php │ └── ZendMonitorHandler.php ├── Logger.php └── Processor │ ├── IntrospectionProcessor.php │ ├── MemoryPeakUsageProcessor.php │ ├── MemoryProcessor.php │ ├── MemoryUsageProcessor.php │ ├── ProcessIdProcessor.php │ ├── PsrLogMessageProcessor.php │ ├── UidProcessor.php │ └── WebProcessor.php ├── MonologInit └── MonologInit.php ├── Psr └── Log │ ├── AbstractLogger.php │ ├── InvalidArgumentException.php │ ├── LogLevel.php │ ├── LoggerAwareInterface.php │ ├── LoggerAwareTrait.php │ ├── LoggerInterface.php │ ├── LoggerTrait.php │ └── NullLogger.php ├── Resque.php ├── Resque ├── Event.php ├── Exception.php ├── Failure.php ├── Failure │ ├── Interface.php │ └── Redis.php ├── Job.php ├── Job │ ├── DirtyExitException.php │ ├── DontPerform.php │ └── Status.php ├── Redis.php ├── Stat.php └── Worker.php ├── ResqueScheduler.php └── ResqueScheduler ├── InvalidTimestampException.php └── Worker.php /RResque.php: -------------------------------------------------------------------------------- 1 | server . ':' . $this->port, $this->database, $this->password); 60 | if ($this->prefix) { 61 | Resque::redis()->prefix($this->prefix); 62 | } 63 | 64 | } 65 | 66 | /** 67 | * Create a new job and save it to the specified queue. 68 | * 69 | * @param string $queue The name of the queue to place the job in. 70 | * @param string $class The name of the class that contains the code to execute the job. 71 | * @param array $args Any optional arguments that should be passed when the job is executed. 72 | * 73 | * @return string 74 | */ 75 | public function createJob($queue, $class, $args = array(), $track_status = false) 76 | { 77 | 78 | return Resque::enqueue($queue, $class, $args, $track_status); 79 | } 80 | 81 | /** 82 | * Create a new scheduled job and save it to the specified queue. 83 | * 84 | * @param int $in Second count down to job. 85 | * @param string $queue The name of the queue to place the job in. 86 | * @param string $class The name of the class that contains the code to execute the job. 87 | * @param array $args Any optional arguments that should be passed when the job is executed. 88 | * 89 | * @return string 90 | */ 91 | public function enqueueJobIn($in, $queue, $class, $args = array()) 92 | { 93 | return ResqueScheduler::enqueueIn($in, $queue, $class, $args); 94 | } 95 | 96 | /** 97 | * Create a new scheduled job and save it to the specified queue. 98 | * 99 | * @param timestamp $at UNIX timestamp when job should be executed. 100 | * @param string $queue The name of the queue to place the job in. 101 | * @param string $class The name of the class that contains the code to execute the job. 102 | * @param array $args Any optional arguments that should be passed when the job is executed. 103 | * 104 | * @return string 105 | */ 106 | public function enqueueJobAt($at, $queue, $class, $args = array()) 107 | { 108 | 109 | return ResqueScheduler::enqueueAt($at, $queue, $class, $args); 110 | } 111 | 112 | /** 113 | * Get delayed jobs count 114 | * 115 | * @return int 116 | */ 117 | public function getDelayedJobsCount() 118 | { 119 | return (int)Resque::redis()->zcard('delayed_queue_schedule'); 120 | } 121 | 122 | /** 123 | * Check job status 124 | * 125 | * @param string $token Job token ID 126 | * 127 | * @return string Job Status 128 | */ 129 | public function status($token) 130 | { 131 | $status = new Resque_Job_Status($token); 132 | return $status->get(); 133 | } 134 | 135 | /** 136 | * Return Redis 137 | * 138 | * @return object Redis instance 139 | */ 140 | public function redis() 141 | { 142 | return Resque::redis(); 143 | } 144 | 145 | /** 146 | * Get queues 147 | * 148 | * @return object Redis instance 149 | */ 150 | public function getQueues() 151 | { 152 | return $this->redis()->zRange('delayed_queue_schedule', 0, -1); 153 | } 154 | 155 | // public function getValueByKey($key){ 156 | // return $this->redis()->get($key); 157 | // } 158 | } 159 | -------------------------------------------------------------------------------- /ResqueAutoloader.php: -------------------------------------------------------------------------------- 1 | basePath.'/../frontend/components')){ 38 | $file= \yii\BaseYii::$app->basePath.'/../frontend/components'; 39 | if(scandir($file)){ 40 | foreach (scandir($file) as $filename) { 41 | $path = $file. $filename; 42 | if (is_file($path)) { 43 | 44 | require_once $path; 45 | } 46 | } 47 | } 48 | } 49 | // yii 2 basic 50 | else{ 51 | $file= \Yii::getAlias('@app').'/components/'; 52 | foreach (scandir($file) as $filename) { 53 | $path = $file. $filename; 54 | if (is_file($path)) { 55 | 56 | require_once $path; 57 | } 58 | } 59 | } 60 | 61 | 62 | require_once(dirname(__FILE__) . '/lib/Resque/Job.php'); 63 | require_once(dirname(__FILE__) . '/lib/Resque/Event.php'); 64 | require_once(dirname(__FILE__) . '/lib/Resque/Redis.php'); 65 | require_once(dirname(__FILE__) . '/lib/Resque/Worker.php'); 66 | require_once(dirname(__FILE__) . '/lib/Resque/Stat.php'); 67 | require_once(dirname(__FILE__) . '/lib/Resque/Job/Status.php'); 68 | require_once(dirname(__FILE__) . '/lib/Resque/Exception.php'); 69 | require_once(dirname(__FILE__) . '/lib/MonologInit/MonologInit.php'); 70 | 71 | } 72 | } -------------------------------------------------------------------------------- /bin/resque: -------------------------------------------------------------------------------- 1 | 1) { 71 | $count = $COUNT; 72 | } 73 | 74 | $PREFIX = getenv('PREFIX'); 75 | if(!empty($PREFIX)) { 76 | fwrite(STDOUT, '*** Prefix set to '.$PREFIX."\n"); 77 | Resque::redis()->prefix($PREFIX); 78 | } 79 | 80 | if($count > 1) { 81 | for($i = 0; $i < $count; ++$i) { 82 | $pid = Resque::fork(); 83 | if($pid == -1) { 84 | die("Could not fork worker ".$i."\n"); 85 | } 86 | // Child, start the worker 87 | else if(!$pid) { 88 | startWorker($QUEUE, $logLevel, $logger, $interval); 89 | break; 90 | } 91 | } 92 | } 93 | // Start a single worker 94 | else { 95 | $PIDFILE = getenv('PIDFILE'); 96 | if ($PIDFILE) { 97 | file_put_contents($PIDFILE, getmypid()) or 98 | die('Could not write PID information to ' . $PIDFILE); 99 | } 100 | 101 | startWorker($QUEUE, $logLevel, $logger, $interval); 102 | } 103 | 104 | function startWorker($QUEUE, $logLevel, $logger, $interval) 105 | { 106 | $queues = explode(',', $QUEUE); 107 | $worker = new Resque_Worker($queues); 108 | 109 | if (!empty($logger)) { 110 | $worker->registerLogger($logger); 111 | } else { 112 | fwrite(STDOUT, '*** Starting worker '.$worker."\n"); 113 | } 114 | 115 | $worker->logLevel = $logLevel; 116 | $worker->work($interval); 117 | } -------------------------------------------------------------------------------- /bin/resque-scheduler: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | prefix($PREFIX); 94 | } 95 | 96 | $worker = new ResqueScheduler_Worker(); 97 | if (!empty($logger)) { 98 | $worker->registerLogger($logger); 99 | } else { 100 | fwrite(STDOUT, "*** Starting scheduler worker\n"); 101 | } 102 | $worker->logLevel = $logLevel; 103 | 104 | $PIDFILE = getenv('PIDFILE'); 105 | if ($PIDFILE) { 106 | file_put_contents($PIDFILE, getmypid()) or 107 | die('Could not write PID information to ' . $PIDFILE); 108 | } 109 | 110 | $worker->work($interval); -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "resque/yii2-resque", 3 | "description": "Yii2 Resque", 4 | "type": "yii2-extension", 5 | "keywords": ["yii2","extension"], 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Sprytechies", 10 | "email": "devteam01@sprytechies.com" 11 | } 12 | ], 13 | 14 | "autoload": { 15 | "psr-4": { 16 | "resque\\": "" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/Credis/Cluster.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright 2009 Justin Poliey 7 | * @license http://www.opensource.org/licenses/mit-license.php The MIT License 8 | * @package Credis 9 | */ 10 | 11 | #require_once 'Credis/Client.php'; 12 | 13 | /** 14 | * A generalized Credis_Client interface for a cluster of Redis servers 15 | */ 16 | class Credis_Cluster 17 | { 18 | 19 | /** 20 | * Collection of Credis_Client objects attached to Redis servers 21 | * @var Credis_Client[] 22 | */ 23 | protected $clients; 24 | 25 | /** 26 | * Aliases of Credis_Client objects attached to Redis servers, used to route commands to specific servers 27 | * @see Credis_Cluster::to 28 | * @var array 29 | */ 30 | protected $aliases; 31 | 32 | /** 33 | * Hash ring of Redis server nodes 34 | * @var array 35 | */ 36 | protected $ring; 37 | 38 | /** 39 | * Individual nodes of pointers to Redis servers on the hash ring 40 | * @var array 41 | */ 42 | protected $nodes; 43 | 44 | /** 45 | * The commands that are not subject to hashing 46 | * @var array 47 | * @access protected 48 | */ 49 | protected $dont_hash; 50 | 51 | /** 52 | * Creates an interface to a cluster of Redis servers 53 | * Each server should be in the format: 54 | * array( 55 | * 'host' => hostname, 56 | * 'port' => port, 57 | * 'timeout' => timeout, 58 | * 'alias' => alias 59 | * ) 60 | * 61 | * @param array $servers The Redis servers in the cluster. 62 | * @param int $replicas 63 | */ 64 | public function __construct($servers, $replicas = 128) 65 | { 66 | $this->clients = array(); 67 | $this->aliases = array(); 68 | $this->ring = array(); 69 | $clientNum = 0; 70 | foreach ($servers as $server) 71 | { 72 | $client = new Credis_Client($server['host'], $server['port'], isset($server['timeout']) ? $server['timeout'] : 2.5); 73 | $this->clients[] = $client; 74 | if (isset($server['alias'])) { 75 | $this->aliases[$server['alias']] = $client; 76 | } 77 | for ($replica = 0; $replica <= $replicas; $replica++) { 78 | $this->ring[crc32($server['host'].':'.$server['port'].'-'.$replica)] = $clientNum; 79 | } 80 | $clientNum++; 81 | } 82 | ksort($this->ring, SORT_NUMERIC); 83 | $this->nodes = array_keys($this->ring); 84 | $this->dont_hash = array_flip(array( 85 | 'RANDOMKEY', 'DBSIZE', 86 | 'SELECT', 'MOVE', 'FLUSHDB', 'FLUSHALL', 87 | 'SAVE', 'BGSAVE', 'LASTSAVE', 'SHUTDOWN', 88 | 'INFO', 'MONITOR', 'SLAVEOF' 89 | )); 90 | } 91 | 92 | /** 93 | * Get a client by index or alias. 94 | * 95 | * @param string|int $alias 96 | * @throws CredisException 97 | * @return Credis_Client 98 | */ 99 | public function client($alias) 100 | { 101 | if (is_int($alias) && isset($this->clients[$alias])) { 102 | return $this->clients[$alias]; 103 | } 104 | else if (isset($this->aliases[$alias])) { 105 | return $this->aliases[$alias]; 106 | } 107 | throw new CredisException("Client $alias does not exist."); 108 | } 109 | 110 | /** 111 | * Get an array of all clients 112 | * 113 | * @return array|Credis_Client[] 114 | */ 115 | public function clients() 116 | { 117 | return $this->clients; 118 | } 119 | 120 | /** 121 | * Execute a command on all clients 122 | * 123 | * @return array 124 | */ 125 | public function all() 126 | { 127 | $args = func_get_args(); 128 | $name = array_shift($args); 129 | $results = array(); 130 | foreach($this->clients as $client) { 131 | $results[] = $client->__call($name, $args); 132 | } 133 | return $results; 134 | } 135 | 136 | /** 137 | * Get the client that the key would hash to. 138 | * 139 | * @param string $key 140 | * @return \Credis_Client 141 | */ 142 | public function byHash($key) 143 | { 144 | return $this->clients[$this->hash($key)]; 145 | } 146 | 147 | /** 148 | * Execute a Redis command on the cluster with automatic consistent hashing 149 | * 150 | * @param string $name 151 | * @param array $args 152 | * @return mixed 153 | */ 154 | public function __call($name, $args) 155 | { 156 | if (isset($this->dont_hash[strtoupper($name)])) { 157 | $client = $this->clients[0]; 158 | } 159 | else { 160 | $client = $this->byHash($args[0]); 161 | } 162 | 163 | return $client->__call($name, $args); 164 | } 165 | 166 | /** 167 | * Get client index for a key by searching ring with binary search 168 | * 169 | * @param string $key The key to hash 170 | * @return int The index of the client object associated with the hash of the key 171 | */ 172 | public function hash($key) 173 | { 174 | $needle = crc32($key); 175 | $server = $min = 0; 176 | $max = count($this->nodes) - 1; 177 | while ($max >= $min) { 178 | $position = (int) (($min + $max) / 2); 179 | $server = $this->nodes[$position]; 180 | if ($needle < $server) { 181 | $max = $position - 1; 182 | } 183 | else if ($needle > $server) { 184 | $min = $position + 1; 185 | } 186 | else { 187 | break; 188 | } 189 | } 190 | return $this->ring[$server]; 191 | } 192 | 193 | } 194 | 195 | -------------------------------------------------------------------------------- /lib/Monolog/ErrorHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog; 13 | 14 | use Psr\Log\LoggerInterface; 15 | use Psr\Log\LogLevel; 16 | 17 | /** 18 | * Monolog error handler 19 | * 20 | * A facility to enable logging of runtime errors, exceptions and fatal errors. 21 | * 22 | * Quick setup: ErrorHandler::register($logger); 23 | * 24 | * @author Jordi Boggiano 25 | */ 26 | class ErrorHandler 27 | { 28 | private $logger; 29 | 30 | private $previousExceptionHandler; 31 | private $uncaughtExceptionLevel; 32 | 33 | private $previousErrorHandler; 34 | private $errorLevelMap; 35 | 36 | private $fatalLevel; 37 | private $reservedMemory; 38 | private static $fatalErrors = array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR); 39 | 40 | public function __construct(LoggerInterface $logger) 41 | { 42 | $this->logger = $logger; 43 | } 44 | 45 | /** 46 | * Registers a new ErrorHandler for a given Logger 47 | * 48 | * By default it will handle errors, exceptions and fatal errors 49 | * 50 | * @param LoggerInterface $logger 51 | * @param array|false $errorLevelMap an array of E_* constant to LogLevel::* constant mapping, or false to disable error handling 52 | * @param int|false $exceptionLevel a LogLevel::* constant, or false to disable exception handling 53 | * @param int|false $fatalLevel a LogLevel::* constant, or false to disable fatal error handling 54 | * @return ErrorHandler 55 | */ 56 | public static function register(LoggerInterface $logger, $errorLevelMap = array(), $exceptionLevel = null, $fatalLevel = null) 57 | { 58 | $handler = new static($logger); 59 | if ($errorLevelMap !== false) { 60 | $handler->registerErrorHandler($errorLevelMap); 61 | } 62 | if ($exceptionLevel !== false) { 63 | $handler->registerExceptionHandler($exceptionLevel); 64 | } 65 | if ($fatalLevel !== false) { 66 | $handler->registerFatalHandler($fatalLevel); 67 | } 68 | 69 | return $handler; 70 | } 71 | 72 | public function registerExceptionHandler($level = null, $callPrevious = true) 73 | { 74 | $prev = set_exception_handler(array($this, 'handleException')); 75 | $this->uncaughtExceptionLevel = $level === null ? LogLevel::ERROR : $level; 76 | if ($callPrevious && $prev) { 77 | $this->previousExceptionHandler = $prev; 78 | } 79 | } 80 | 81 | public function registerErrorHandler(array $levelMap = array(), $callPrevious = true, $errorTypes = -1) 82 | { 83 | $prev = set_error_handler(array($this, 'handleError'), $errorTypes); 84 | $this->errorLevelMap = array_replace($this->defaultErrorLevelMap(), $levelMap); 85 | if ($callPrevious) { 86 | $this->previousErrorHandler = $prev ?: true; 87 | } 88 | } 89 | 90 | public function registerFatalHandler($level = null, $reservedMemorySize = 20) 91 | { 92 | register_shutdown_function(array($this, 'handleFatalError')); 93 | 94 | $this->reservedMemory = str_repeat(' ', 1024 * $reservedMemorySize); 95 | $this->fatalLevel = $level === null ? LogLevel::ALERT : $level; 96 | } 97 | 98 | protected function defaultErrorLevelMap() 99 | { 100 | return array( 101 | E_ERROR => LogLevel::CRITICAL, 102 | E_WARNING => LogLevel::WARNING, 103 | E_PARSE => LogLevel::ALERT, 104 | E_NOTICE => LogLevel::NOTICE, 105 | E_CORE_ERROR => LogLevel::CRITICAL, 106 | E_CORE_WARNING => LogLevel::WARNING, 107 | E_COMPILE_ERROR => LogLevel::ALERT, 108 | E_COMPILE_WARNING => LogLevel::WARNING, 109 | E_USER_ERROR => LogLevel::ERROR, 110 | E_USER_WARNING => LogLevel::WARNING, 111 | E_USER_NOTICE => LogLevel::NOTICE, 112 | E_STRICT => LogLevel::NOTICE, 113 | E_RECOVERABLE_ERROR => LogLevel::ERROR, 114 | E_DEPRECATED => LogLevel::NOTICE, 115 | E_USER_DEPRECATED => LogLevel::NOTICE, 116 | ); 117 | } 118 | 119 | /** 120 | * @private 121 | */ 122 | public function handleException(\Exception $e) 123 | { 124 | $this->logger->log($this->uncaughtExceptionLevel, 'Uncaught exception', array('exception' => $e)); 125 | 126 | if ($this->previousExceptionHandler) { 127 | call_user_func($this->previousExceptionHandler, $e); 128 | } 129 | } 130 | 131 | /** 132 | * @private 133 | */ 134 | public function handleError($code, $message, $file = '', $line = 0, $context = array()) 135 | { 136 | if (!(error_reporting() & $code)) { 137 | return; 138 | } 139 | 140 | $level = isset($this->errorLevelMap[$code]) ? $this->errorLevelMap[$code] : LogLevel::CRITICAL; 141 | $this->logger->log($level, self::codeToString($code).': '.$message, array('file' => $file, 'line' => $line)); 142 | 143 | if ($this->previousErrorHandler === true) { 144 | return false; 145 | } elseif ($this->previousErrorHandler) { 146 | return call_user_func($this->previousErrorHandler, $code, $message, $file, $line, $context); 147 | } 148 | } 149 | 150 | /** 151 | * @private 152 | */ 153 | public function handleFatalError() 154 | { 155 | $this->reservedMemory = null; 156 | 157 | $lastError = error_get_last(); 158 | if ($lastError && in_array($lastError['type'], self::$fatalErrors)) { 159 | $this->logger->log( 160 | $this->fatalLevel, 161 | 'Fatal Error ('.self::codeToString($lastError['type']).'): '.$lastError['message'], 162 | array('file' => $lastError['file'], 'line' => $lastError['line']) 163 | ); 164 | } 165 | } 166 | 167 | private static function codeToString($code) 168 | { 169 | switch ($code) { 170 | case E_ERROR: 171 | return 'E_ERROR'; 172 | case E_WARNING: 173 | return 'E_WARNING'; 174 | case E_PARSE: 175 | return 'E_PARSE'; 176 | case E_NOTICE: 177 | return 'E_NOTICE'; 178 | case E_CORE_ERROR: 179 | return 'E_CORE_ERROR'; 180 | case E_CORE_WARNING: 181 | return 'E_CORE_WARNING'; 182 | case E_COMPILE_ERROR: 183 | return 'E_COMPILE_ERROR'; 184 | case E_COMPILE_WARNING: 185 | return 'E_COMPILE_WARNING'; 186 | case E_USER_ERROR: 187 | return 'E_USER_ERROR'; 188 | case E_USER_WARNING: 189 | return 'E_USER_WARNING'; 190 | case E_USER_NOTICE: 191 | return 'E_USER_NOTICE'; 192 | case E_STRICT: 193 | return 'E_STRICT'; 194 | case E_RECOVERABLE_ERROR: 195 | return 'E_RECOVERABLE_ERROR'; 196 | case E_DEPRECATED: 197 | return 'E_DEPRECATED'; 198 | case E_USER_DEPRECATED: 199 | return 'E_USER_DEPRECATED'; 200 | } 201 | 202 | return 'Unknown PHP error'; 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /lib/Monolog/Formatter/ChromePHPFormatter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Formatter; 13 | 14 | use Monolog\Logger; 15 | 16 | /** 17 | * Formats a log message according to the ChromePHP array format 18 | * 19 | * @author Christophe Coevoet 20 | */ 21 | class ChromePHPFormatter implements FormatterInterface 22 | { 23 | /** 24 | * Translates Monolog log levels to Wildfire levels. 25 | */ 26 | private $logLevels = array( 27 | Logger::DEBUG => 'log', 28 | Logger::INFO => 'info', 29 | Logger::NOTICE => 'info', 30 | Logger::WARNING => 'warn', 31 | Logger::ERROR => 'error', 32 | Logger::CRITICAL => 'error', 33 | Logger::ALERT => 'error', 34 | Logger::EMERGENCY => 'error', 35 | ); 36 | 37 | /** 38 | * {@inheritdoc} 39 | */ 40 | public function format(array $record) 41 | { 42 | // Retrieve the line and file if set and remove them from the formatted extra 43 | $backtrace = 'unknown'; 44 | if (isset($record['extra']['file']) && isset($record['extra']['line'])) { 45 | $backtrace = $record['extra']['file'].' : '.$record['extra']['line']; 46 | unset($record['extra']['file']); 47 | unset($record['extra']['line']); 48 | } 49 | 50 | $message = array('message' => $record['message']); 51 | if ($record['context']) { 52 | $message['context'] = $record['context']; 53 | } 54 | if ($record['extra']) { 55 | $message['extra'] = $record['extra']; 56 | } 57 | if (count($message) === 1) { 58 | $message = reset($message); 59 | } 60 | 61 | return array( 62 | $record['channel'], 63 | $message, 64 | $backtrace, 65 | $this->logLevels[$record['level']], 66 | ); 67 | } 68 | 69 | public function formatBatch(array $records) 70 | { 71 | $formatted = array(); 72 | 73 | foreach ($records as $record) { 74 | $formatted[] = $this->format($record); 75 | } 76 | 77 | return $formatted; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /lib/Monolog/Formatter/FormatterInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Formatter; 13 | 14 | /** 15 | * Interface for formatters 16 | * 17 | * @author Jordi Boggiano 18 | */ 19 | interface FormatterInterface 20 | { 21 | /** 22 | * Formats a log record. 23 | * 24 | * @param array $record A record to format 25 | * @return mixed The formatted record 26 | */ 27 | public function format(array $record); 28 | 29 | /** 30 | * Formats a set of log records. 31 | * 32 | * @param array $records A set of records to format 33 | * @return mixed The formatted set of records 34 | */ 35 | public function formatBatch(array $records); 36 | } 37 | -------------------------------------------------------------------------------- /lib/Monolog/Formatter/GelfMessageFormatter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Formatter; 13 | 14 | use Monolog\Logger; 15 | use Gelf\Message; 16 | 17 | /** 18 | * Serializes a log message to GELF 19 | * @see http://www.graylog2.org/about/gelf 20 | * 21 | * @author Matt Lehner 22 | */ 23 | class GelfMessageFormatter extends NormalizerFormatter 24 | { 25 | /** 26 | * @var string the name of the system for the Gelf log message 27 | */ 28 | protected $systemName; 29 | 30 | /** 31 | * @var string a prefix for 'extra' fields from the Monolog record (optional) 32 | */ 33 | protected $extraPrefix; 34 | 35 | /** 36 | * @var string a prefix for 'context' fields from the Monolog record (optional) 37 | */ 38 | protected $contextPrefix; 39 | 40 | /** 41 | * Translates Monolog log levels to Graylog2 log priorities. 42 | */ 43 | private $logLevels = array( 44 | Logger::DEBUG => 7, 45 | Logger::INFO => 6, 46 | Logger::NOTICE => 5, 47 | Logger::WARNING => 4, 48 | Logger::ERROR => 3, 49 | Logger::CRITICAL => 2, 50 | Logger::ALERT => 1, 51 | Logger::EMERGENCY => 0, 52 | ); 53 | 54 | public function __construct($systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_') 55 | { 56 | parent::__construct('U.u'); 57 | 58 | $this->systemName = $systemName ?: gethostname(); 59 | 60 | $this->extraPrefix = $extraPrefix; 61 | $this->contextPrefix = $contextPrefix; 62 | } 63 | 64 | /** 65 | * {@inheritdoc} 66 | */ 67 | public function format(array $record) 68 | { 69 | $record = parent::format($record); 70 | $message = new Message(); 71 | $message 72 | ->setTimestamp($record['datetime']) 73 | ->setShortMessage((string) $record['message']) 74 | ->setFacility($record['channel']) 75 | ->setHost($this->systemName) 76 | ->setLine(isset($record['extra']['line']) ? $record['extra']['line'] : null) 77 | ->setFile(isset($record['extra']['file']) ? $record['extra']['file'] : null) 78 | ->setLevel($this->logLevels[$record['level']]); 79 | 80 | // Do not duplicate these values in the additional fields 81 | unset($record['extra']['line']); 82 | unset($record['extra']['file']); 83 | 84 | foreach ($record['extra'] as $key => $val) { 85 | $message->setAdditional($this->extraPrefix . $key, is_scalar($val) ? $val : $this->toJson($val)); 86 | } 87 | 88 | foreach ($record['context'] as $key => $val) { 89 | $message->setAdditional($this->contextPrefix . $key, is_scalar($val) ? $val : $this->toJson($val)); 90 | } 91 | 92 | return $message; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /lib/Monolog/Formatter/JsonFormatter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Formatter; 13 | 14 | /** 15 | * Encodes whatever record data is passed to it as json 16 | * 17 | * This can be useful to log to databases or remote APIs 18 | * 19 | * @author Jordi Boggiano 20 | */ 21 | class JsonFormatter implements FormatterInterface 22 | { 23 | /** 24 | * {@inheritdoc} 25 | */ 26 | public function format(array $record) 27 | { 28 | return json_encode($record); 29 | } 30 | 31 | /** 32 | * {@inheritdoc} 33 | */ 34 | public function formatBatch(array $records) 35 | { 36 | return json_encode($records); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/Monolog/Formatter/LineFormatter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Formatter; 13 | 14 | /** 15 | * Formats incoming records into a one-line string 16 | * 17 | * This is especially useful for logging to files 18 | * 19 | * @author Jordi Boggiano 20 | * @author Christophe Coevoet 21 | */ 22 | class LineFormatter extends NormalizerFormatter 23 | { 24 | const SIMPLE_FORMAT = "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"; 25 | 26 | protected $format; 27 | 28 | /** 29 | * @param string $format The format of the message 30 | * @param string $dateFormat The format of the timestamp: one supported by DateTime::format 31 | */ 32 | public function __construct($format = null, $dateFormat = null) 33 | { 34 | $this->format = $format ?: static::SIMPLE_FORMAT; 35 | parent::__construct($dateFormat); 36 | } 37 | 38 | /** 39 | * {@inheritdoc} 40 | */ 41 | public function format(array $record) 42 | { 43 | $vars = parent::format($record); 44 | 45 | $output = $this->format; 46 | foreach ($vars['extra'] as $var => $val) { 47 | if (false !== strpos($output, '%extra.'.$var.'%')) { 48 | $output = str_replace('%extra.'.$var.'%', $this->convertToString($val), $output); 49 | unset($vars['extra'][$var]); 50 | } 51 | } 52 | foreach ($vars as $var => $val) { 53 | $output = str_replace('%'.$var.'%', $this->convertToString($val), $output); 54 | } 55 | 56 | return $output; 57 | } 58 | 59 | public function formatBatch(array $records) 60 | { 61 | $message = ''; 62 | foreach ($records as $record) { 63 | $message .= $this->format($record); 64 | } 65 | 66 | return $message; 67 | } 68 | 69 | protected function normalize($data) 70 | { 71 | if (is_bool($data) || is_null($data)) { 72 | return var_export($data, true); 73 | } 74 | 75 | if ($data instanceof \Exception) { 76 | $previousText = ''; 77 | if ($previous = $data->getPrevious()) { 78 | do { 79 | $previousText .= ', '.get_class($previous).': '.$previous->getMessage().' at '.$previous->getFile().':'.$previous->getLine(); 80 | } while ($previous = $previous->getPrevious()); 81 | } 82 | 83 | return '[object] ('.get_class($data).': '.$data->getMessage().' at '.$data->getFile().':'.$data->getLine().$previousText.')'; 84 | } 85 | 86 | return parent::normalize($data); 87 | } 88 | 89 | protected function convertToString($data) 90 | { 91 | if (null === $data || is_scalar($data)) { 92 | return (string) $data; 93 | } 94 | 95 | $data = $this->normalize($data); 96 | if (version_compare(PHP_VERSION, '5.4.0', '>=')) { 97 | return $this->toJson($data); 98 | } 99 | 100 | return str_replace('\\/', '/', json_encode($data)); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /lib/Monolog/Formatter/LogstashFormatter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Formatter; 13 | 14 | /** 15 | * Serializes a log message to Logstash Event Format 16 | * 17 | * @see http://logstash.net/ 18 | * @see https://github.com/logstash/logstash/blob/master/lib/logstash/event.rb 19 | * 20 | * @author Tim Mower 21 | */ 22 | class LogstashFormatter extends NormalizerFormatter 23 | { 24 | /** 25 | * @var string the name of the system for the Logstash log message, used to fill the @source field 26 | */ 27 | protected $systemName; 28 | 29 | /** 30 | * @var string an application name for the Logstash log message, used to fill the @type field 31 | */ 32 | protected $applicationName; 33 | 34 | /** 35 | * @var string a prefix for 'extra' fields from the Monolog record (optional) 36 | */ 37 | protected $extraPrefix; 38 | 39 | /** 40 | * @var string a prefix for 'context' fields from the Monolog record (optional) 41 | */ 42 | protected $contextPrefix; 43 | 44 | /** 45 | * @param string $applicationName the application that sends the data, used as the "type" field of logstash 46 | * @param string $systemName the system/machine name, used as the "source" field of logstash, defaults to the hostname of the machine 47 | * @param string $extraPrefix prefix for extra keys inside logstash "fields" 48 | * @param string $contextPrefix prefix for context keys inside logstash "fields", defaults to ctxt_ 49 | */ 50 | public function __construct($applicationName, $systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_') 51 | { 52 | //log stash requires a ISO 8601 format date 53 | parent::__construct('c'); 54 | 55 | $this->systemName = $systemName ?: gethostname(); 56 | $this->applicationName = $applicationName; 57 | 58 | $this->extraPrefix = $extraPrefix; 59 | $this->contextPrefix = $contextPrefix; 60 | } 61 | 62 | /** 63 | * {@inheritdoc} 64 | */ 65 | public function format(array $record) 66 | { 67 | $record = parent::format($record); 68 | $message = array( 69 | '@timestamp' => $record['datetime'], 70 | '@message' => $record['message'], 71 | '@tags' => array($record['channel']), 72 | '@source' => $this->systemName 73 | ); 74 | 75 | if ($this->applicationName) { 76 | $message['@type'] = $this->applicationName; 77 | } 78 | $message['@fields'] = array(); 79 | $message['@fields']['channel'] = $record['channel']; 80 | $message['@fields']['level'] = $record['level']; 81 | 82 | if (isset($record['extra']['server'])) { 83 | $message['@source_host'] = $record['extra']['server']; 84 | } 85 | if (isset($record['extra']['url'])) { 86 | $message['@source_path'] = $record['extra']['url']; 87 | } 88 | foreach ($record['extra'] as $key => $val) { 89 | $message['@fields'][$this->extraPrefix . $key] = $val; 90 | } 91 | 92 | foreach ($record['context'] as $key => $val) { 93 | $message['@fields'][$this->contextPrefix . $key] = $val; 94 | } 95 | 96 | return json_encode($message) . "\n"; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /lib/Monolog/Formatter/NormalizerFormatter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Formatter; 13 | 14 | use Exception; 15 | 16 | /** 17 | * Normalizes incoming records to remove objects/resources so it's easier to dump to various targets 18 | * 19 | * @author Jordi Boggiano 20 | */ 21 | class NormalizerFormatter implements FormatterInterface 22 | { 23 | const SIMPLE_DATE = "Y-m-d H:i:s"; 24 | 25 | protected $dateFormat; 26 | 27 | /** 28 | * @param string $dateFormat The format of the timestamp: one supported by DateTime::format 29 | */ 30 | public function __construct($dateFormat = null) 31 | { 32 | $this->dateFormat = $dateFormat ?: static::SIMPLE_DATE; 33 | } 34 | 35 | /** 36 | * {@inheritdoc} 37 | */ 38 | public function format(array $record) 39 | { 40 | return $this->normalize($record); 41 | } 42 | 43 | /** 44 | * {@inheritdoc} 45 | */ 46 | public function formatBatch(array $records) 47 | { 48 | foreach ($records as $key => $record) { 49 | $records[$key] = $this->format($record); 50 | } 51 | 52 | return $records; 53 | } 54 | 55 | protected function normalize($data) 56 | { 57 | if (null === $data || is_scalar($data)) { 58 | return $data; 59 | } 60 | 61 | if (is_array($data) || $data instanceof \Traversable) { 62 | $normalized = array(); 63 | 64 | $count = 1; 65 | foreach ($data as $key => $value) { 66 | if ($count++ >= 1000) { 67 | $normalized['...'] = 'Over 1000 items, aborting normalization'; 68 | break; 69 | } 70 | $normalized[$key] = $this->normalize($value); 71 | } 72 | 73 | return $normalized; 74 | } 75 | 76 | if ($data instanceof \DateTime) { 77 | return $data->format($this->dateFormat); 78 | } 79 | 80 | if (is_object($data)) { 81 | if ($data instanceof Exception) { 82 | return $this->normalizeException($data); 83 | } 84 | 85 | return sprintf("[object] (%s: %s)", get_class($data), $this->toJson($data, true)); 86 | } 87 | 88 | if (is_resource($data)) { 89 | return '[resource]'; 90 | } 91 | 92 | return '[unknown('.gettype($data).')]'; 93 | } 94 | 95 | protected function normalizeException(Exception $e) 96 | { 97 | $data = array( 98 | 'class' => get_class($e), 99 | 'message' => $e->getMessage(), 100 | 'file' => $e->getFile().':'.$e->getLine(), 101 | ); 102 | 103 | $trace = $e->getTrace(); 104 | array_shift($trace); 105 | foreach ($trace as $frame) { 106 | if (isset($frame['file'])) { 107 | $data['trace'][] = $frame['file'].':'.$frame['line']; 108 | } else { 109 | $data['trace'][] = json_encode($frame); 110 | } 111 | } 112 | 113 | if ($previous = $e->getPrevious()) { 114 | $data['previous'] = $this->normalizeException($previous); 115 | } 116 | 117 | return $data; 118 | } 119 | 120 | protected function toJson($data, $ignoreErrors = false) 121 | { 122 | // suppress json_encode errors since it's twitchy with some inputs 123 | if ($ignoreErrors) { 124 | if (version_compare(PHP_VERSION, '5.4.0', '>=')) { 125 | return @json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); 126 | } 127 | 128 | return @json_encode($data); 129 | } 130 | 131 | if (version_compare(PHP_VERSION, '5.4.0', '>=')) { 132 | return json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); 133 | } 134 | 135 | return json_encode($data); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /lib/Monolog/Formatter/WildfireFormatter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Formatter; 13 | 14 | use Monolog\Logger; 15 | 16 | /** 17 | * Serializes a log message according to Wildfire's header requirements 18 | * 19 | * @author Eric Clemmons (@ericclemmons) 20 | * @author Christophe Coevoet 21 | * @author Kirill chEbba Chebunin 22 | */ 23 | class WildfireFormatter extends NormalizerFormatter 24 | { 25 | /** 26 | * Translates Monolog log levels to Wildfire levels. 27 | */ 28 | private $logLevels = array( 29 | Logger::DEBUG => 'LOG', 30 | Logger::INFO => 'INFO', 31 | Logger::NOTICE => 'INFO', 32 | Logger::WARNING => 'WARN', 33 | Logger::ERROR => 'ERROR', 34 | Logger::CRITICAL => 'ERROR', 35 | Logger::ALERT => 'ERROR', 36 | Logger::EMERGENCY => 'ERROR', 37 | ); 38 | 39 | /** 40 | * {@inheritdoc} 41 | */ 42 | public function format(array $record) 43 | { 44 | // Retrieve the line and file if set and remove them from the formatted extra 45 | $file = $line = ''; 46 | if (isset($record['extra']['file'])) { 47 | $file = $record['extra']['file']; 48 | unset($record['extra']['file']); 49 | } 50 | if (isset($record['extra']['line'])) { 51 | $line = $record['extra']['line']; 52 | unset($record['extra']['line']); 53 | } 54 | 55 | $record = $this->normalize($record); 56 | $message = array('message' => $record['message']); 57 | $handleError = false; 58 | if ($record['context']) { 59 | $message['context'] = $record['context']; 60 | $handleError = true; 61 | } 62 | if ($record['extra']) { 63 | $message['extra'] = $record['extra']; 64 | $handleError = true; 65 | } 66 | if (count($message) === 1) { 67 | $message = reset($message); 68 | } 69 | 70 | // Create JSON object describing the appearance of the message in the console 71 | $json = $this->toJson(array( 72 | array( 73 | 'Type' => $this->logLevels[$record['level']], 74 | 'File' => $file, 75 | 'Line' => $line, 76 | 'Label' => $record['channel'], 77 | ), 78 | $message, 79 | ), $handleError); 80 | 81 | // The message itself is a serialization of the above JSON object + it's length 82 | return sprintf( 83 | '%s|%s|', 84 | strlen($json), 85 | $json 86 | ); 87 | } 88 | 89 | public function formatBatch(array $records) 90 | { 91 | throw new \BadMethodCallException('Batch formatting does not make sense for the WildfireFormatter'); 92 | } 93 | 94 | protected function normalize($data) 95 | { 96 | if (is_object($data) && !$data instanceof \DateTime) { 97 | return $data; 98 | } 99 | 100 | return parent::normalize($data); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/AbstractHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Logger; 15 | use Monolog\Formatter\FormatterInterface; 16 | use Monolog\Formatter\LineFormatter; 17 | 18 | /** 19 | * Base Handler class providing the Handler structure 20 | * 21 | * @author Jordi Boggiano 22 | */ 23 | abstract class AbstractHandler implements HandlerInterface 24 | { 25 | protected $level = Logger::DEBUG; 26 | protected $bubble = true; 27 | 28 | /** 29 | * @var FormatterInterface 30 | */ 31 | protected $formatter; 32 | protected $processors = array(); 33 | 34 | /** 35 | * @param integer $level The minimum logging level at which this handler will be triggered 36 | * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not 37 | */ 38 | public function __construct($level = Logger::DEBUG, $bubble = true) 39 | { 40 | $this->level = $level; 41 | $this->bubble = $bubble; 42 | } 43 | 44 | /** 45 | * {@inheritdoc} 46 | */ 47 | public function isHandling(array $record) 48 | { 49 | return $record['level'] >= $this->level; 50 | } 51 | 52 | /** 53 | * {@inheritdoc} 54 | */ 55 | public function handleBatch(array $records) 56 | { 57 | foreach ($records as $record) { 58 | $this->handle($record); 59 | } 60 | } 61 | 62 | /** 63 | * Closes the handler. 64 | * 65 | * This will be called automatically when the object is destroyed 66 | */ 67 | public function close() 68 | { 69 | } 70 | 71 | /** 72 | * {@inheritdoc} 73 | */ 74 | public function pushProcessor($callback) 75 | { 76 | if (!is_callable($callback)) { 77 | throw new \InvalidArgumentException('Processors must be valid callables (callback or object with an __invoke method), '.var_export($callback, true).' given'); 78 | } 79 | array_unshift($this->processors, $callback); 80 | 81 | return $this; 82 | } 83 | 84 | /** 85 | * {@inheritdoc} 86 | */ 87 | public function popProcessor() 88 | { 89 | if (!$this->processors) { 90 | throw new \LogicException('You tried to pop from an empty processor stack.'); 91 | } 92 | 93 | return array_shift($this->processors); 94 | } 95 | 96 | /** 97 | * {@inheritdoc} 98 | */ 99 | public function setFormatter(FormatterInterface $formatter) 100 | { 101 | $this->formatter = $formatter; 102 | 103 | return $this; 104 | } 105 | 106 | /** 107 | * {@inheritdoc} 108 | */ 109 | public function getFormatter() 110 | { 111 | if (!$this->formatter) { 112 | $this->formatter = $this->getDefaultFormatter(); 113 | } 114 | 115 | return $this->formatter; 116 | } 117 | 118 | /** 119 | * Sets minimum logging level at which this handler will be triggered. 120 | * 121 | * @param integer $level 122 | * @return self 123 | */ 124 | public function setLevel($level) 125 | { 126 | $this->level = $level; 127 | 128 | return $this; 129 | } 130 | 131 | /** 132 | * Gets minimum logging level at which this handler will be triggered. 133 | * 134 | * @return integer 135 | */ 136 | public function getLevel() 137 | { 138 | return $this->level; 139 | } 140 | 141 | /** 142 | * Sets the bubbling behavior. 143 | * 144 | * @param Boolean $bubble true means that this handler allows bubbling. 145 | * false means that bubbling is not permitted. 146 | * @return self 147 | */ 148 | public function setBubble($bubble) 149 | { 150 | $this->bubble = $bubble; 151 | 152 | return $this; 153 | } 154 | 155 | /** 156 | * Gets the bubbling behavior. 157 | * 158 | * @return Boolean true means that this handler allows bubbling. 159 | * false means that bubbling is not permitted. 160 | */ 161 | public function getBubble() 162 | { 163 | return $this->bubble; 164 | } 165 | 166 | public function __destruct() 167 | { 168 | try { 169 | $this->close(); 170 | } catch (\Exception $e) { 171 | // do nothing 172 | } 173 | } 174 | 175 | /** 176 | * Gets the default formatter. 177 | * 178 | * @return FormatterInterface 179 | */ 180 | protected function getDefaultFormatter() 181 | { 182 | return new LineFormatter(); 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/AbstractProcessingHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | /** 15 | * Base Handler class providing the Handler structure 16 | * 17 | * Classes extending it should (in most cases) only implement write($record) 18 | * 19 | * @author Jordi Boggiano 20 | * @author Christophe Coevoet 21 | */ 22 | abstract class AbstractProcessingHandler extends AbstractHandler 23 | { 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | public function handle(array $record) 28 | { 29 | if ($record['level'] < $this->level) { 30 | return false; 31 | } 32 | 33 | $record = $this->processRecord($record); 34 | 35 | $record['formatted'] = $this->getFormatter()->format($record); 36 | 37 | $this->write($record); 38 | 39 | return false === $this->bubble; 40 | } 41 | 42 | /** 43 | * Writes the record down to the log of the implementing handler 44 | * 45 | * @param array $record 46 | * @return void 47 | */ 48 | abstract protected function write(array $record); 49 | 50 | /** 51 | * Processes a record. 52 | * 53 | * @param array $record 54 | * @return array 55 | */ 56 | protected function processRecord(array $record) 57 | { 58 | if ($this->processors) { 59 | foreach ($this->processors as $processor) { 60 | $record = call_user_func($processor, $record); 61 | } 62 | } 63 | 64 | return $record; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/AmqpHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Logger; 15 | use Monolog\Formatter\JsonFormatter; 16 | 17 | class AmqpHandler extends AbstractProcessingHandler 18 | { 19 | /** 20 | * @var \AMQPExchange $exchange 21 | */ 22 | protected $exchange; 23 | 24 | /** 25 | * @param \AMQPExchange $exchange AMQP exchange, ready for use 26 | * @param string $exchangeName 27 | * @param int $level 28 | * @param bool $bubble Whether the messages that are handled can bubble up the stack or not 29 | */ 30 | public function __construct(\AMQPExchange $exchange, $exchangeName = 'log', $level = Logger::DEBUG, $bubble = true) 31 | { 32 | $this->exchange = $exchange; 33 | $this->exchange->setName($exchangeName); 34 | 35 | parent::__construct($level, $bubble); 36 | } 37 | 38 | /** 39 | * {@inheritDoc} 40 | */ 41 | protected function write(array $record) 42 | { 43 | $data = $record["formatted"]; 44 | 45 | $routingKey = sprintf( 46 | '%s.%s', 47 | substr($record['level_name'], 0, 4), 48 | $record['channel'] 49 | ); 50 | 51 | $this->exchange->publish( 52 | $data, 53 | strtolower($routingKey), 54 | 0, 55 | array( 56 | 'delivery_mode' => 2, 57 | 'Content-type' => 'application/json' 58 | ) 59 | ); 60 | } 61 | 62 | /** 63 | * {@inheritDoc} 64 | */ 65 | protected function getDefaultFormatter() 66 | { 67 | return new JsonFormatter(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/BufferHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Logger; 15 | 16 | /** 17 | * Buffers all records until closing the handler and then pass them as batch. 18 | * 19 | * This is useful for a MailHandler to send only one mail per request instead of 20 | * sending one per log message. 21 | * 22 | * @author Christophe Coevoet 23 | */ 24 | class BufferHandler extends AbstractHandler 25 | { 26 | protected $handler; 27 | protected $bufferSize = 0; 28 | protected $bufferLimit; 29 | protected $flushOnOverflow; 30 | protected $buffer = array(); 31 | 32 | /** 33 | * @param HandlerInterface $handler Handler. 34 | * @param integer $bufferLimit How many entries should be buffered at most, beyond that the oldest items are removed from the buffer. 35 | * @param integer $level The minimum logging level at which this handler will be triggered 36 | * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not 37 | * @param Boolean $flushOnOverflow If true, the buffer is flushed when the max size has been reached, by default oldest entries are discarded 38 | */ 39 | public function __construct(HandlerInterface $handler, $bufferLimit = 0, $level = Logger::DEBUG, $bubble = true, $flushOnOverflow = false) 40 | { 41 | parent::__construct($level, $bubble); 42 | $this->handler = $handler; 43 | $this->bufferLimit = (int) $bufferLimit; 44 | $this->flushOnOverflow = $flushOnOverflow; 45 | 46 | // __destructor() doesn't get called on Fatal errors 47 | register_shutdown_function(array($this, 'close')); 48 | } 49 | 50 | /** 51 | * {@inheritdoc} 52 | */ 53 | public function handle(array $record) 54 | { 55 | if ($record['level'] < $this->level) { 56 | return false; 57 | } 58 | 59 | if ($this->bufferLimit > 0 && $this->bufferSize === $this->bufferLimit) { 60 | if ($this->flushOnOverflow) { 61 | $this->flush(); 62 | } else { 63 | array_shift($this->buffer); 64 | $this->bufferSize--; 65 | } 66 | } 67 | 68 | if ($this->processors) { 69 | foreach ($this->processors as $processor) { 70 | $record = call_user_func($processor, $record); 71 | } 72 | } 73 | 74 | $this->buffer[] = $record; 75 | $this->bufferSize++; 76 | 77 | return false === $this->bubble; 78 | } 79 | 80 | public function flush() 81 | { 82 | if ($this->bufferSize === 0) { 83 | return; 84 | } 85 | 86 | $this->handler->handleBatch($this->buffer); 87 | $this->bufferSize = 0; 88 | $this->buffer = array(); 89 | } 90 | 91 | /** 92 | * {@inheritdoc} 93 | */ 94 | public function close() 95 | { 96 | $this->flush(); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/ChromePHPHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Formatter\ChromePHPFormatter; 15 | use Monolog\Logger; 16 | 17 | /** 18 | * Handler sending logs to the ChromePHP extension (http://www.chromephp.com/) 19 | * 20 | * @author Christophe Coevoet 21 | */ 22 | class ChromePHPHandler extends AbstractProcessingHandler 23 | { 24 | /** 25 | * Version of the extension 26 | */ 27 | const VERSION = '4.0'; 28 | 29 | /** 30 | * Header name 31 | */ 32 | const HEADER_NAME = 'X-ChromeLogger-Data'; 33 | 34 | protected static $initialized = false; 35 | 36 | /** 37 | * Tracks whether we sent too much data 38 | * 39 | * Chrome limits the headers to 256KB, so when we sent 240KB we stop sending 40 | * 41 | * @var Boolean 42 | */ 43 | protected static $overflowed = false; 44 | 45 | protected static $json = array( 46 | 'version' => self::VERSION, 47 | 'columns' => array('label', 'log', 'backtrace', 'type'), 48 | 'rows' => array(), 49 | ); 50 | 51 | protected static $sendHeaders = true; 52 | 53 | /** 54 | * {@inheritdoc} 55 | */ 56 | public function handleBatch(array $records) 57 | { 58 | $messages = array(); 59 | 60 | foreach ($records as $record) { 61 | if ($record['level'] < $this->level) { 62 | continue; 63 | } 64 | $messages[] = $this->processRecord($record); 65 | } 66 | 67 | if (!empty($messages)) { 68 | $messages = $this->getFormatter()->formatBatch($messages); 69 | self::$json['rows'] = array_merge(self::$json['rows'], $messages); 70 | $this->send(); 71 | } 72 | } 73 | 74 | /** 75 | * {@inheritDoc} 76 | */ 77 | protected function getDefaultFormatter() 78 | { 79 | return new ChromePHPFormatter(); 80 | } 81 | 82 | /** 83 | * Creates & sends header for a record 84 | * 85 | * @see sendHeader() 86 | * @see send() 87 | * @param array $record 88 | */ 89 | protected function write(array $record) 90 | { 91 | self::$json['rows'][] = $record['formatted']; 92 | 93 | $this->send(); 94 | } 95 | 96 | /** 97 | * Sends the log header 98 | * 99 | * @see sendHeader() 100 | */ 101 | protected function send() 102 | { 103 | if (self::$overflowed) { 104 | return; 105 | } 106 | 107 | if (!self::$initialized) { 108 | self::$sendHeaders = $this->headersAccepted(); 109 | self::$json['request_uri'] = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; 110 | 111 | self::$initialized = true; 112 | } 113 | 114 | $json = @json_encode(self::$json); 115 | $data = base64_encode(utf8_encode($json)); 116 | if (strlen($data) > 240*1024) { 117 | self::$overflowed = true; 118 | 119 | $record = array( 120 | 'message' => 'Incomplete logs, chrome header size limit reached', 121 | 'context' => array(), 122 | 'level' => Logger::WARNING, 123 | 'level_name' => Logger::getLevelName(Logger::WARNING), 124 | 'channel' => 'monolog', 125 | 'datetime' => new \DateTime(), 126 | 'extra' => array(), 127 | ); 128 | self::$json['rows'][count(self::$json['rows']) - 1] = $this->getFormatter()->format($record); 129 | $json = @json_encode(self::$json); 130 | $data = base64_encode(utf8_encode($json)); 131 | } 132 | 133 | $this->sendHeader(self::HEADER_NAME, $data); 134 | } 135 | 136 | /** 137 | * Send header string to the client 138 | * 139 | * @param string $header 140 | * @param string $content 141 | */ 142 | protected function sendHeader($header, $content) 143 | { 144 | if (!headers_sent() && self::$sendHeaders) { 145 | header(sprintf('%s: %s', $header, $content)); 146 | } 147 | } 148 | 149 | /** 150 | * Verifies if the headers are accepted by the current user agent 151 | * 152 | * @return Boolean 153 | */ 154 | protected function headersAccepted() 155 | { 156 | return !isset($_SERVER['HTTP_USER_AGENT']) 157 | || preg_match('{\bChrome/\d+[\.\d+]*\b}', $_SERVER['HTTP_USER_AGENT']); 158 | } 159 | 160 | /** 161 | * BC getter for the sendHeaders property that has been made static 162 | */ 163 | public function __get($property) 164 | { 165 | if ('sendHeaders' !== $property) { 166 | throw new \InvalidArgumentException('Undefined property '.$property); 167 | } 168 | 169 | return static::$sendHeaders; 170 | } 171 | 172 | /** 173 | * BC setter for the sendHeaders property that has been made static 174 | */ 175 | public function __set($property, $value) 176 | { 177 | if ('sendHeaders' !== $property) { 178 | throw new \InvalidArgumentException('Undefined property '.$property); 179 | } 180 | 181 | static::$sendHeaders = $value; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/CouchDBHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Formatter\JsonFormatter; 15 | use Monolog\Logger; 16 | 17 | /** 18 | * CouchDB handler 19 | * 20 | * @author Markus Bachmann 21 | */ 22 | class CouchDBHandler extends AbstractProcessingHandler 23 | { 24 | private $options; 25 | 26 | public function __construct(array $options = array(), $level = Logger::DEBUG, $bubble = true) 27 | { 28 | $this->options = array_merge(array( 29 | 'host' => 'localhost', 30 | 'port' => 5984, 31 | 'dbname' => 'logger', 32 | 'username' => null, 33 | 'password' => null, 34 | ), $options); 35 | 36 | parent::__construct($level, $bubble); 37 | } 38 | 39 | /** 40 | * {@inheritDoc} 41 | */ 42 | protected function write(array $record) 43 | { 44 | $basicAuth = null; 45 | if ($this->options['username']) { 46 | $basicAuth = sprintf('%s:%s@', $this->options['username'], $this->options['password']); 47 | } 48 | 49 | $url = 'http://'.$basicAuth.$this->options['host'].':'.$this->options['port'].'/'.$this->options['dbname']; 50 | $context = stream_context_create(array( 51 | 'http' => array( 52 | 'method' => 'POST', 53 | 'content' => $record['formatted'], 54 | 'ignore_errors' => true, 55 | 'max_redirects' => 0, 56 | 'header' => 'Content-type: application/json', 57 | ) 58 | )); 59 | 60 | if (false === @file_get_contents($url, null, $context)) { 61 | throw new \RuntimeException(sprintf('Could not connect to %s', $url)); 62 | } 63 | } 64 | 65 | /** 66 | * {@inheritDoc} 67 | */ 68 | protected function getDefaultFormatter() 69 | { 70 | return new JsonFormatter(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/CubeHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Logger; 15 | 16 | /** 17 | * Logs to Cube. 18 | * 19 | * @link http://square.github.com/cube/ 20 | * @author Wan Chen 21 | */ 22 | class CubeHandler extends AbstractProcessingHandler 23 | { 24 | private $udpConnection = null; 25 | private $httpConnection = null; 26 | private $scheme = null; 27 | private $host = null; 28 | private $port = null; 29 | private $acceptedSchemes = array('http', 'udp'); 30 | 31 | /** 32 | * Create a Cube handler 33 | * 34 | * @throws UnexpectedValueException when given url is not a valid url. 35 | * A valid url must consists of three parts : protocol://host:port 36 | * Only valid protocol used by Cube are http and udp 37 | */ 38 | public function __construct($url, $level = Logger::DEBUG, $bubble = true) 39 | { 40 | $urlInfos = parse_url($url); 41 | 42 | if (!isset($urlInfos['scheme']) || !isset($urlInfos['host']) || !isset($urlInfos['port'])) { 43 | throw new \UnexpectedValueException('URL "'.$url.'" is not valid'); 44 | } 45 | 46 | if (!in_array($urlInfos['scheme'], $this->acceptedSchemes)) { 47 | throw new \UnexpectedValueException( 48 | 'Invalid protocol (' . $urlInfos['scheme'] . ').' 49 | . ' Valid options are ' . implode(', ', $this->acceptedSchemes)); 50 | } 51 | 52 | $this->scheme = $urlInfos['scheme']; 53 | $this->host = $urlInfos['host']; 54 | $this->port = $urlInfos['port']; 55 | 56 | parent::__construct($level, $bubble); 57 | } 58 | 59 | /** 60 | * Establish a connection to an UDP socket 61 | * 62 | * @throws LogicException when unable to connect to the socket 63 | */ 64 | protected function connectUdp() 65 | { 66 | if (!extension_loaded('sockets')) { 67 | throw new MissingExtensionException('The sockets extension is required to use udp URLs with the CubeHandler'); 68 | } 69 | 70 | $this->udpConnection = socket_create(AF_INET, SOCK_DGRAM, 0); 71 | if (!$this->udpConnection) { 72 | throw new \LogicException('Unable to create a socket'); 73 | } 74 | 75 | if (!socket_connect($this->udpConnection, $this->host, $this->port)) { 76 | throw new \LogicException('Unable to connect to the socket at ' . $this->host . ':' . $this->port); 77 | } 78 | } 79 | 80 | /** 81 | * Establish a connection to a http server 82 | */ 83 | protected function connectHttp() 84 | { 85 | if (!extension_loaded('curl')) { 86 | throw new \LogicException('The curl extension is needed to use http URLs with the CubeHandler'); 87 | } 88 | 89 | $this->httpConnection = curl_init('http://'.$this->host.':'.$this->port.'/1.0/event/put'); 90 | 91 | if (!$this->httpConnection) { 92 | throw new \LogicException('Unable to connect to ' . $this->host . ':' . $this->port); 93 | } 94 | 95 | curl_setopt($this->httpConnection, CURLOPT_CUSTOMREQUEST, "POST"); 96 | curl_setopt($this->httpConnection, CURLOPT_RETURNTRANSFER, true); 97 | } 98 | 99 | /** 100 | * {@inheritdoc} 101 | */ 102 | protected function write(array $record) 103 | { 104 | $date = $record['datetime']; 105 | 106 | $data = array('time' => $date->format('Y-m-d\TH:i:s.u')); 107 | unset($record['datetime']); 108 | 109 | if (isset($record['context']['type'])) { 110 | $data['type'] = $record['context']['type']; 111 | unset($record['context']['type']); 112 | } else { 113 | $data['type'] = $record['channel']; 114 | } 115 | 116 | $data['data'] = $record['context']; 117 | $data['data']['level'] = $record['level']; 118 | 119 | $this->{'write'.$this->scheme}(json_encode($data)); 120 | } 121 | 122 | private function writeUdp($data) 123 | { 124 | if (!$this->udpConnection) { 125 | $this->connectUdp(); 126 | } 127 | 128 | socket_send($this->udpConnection, $data, strlen($data), 0); 129 | } 130 | 131 | private function writeHttp($data) 132 | { 133 | if (!$this->httpConnection) { 134 | $this->connectHttp(); 135 | } 136 | 137 | curl_setopt($this->httpConnection, CURLOPT_POSTFIELDS, '['.$data.']'); 138 | curl_setopt($this->httpConnection, CURLOPT_HTTPHEADER, array( 139 | 'Content-Type: application/json', 140 | 'Content-Length: ' . strlen('['.$data.']')) 141 | ); 142 | 143 | return curl_exec($this->httpConnection); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/DoctrineCouchDBHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Logger; 15 | use Monolog\Formatter\NormalizerFormatter; 16 | use Doctrine\CouchDB\CouchDBClient; 17 | 18 | /** 19 | * CouchDB handler for Doctrine CouchDB ODM 20 | * 21 | * @author Markus Bachmann 22 | */ 23 | class DoctrineCouchDBHandler extends AbstractProcessingHandler 24 | { 25 | private $client; 26 | 27 | public function __construct(CouchDBClient $client, $level = Logger::DEBUG, $bubble = true) 28 | { 29 | $this->client = $client; 30 | parent::__construct($level, $bubble); 31 | } 32 | 33 | /** 34 | * {@inheritDoc} 35 | */ 36 | protected function write(array $record) 37 | { 38 | $this->client->postDocument($record['formatted']); 39 | } 40 | 41 | protected function getDefaultFormatter() 42 | { 43 | return new NormalizerFormatter; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/ErrorLogHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Logger; 15 | 16 | /** 17 | * Stores to PHP error_log() handler. 18 | * 19 | * @author Elan Ruusamäe 20 | */ 21 | class ErrorLogHandler extends AbstractProcessingHandler 22 | { 23 | const OPERATING_SYSTEM = 0; 24 | const SAPI = 4; 25 | 26 | protected $messageType; 27 | 28 | /** 29 | * @param integer $messageType Says where the error should go. 30 | * @param integer $level The minimum logging level at which this handler will be triggered 31 | * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not 32 | */ 33 | public function __construct($messageType = self::OPERATING_SYSTEM, $level = Logger::DEBUG, $bubble = true) 34 | { 35 | parent::__construct($level, $bubble); 36 | 37 | if (false === in_array($messageType, self::getAvailableTypes())) { 38 | $message = sprintf('The given message type "%s" is not supported', print_r($messageType, true)); 39 | throw new \InvalidArgumentException($message); 40 | } 41 | 42 | $this->messageType = $messageType; 43 | } 44 | 45 | /** 46 | * @return array With all available types 47 | */ 48 | public static function getAvailableTypes() 49 | { 50 | return array( 51 | self::OPERATING_SYSTEM, 52 | self::SAPI, 53 | ); 54 | } 55 | 56 | /** 57 | * {@inheritdoc} 58 | */ 59 | protected function write(array $record) 60 | { 61 | error_log((string) $record['formatted'], $this->messageType); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler\FingersCrossed; 13 | 14 | /** 15 | * Interface for activation strategies for the FingersCrossedHandler. 16 | * 17 | * @author Johannes M. Schmitt 18 | */ 19 | interface ActivationStrategyInterface 20 | { 21 | /** 22 | * Returns whether the given record activates the handler. 23 | * 24 | * @param array $record 25 | * @return Boolean 26 | */ 27 | public function isHandlerActivated(array $record); 28 | } 29 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler\FingersCrossed; 13 | 14 | /** 15 | * Channel and Error level based monolog activation strategy. Allows to trigger activation 16 | * based on level per channel. e.g. trigger activation on level 'ERROR' by default, except 17 | * for records of the 'sql' channel; those should trigger activation on level 'WARN'. 18 | * 19 | * Example: 20 | * 21 | * 22 | * $activationStrategy = new ChannelLevelActivationStrategy( 23 | * Logger::CRITICAL, 24 | * array( 25 | * 'request' => Logger::ALERT, 26 | * 'sensitive' => Logger::ERROR, 27 | * ) 28 | * ); 29 | * $handler = new FingersCrossedHandler(new StreamHandler('php://stderr'), $activationStrategy); 30 | * 31 | * 32 | * @author Mike Meessen 33 | */ 34 | class ChannelLevelActivationStrategy implements ActivationStrategyInterface 35 | { 36 | private $defaultActionLevel; 37 | private $channelToActionLevel; 38 | 39 | /** 40 | * @param int $defaultActionLevel The default action level to be used if the record's category doesn't match any 41 | * @param array $categoryToActionLevel An array that maps channel names to action levels. 42 | */ 43 | public function __construct($defaultActionLevel, $channelToActionLevel = array()) 44 | { 45 | $this->defaultActionLevel = $defaultActionLevel; 46 | $this->channelToActionLevel = $channelToActionLevel; 47 | } 48 | 49 | public function isHandlerActivated(array $record) 50 | { 51 | if (isset($this->channelToActionLevel[$record['channel']])) { 52 | return $record['level'] >= $this->channelToActionLevel[$record['channel']]; 53 | } 54 | 55 | return $record['level'] >= $this->defaultActionLevel; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler\FingersCrossed; 13 | 14 | /** 15 | * Error level based activation strategy. 16 | * 17 | * @author Johannes M. Schmitt 18 | */ 19 | class ErrorLevelActivationStrategy implements ActivationStrategyInterface 20 | { 21 | private $actionLevel; 22 | 23 | public function __construct($actionLevel) 24 | { 25 | $this->actionLevel = $actionLevel; 26 | } 27 | 28 | public function isHandlerActivated(array $record) 29 | { 30 | return $record['level'] >= $this->actionLevel; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/FingersCrossedHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy; 15 | use Monolog\Handler\FingersCrossed\ActivationStrategyInterface; 16 | use Monolog\Logger; 17 | 18 | /** 19 | * Buffers all records until a certain level is reached 20 | * 21 | * The advantage of this approach is that you don't get any clutter in your log files. 22 | * Only requests which actually trigger an error (or whatever your actionLevel is) will be 23 | * in the logs, but they will contain all records, not only those above the level threshold. 24 | * 25 | * You can find the various activation strategies in the 26 | * Monolog\Handler\FingersCrossed\ namespace. 27 | * 28 | * @author Jordi Boggiano 29 | */ 30 | class FingersCrossedHandler extends AbstractHandler 31 | { 32 | protected $handler; 33 | protected $activationStrategy; 34 | protected $buffering = true; 35 | protected $bufferSize; 36 | protected $buffer = array(); 37 | protected $stopBuffering; 38 | 39 | /** 40 | * @param callable|HandlerInterface $handler Handler or factory callable($record, $fingersCrossedHandler). 41 | * @param int|ActivationStrategyInterface $activationStrategy Strategy which determines when this handler takes action 42 | * @param int $bufferSize How many entries should be buffered at most, beyond that the oldest items are removed from the buffer. 43 | * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not 44 | * @param Boolean $stopBuffering Whether the handler should stop buffering after being triggered (default true) 45 | */ 46 | public function __construct($handler, $activationStrategy = null, $bufferSize = 0, $bubble = true, $stopBuffering = true) 47 | { 48 | if (null === $activationStrategy) { 49 | $activationStrategy = new ErrorLevelActivationStrategy(Logger::WARNING); 50 | } 51 | 52 | // convert simple int activationStrategy to an object 53 | if (!$activationStrategy instanceof ActivationStrategyInterface) { 54 | $activationStrategy = new ErrorLevelActivationStrategy($activationStrategy); 55 | } 56 | 57 | $this->handler = $handler; 58 | $this->activationStrategy = $activationStrategy; 59 | $this->bufferSize = $bufferSize; 60 | $this->bubble = $bubble; 61 | $this->stopBuffering = $stopBuffering; 62 | } 63 | 64 | /** 65 | * {@inheritdoc} 66 | */ 67 | public function isHandling(array $record) 68 | { 69 | return true; 70 | } 71 | 72 | /** 73 | * {@inheritdoc} 74 | */ 75 | public function handle(array $record) 76 | { 77 | if ($this->processors) { 78 | foreach ($this->processors as $processor) { 79 | $record = call_user_func($processor, $record); 80 | } 81 | } 82 | 83 | if ($this->buffering) { 84 | $this->buffer[] = $record; 85 | if ($this->bufferSize > 0 && count($this->buffer) > $this->bufferSize) { 86 | array_shift($this->buffer); 87 | } 88 | if ($this->activationStrategy->isHandlerActivated($record)) { 89 | if ($this->stopBuffering) { 90 | $this->buffering = false; 91 | } 92 | if (!$this->handler instanceof HandlerInterface) { 93 | if (!is_callable($this->handler)) { 94 | throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object"); 95 | } 96 | $this->handler = call_user_func($this->handler, $record, $this); 97 | if (!$this->handler instanceof HandlerInterface) { 98 | throw new \RuntimeException("The factory callable should return a HandlerInterface"); 99 | } 100 | } 101 | $this->handler->handleBatch($this->buffer); 102 | $this->buffer = array(); 103 | } 104 | } else { 105 | $this->handler->handle($record); 106 | } 107 | 108 | return false === $this->bubble; 109 | } 110 | 111 | /** 112 | * Resets the state of the handler. Stops forwarding records to the wrapped handler. 113 | */ 114 | public function reset() 115 | { 116 | $this->buffering = true; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/FirePHPHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Formatter\WildfireFormatter; 15 | 16 | /** 17 | * Simple FirePHP Handler (http://www.firephp.org/), which uses the Wildfire protocol. 18 | * 19 | * @author Eric Clemmons (@ericclemmons) 20 | */ 21 | class FirePHPHandler extends AbstractProcessingHandler 22 | { 23 | /** 24 | * WildFire JSON header message format 25 | */ 26 | const PROTOCOL_URI = 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2'; 27 | 28 | /** 29 | * FirePHP structure for parsing messages & their presentation 30 | */ 31 | const STRUCTURE_URI = 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1'; 32 | 33 | /** 34 | * Must reference a "known" plugin, otherwise headers won't display in FirePHP 35 | */ 36 | const PLUGIN_URI = 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3'; 37 | 38 | /** 39 | * Header prefix for Wildfire to recognize & parse headers 40 | */ 41 | const HEADER_PREFIX = 'X-Wf'; 42 | 43 | /** 44 | * Whether or not Wildfire vendor-specific headers have been generated & sent yet 45 | */ 46 | protected static $initialized = false; 47 | 48 | /** 49 | * Shared static message index between potentially multiple handlers 50 | * @var int 51 | */ 52 | protected static $messageIndex = 1; 53 | 54 | protected static $sendHeaders = true; 55 | 56 | /** 57 | * Base header creation function used by init headers & record headers 58 | * 59 | * @param array $meta Wildfire Plugin, Protocol & Structure Indexes 60 | * @param string $message Log message 61 | * @return array Complete header string ready for the client as key and message as value 62 | */ 63 | protected function createHeader(array $meta, $message) 64 | { 65 | $header = sprintf('%s-%s', self::HEADER_PREFIX, join('-', $meta)); 66 | 67 | return array($header => $message); 68 | } 69 | 70 | /** 71 | * Creates message header from record 72 | * 73 | * @see createHeader() 74 | * @param array $record 75 | * @return string 76 | */ 77 | protected function createRecordHeader(array $record) 78 | { 79 | // Wildfire is extensible to support multiple protocols & plugins in a single request, 80 | // but we're not taking advantage of that (yet), so we're using "1" for simplicity's sake. 81 | return $this->createHeader( 82 | array(1, 1, 1, self::$messageIndex++), 83 | $record['formatted'] 84 | ); 85 | } 86 | 87 | /** 88 | * {@inheritDoc} 89 | */ 90 | protected function getDefaultFormatter() 91 | { 92 | return new WildfireFormatter(); 93 | } 94 | 95 | /** 96 | * Wildfire initialization headers to enable message parsing 97 | * 98 | * @see createHeader() 99 | * @see sendHeader() 100 | * @return array 101 | */ 102 | protected function getInitHeaders() 103 | { 104 | // Initial payload consists of required headers for Wildfire 105 | return array_merge( 106 | $this->createHeader(array('Protocol', 1), self::PROTOCOL_URI), 107 | $this->createHeader(array(1, 'Structure', 1), self::STRUCTURE_URI), 108 | $this->createHeader(array(1, 'Plugin', 1), self::PLUGIN_URI) 109 | ); 110 | } 111 | 112 | /** 113 | * Send header string to the client 114 | * 115 | * @param string $header 116 | * @param string $content 117 | */ 118 | protected function sendHeader($header, $content) 119 | { 120 | if (!headers_sent() && self::$sendHeaders) { 121 | header(sprintf('%s: %s', $header, $content)); 122 | } 123 | } 124 | 125 | /** 126 | * Creates & sends header for a record, ensuring init headers have been sent prior 127 | * 128 | * @see sendHeader() 129 | * @see sendInitHeaders() 130 | * @param array $record 131 | */ 132 | protected function write(array $record) 133 | { 134 | // WildFire-specific headers must be sent prior to any messages 135 | if (!self::$initialized) { 136 | self::$sendHeaders = $this->headersAccepted(); 137 | 138 | foreach ($this->getInitHeaders() as $header => $content) { 139 | $this->sendHeader($header, $content); 140 | } 141 | 142 | self::$initialized = true; 143 | } 144 | 145 | $header = $this->createRecordHeader($record); 146 | $this->sendHeader(key($header), current($header)); 147 | } 148 | 149 | /** 150 | * Verifies if the headers are accepted by the current user agent 151 | * 152 | * @return Boolean 153 | */ 154 | protected function headersAccepted() 155 | { 156 | return !isset($_SERVER['HTTP_USER_AGENT']) 157 | || preg_match('{\bFirePHP/\d+\.\d+\b}', $_SERVER['HTTP_USER_AGENT']) 158 | || isset($_SERVER['HTTP_X_FIREPHP_VERSION']); 159 | } 160 | 161 | /** 162 | * BC getter for the sendHeaders property that has been made static 163 | */ 164 | public function __get($property) 165 | { 166 | if ('sendHeaders' !== $property) { 167 | throw new \InvalidArgumentException('Undefined property '.$property); 168 | } 169 | 170 | return static::$sendHeaders; 171 | } 172 | 173 | /** 174 | * BC setter for the sendHeaders property that has been made static 175 | */ 176 | public function __set($property, $value) 177 | { 178 | if ('sendHeaders' !== $property) { 179 | throw new \InvalidArgumentException('Undefined property '.$property); 180 | } 181 | 182 | static::$sendHeaders = $value; 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/GelfHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Gelf\IMessagePublisher; 15 | use Monolog\Logger; 16 | use Monolog\Handler\AbstractProcessingHandler; 17 | use Monolog\Formatter\GelfMessageFormatter; 18 | 19 | /** 20 | * Handler to send messages to a Graylog2 (http://www.graylog2.org) server 21 | * 22 | * @author Matt Lehner 23 | */ 24 | class GelfHandler extends AbstractProcessingHandler 25 | { 26 | /** 27 | * @var Gelf\IMessagePublisher the publisher object that sends the message to the server 28 | */ 29 | protected $publisher; 30 | 31 | /** 32 | * @param Gelf\IMessagePublisher $publisher a publisher object 33 | * @param integer $level The minimum logging level at which this handler will be triggered 34 | * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not 35 | */ 36 | public function __construct(IMessagePublisher $publisher, $level = Logger::DEBUG, $bubble = true) 37 | { 38 | parent::__construct($level, $bubble); 39 | 40 | $this->publisher = $publisher; 41 | } 42 | 43 | /** 44 | * {@inheritdoc} 45 | */ 46 | public function close() 47 | { 48 | $this->publisher = null; 49 | } 50 | 51 | /** 52 | * {@inheritdoc} 53 | */ 54 | protected function write(array $record) 55 | { 56 | $this->publisher->publish($record['formatted']); 57 | } 58 | 59 | /** 60 | * {@inheritDoc} 61 | */ 62 | protected function getDefaultFormatter() 63 | { 64 | return new GelfMessageFormatter(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/GroupHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | /** 15 | * Forwards records to multiple handlers 16 | * 17 | * @author Lenar Lõhmus 18 | */ 19 | class GroupHandler extends AbstractHandler 20 | { 21 | protected $handlers; 22 | 23 | /** 24 | * @param array $handlers Array of Handlers. 25 | * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not 26 | */ 27 | public function __construct(array $handlers, $bubble = true) 28 | { 29 | foreach ($handlers as $handler) { 30 | if (!$handler instanceof HandlerInterface) { 31 | throw new \InvalidArgumentException('The first argument of the GroupHandler must be an array of HandlerInterface instances.'); 32 | } 33 | } 34 | 35 | $this->handlers = $handlers; 36 | $this->bubble = $bubble; 37 | } 38 | 39 | /** 40 | * {@inheritdoc} 41 | */ 42 | public function isHandling(array $record) 43 | { 44 | foreach ($this->handlers as $handler) { 45 | if ($handler->isHandling($record)) { 46 | return true; 47 | } 48 | } 49 | 50 | return false; 51 | } 52 | 53 | /** 54 | * {@inheritdoc} 55 | */ 56 | public function handle(array $record) 57 | { 58 | if ($this->processors) { 59 | foreach ($this->processors as $processor) { 60 | $record = call_user_func($processor, $record); 61 | } 62 | } 63 | 64 | foreach ($this->handlers as $handler) { 65 | $handler->handle($record); 66 | } 67 | 68 | return false === $this->bubble; 69 | } 70 | 71 | /** 72 | * {@inheritdoc} 73 | */ 74 | public function handleBatch(array $records) 75 | { 76 | foreach ($this->handlers as $handler) { 77 | $handler->handleBatch($records); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/HandlerInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Formatter\FormatterInterface; 15 | 16 | /** 17 | * Interface that all Monolog Handlers must implement 18 | * 19 | * @author Jordi Boggiano 20 | */ 21 | interface HandlerInterface 22 | { 23 | /** 24 | * Checks whether the given record will be handled by this handler. 25 | * 26 | * This is mostly done for performance reasons, to avoid calling processors for nothing. 27 | * 28 | * Handlers should still check the record levels within handle(), returning false in isHandling() 29 | * is no guarantee that handle() will not be called, and isHandling() might not be called 30 | * for a given record. 31 | * 32 | * @param array $record 33 | * 34 | * @return Boolean 35 | */ 36 | public function isHandling(array $record); 37 | 38 | /** 39 | * Handles a record. 40 | * 41 | * All records may be passed to this method, and the handler should discard 42 | * those that it does not want to handle. 43 | * 44 | * The return value of this function controls the bubbling process of the handler stack. 45 | * Unless the bubbling is interrupted (by returning true), the Logger class will keep on 46 | * calling further handlers in the stack with a given log record. 47 | * 48 | * @param array $record The record to handle 49 | * @return Boolean true means that this handler handled the record, and that bubbling is not permitted. 50 | * false means the record was either not processed or that this handler allows bubbling. 51 | */ 52 | public function handle(array $record); 53 | 54 | /** 55 | * Handles a set of records at once. 56 | * 57 | * @param array $records The records to handle (an array of record arrays) 58 | */ 59 | public function handleBatch(array $records); 60 | 61 | /** 62 | * Adds a processor in the stack. 63 | * 64 | * @param callable $callback 65 | * @return self 66 | */ 67 | public function pushProcessor($callback); 68 | 69 | /** 70 | * Removes the processor on top of the stack and returns it. 71 | * 72 | * @return callable 73 | */ 74 | public function popProcessor(); 75 | 76 | /** 77 | * Sets the formatter. 78 | * 79 | * @param FormatterInterface $formatter 80 | * @return self 81 | */ 82 | public function setFormatter(FormatterInterface $formatter); 83 | 84 | /** 85 | * Gets the formatter. 86 | * 87 | * @return FormatterInterface 88 | */ 89 | public function getFormatter(); 90 | } 91 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/HipChatHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Logger; 15 | 16 | /** 17 | * Sends notifications through the hipchat api to a hipchat room 18 | * 19 | * Notes: 20 | * API token - HipChat API token 21 | * Room - HipChat Room Id or name, where messages are sent 22 | * Name - Name used to send the message (from) 23 | * notify - Should the message trigger a notification in the clients 24 | * 25 | * @author Rafael Dohms 26 | * @see https://www.hipchat.com/docs/api 27 | */ 28 | class HipChatHandler extends SocketHandler 29 | { 30 | /** 31 | * @var string 32 | */ 33 | private $token; 34 | 35 | /** 36 | * @var array 37 | */ 38 | private $room; 39 | 40 | /** 41 | * @var string 42 | */ 43 | private $name; 44 | 45 | /** 46 | * @var boolean 47 | */ 48 | private $notify; 49 | 50 | /** 51 | * @param string $token HipChat API Token 52 | * @param string $room The room that should be alerted of the message (Id or Name) 53 | * @param string $name Name used in the "from" field 54 | * @param bool $notify Trigger a notification in clients or not 55 | * @param int $level The minimum logging level at which this handler will be triggered 56 | * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not 57 | * @param Boolean $useSSL Whether to connect via SSL. 58 | */ 59 | public function __construct($token, $room, $name = 'Monolog', $notify = false, $level = Logger::CRITICAL, $bubble = true, $useSSL = true) 60 | { 61 | $connectionString = $useSSL ? 'ssl://api.hipchat.com:443' : 'api.hipchat.com:80'; 62 | parent::__construct($connectionString, $level, $bubble); 63 | 64 | $this->token = $token; 65 | $this->name = $name; 66 | $this->notify = $notify; 67 | $this->room = $room; 68 | } 69 | 70 | /** 71 | * {@inheritdoc} 72 | * 73 | * @param array $record 74 | * @return string 75 | */ 76 | protected function generateDataStream($record) 77 | { 78 | $content = $this->buildContent($record); 79 | 80 | return $this->buildHeader($content) . $content; 81 | } 82 | 83 | /** 84 | * Builds the body of API call 85 | * 86 | * @param array $record 87 | * @return string 88 | */ 89 | private function buildContent($record) 90 | { 91 | $dataArray = array( 92 | 'from' => $this->name, 93 | 'room_id' => $this->room, 94 | 'notify' => $this->notify, 95 | 'message' => $record['formatted'], 96 | 'message_format' => 'text', 97 | 'color' => $this->getAlertColor($record['level']), 98 | ); 99 | 100 | return http_build_query($dataArray); 101 | } 102 | 103 | /** 104 | * Builds the header of the API Call 105 | * 106 | * @param string $content 107 | * @return string 108 | */ 109 | private function buildHeader($content) 110 | { 111 | $header = "POST /v1/rooms/message?format=json&auth_token=".$this->token." HTTP/1.1\r\n"; 112 | $header .= "Host: api.hipchat.com\r\n"; 113 | $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; 114 | $header .= "Content-Length: " . strlen($content) . "\r\n"; 115 | $header .= "\r\n"; 116 | 117 | return $header; 118 | } 119 | 120 | /** 121 | * Assigns a color to each level of log records. 122 | * 123 | * @param integer $level 124 | * @return string 125 | */ 126 | protected function getAlertColor($level) 127 | { 128 | switch (true) { 129 | case $level >= Logger::ERROR: 130 | return 'red'; 131 | case $level >= Logger::WARNING: 132 | return 'yellow'; 133 | case $level >= Logger::INFO: 134 | return 'green'; 135 | case $level == Logger::DEBUG: 136 | return 'gray'; 137 | default: 138 | return 'yellow'; 139 | } 140 | } 141 | 142 | /** 143 | * {@inheritdoc} 144 | * 145 | * @param array $record 146 | */ 147 | public function write(array $record) 148 | { 149 | parent::write($record); 150 | $this->closeSocket(); 151 | } 152 | 153 | } 154 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/MailHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | /** 15 | * Base class for all mail handlers 16 | * 17 | * @author Gyula Sallai 18 | */ 19 | abstract class MailHandler extends AbstractProcessingHandler 20 | { 21 | /** 22 | * {@inheritdoc} 23 | */ 24 | public function handleBatch(array $records) 25 | { 26 | $messages = array(); 27 | 28 | foreach ($records as $record) { 29 | if ($record['level'] < $this->level) { 30 | continue; 31 | } 32 | $messages[] = $this->processRecord($record); 33 | } 34 | 35 | if (!empty($messages)) { 36 | $this->send((string) $this->getFormatter()->formatBatch($messages), $messages); 37 | } 38 | } 39 | 40 | /** 41 | * Send a mail with the given content 42 | * 43 | * @param string $content 44 | * @param array $records the array of log records that formed this content 45 | */ 46 | abstract protected function send($content, array $records); 47 | 48 | /** 49 | * {@inheritdoc} 50 | */ 51 | protected function write(array $record) 52 | { 53 | $this->send((string) $record['formatted'], array($record)); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/MissingExtensionException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | /** 15 | * Exception can be thrown if an extension for an handler is missing 16 | * 17 | * @author Christian Bergau 18 | */ 19 | class MissingExtensionException extends \Exception 20 | { 21 | 22 | } 23 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/MongoDBHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Logger; 15 | use Monolog\Formatter\NormalizerFormatter; 16 | 17 | /** 18 | * Logs to a MongoDB database. 19 | * 20 | * usage example: 21 | * 22 | * $log = new Logger('application'); 23 | * $mongodb = new MongoDBHandler(new \Mongo("mongodb://localhost:27017"), "logs", "prod"); 24 | * $log->pushHandler($mongodb); 25 | * 26 | * @author Thomas Tourlourat 27 | */ 28 | class MongoDBHandler extends AbstractProcessingHandler 29 | { 30 | private $mongoCollection; 31 | 32 | public function __construct($mongo, $database, $collection, $level = Logger::DEBUG, $bubble = true) 33 | { 34 | if (!($mongo instanceof \MongoClient || $mongo instanceof \Mongo)) { 35 | throw new \InvalidArgumentException('MongoClient or Mongo instance required'); 36 | } 37 | 38 | $this->mongoCollection = $mongo->selectCollection($database, $collection); 39 | 40 | parent::__construct($level, $bubble); 41 | } 42 | 43 | protected function write(array $record) 44 | { 45 | $this->mongoCollection->save($record["formatted"]); 46 | } 47 | 48 | /** 49 | * {@inheritDoc} 50 | */ 51 | protected function getDefaultFormatter() 52 | { 53 | return new NormalizerFormatter(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/NativeMailerHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Logger; 15 | 16 | /** 17 | * NativeMailerHandler uses the mail() function to send the emails 18 | * 19 | * @author Christophe Coevoet 20 | */ 21 | class NativeMailerHandler extends MailHandler 22 | { 23 | protected $to; 24 | protected $subject; 25 | protected $headers = array( 26 | 'Content-type: text/plain; charset=utf-8' 27 | ); 28 | protected $maxColumnWidth; 29 | 30 | /** 31 | * @param string|array $to The receiver of the mail 32 | * @param string $subject The subject of the mail 33 | * @param string $from The sender of the mail 34 | * @param integer $level The minimum logging level at which this handler will be triggered 35 | * @param boolean $bubble Whether the messages that are handled can bubble up the stack or not 36 | * @param int $maxColumnWidth The maximum column width that the message lines will have 37 | */ 38 | public function __construct($to, $subject, $from, $level = Logger::ERROR, $bubble = true, $maxColumnWidth = 70) 39 | { 40 | parent::__construct($level, $bubble); 41 | $this->to = is_array($to) ? $to : array($to); 42 | $this->subject = $subject; 43 | $this->addHeader(sprintf('From: %s', $from)); 44 | $this->maxColumnWidth = $maxColumnWidth; 45 | } 46 | 47 | /** 48 | * @param string|array $headers Custom added headers 49 | */ 50 | public function addHeader($headers) 51 | { 52 | foreach ((array) $headers as $header) { 53 | if (strpos($header, "\n") !== false || strpos($header, "\r") !== false) { 54 | throw new \InvalidArgumentException('Headers can not contain newline characters for security reasons'); 55 | } 56 | $this->headers[] = $header; 57 | } 58 | } 59 | 60 | /** 61 | * {@inheritdoc} 62 | */ 63 | protected function send($content, array $records) 64 | { 65 | $content = wordwrap($content, $this->maxColumnWidth); 66 | $headers = implode("\r\n", $this->headers) . "\r\n"; 67 | foreach ($this->to as $to) { 68 | mail($to, $this->subject, $content, $headers); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/NewRelicHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Logger; 15 | 16 | /** 17 | * Class to record a log on a NewRelic application 18 | * 19 | * @see https://newrelic.com/docs/php/new-relic-for-php 20 | */ 21 | class NewRelicHandler extends AbstractProcessingHandler 22 | { 23 | /** 24 | * Name of the New Relic application that will receive logs from this handler. 25 | * 26 | * @var string 27 | */ 28 | protected $appName; 29 | 30 | /** 31 | * {@inheritDoc} 32 | * 33 | * @param string $appName 34 | */ 35 | public function __construct($level = Logger::ERROR, $bubble = true, $appName = null) 36 | { 37 | parent::__construct($level, $bubble); 38 | 39 | $this->appName = $appName; 40 | } 41 | 42 | /** 43 | * {@inheritDoc} 44 | */ 45 | protected function write(array $record) 46 | { 47 | if (!$this->isNewRelicEnabled()) { 48 | throw new MissingExtensionException('The newrelic PHP extension is required to use the NewRelicHandler'); 49 | } 50 | 51 | if ($appName = $this->getAppName($record['context'])) { 52 | $this->setNewRelicAppName($appName); 53 | } 54 | 55 | if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Exception) { 56 | newrelic_notice_error($record['message'], $record['context']['exception']); 57 | unset($record['context']['exception']); 58 | } else { 59 | newrelic_notice_error($record['message']); 60 | } 61 | 62 | foreach ($record['context'] as $key => $parameter) { 63 | newrelic_add_custom_parameter($key, $parameter); 64 | } 65 | } 66 | 67 | /** 68 | * Checks whether the NewRelic extension is enabled in the system. 69 | * 70 | * @return bool 71 | */ 72 | protected function isNewRelicEnabled() 73 | { 74 | return extension_loaded('newrelic'); 75 | } 76 | 77 | /** 78 | * Returns the appname where this log should be sent. Each log can override the default appname, set in this 79 | * handler's constructor, by providing the appname in its context. 80 | * 81 | * @param array $context 82 | * @return null|string 83 | */ 84 | protected function getAppName(array $context) 85 | { 86 | if (isset($context['appname'])) { 87 | return $context['appname']; 88 | } 89 | 90 | return $this->appName; 91 | } 92 | 93 | /** 94 | * Sets the NewRelic application that should receive this log. 95 | * 96 | * @param string $appName 97 | */ 98 | protected function setNewRelicAppName($appName) 99 | { 100 | newrelic_set_appname($appName); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/NullHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Logger; 15 | 16 | /** 17 | * Blackhole 18 | * 19 | * Any record it can handle will be thrown away. This can be used 20 | * to put on top of an existing stack to override it temporarily. 21 | * 22 | * @author Jordi Boggiano 23 | */ 24 | class NullHandler extends AbstractHandler 25 | { 26 | /** 27 | * @param integer $level The minimum logging level at which this handler will be triggered 28 | */ 29 | public function __construct($level = Logger::DEBUG) 30 | { 31 | parent::__construct($level, false); 32 | } 33 | 34 | /** 35 | * {@inheritdoc} 36 | */ 37 | public function handle(array $record) 38 | { 39 | if ($record['level'] < $this->level) { 40 | return false; 41 | } 42 | 43 | return true; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/PushoverHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Logger; 15 | 16 | /** 17 | * Sends notifications through the pushover api to mobile phones 18 | * 19 | * @author Sebastian Göttschkes 20 | * @see https://www.pushover.net/api 21 | */ 22 | class PushoverHandler extends SocketHandler 23 | { 24 | private $token; 25 | private $users; 26 | private $title; 27 | private $user; 28 | private $retry; 29 | private $expire; 30 | 31 | private $highPriorityLevel; 32 | private $emergencyLevel; 33 | 34 | /** 35 | * @param string $token Pushover api token 36 | * @param string|array $users Pushover user id or array of ids the message will be sent to 37 | * @param string $title Title sent to the Pushover API 38 | * @param integer $level The minimum logging level at which this handler will be triggered 39 | * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not 40 | * @param Boolean $useSSL Whether to connect via SSL. Required when pushing messages to users that are not 41 | * the pushover.net app owner. OpenSSL is required for this option. 42 | * @param integer $highPriorityLevel The minimum logging level at which this handler will start 43 | * sending "high priority" requests to the Pushover API 44 | * @param integer $emergencyLevel The minimum logging level at which this handler will start 45 | * sending "emergency" requests to the Pushover API 46 | * @param integer $retry The retry parameter specifies how often (in seconds) the Pushover servers will send the same notification to the user. 47 | * @param integer $expire The expire parameter specifies how many seconds your notification will continue to be retried for (every retry seconds). 48 | */ 49 | public function __construct($token, $users, $title = null, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $highPriorityLevel = Logger::CRITICAL, $emergencyLevel = Logger::EMERGENCY, $retry = 30, $expire = 25200) 50 | { 51 | $connectionString = $useSSL ? 'ssl://api.pushover.net:443' : 'api.pushover.net:80'; 52 | parent::__construct($connectionString, $level, $bubble); 53 | 54 | $this->token = $token; 55 | $this->users = (array) $users; 56 | $this->title = $title ?: gethostname(); 57 | $this->highPriorityLevel = $highPriorityLevel; 58 | $this->emergencyLevel = $emergencyLevel; 59 | $this->retry = $retry; 60 | $this->expire = $expire; 61 | } 62 | 63 | protected function generateDataStream($record) 64 | { 65 | $content = $this->buildContent($record); 66 | 67 | return $this->buildHeader($content) . $content; 68 | } 69 | 70 | private function buildContent($record) 71 | { 72 | // Pushover has a limit of 512 characters on title and message combined. 73 | $maxMessageLength = 512 - strlen($this->title); 74 | $message = substr($record['message'], 0, $maxMessageLength); 75 | $timestamp = $record['datetime']->getTimestamp(); 76 | 77 | $dataArray = array( 78 | 'token' => $this->token, 79 | 'user' => $this->user, 80 | 'message' => $message, 81 | 'title' => $this->title, 82 | 'timestamp' => $timestamp 83 | ); 84 | 85 | if ($record['level'] >= $this->emergencyLevel) { 86 | $dataArray['priority'] = 2; 87 | $dataArray['retry'] = $this->retry; 88 | $dataArray['expire'] = $this->expire; 89 | } elseif ($record['level'] >= $this->highPriorityLevel) { 90 | $dataArray['priority'] = 1; 91 | } 92 | 93 | return http_build_query($dataArray); 94 | } 95 | 96 | private function buildHeader($content) 97 | { 98 | $header = "POST /1/messages.json HTTP/1.1\r\n"; 99 | $header .= "Host: api.pushover.net\r\n"; 100 | $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; 101 | $header .= "Content-Length: " . strlen($content) . "\r\n"; 102 | $header .= "\r\n"; 103 | 104 | return $header; 105 | } 106 | 107 | public function write(array $record) 108 | { 109 | foreach ($this->users as $user) { 110 | $this->user = $user; 111 | 112 | parent::write($record); 113 | $this->closeSocket(); 114 | } 115 | 116 | $this->user = null; 117 | } 118 | 119 | public function setHighPriorityLevel($value) 120 | { 121 | $this->highPriorityLevel = $value; 122 | } 123 | 124 | public function setEmergencyLevel($value) 125 | { 126 | $this->emergencyLevel = $value; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/RavenHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Formatter\LineFormatter; 15 | use Monolog\Formatter\FormatterInterface; 16 | use Monolog\Logger; 17 | use Monolog\Handler\AbstractProcessingHandler; 18 | use Raven_Client; 19 | 20 | /** 21 | * Handler to send messages to a Sentry (https://github.com/dcramer/sentry) server 22 | * using raven-php (https://github.com/getsentry/raven-php) 23 | * 24 | * @author Marc Abramowitz 25 | */ 26 | class RavenHandler extends AbstractProcessingHandler 27 | { 28 | /** 29 | * Translates Monolog log levels to Raven log levels. 30 | */ 31 | private $logLevels = array( 32 | Logger::DEBUG => Raven_Client::DEBUG, 33 | Logger::INFO => Raven_Client::INFO, 34 | Logger::NOTICE => Raven_Client::INFO, 35 | Logger::WARNING => Raven_Client::WARNING, 36 | Logger::ERROR => Raven_Client::ERROR, 37 | Logger::CRITICAL => Raven_Client::FATAL, 38 | Logger::ALERT => Raven_Client::FATAL, 39 | Logger::EMERGENCY => Raven_Client::FATAL, 40 | ); 41 | 42 | /** 43 | * @var Raven_Client the client object that sends the message to the server 44 | */ 45 | protected $ravenClient; 46 | 47 | /** 48 | * @var LineFormatter The formatter to use for the logs generated via handleBatch() 49 | */ 50 | protected $batchFormatter; 51 | 52 | /** 53 | * @param Raven_Client $ravenClient 54 | * @param integer $level The minimum logging level at which this handler will be triggered 55 | * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not 56 | */ 57 | public function __construct(Raven_Client $ravenClient, $level = Logger::DEBUG, $bubble = true) 58 | { 59 | parent::__construct($level, $bubble); 60 | 61 | $this->ravenClient = $ravenClient; 62 | } 63 | 64 | /** 65 | * {@inheritdoc} 66 | */ 67 | public function handleBatch(array $records) 68 | { 69 | $level = $this->level; 70 | 71 | // filter records based on their level 72 | $records = array_filter($records, function($record) use ($level) { 73 | return $record['level'] >= $level; 74 | }); 75 | 76 | if (!$records) { 77 | return; 78 | } 79 | 80 | // the record with the highest severity is the "main" one 81 | $record = array_reduce($records, function($highest, $record) { 82 | if ($record['level'] >= $highest['level']) { 83 | $highest = $record; 84 | 85 | return $highest; 86 | } 87 | }); 88 | 89 | // the other ones are added as a context item 90 | $logs = array(); 91 | foreach ($records as $r) { 92 | $logs[] = $this->processRecord($r); 93 | } 94 | 95 | if ($logs) { 96 | $record['context']['logs'] = (string) $this->getBatchFormatter()->formatBatch($logs); 97 | } 98 | 99 | $this->handle($record); 100 | } 101 | 102 | /** 103 | * Sets the formatter for the logs generated by handleBatch(). 104 | * 105 | * @param FormatterInterface $formatter 106 | */ 107 | public function setBatchFormatter(FormatterInterface $formatter) 108 | { 109 | $this->batchFormatter = $formatter; 110 | } 111 | 112 | /** 113 | * Gets the formatter for the logs generated by handleBatch(). 114 | * 115 | * @return FormatterInterface 116 | */ 117 | public function getBatchFormatter() 118 | { 119 | if (!$this->batchFormatter) { 120 | $this->batchFormatter = $this->getDefaultBatchFormatter(); 121 | } 122 | 123 | return $this->batchFormatter; 124 | } 125 | 126 | /** 127 | * {@inheritdoc} 128 | */ 129 | protected function write(array $record) 130 | { 131 | $options = array(); 132 | $options['level'] = $this->logLevels[$record['level']]; 133 | if (!empty($record['context'])) { 134 | $options['extra']['context'] = $record['context']; 135 | } 136 | if (!empty($record['extra'])) { 137 | $options['extra']['extra'] = $record['extra']; 138 | } 139 | 140 | if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Exception) { 141 | $options['extra']['message'] = $record['formatted']; 142 | $this->ravenClient->captureException($record['context']['exception'], $options); 143 | 144 | return; 145 | } 146 | 147 | $this->ravenClient->captureMessage($record['formatted'], array(), $options); 148 | } 149 | 150 | /** 151 | * {@inheritDoc} 152 | */ 153 | protected function getDefaultFormatter() 154 | { 155 | return new LineFormatter('[%channel%] %message%'); 156 | } 157 | 158 | /** 159 | * Gets the default formatter for the logs generated by handleBatch(). 160 | * 161 | * @return FormatterInterface 162 | */ 163 | protected function getDefaultBatchFormatter() 164 | { 165 | return new LineFormatter(); 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/RedisHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Logger; 15 | use Monolog\Formatter\LineFormatter; 16 | 17 | /** 18 | * Logs to a Redis key using rpush 19 | * 20 | * usage example: 21 | * 22 | * $log = new Logger('application'); 23 | * $redis = new RedisHandler(new Predis\Client("tcp://localhost:6379"), "logs", "prod"); 24 | * $log->pushHandler($redis); 25 | * 26 | * @author Thomas Tourlourat 27 | */ 28 | class RedisHandler extends AbstractProcessingHandler 29 | { 30 | private $redisClient; 31 | private $redisKey; 32 | 33 | # redis instance, key to use 34 | public function __construct($redis, $key, $level = Logger::DEBUG, $bubble = true) 35 | { 36 | if (!(($redis instanceof \Predis\Client) || ($redis instanceof \Redis))) { 37 | throw new \InvalidArgumentException('Predis\Client or Redis instance required'); 38 | } 39 | 40 | $this->redisClient = $redis; 41 | $this->redisKey = $key; 42 | 43 | parent::__construct($level, $bubble); 44 | } 45 | 46 | protected function write(array $record) 47 | { 48 | $this->redisClient->rpush($this->redisKey, $record["formatted"]); 49 | } 50 | 51 | /** 52 | * {@inheritDoc} 53 | */ 54 | protected function getDefaultFormatter() 55 | { 56 | return new LineFormatter(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/RotatingFileHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Logger; 15 | 16 | /** 17 | * Stores logs to files that are rotated every day and a limited number of files are kept. 18 | * 19 | * This rotation is only intended to be used as a workaround. Using logrotate to 20 | * handle the rotation is strongly encouraged when you can use it. 21 | * 22 | * @author Christophe Coevoet 23 | * @author Jordi Boggiano 24 | */ 25 | class RotatingFileHandler extends StreamHandler 26 | { 27 | protected $filename; 28 | protected $maxFiles; 29 | protected $mustRotate; 30 | protected $nextRotation; 31 | 32 | /** 33 | * @param string $filename 34 | * @param integer $maxFiles The maximal amount of files to keep (0 means unlimited) 35 | * @param integer $level The minimum logging level at which this handler will be triggered 36 | * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not 37 | */ 38 | public function __construct($filename, $maxFiles = 0, $level = Logger::DEBUG, $bubble = true) 39 | { 40 | $this->filename = $filename; 41 | $this->maxFiles = (int) $maxFiles; 42 | $this->nextRotation = new \DateTime('tomorrow'); 43 | 44 | parent::__construct($this->getTimedFilename(), $level, $bubble); 45 | } 46 | 47 | /** 48 | * {@inheritdoc} 49 | */ 50 | public function close() 51 | { 52 | parent::close(); 53 | 54 | if (true === $this->mustRotate) { 55 | $this->rotate(); 56 | } 57 | } 58 | 59 | /** 60 | * {@inheritdoc} 61 | */ 62 | protected function write(array $record) 63 | { 64 | // on the first record written, if the log is new, we should rotate (once per day) 65 | if (null === $this->mustRotate) { 66 | $this->mustRotate = !file_exists($this->url); 67 | } 68 | 69 | if ($this->nextRotation < $record['datetime']) { 70 | $this->mustRotate = true; 71 | $this->close(); 72 | } 73 | 74 | parent::write($record); 75 | } 76 | 77 | /** 78 | * Rotates the files. 79 | */ 80 | protected function rotate() 81 | { 82 | // update filename 83 | $this->url = $this->getTimedFilename(); 84 | $this->nextRotation = new \DateTime('tomorrow'); 85 | 86 | // skip GC of old logs if files are unlimited 87 | if (0 === $this->maxFiles) { 88 | return; 89 | } 90 | 91 | $fileInfo = pathinfo($this->filename); 92 | $glob = $fileInfo['dirname'].'/'.$fileInfo['filename'].'-*'; 93 | if (!empty($fileInfo['extension'])) { 94 | $glob .= '.'.$fileInfo['extension']; 95 | } 96 | $logFiles = glob($glob); 97 | if ($this->maxFiles >= count($logFiles)) { 98 | // no files to remove 99 | return; 100 | } 101 | 102 | // Sorting the files by name to remove the older ones 103 | usort($logFiles, function($a, $b) { 104 | return strcmp($b, $a); 105 | }); 106 | 107 | foreach (array_slice($logFiles, $this->maxFiles) as $file) { 108 | if (is_writable($file)) { 109 | unlink($file); 110 | } 111 | } 112 | } 113 | 114 | protected function getTimedFilename() 115 | { 116 | $fileInfo = pathinfo($this->filename); 117 | $timedFilename = $fileInfo['dirname'].'/'.$fileInfo['filename'].'-'.date('Y-m-d'); 118 | if (!empty($fileInfo['extension'])) { 119 | $timedFilename .= '.'.$fileInfo['extension']; 120 | } 121 | 122 | return $timedFilename; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/SocketHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Logger; 15 | 16 | /** 17 | * Stores to any socket - uses fsockopen() or pfsockopen(). 18 | * 19 | * @author Pablo de Leon Belloc 20 | * @see http://php.net/manual/en/function.fsockopen.php 21 | */ 22 | class SocketHandler extends AbstractProcessingHandler 23 | { 24 | private $connectionString; 25 | private $connectionTimeout; 26 | private $resource; 27 | private $timeout = 0; 28 | private $persistent = false; 29 | private $errno; 30 | private $errstr; 31 | 32 | /** 33 | * @param string $connectionString Socket connection string 34 | * @param integer $level The minimum logging level at which this handler will be triggered 35 | * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not 36 | */ 37 | public function __construct($connectionString, $level = Logger::DEBUG, $bubble = true) 38 | { 39 | parent::__construct($level, $bubble); 40 | $this->connectionString = $connectionString; 41 | $this->connectionTimeout = (float) ini_get('default_socket_timeout'); 42 | } 43 | 44 | /** 45 | * Connect (if necessary) and write to the socket 46 | * 47 | * @param array $record 48 | * 49 | * @throws \UnexpectedValueException 50 | * @throws \RuntimeException 51 | */ 52 | public function write(array $record) 53 | { 54 | $this->connectIfNotConnected(); 55 | $data = $this->generateDataStream($record); 56 | $this->writeToSocket($data); 57 | } 58 | 59 | /** 60 | * We will not close a PersistentSocket instance so it can be reused in other requests. 61 | */ 62 | public function close() 63 | { 64 | if (!$this->isPersistent()) { 65 | $this->closeSocket(); 66 | } 67 | } 68 | 69 | /** 70 | * Close socket, if open 71 | */ 72 | public function closeSocket() 73 | { 74 | if (is_resource($this->resource)) { 75 | fclose($this->resource); 76 | $this->resource = null; 77 | } 78 | } 79 | 80 | /** 81 | * Set socket connection to nbe persistent. It only has effect before the connection is initiated. 82 | * 83 | * @param type $boolean 84 | */ 85 | public function setPersistent($boolean) 86 | { 87 | $this->persistent = (boolean) $boolean; 88 | } 89 | 90 | /** 91 | * Set connection timeout. Only has effect before we connect. 92 | * 93 | * @param float $seconds 94 | * 95 | * @see http://php.net/manual/en/function.fsockopen.php 96 | */ 97 | public function setConnectionTimeout($seconds) 98 | { 99 | $this->validateTimeout($seconds); 100 | $this->connectionTimeout = (float) $seconds; 101 | } 102 | 103 | /** 104 | * Set write timeout. Only has effect before we connect. 105 | * 106 | * @param float $seconds 107 | * 108 | * @see http://php.net/manual/en/function.stream-set-timeout.php 109 | */ 110 | public function setTimeout($seconds) 111 | { 112 | $this->validateTimeout($seconds); 113 | $this->timeout = (float) $seconds; 114 | } 115 | 116 | /** 117 | * Get current connection string 118 | * 119 | * @return string 120 | */ 121 | public function getConnectionString() 122 | { 123 | return $this->connectionString; 124 | } 125 | 126 | /** 127 | * Get persistent setting 128 | * 129 | * @return boolean 130 | */ 131 | public function isPersistent() 132 | { 133 | return $this->persistent; 134 | } 135 | 136 | /** 137 | * Get current connection timeout setting 138 | * 139 | * @return float 140 | */ 141 | public function getConnectionTimeout() 142 | { 143 | return $this->connectionTimeout; 144 | } 145 | 146 | /** 147 | * Get current in-transfer timeout 148 | * 149 | * @return float 150 | */ 151 | public function getTimeout() 152 | { 153 | return $this->timeout; 154 | } 155 | 156 | /** 157 | * Check to see if the socket is currently available. 158 | * 159 | * UDP might appear to be connected but might fail when writing. See http://php.net/fsockopen for details. 160 | * 161 | * @return boolean 162 | */ 163 | public function isConnected() 164 | { 165 | return is_resource($this->resource) 166 | && !feof($this->resource); // on TCP - other party can close connection. 167 | } 168 | 169 | /** 170 | * Wrapper to allow mocking 171 | */ 172 | protected function pfsockopen() 173 | { 174 | return @pfsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout); 175 | } 176 | 177 | /** 178 | * Wrapper to allow mocking 179 | */ 180 | protected function fsockopen() 181 | { 182 | return @fsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout); 183 | } 184 | 185 | /** 186 | * Wrapper to allow mocking 187 | * 188 | * @see http://php.net/manual/en/function.stream-set-timeout.php 189 | */ 190 | protected function streamSetTimeout() 191 | { 192 | $seconds = floor($this->timeout); 193 | $microseconds = round(($this->timeout - $seconds)*1e6); 194 | 195 | return stream_set_timeout($this->resource, $seconds, $microseconds); 196 | } 197 | 198 | /** 199 | * Wrapper to allow mocking 200 | */ 201 | protected function fwrite($data) 202 | { 203 | return @fwrite($this->resource, $data); 204 | } 205 | 206 | /** 207 | * Wrapper to allow mocking 208 | */ 209 | protected function streamGetMetadata() 210 | { 211 | return stream_get_meta_data($this->resource); 212 | } 213 | 214 | private function validateTimeout($value) 215 | { 216 | $ok = filter_var($value, FILTER_VALIDATE_FLOAT); 217 | if ($ok === false || $value < 0) { 218 | throw new \InvalidArgumentException("Timeout must be 0 or a positive float (got $value)"); 219 | } 220 | } 221 | 222 | private function connectIfNotConnected() 223 | { 224 | if ($this->isConnected()) { 225 | return; 226 | } 227 | $this->connect(); 228 | } 229 | 230 | protected function generateDataStream($record) 231 | { 232 | return (string) $record['formatted']; 233 | } 234 | 235 | private function connect() 236 | { 237 | $this->createSocketResource(); 238 | $this->setSocketTimeout(); 239 | } 240 | 241 | private function createSocketResource() 242 | { 243 | if ($this->isPersistent()) { 244 | $resource = $this->pfsockopen(); 245 | } else { 246 | $resource = $this->fsockopen(); 247 | } 248 | if (!$resource) { 249 | throw new \UnexpectedValueException("Failed connecting to $this->connectionString ($this->errno: $this->errstr)"); 250 | } 251 | $this->resource = $resource; 252 | } 253 | 254 | private function setSocketTimeout() 255 | { 256 | if (!$this->streamSetTimeout()) { 257 | throw new \UnexpectedValueException("Failed setting timeout with stream_set_timeout()"); 258 | } 259 | } 260 | 261 | private function writeToSocket($data) 262 | { 263 | $length = strlen($data); 264 | $sent = 0; 265 | while ($this->isConnected() && $sent < $length) { 266 | if (0 == $sent) { 267 | $chunk = $this->fwrite($data); 268 | } else { 269 | $chunk = $this->fwrite(substr($data, $sent)); 270 | } 271 | if ($chunk === false) { 272 | throw new \RuntimeException("Could not write to socket"); 273 | } 274 | $sent += $chunk; 275 | $socketInfo = $this->streamGetMetadata(); 276 | if ($socketInfo['timed_out']) { 277 | throw new \RuntimeException("Write timed-out"); 278 | } 279 | } 280 | if (!$this->isConnected() && $sent < $length) { 281 | throw new \RuntimeException("End-of-file reached, probably we got disconnected (sent $sent of $length)"); 282 | } 283 | } 284 | 285 | } 286 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/StreamHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Logger; 15 | 16 | /** 17 | * Stores to any stream resource 18 | * 19 | * Can be used to store into php://stderr, remote and local files, etc. 20 | * 21 | * @author Jordi Boggiano 22 | */ 23 | class StreamHandler extends AbstractProcessingHandler 24 | { 25 | protected $stream; 26 | protected $url; 27 | 28 | /** 29 | * @param string $stream 30 | * @param integer $level The minimum logging level at which this handler will be triggered 31 | * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not 32 | */ 33 | public function __construct($stream, $level = Logger::DEBUG, $bubble = true) 34 | { 35 | parent::__construct($level, $bubble); 36 | if (is_resource($stream)) { 37 | $this->stream = $stream; 38 | } else { 39 | $this->url = $stream; 40 | } 41 | } 42 | 43 | /** 44 | * {@inheritdoc} 45 | */ 46 | public function close() 47 | { 48 | if (is_resource($this->stream)) { 49 | fclose($this->stream); 50 | } 51 | $this->stream = null; 52 | } 53 | 54 | /** 55 | * {@inheritdoc} 56 | */ 57 | protected function write(array $record) 58 | { 59 | if (null === $this->stream) { 60 | if (!$this->url) { 61 | throw new \LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().'); 62 | } 63 | $errorMessage = null; 64 | set_error_handler(function ($code, $msg) use (&$errorMessage) { 65 | $errorMessage = preg_replace('{^fopen\(.*?\): }', '', $msg); 66 | }); 67 | $this->stream = fopen($this->url, 'a'); 68 | restore_error_handler(); 69 | if (!is_resource($this->stream)) { 70 | $this->stream = null; 71 | throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened: '.$errorMessage, $this->url)); 72 | } 73 | } 74 | fwrite($this->stream, (string) $record['formatted']); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/SwiftMailerHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Logger; 15 | 16 | /** 17 | * SwiftMailerHandler uses Swift_Mailer to send the emails 18 | * 19 | * @author Gyula Sallai 20 | */ 21 | class SwiftMailerHandler extends MailHandler 22 | { 23 | protected $mailer; 24 | protected $message; 25 | 26 | /** 27 | * @param \Swift_Mailer $mailer The mailer to use 28 | * @param callable|\Swift_Message $message An example message for real messages, only the body will be replaced 29 | * @param integer $level The minimum logging level at which this handler will be triggered 30 | * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not 31 | */ 32 | public function __construct(\Swift_Mailer $mailer, $message, $level = Logger::ERROR, $bubble = true) 33 | { 34 | parent::__construct($level, $bubble); 35 | $this->mailer = $mailer; 36 | if (!$message instanceof \Swift_Message && is_callable($message)) { 37 | $message = call_user_func($message); 38 | } 39 | if (!$message instanceof \Swift_Message) { 40 | throw new \InvalidArgumentException('You must provide either a Swift_Message instance or a callable returning it'); 41 | } 42 | $this->message = $message; 43 | } 44 | 45 | /** 46 | * {@inheritdoc} 47 | */ 48 | protected function send($content, array $records) 49 | { 50 | $message = clone $this->message; 51 | $message->setBody($content); 52 | 53 | $this->mailer->send($message); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/SyslogHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Logger; 15 | use Monolog\Formatter\LineFormatter; 16 | 17 | /** 18 | * Logs to syslog service. 19 | * 20 | * usage example: 21 | * 22 | * $log = new Logger('application'); 23 | * $syslog = new SyslogHandler('myfacility', 'local6'); 24 | * $formatter = new LineFormatter("%channel%.%level_name%: %message% %extra%"); 25 | * $syslog->setFormatter($formatter); 26 | * $log->pushHandler($syslog); 27 | * 28 | * @author Sven Paulus 29 | */ 30 | class SyslogHandler extends AbstractProcessingHandler 31 | { 32 | protected $ident; 33 | protected $logopts; 34 | protected $facility; 35 | 36 | /** 37 | * Translates Monolog log levels to syslog log priorities. 38 | */ 39 | private $logLevels = array( 40 | Logger::DEBUG => LOG_DEBUG, 41 | Logger::INFO => LOG_INFO, 42 | Logger::NOTICE => LOG_NOTICE, 43 | Logger::WARNING => LOG_WARNING, 44 | Logger::ERROR => LOG_ERR, 45 | Logger::CRITICAL => LOG_CRIT, 46 | Logger::ALERT => LOG_ALERT, 47 | Logger::EMERGENCY => LOG_EMERG, 48 | ); 49 | 50 | /** 51 | * List of valid log facility names. 52 | */ 53 | private $facilities = array( 54 | 'auth' => LOG_AUTH, 55 | 'authpriv' => LOG_AUTHPRIV, 56 | 'cron' => LOG_CRON, 57 | 'daemon' => LOG_DAEMON, 58 | 'kern' => LOG_KERN, 59 | 'lpr' => LOG_LPR, 60 | 'mail' => LOG_MAIL, 61 | 'news' => LOG_NEWS, 62 | 'syslog' => LOG_SYSLOG, 63 | 'user' => LOG_USER, 64 | 'uucp' => LOG_UUCP, 65 | ); 66 | 67 | /** 68 | * @param string $ident 69 | * @param mixed $facility 70 | * @param integer $level The minimum logging level at which this handler will be triggered 71 | * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not 72 | * @param int $logopts Option flags for the openlog() call, defaults to LOG_PID 73 | */ 74 | public function __construct($ident, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $logopts = LOG_PID) 75 | { 76 | parent::__construct($level, $bubble); 77 | 78 | if (!defined('PHP_WINDOWS_VERSION_BUILD')) { 79 | $this->facilities['local0'] = LOG_LOCAL0; 80 | $this->facilities['local1'] = LOG_LOCAL1; 81 | $this->facilities['local2'] = LOG_LOCAL2; 82 | $this->facilities['local3'] = LOG_LOCAL3; 83 | $this->facilities['local4'] = LOG_LOCAL4; 84 | $this->facilities['local5'] = LOG_LOCAL5; 85 | $this->facilities['local6'] = LOG_LOCAL6; 86 | $this->facilities['local7'] = LOG_LOCAL7; 87 | } 88 | 89 | // convert textual description of facility to syslog constant 90 | if (array_key_exists(strtolower($facility), $this->facilities)) { 91 | $facility = $this->facilities[strtolower($facility)]; 92 | } elseif (!in_array($facility, array_values($this->facilities), true)) { 93 | throw new \UnexpectedValueException('Unknown facility value "'.$facility.'" given'); 94 | } 95 | 96 | $this->ident = $ident; 97 | $this->logopts = $logopts; 98 | $this->facility = $facility; 99 | } 100 | 101 | /** 102 | * {@inheritdoc} 103 | */ 104 | public function close() 105 | { 106 | closelog(); 107 | } 108 | 109 | /** 110 | * {@inheritdoc} 111 | */ 112 | protected function write(array $record) 113 | { 114 | if (!openlog($this->ident, $this->logopts, $this->facility)) { 115 | throw new \LogicException('Can\'t open syslog for ident "'.$this->ident.'" and facility "'.$this->facility.'"'); 116 | } 117 | syslog($this->logLevels[$record['level']], (string) $record['formatted']); 118 | } 119 | 120 | /** 121 | * {@inheritdoc} 122 | */ 123 | protected function getDefaultFormatter() 124 | { 125 | return new LineFormatter('%channel%.%level_name%: %message% %context% %extra%'); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/TestHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Handler; 13 | 14 | use Monolog\Logger; 15 | 16 | /** 17 | * Used for testing purposes. 18 | * 19 | * It records all records and gives you access to them for verification. 20 | * 21 | * @author Jordi Boggiano 22 | */ 23 | class TestHandler extends AbstractProcessingHandler 24 | { 25 | protected $records = array(); 26 | protected $recordsByLevel = array(); 27 | 28 | public function getRecords() 29 | { 30 | return $this->records; 31 | } 32 | 33 | public function hasEmergency($record) 34 | { 35 | return $this->hasRecord($record, Logger::EMERGENCY); 36 | } 37 | 38 | public function hasAlert($record) 39 | { 40 | return $this->hasRecord($record, Logger::ALERT); 41 | } 42 | 43 | public function hasCritical($record) 44 | { 45 | return $this->hasRecord($record, Logger::CRITICAL); 46 | } 47 | 48 | public function hasError($record) 49 | { 50 | return $this->hasRecord($record, Logger::ERROR); 51 | } 52 | 53 | public function hasWarning($record) 54 | { 55 | return $this->hasRecord($record, Logger::WARNING); 56 | } 57 | 58 | public function hasNotice($record) 59 | { 60 | return $this->hasRecord($record, Logger::NOTICE); 61 | } 62 | 63 | public function hasInfo($record) 64 | { 65 | return $this->hasRecord($record, Logger::INFO); 66 | } 67 | 68 | public function hasDebug($record) 69 | { 70 | return $this->hasRecord($record, Logger::DEBUG); 71 | } 72 | 73 | public function hasEmergencyRecords() 74 | { 75 | return isset($this->recordsByLevel[Logger::EMERGENCY]); 76 | } 77 | 78 | public function hasAlertRecords() 79 | { 80 | return isset($this->recordsByLevel[Logger::ALERT]); 81 | } 82 | 83 | public function hasCriticalRecords() 84 | { 85 | return isset($this->recordsByLevel[Logger::CRITICAL]); 86 | } 87 | 88 | public function hasErrorRecords() 89 | { 90 | return isset($this->recordsByLevel[Logger::ERROR]); 91 | } 92 | 93 | public function hasWarningRecords() 94 | { 95 | return isset($this->recordsByLevel[Logger::WARNING]); 96 | } 97 | 98 | public function hasNoticeRecords() 99 | { 100 | return isset($this->recordsByLevel[Logger::NOTICE]); 101 | } 102 | 103 | public function hasInfoRecords() 104 | { 105 | return isset($this->recordsByLevel[Logger::INFO]); 106 | } 107 | 108 | public function hasDebugRecords() 109 | { 110 | return isset($this->recordsByLevel[Logger::DEBUG]); 111 | } 112 | 113 | protected function hasRecord($record, $level) 114 | { 115 | if (!isset($this->recordsByLevel[$level])) { 116 | return false; 117 | } 118 | 119 | if (is_array($record)) { 120 | $record = $record['message']; 121 | } 122 | 123 | foreach ($this->recordsByLevel[$level] as $rec) { 124 | if ($rec['message'] === $record) { 125 | return true; 126 | } 127 | } 128 | 129 | return false; 130 | } 131 | 132 | /** 133 | * {@inheritdoc} 134 | */ 135 | protected function write(array $record) 136 | { 137 | $this->recordsByLevel[$record['level']][] = $record; 138 | $this->records[] = $record; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /lib/Monolog/Handler/ZendMonitorHandler.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | namespace Monolog\Handler; 12 | 13 | use Monolog\Formatter\NormalizerFormatter; 14 | use Monolog\Logger; 15 | 16 | /** 17 | * Handler sending logs to Zend Monitor 18 | * 19 | * @author Christian Bergau 20 | */ 21 | class ZendMonitorHandler extends AbstractProcessingHandler 22 | { 23 | /** 24 | * Monolog level / ZendMonitor Custom Event priority map 25 | * 26 | * @var array 27 | */ 28 | protected $levelMap = array( 29 | Logger::DEBUG => 1, 30 | Logger::INFO => 2, 31 | Logger::NOTICE => 3, 32 | Logger::WARNING => 4, 33 | Logger::ERROR => 5, 34 | Logger::CRITICAL => 6, 35 | Logger::ALERT => 7, 36 | Logger::EMERGENCY => 0, 37 | ); 38 | 39 | /** 40 | * Construct 41 | * 42 | * @param int $level 43 | * @param bool $bubble 44 | * @throws MissingExtensionException 45 | */ 46 | public function __construct($level = Logger::DEBUG, $bubble = true) 47 | { 48 | if (!function_exists('zend_monitor_custom_event')) { 49 | throw new MissingExtensionException('You must have Zend Server installed in order to use this handler'); 50 | } 51 | parent::__construct($level, $bubble); 52 | } 53 | 54 | /** 55 | * {@inheritdoc} 56 | */ 57 | protected function write(array $record) 58 | { 59 | $this->writeZendMonitorCustomEvent( 60 | $this->levelMap[$record['level']], 61 | $record['message'], 62 | $record['formatted'] 63 | ); 64 | } 65 | 66 | /** 67 | * Write a record to Zend Monitor 68 | * 69 | * @param int $level 70 | * @param string $message 71 | * @param array $formatted 72 | */ 73 | protected function writeZendMonitorCustomEvent($level, $message, $formatted) 74 | { 75 | zend_monitor_custom_event($level, $message, $formatted); 76 | } 77 | 78 | /** 79 | * {@inheritdoc} 80 | */ 81 | public function getDefaultFormatter() 82 | { 83 | return new NormalizerFormatter(); 84 | } 85 | 86 | /** 87 | * Get the level map 88 | * 89 | * @return array 90 | */ 91 | public function getLevelMap() 92 | { 93 | return $this->levelMap; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /lib/Monolog/Processor/IntrospectionProcessor.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Processor; 13 | 14 | /** 15 | * Injects line/file:class/function where the log message came from 16 | * 17 | * Warning: This only works if the handler processes the logs directly. 18 | * If you put the processor on a handler that is behind a FingersCrossedHandler 19 | * for example, the processor will only be called once the trigger level is reached, 20 | * and all the log records will have the same file/line/.. data from the call that 21 | * triggered the FingersCrossedHandler. 22 | * 23 | * @author Jordi Boggiano 24 | */ 25 | class IntrospectionProcessor 26 | { 27 | /** 28 | * @param array $record 29 | * @return array 30 | */ 31 | public function __invoke(array $record) 32 | { 33 | $trace = debug_backtrace(); 34 | 35 | // skip first since it's always the current method 36 | array_shift($trace); 37 | // the call_user_func call is also skipped 38 | array_shift($trace); 39 | 40 | $i = 0; 41 | while (isset($trace[$i]['class']) && false !== strpos($trace[$i]['class'], 'Monolog\\')) { 42 | $i++; 43 | } 44 | 45 | // we should have the call source now 46 | $record['extra'] = array_merge( 47 | $record['extra'], 48 | array( 49 | 'file' => isset($trace[$i-1]['file']) ? $trace[$i-1]['file'] : null, 50 | 'line' => isset($trace[$i-1]['line']) ? $trace[$i-1]['line'] : null, 51 | 'class' => isset($trace[$i]['class']) ? $trace[$i]['class'] : null, 52 | 'function' => isset($trace[$i]['function']) ? $trace[$i]['function'] : null, 53 | ) 54 | ); 55 | 56 | return $record; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/Monolog/Processor/MemoryPeakUsageProcessor.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Processor; 13 | 14 | /** 15 | * Injects memory_get_peak_usage in all records 16 | * 17 | * @see Monolog\Processor\MemoryProcessor::__construct() for options 18 | * @author Rob Jensen 19 | */ 20 | class MemoryPeakUsageProcessor extends MemoryProcessor 21 | { 22 | /** 23 | * @param array $record 24 | * @return array 25 | */ 26 | public function __invoke(array $record) 27 | { 28 | $bytes = memory_get_peak_usage($this->realUsage); 29 | $formatted = self::formatBytes($bytes); 30 | 31 | $record['extra'] = array_merge( 32 | $record['extra'], 33 | array( 34 | 'memory_peak_usage' => $formatted, 35 | ) 36 | ); 37 | 38 | return $record; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/Monolog/Processor/MemoryProcessor.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Processor; 13 | 14 | /** 15 | * Some methods that are common for all memory processors 16 | * 17 | * @author Rob Jensen 18 | */ 19 | abstract class MemoryProcessor 20 | { 21 | protected $realUsage; 22 | 23 | /** 24 | * @param boolean $realUsage 25 | */ 26 | public function __construct($realUsage = true) 27 | { 28 | $this->realUsage = (boolean) $realUsage; 29 | } 30 | 31 | /** 32 | * Formats bytes into a human readable string 33 | * 34 | * @param int $bytes 35 | * @return string 36 | */ 37 | protected static function formatBytes($bytes) 38 | { 39 | $bytes = (int) $bytes; 40 | 41 | if ($bytes > 1024*1024) { 42 | return round($bytes/1024/1024, 2).' MB'; 43 | } elseif ($bytes > 1024) { 44 | return round($bytes/1024, 2).' KB'; 45 | } 46 | 47 | return $bytes . ' B'; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /lib/Monolog/Processor/MemoryUsageProcessor.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Processor; 13 | 14 | /** 15 | * Injects memory_get_usage in all records 16 | * 17 | * @see Monolog\Processor\MemoryProcessor::__construct() for options 18 | * @author Rob Jensen 19 | */ 20 | class MemoryUsageProcessor extends MemoryProcessor 21 | { 22 | /** 23 | * @param array $record 24 | * @return array 25 | */ 26 | public function __invoke(array $record) 27 | { 28 | $bytes = memory_get_usage($this->realUsage); 29 | $formatted = self::formatBytes($bytes); 30 | 31 | $record['extra'] = array_merge( 32 | $record['extra'], 33 | array( 34 | 'memory_usage' => $formatted, 35 | ) 36 | ); 37 | 38 | return $record; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/Monolog/Processor/ProcessIdProcessor.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Processor; 13 | 14 | /** 15 | * Adds value of getmypid into records 16 | * 17 | * @author Andreas Hörnicke 18 | */ 19 | class ProcessIdProcessor 20 | { 21 | private static $pid; 22 | 23 | public function __construct() 24 | { 25 | if (null === self::$pid) { 26 | self::$pid = getmypid(); 27 | } 28 | } 29 | 30 | /** 31 | * @param array $record 32 | * @return array 33 | */ 34 | public function __invoke(array $record) 35 | { 36 | $record['extra']['process_id'] = self::$pid; 37 | 38 | return $record; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/Monolog/Processor/PsrLogMessageProcessor.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Processor; 13 | 14 | /** 15 | * Processes a record's message according to PSR-3 rules 16 | * 17 | * It replaces {foo} with the value from $context['foo'] 18 | * 19 | * @author Jordi Boggiano 20 | */ 21 | class PsrLogMessageProcessor 22 | { 23 | /** 24 | * @param array $record 25 | * @return array 26 | */ 27 | public function __invoke(array $record) 28 | { 29 | if (false === strpos($record['message'], '{')) { 30 | return $record; 31 | } 32 | 33 | $replacements = array(); 34 | foreach ($record['context'] as $key => $val) { 35 | $replacements['{'.$key.'}'] = $val; 36 | } 37 | 38 | $record['message'] = strtr($record['message'], $replacements); 39 | 40 | return $record; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/Monolog/Processor/UidProcessor.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Processor; 13 | 14 | /** 15 | * Adds a unique identifier into records 16 | * 17 | * @author Simon Mönch 18 | */ 19 | class UidProcessor 20 | { 21 | private $uid; 22 | 23 | public function __construct($length = 7) 24 | { 25 | if (!is_int($length) || $length > 32 || $length < 1) { 26 | throw new \InvalidArgumentException('The uid length must be an integer between 1 and 32'); 27 | } 28 | 29 | $this->uid = substr(hash('md5', uniqid('', true)), 0, $length); 30 | } 31 | 32 | public function __invoke(array $record) 33 | { 34 | $record['extra']['uid'] = $this->uid; 35 | 36 | return $record; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/Monolog/Processor/WebProcessor.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Monolog\Processor; 13 | 14 | /** 15 | * Injects url/method and remote IP of the current web request in all records 16 | * 17 | * @author Jordi Boggiano 18 | */ 19 | class WebProcessor 20 | { 21 | protected $serverData; 22 | 23 | /** 24 | * @param mixed $serverData array or object w/ ArrayAccess that provides access to the $_SERVER data 25 | */ 26 | public function __construct($serverData = null) 27 | { 28 | if (null === $serverData) { 29 | $this->serverData =& $_SERVER; 30 | } elseif (is_array($serverData) || $serverData instanceof \ArrayAccess) { 31 | $this->serverData = $serverData; 32 | } else { 33 | throw new \UnexpectedValueException('$serverData must be an array or object implementing ArrayAccess.'); 34 | } 35 | } 36 | 37 | /** 38 | * @param array $record 39 | * @return array 40 | */ 41 | public function __invoke(array $record) 42 | { 43 | // skip processing if for some reason request data 44 | // is not present (CLI or wonky SAPIs) 45 | if (!isset($this->serverData['REQUEST_URI'])) { 46 | return $record; 47 | } 48 | 49 | $record['extra'] = array_merge( 50 | $record['extra'], 51 | array( 52 | 'url' => $this->serverData['REQUEST_URI'], 53 | 'ip' => isset($this->serverData['REMOTE_ADDR']) ? $this->serverData['REMOTE_ADDR'] : null, 54 | 'http_method' => isset($this->serverData['REQUEST_METHOD']) ? $this->serverData['REQUEST_METHOD'] : null, 55 | 'server' => isset($this->serverData['SERVER_NAME']) ? $this->serverData['SERVER_NAME'] : null, 56 | 'referrer' => isset($this->serverData['HTTP_REFERER']) ? $this->serverData['HTTP_REFERER'] : null, 57 | ) 58 | ); 59 | 60 | return $record; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/MonologInit/MonologInit.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Copyright 2012, Wan Qi Chen 14 | * @link https://github.com/kamisama/Monolog-Init 15 | * @package MonologInit 16 | * @since 0.1.0 17 | * @license MIT License (http://www.opensource.org/licenses/mit-license.php) 18 | */ 19 | // namespace MonologInit; 20 | 21 | // use Monolog\Handler; 22 | namespace resque\lib\MonologInit; 23 | class MonologInit_MonologInit 24 | { 25 | public $handler = null; 26 | public $target = null; 27 | protected $instance = null; 28 | 29 | const VERSION = '0.1.1'; 30 | 31 | 32 | public function __construct($handler = false, $target = false) 33 | { 34 | if ($handler === false || $target === false) { 35 | return null; 36 | } 37 | 38 | $this->createLoggerInstance($handler, $target); 39 | } 40 | 41 | /** 42 | * Return a Monolog Logger instance 43 | * 44 | * @return Monolog\Logger instance, ready to use 45 | */ 46 | public function getInstance() 47 | { 48 | return $this->instance; 49 | } 50 | 51 | /** 52 | * Create a Monolog\Logger instance and attach a handler 53 | * 54 | * @param string $handler Name of the handler, without the "Handler" part 55 | * @param string $target Comma separated list of arguments to pass to the handler 56 | * @return void 57 | */ 58 | protected function createLoggerInstance($handler, $target) 59 | { 60 | $handlerClassName = $handler . 'Handler'; 61 | 62 | if (class_exists('\Monolog\Logger') && class_exists('\Monolog\Handler\\' . $handlerClassName)) { 63 | if (null !== $handlerInstance = $this->createHandlerInstance($handlerClassName, $target)) { 64 | $this->instance = new \Monolog\Logger('main'); 65 | $this->instance->pushHandler($handlerInstance); 66 | } 67 | 68 | $this->handler = $handler; 69 | $this->target = $target; 70 | } 71 | } 72 | 73 | /** 74 | * Create an Monolog Handler instance 75 | * 76 | * @param string $className Monolog handler classname 77 | * @param string $handlerArgs Comma separated list of arguments to pass to the handler 78 | * @return Monolog\Handler instance if successfull, null otherwise 79 | */ 80 | protected function createHandlerInstance($className, $handlerArgs) 81 | { 82 | if (method_exists($this, 'init' . $className)) { 83 | return call_user_func(array($this, 'init' . $className), explode(',', $handlerArgs)); 84 | } else { 85 | return null; 86 | } 87 | } 88 | 89 | public function initCubeHandler($args) 90 | { 91 | $reflect = new \ReflectionClass('\Monolog\Handler\CubeHandler'); 92 | return $reflect->newInstanceArgs($args); 93 | } 94 | 95 | public function initRotatingFileHandler($args) 96 | { 97 | $reflect = new \ReflectionClass('\Monolog\Handler\RotatingFileHandler'); 98 | return $reflect->newInstanceArgs($args); 99 | } 100 | 101 | public function initChromePHPHandler($args) 102 | { 103 | $reflect = new \ReflectionClass('\Monolog\Handler\ChromePHPHandler'); 104 | return $reflect->newInstanceArgs($args); 105 | } 106 | 107 | public function initSyslogHandler($args) 108 | { 109 | $reflect = new \ReflectionClass('\Monolog\Handler\SyslogHandler'); 110 | return $reflect->newInstanceArgs($args); 111 | } 112 | 113 | public function initSocketHandler($args) 114 | { 115 | $reflect = new \ReflectionClass('\Monolog\Handler\SocketHandler'); 116 | return $reflect->newInstanceArgs($args); 117 | } 118 | 119 | public function initMongoDBHandler($args) 120 | { 121 | $reflect = new \ReflectionClass('\Monolog\Handler\MongoDBHandler'); 122 | $mongo = new \Mongo(array_shift($args)); 123 | array_unshift($args, $mongo); 124 | return $reflect->newInstanceArgs($args); 125 | } 126 | 127 | /** 128 | * 129 | * @since 0.1.1 130 | */ 131 | public function initCouchDBHandler($args) 132 | { 133 | $reflect = new \ReflectionClass('\Monolog\Handler\CouchDBHandler'); 134 | if (isset($args[0])) { 135 | $args[0] = explode(':', $args[0]); 136 | } 137 | return $reflect->newInstanceArgs($args); 138 | } 139 | 140 | /** 141 | * 142 | * @since 0.1.1 143 | */ 144 | public function initHipChatHandler($args) 145 | { 146 | $reflect = new \ReflectionClass('\Monolog\Handler\HipChatHandler'); 147 | return $reflect->newInstanceArgs($args); 148 | } 149 | 150 | /** 151 | * 152 | * @since 0.1.1 153 | */ 154 | public function initPushOverHandler($args) 155 | { 156 | $reflect = new \ReflectionClass('\Monolog\Handler\PushOverHandler'); 157 | return $reflect->newInstanceArgs($args); 158 | } 159 | 160 | /** 161 | * 162 | * @since 0.1.1 163 | */ 164 | public function initZendMonitorHandler($args) 165 | { 166 | $reflect = new \ReflectionClass('\Monolog\Handler\ZendMonitorHandler'); 167 | return $reflect->newInstanceArgs($args); 168 | } 169 | } 170 | 171 | -------------------------------------------------------------------------------- /lib/Psr/Log/AbstractLogger.php: -------------------------------------------------------------------------------- 1 | log(LogLevel::EMERGENCY, $message, $context); 24 | } 25 | 26 | /** 27 | * Action must be taken immediately. 28 | * 29 | * Example: Entire website down, database unavailable, etc. This should 30 | * trigger the SMS alerts and wake you up. 31 | * 32 | * @param string $message 33 | * @param array $context 34 | * @return null 35 | */ 36 | public function alert($message, array $context = array()) 37 | { 38 | $this->log(LogLevel::ALERT, $message, $context); 39 | } 40 | 41 | /** 42 | * Critical conditions. 43 | * 44 | * Example: Application component unavailable, unexpected exception. 45 | * 46 | * @param string $message 47 | * @param array $context 48 | * @return null 49 | */ 50 | public function critical($message, array $context = array()) 51 | { 52 | $this->log(LogLevel::CRITICAL, $message, $context); 53 | } 54 | 55 | /** 56 | * Runtime errors that do not require immediate action but should typically 57 | * be logged and monitored. 58 | * 59 | * @param string $message 60 | * @param array $context 61 | * @return null 62 | */ 63 | public function error($message, array $context = array()) 64 | { 65 | $this->log(LogLevel::ERROR, $message, $context); 66 | } 67 | 68 | /** 69 | * Exceptional occurrences that are not errors. 70 | * 71 | * Example: Use of deprecated APIs, poor use of an API, undesirable things 72 | * that are not necessarily wrong. 73 | * 74 | * @param string $message 75 | * @param array $context 76 | * @return null 77 | */ 78 | public function warning($message, array $context = array()) 79 | { 80 | $this->log(LogLevel::WARNING, $message, $context); 81 | } 82 | 83 | /** 84 | * Normal but significant events. 85 | * 86 | * @param string $message 87 | * @param array $context 88 | * @return null 89 | */ 90 | public function notice($message, array $context = array()) 91 | { 92 | $this->log(LogLevel::NOTICE, $message, $context); 93 | } 94 | 95 | /** 96 | * Interesting events. 97 | * 98 | * Example: User logs in, SQL logs. 99 | * 100 | * @param string $message 101 | * @param array $context 102 | * @return null 103 | */ 104 | public function info($message, array $context = array()) 105 | { 106 | $this->log(LogLevel::INFO, $message, $context); 107 | } 108 | 109 | /** 110 | * Detailed debug information. 111 | * 112 | * @param string $message 113 | * @param array $context 114 | * @return null 115 | */ 116 | public function debug($message, array $context = array()) 117 | { 118 | $this->log(LogLevel::DEBUG, $message, $context); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /lib/Psr/Log/InvalidArgumentException.php: -------------------------------------------------------------------------------- 1 | logger = $logger; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/Psr/Log/LoggerInterface.php: -------------------------------------------------------------------------------- 1 | log(LogLevel::EMERGENCY, $message, $context); 25 | } 26 | 27 | /** 28 | * Action must be taken immediately. 29 | * 30 | * Example: Entire website down, database unavailable, etc. This should 31 | * trigger the SMS alerts and wake you up. 32 | * 33 | * @param string $message 34 | * @param array $context 35 | * @return null 36 | */ 37 | public function alert($message, array $context = array()) 38 | { 39 | $this->log(LogLevel::ALERT, $message, $context); 40 | } 41 | 42 | /** 43 | * Critical conditions. 44 | * 45 | * Example: Application component unavailable, unexpected exception. 46 | * 47 | * @param string $message 48 | * @param array $context 49 | * @return null 50 | */ 51 | public function critical($message, array $context = array()) 52 | { 53 | $this->log(LogLevel::CRITICAL, $message, $context); 54 | } 55 | 56 | /** 57 | * Runtime errors that do not require immediate action but should typically 58 | * be logged and monitored. 59 | * 60 | * @param string $message 61 | * @param array $context 62 | * @return null 63 | */ 64 | public function error($message, array $context = array()) 65 | { 66 | $this->log(LogLevel::ERROR, $message, $context); 67 | } 68 | 69 | /** 70 | * Exceptional occurrences that are not errors. 71 | * 72 | * Example: Use of deprecated APIs, poor use of an API, undesirable things 73 | * that are not necessarily wrong. 74 | * 75 | * @param string $message 76 | * @param array $context 77 | * @return null 78 | */ 79 | public function warning($message, array $context = array()) 80 | { 81 | $this->log(LogLevel::WARNING, $message, $context); 82 | } 83 | 84 | /** 85 | * Normal but significant events. 86 | * 87 | * @param string $message 88 | * @param array $context 89 | * @return null 90 | */ 91 | public function notice($message, array $context = array()) 92 | { 93 | $this->log(LogLevel::NOTICE, $message, $context); 94 | } 95 | 96 | /** 97 | * Interesting events. 98 | * 99 | * Example: User logs in, SQL logs. 100 | * 101 | * @param string $message 102 | * @param array $context 103 | * @return null 104 | */ 105 | public function info($message, array $context = array()) 106 | { 107 | $this->log(LogLevel::INFO, $message, $context); 108 | } 109 | 110 | /** 111 | * Detailed debug information. 112 | * 113 | * @param string $message 114 | * @param array $context 115 | * @return null 116 | */ 117 | public function debug($message, array $context = array()) 118 | { 119 | $this->log(LogLevel::DEBUG, $message, $context); 120 | } 121 | 122 | /** 123 | * Logs with an arbitrary level. 124 | * 125 | * @param mixed $level 126 | * @param string $message 127 | * @param array $context 128 | * @return null 129 | */ 130 | abstract public function log($level, $message, array $context = array()); 131 | } 132 | -------------------------------------------------------------------------------- /lib/Psr/Log/NullLogger.php: -------------------------------------------------------------------------------- 1 | logger) { }` 11 | * blocks. 12 | */ 13 | class NullLogger extends AbstractLogger 14 | { 15 | /** 16 | * Logs with an arbitrary level. 17 | * 18 | * @param mixed $level 19 | * @param string $message 20 | * @param array $context 21 | * @return null 22 | */ 23 | public function log($level, $message, array $context = array()) 24 | { 25 | // noop 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/Resque.php: -------------------------------------------------------------------------------- 1 | 15 | * @license http://www.opensource.org/licenses/mit-license.php 16 | */ 17 | class Resque 18 | { 19 | const VERSION = '1.2'; 20 | 21 | /** 22 | * @var Resque_Redis Instance of Resque_Redis that talks to redis. 23 | */ 24 | public static $redis = null; 25 | 26 | /** 27 | * @var mixed Host/port conbination separated by a colon, or a nested 28 | * array of server swith host/port pairs 29 | */ 30 | protected static $redisServer = null; 31 | 32 | /** 33 | * @var int ID of Redis database to select. 34 | */ 35 | protected static $redisDatabase = 0; 36 | 37 | /** 38 | * @var int ID of Redis database to select. 39 | */ 40 | protected static $redisPassword = ''; 41 | 42 | /** 43 | * Given a host/port combination separated by a colon, set it as 44 | * the redis server that Resque will talk to. 45 | * 46 | * @param mixed $server Host/port combination separated by a colon, or 47 | * a nested array of servers with host/port pairs. 48 | * @param int $database 49 | */ 50 | public static function setBackend($server, $database = 0, $password = '') 51 | { 52 | self::$redisServer = $server; 53 | self::$redisDatabase = $database; 54 | self::$redisPassword = $password; 55 | self::$redis = null; 56 | } 57 | 58 | /** 59 | * Return an instance of the Resque_Redis class instantiated for Resque. 60 | * 61 | * @return Resque_Redis Instance of Resque_Redis. 62 | */ 63 | public static function redis() 64 | { 65 | if (self::$redis !== null) { 66 | return self::$redis; 67 | } 68 | 69 | $server = self::$redisServer; 70 | if (empty($server)) { 71 | $server = 'localhost:6379'; 72 | } 73 | 74 | 75 | 76 | self::$redis = new Resque_Redis($server, self::$redisDatabase, self::$redisPassword); 77 | 78 | # Select Database 79 | self::$redis->select(self::$redisDatabase); 80 | //echo "
";print_r(self::$redis);
 81 |         return self::$redis;
 82 |     }
 83 | 
 84 |     /**
 85 |      * fork() helper method for php-resque that handles issues PHP socket
 86 |      * and phpredis have with passing around sockets between child/parent
 87 |      * processes.
 88 |      *
 89 |      * Will close connection to Redis before forking.
 90 |      *
 91 |      * @return int Return vars as per pcntl_fork()
 92 |      */
 93 |     public static function fork()
 94 |     {
 95 |         if(!function_exists('pcntl_fork')) {
 96 |             return -1;
 97 |         }
 98 | 
 99 |         // Close the connection to Redis before forking.
100 |         // This is a workaround for issues phpredis has.
101 |         self::$redis = null;
102 | 
103 |         $pid = pcntl_fork();
104 |         if($pid === -1) {
105 |             throw new RuntimeException('Unable to fork child worker.');
106 |         }
107 | 
108 |         return $pid;
109 |     }
110 | 
111 |     /**
112 |      * Push a job to the end of a specific queue. If the queue does not
113 |      * exist, then create it as well.
114 |      *
115 |      * @param string $queue The name of the queue to add the job to.
116 |      * @param array $item Job description as an array to be JSON encoded.
117 |      */
118 |     public static function push($queue, $item)
119 |     {
120 |         
121 |         self::redis()->sadd('queues', $queue);
122 |         self::redis()->rpush('queue:' . $queue, json_encode($item));
123 | //        self::redis()->get('queue:mohit');
124 |     }
125 | 
126 |     /**
127 |      * Pop an item off the end of the specified queue, decode it and
128 |      * return it.
129 |      *
130 |      * @param string $queue The name of the queue to fetch an item from.
131 |      * @return array Decoded item from the queue.
132 |      */
133 |     public static function pop($queue)
134 |     {
135 |         $item = self::redis()->lpop('queue:' . $queue);
136 |         if(!$item) {
137 |             return;
138 |         }
139 | 
140 |         return json_decode($item, true);
141 |     }
142 | 
143 |     /**
144 |      * Return the size (number of pending jobs) of the specified queue.
145 |      *
146 |      * @param $queue name of the queue to be checked for pending jobs
147 |      *
148 |      * @return int The size of the queue.
149 |      */
150 |     public static function size($queue)
151 |     {
152 |         return self::redis()->llen('queue:' . $queue);
153 |     }
154 | 
155 |     /**
156 |      * Create a new job and save it to the specified queue.
157 |      *
158 |      * @param string $queue The name of the queue to place the job in.
159 |      * @param string $class The name of the class that contains the code to execute the job.
160 |      * @param array $args Any optional arguments that should be passed when the job is executed.
161 |      * @param boolean $trackStatus Set to true to be able to monitor the status of a job.
162 |      *
163 |      * @return string
164 |      */
165 |     public static function enqueue($queue, $class, $args = null, $trackStatus = false)
166 |     {
167 |         
168 |         
169 |         $result = Resque_Job::create($queue, $class, $args, $trackStatus);
170 |         	
171 |         if ($result) {
172 |             
173 |             Resque_Event::trigger('afterEnqueue', array(
174 |                 'class' => $class,
175 |                 'args'  => $args,
176 |                 'queue' => $queue,
177 |             ));
178 |         }
179 | 
180 |         return $result;
181 |     }
182 | 
183 |     /**
184 |      * Reserve and return the next available job in the specified queue.
185 |      *
186 |      * @param string $queue Queue to fetch next available job from.
187 |      * @return Resque_Job Instance of Resque_Job to be processed, false if none or error.
188 |      */
189 |     public static function reserve($queue)
190 |     {
191 |         return Resque_Job::reserve($queue);
192 |     }
193 | 
194 |     /**
195 |      * Get an array of all known queues.
196 |      *
197 |      * @return array Array of queues.
198 |      */
199 |     public static function queues()
200 |     {
201 |         $queues = self::redis()->smembers('queues');
202 |         if(!is_array($queues)) {
203 |             $queues = array();
204 |         }
205 |         return $queues;
206 |     }
207 | }


--------------------------------------------------------------------------------
/lib/Resque/Event.php:
--------------------------------------------------------------------------------
 1 | 
 9 |  * @license		http://www.opensource.org/licenses/mit-license.php
10 |  */
11 | class Resque_Event
12 | {
13 | 	/**
14 | 	 * @var array Array containing all registered callbacks, indexked by event name.
15 | 	 */
16 | 	private static $events = array();
17 | 
18 | 	/**
19 | 	 * Raise a given event with the supplied data.
20 | 	 *
21 | 	 * @param string $event Name of event to be raised.
22 | 	 * @param mixed $data Optional, any data that should be passed to each callback.
23 | 	 * @return true
24 | 	 */
25 | 	public static function trigger($event, $data = null)
26 | 	{
27 | 		if (!is_array($data)) {
28 | 			$data = array($data);
29 | 		}
30 | 
31 | 		if (empty(self::$events[$event])) {
32 | 			return true;
33 | 		}
34 | 		
35 | 		foreach (self::$events[$event] as $callback) {
36 | 			if (!is_callable($callback)) {
37 | 				continue;
38 | 			}
39 | 			call_user_func_array($callback, $data);
40 | 		}
41 | 		
42 | 		return true;
43 | 	}
44 | 	
45 | 	/**
46 | 	 * Listen in on a given event to have a specified callback fired.
47 | 	 *
48 | 	 * @param string $event Name of event to listen on.
49 | 	 * @param mixed $callback Any callback callable by call_user_func_array.
50 | 	 * @return true
51 | 	 */
52 | 	public static function listen($event, $callback)
53 | 	{
54 | 		if (!isset(self::$events[$event])) {
55 | 			self::$events[$event] = array();
56 | 		}
57 | 		
58 | 		self::$events[$event][] = $callback;
59 | 		return true;
60 | 	}
61 | 	
62 | 	/**
63 | 	 * Stop a given callback from listening on a specific event.
64 | 	 *
65 | 	 * @param string $event Name of event.
66 | 	 * @param mixed $callback The callback as defined when listen() was called.
67 | 	 * @return true
68 | 	 */
69 | 	public static function stopListening($event, $callback)
70 | 	{
71 | 		if (!isset(self::$events[$event])) {
72 | 			return true;
73 | 		}
74 | 		
75 | 		$key = array_search($callback, self::$events[$event]);
76 | 		if ($key !== false) {
77 | 			unset(self::$events[$event][$key]);
78 | 		}
79 | 		
80 | 		return true;
81 | 	}
82 | 	
83 | 	/**
84 | 	 * Call all registered listeners.
85 | 	 */
86 | 	public static function clearListeners()
87 | 	{
88 | 		self::$events = array();
89 | 	}
90 | }
91 | 


--------------------------------------------------------------------------------
/lib/Resque/Exception.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  * @license		http://www.opensource.org/licenses/mit-license.php
 8 |  */
 9 | namespace resque\lib\Resque;
10 | 
11 | //class Resque_Exception extends Exception
12 | //{
13 | //}
14 | ?>


--------------------------------------------------------------------------------
/lib/Resque/Failure.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  * @license		http://www.opensource.org/licenses/mit-license.php
 8 |  */
 9 | class Resque_Failure
10 | {
11 | 	/**
12 | 	 * @var string Class name representing the backend to pass failed jobs off to.
13 | 	 */
14 | 	private static $backend;
15 | 
16 | 	/**
17 | 	 * Create a new failed job on the backend.
18 | 	 *
19 | 	 * @param object $payload        The contents of the job that has just failed.
20 | 	 * @param \Exception $exception  The exception generated when the job failed to run.
21 | 	 * @param \Resque_Worker $worker Instance of Resque_Worker that was running this job when it failed.
22 | 	 * @param string $queue          The name of the queue that this job was fetched from.
23 | 	 */
24 | 	public static function create($payload, Exception $exception, Resque_Worker $worker, $queue)
25 | 	{
26 | 		$backend = self::getBackend();
27 | 		new $backend($payload, $exception, $worker, $queue);
28 | 	}
29 | 
30 | 	/**
31 | 	 * Return an instance of the backend for saving job failures.
32 | 	 *
33 | 	 * @return object Instance of backend object.
34 | 	 */
35 | 	public static function getBackend()
36 | 	{
37 | 		if(self::$backend === null) {
38 | 			require  dirname(__FILE__) . '/Failure/Redis.php';
39 | 			self::$backend = 'Resque_Failure_Redis';
40 | 		}
41 | 
42 | 		return self::$backend;
43 | 	}
44 | 
45 | 	/**
46 | 	 * Set the backend to use for raised job failures. The supplied backend
47 | 	 * should be the name of a class to be instantiated when a job fails.
48 | 	 * It is your responsibility to have the backend class loaded (or autoloaded)
49 | 	 *
50 | 	 * @param string $backend The class name of the backend to pipe failures to.
51 | 	 */
52 | 	public static function setBackend($backend)
53 | 	{
54 | 		self::$backend = $backend;
55 | 	}
56 | }


--------------------------------------------------------------------------------
/lib/Resque/Failure/Interface.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  * @license		http://www.opensource.org/licenses/mit-license.php
 8 |  */
 9 | interface Resque_Failure_Interface
10 | {
11 | 	/**
12 | 	 * Initialize a failed job class and save it (where appropriate).
13 | 	 *
14 | 	 * @param object $payload Object containing details of the failed job.
15 | 	 * @param object $exception Instance of the exception that was thrown by the failed job.
16 | 	 * @param object $worker Instance of Resque_Worker that received the job.
17 | 	 * @param string $queue The name of the queue the job was fetched from.
18 | 	 */
19 | 	public function __construct($payload, $exception, $worker, $queue);
20 | 
21 |     /**
22 |      * Return details about a failed jobs
23 |      * @param  string   job Id
24 |      * @return object   Object containing details of the failed job.
25 |      */
26 |     static public function get($jobId);
27 | }
28 | ?>


--------------------------------------------------------------------------------
/lib/Resque/Failure/Redis.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  * @license		http://www.opensource.org/licenses/mit-license.php
 8 |  */
 9 | 
10 | class Resque_Failure_Redis implements Resque_Failure_Interface
11 | {
12 | 	/**
13 | 	 * Initialize a failed job class and save it (where appropriate).
14 | 	 *
15 | 	 * @param object $payload Object containing details of the failed job.
16 | 	 * @param object $exception Instance of the exception that was thrown by the failed job.
17 | 	 * @param object $worker Instance of Resque_Worker that received the job.
18 | 	 * @param string $queue The name of the queue the job was fetched from.
19 | 	 */
20 | 	public function __construct($payload, $exception, $worker, $queue)
21 | 	{
22 | 		$data = array();
23 | 		$data['failed_at'] = strftime('%a %b %d %H:%M:%S %Z %Y');
24 | 		$data['payload'] = $payload;
25 | 		$data['exception'] = get_class($exception);
26 | 		$data['error'] = $exception->getMessage();
27 | 		$data['backtrace'] = explode("\n", $exception->getTraceAsString());
28 | 		$data['worker'] = (string)$worker;
29 | 		$data['queue'] = $queue;
30 | 		Resque::Redis()->setex('failed:'.$payload['id'], 3600*14, serialize($data));
31 | 	}
32 | 
33 | 	static public function get($jobId)
34 | 	{
35 | 		$data = Resque::Redis()->get('failed:' . $jobId);
36 | 		return unserialize($data);
37 | 	}
38 | }
39 | ?>


--------------------------------------------------------------------------------
/lib/Resque/Job.php:
--------------------------------------------------------------------------------
  1 | 
 10 |  * @license		http://www.opensource.org/licenses/mit-license.php
 11 |  */
 12 | class Resque_Job
 13 | {
 14 | 	/**
 15 | 	 * @var string The name of the queue that this job belongs to.
 16 | 	 */
 17 | 	public $queue;
 18 | 
 19 | 	/**
 20 | 	 * @var Resque_Worker Instance of the Resque worker running this job.
 21 | 	 */
 22 | 	public $worker;
 23 | 
 24 | 	/**
 25 | 	 * @var object Object containing details of the job.
 26 | 	 */
 27 | 	public $payload;
 28 | 
 29 | 	/**
 30 | 	 * @var object Instance of the class performing work for this job.
 31 | 	 */
 32 | 	private $instance;
 33 | 
 34 | 	/**
 35 | 	 * Instantiate a new instance of a job.
 36 | 	 *
 37 | 	 * @param string $queue The queue that the job belongs to.
 38 | 	 * @param array $payload array containing details of the job.
 39 | 	 */
 40 | 	public function __construct($queue, $payload)
 41 | 	{
 42 | 		$this->queue = $queue;
 43 | 		$this->payload = $payload;
 44 | 		if(file_exists(\yii\BaseYii::$app->basePath.'/../frontend/components')){
 45 | 			 // yii 2 advanced
 46 |                 $this->payload['class'] = 'frontend\\components\\'.$this->payload['class'];
 47 |         }
 48 |         else{
 49 |         	// yii2 basic
 50 |         	 $this->payload['class'] = 'app\\components\\'.$this->payload['class'];
 51 |         }
 52 | 
 53 | 	}
 54 | 
 55 | 	/**
 56 | 	 * Create a new job and save it to the specified queue.
 57 | 	 *
 58 | 	 * @param string $queue The name of the queue to place the job in.
 59 | 	 * @param string $class The name of the class that contains the code to execute the job.
 60 | 	 * @param array $args Any optional arguments that should be passed when the job is executed.
 61 | 	 * @param boolean $monitor Set to true to be able to monitor the status of a job.
 62 | 	 *
 63 | 	 * @return string
 64 | 	 */
 65 | 	public static function create($queue, $class, $args = null, $monitor = false)
 66 | 	{
 67 |                 
 68 |                 if ($args !== null && !is_array($args)) {
 69 | 			throw new InvalidArgumentException(
 70 | 				'Supplied $args must be an array.'
 71 | 			);
 72 | 		}
 73 | 
 74 | 		$new = true;
 75 | 		if(isset($args['id'])) {
 76 | 			$id = $args['id'];
 77 | 			// unset($args['id']);
 78 | 			$new = false;
 79 | 		} else {
 80 | 			$id = md5(uniqid('', true));
 81 | 		}
 82 | 		Resque::push($queue, array(
 83 | 			'class'	=> $class,
 84 | 			'args'	=> array($args),
 85 | 			'id'	=> $id,
 86 | 		));
 87 |                 
 88 | 		if ($monitor) {
 89 | 			if ($new) {
 90 | 				Resque_Job_Status::create($id);
 91 | 			} else {
 92 | 				$statusInstance = new Resque_Job_Status($id);
 93 | 				$statusInstance->update($id, Resque_Job_Status::STATUS_WAITING);
 94 | 			}
 95 | 		}
 96 |                 
 97 | 		return $id;
 98 | 	}
 99 | 
100 | 	/**
101 | 	 * Find the next available job from the specified queue and return an
102 | 	 * instance of Resque_Job for it.
103 | 	 *
104 | 	 * @param string $queue The name of the queue to check for a job in.
105 | 	 * @return null|object Null when there aren't any waiting jobs, instance of Resque_Job when a job was found.
106 | 	 */
107 | 	public static function reserve($queue)
108 | 	{
109 | 		$payload = Resque::pop($queue);
110 | 		if(!is_array($payload)) {
111 | 			return false;
112 | 		}
113 | 
114 | 		return new Resque_Job($queue, $payload);
115 | 	}
116 | 
117 | 	/**
118 | 	 * Update the status of the current job.
119 | 	 *
120 | 	 * @param int $status Status constant from Resque_Job_Status indicating the current status of a job.
121 | 	 */
122 | 	public function updateStatus($status)
123 | 	{
124 | 		if(empty($this->payload['id'])) {
125 | 			return;
126 | 		}
127 | 
128 | 		$statusInstance = new Resque_Job_Status($this->payload['id']);
129 | 		$statusInstance->update($status);
130 | 	}
131 | 
132 | 	/**
133 | 	 * Return the status of the current job.
134 | 	 *
135 | 	 * @return int The status of the job as one of the Resque_Job_Status constants.
136 | 	 */
137 | 	public function getStatus()
138 | 	{
139 | 		$status = new Resque_Job_Status($this->payload['id']);
140 | 		return $status->get();
141 | 	}
142 | 
143 | 	/**
144 | 	 * Get the arguments supplied to this job.
145 | 	 *
146 | 	 * @return array Array of arguments.
147 | 	 */
148 | 	public function getArguments()
149 | 	{
150 | 		if (!isset($this->payload['args'])) {
151 | 			return array();
152 | 		}
153 | 
154 | 		return $this->payload['args'][0];
155 | 	}
156 | 
157 | 	/**
158 | 	 * Get the instantiated object for this job that will be performing work.
159 | 	 *
160 | 	 * @return object Instance of the object that this job belongs to.
161 | 	 */
162 | 	public function getInstance()
163 | 	{
164 | 		if (!is_null($this->instance)) {
165 | 			return $this->instance;
166 | 		}
167 | 
168 | 		if (class_exists('Resque_Job_Creator')) {
169 | 			$this->instance = Resque_Job_Creator::createJob($this->payload['class'], $this->getArguments());
170 | 		} else {
171 | 			if(!class_exists($this->payload['class'])) {
172 | //				throw new Resque_Exception(
173 | //					'Could not find job class ' . $this->payload['class'] . '.'
174 | //				);
175 |                             echo 'Could not find job class ' . $this->payload['class'] . '.';die;
176 | 			}
177 | 
178 | 			if(!method_exists($this->payload['class'], 'perform')) {
179 | 				throw new Resque_Exception(
180 | 					'Job class ' . $this->payload['class'] . ' does not contain a perform method.'
181 | 				);
182 | 			}
183 |                         
184 | 			$this->instance = new $this->payload['class']();
185 | 		}
186 | 
187 | 		$this->instance->job = $this;
188 | 		$this->instance->args = $this->getArguments();
189 | 		$this->instance->queue = $this->queue;
190 | 		return $this->instance;
191 | 	}
192 | 
193 | 	/**
194 | 	 * Actually execute a job by calling the perform method on the class
195 | 	 * associated with the job with the supplied arguments.
196 | 	 *
197 | 	 * @return bool
198 | 	 * @throws Resque_Exception When the job's class could not be found or it does not contain a perform method.
199 | 	 */
200 | 	public function perform()
201 | 	{
202 | 		$instance = $this->getInstance();
203 |                 try {
204 | 			Resque_Event::trigger('beforePerform', $this);
205 | 
206 | 			if(method_exists($instance, 'setUp')) {
207 | 				$instance->setUp();
208 | 			}
209 | 
210 | 			$instance->perform();
211 | 
212 | 			if(method_exists($instance, 'tearDown')) {
213 | 				$instance->tearDown();
214 | 			}
215 | 
216 | 			Resque_Event::trigger('afterPerform', $this);
217 | 		}
218 | 		// beforePerform/setUp have said don't perform this job. Return.
219 | 		catch(Resque_Job_DontPerform $e) {
220 | 			return false;
221 | 		}
222 | 
223 | 		return true;
224 | 	}
225 | 
226 | 	/**
227 | 	 * Mark the current job as having failed.
228 | 	 *
229 | 	 * @param $exception
230 | 	 */
231 | 	public function fail($exception)
232 | 	{
233 | 		Resque_Event::trigger('onFailure', array(
234 | 			'exception' => $exception,
235 | 			'job' => $this,
236 | 		));
237 | 
238 | 		$this->updateStatus(Resque_Job_Status::STATUS_FAILED);
239 | 		require_once dirname(__FILE__) . '/Failure.php';
240 | 		Resque_Failure::create(
241 | 			$this->payload,
242 | 			$exception,
243 | 			$this->worker,
244 | 			$this->queue
245 | 		);
246 | 		Resque_Stat::incr('failed');
247 | 		Resque_Stat::incr('failed:' . $this->worker);
248 | 	}
249 | 
250 | 	/**
251 | 	 * Re-queue the current job.
252 | 	 * @return string
253 | 	 */
254 | 	public function recreate()
255 | 	{
256 | 		$status = new Resque_Job_Status($this->payload['id']);
257 | 		$monitor = false;
258 | 		if($status->isTracking()) {
259 | 			$monitor = true;
260 | 		}
261 | 
262 | 		return self::create($this->queue, $this->payload['class'], $this->payload['args'], $monitor);
263 | 	}
264 | 
265 | 	/**
266 | 	 * Generate a string representation used to describe the current job.
267 | 	 *
268 | 	 * @return string The string representation of the job.
269 | 	 */
270 | 	public function __toString()
271 | 	{
272 | 		return json_encode(array(
273 | 					'queue' => $this->queue,
274 | 					'id' => !empty($this->payload['id']) ? $this->payload['id'] : '',
275 | 					'class' => $this->payload['class'],
276 | 					'args' => !empty($this->payload['args']) ? $this->payload['args'] : ''
277 | 				));
278 | 	}
279 | }
280 | 
281 | 


--------------------------------------------------------------------------------
/lib/Resque/Job/DirtyExitException.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  * @license		http://www.opensource.org/licenses/mit-license.php
 8 |  */
 9 | class Resque_Job_DirtyExitException extends RuntimeException
10 | {
11 | 
12 | }


--------------------------------------------------------------------------------
/lib/Resque/Job/DontPerform.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  * @license		http://www.opensource.org/licenses/mit-license.php
 8 |  */
 9 | class Resque_Job_DontPerform extends Exception
10 | {
11 | 
12 | }


--------------------------------------------------------------------------------
/lib/Resque/Job/Status.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  * @license		http://www.opensource.org/licenses/mit-license.php
  8 |  */
  9 | namespace resque\lib\Resque\Job;
 10 | use resque\lib\Resque;
 11 | class Resque_Job_Status
 12 | {
 13 | 	const STATUS_WAITING = 1;
 14 | 	const STATUS_RUNNING = 2;
 15 | 	const STATUS_FAILED = 3;
 16 | 	const STATUS_COMPLETE = 4;
 17 | 
 18 | 	/**
 19 | 	 * @var string The ID of the job this status class refers back to.
 20 | 	 */
 21 | 	private $id;
 22 | 
 23 | 	/**
 24 | 	 * @var mixed Cache variable if the status of this job is being monitored or not.
 25 | 	 * 	True/false when checked at least once or null if not checked yet.
 26 | 	 */
 27 | 	private $isTracking = null;
 28 | 
 29 | 	/**
 30 | 	 * @var array Array of statuses that are considered final/complete.
 31 | 	 */
 32 | 	private static $completeStatuses = array(
 33 | 		self::STATUS_FAILED,
 34 | 		self::STATUS_COMPLETE
 35 | 	);
 36 | 
 37 | 	/**
 38 | 	 * Setup a new instance of the job monitor class for the supplied job ID.
 39 | 	 *
 40 | 	 * @param string $id The ID of the job to manage the status for.
 41 | 	 */
 42 | 	public function __construct($id)
 43 | 	{
 44 | 		$this->id = $id;
 45 | 	}
 46 | 
 47 | 	/**
 48 | 	 * Create a new status monitor item for the supplied job ID. Will create
 49 | 	 * all necessary keys in Redis to monitor the status of a job.
 50 | 	 *
 51 | 	 * @param string $id The ID of the job to monitor the status of.
 52 | 	 */
 53 | 	public static function create($id, $status = self::STATUS_WAITING)
 54 | 	{
 55 | 		$statusPacket = array(
 56 | 			'status' => $status,
 57 | 			'updated' => time(),
 58 | 			'started' => time(),
 59 | 		);
 60 | 		Resque::redis()->set('job:' . $id . ':status', json_encode($statusPacket));
 61 | 	}
 62 | 
 63 | 	/**
 64 | 	 * Check if we're actually checking the status of the loaded job status
 65 | 	 * instance.
 66 | 	 *
 67 | 	 * @return boolean True if the status is being monitored, false if not.
 68 | 	 */
 69 | 	public function isTracking()
 70 | 	{
 71 | 		if($this->isTracking === false) {
 72 | 			return false;
 73 | 		}
 74 | 
 75 | 		if(!Resque::redis()->exists((string)$this)) {
 76 | 			$this->isTracking = false;
 77 | 			return false;
 78 | 		}
 79 | 
 80 | 		$this->isTracking = true;
 81 | 		return true;
 82 | 	}
 83 | 
 84 | 	/**
 85 | 	 * Update the status indicator for the current job with a new status.
 86 | 	 *
 87 | 	 * @param int The status of the job (see constants in Resque_Job_Status)
 88 | 	 */
 89 | 	public function update($status)
 90 | 	{
 91 | 		if(!$this->isTracking()) {
 92 | 			return;
 93 | 		}
 94 | 
 95 | 		$statusPacket = array(
 96 | 			'status' => $status,
 97 | 			'updated' => time(),
 98 | 		);
 99 | 		Resque::redis()->set((string)$this, json_encode($statusPacket));
100 | 
101 | 		// Expire the status for completed jobs after 24 hours
102 | 		if(in_array($status, self::$completeStatuses)) {
103 | 			Resque::redis()->expire((string)$this, 86400);
104 | 		}
105 | 	}
106 | 
107 | 	/**
108 | 	 * Fetch the status for the job being monitored.
109 | 	 *
110 | 	 * @return mixed False if the status is not being monitored, otherwise the status as
111 | 	 * 	as an integer, based on the Resque_Job_Status constants.
112 | 	 */
113 | 	public function get()
114 | 	{
115 | 		if(!$this->isTracking()) {
116 | 			return false;
117 | 		}
118 | 
119 | 		$statusPacket = json_decode(Resque::redis()->get((string)$this), true);
120 | 		if(!$statusPacket) {
121 | 			return false;
122 | 		}
123 | 
124 | 		return $statusPacket['status'];
125 | 	}
126 | 
127 | 	/**
128 | 	 * Stop tracking the status of a job.
129 | 	 */
130 | 	public function stop()
131 | 	{
132 | 		Resque::redis()->del((string)$this);
133 | 	}
134 | 
135 | 	/**
136 | 	 * Generate a string representation of this object.
137 | 	 *
138 | 	 * @return string String representation of the current job status class.
139 | 	 */
140 | 	public function __toString()
141 | 	{
142 | 		return 'job:' . $this->id . ':status';
143 | 	}
144 | }
145 | ?>


--------------------------------------------------------------------------------
/lib/Resque/Redis.php:
--------------------------------------------------------------------------------
  1 | host = $server[0];
 20 | 			$this->port = $server[1];
 21 | 			$this->password = $password;
 22 | 			$this->timeout = $timeout;
 23 | 
 24 | 			$this->establishConnection();
 25 | 		}
 26 | 
 27 | 		function establishConnection()
 28 | 		{
 29 | 			$this->connect($this->host, (int) $this->port, (int) $this->timeout);
 30 | 
 31 | 	        if (isset($this->password) && !empty($this->password)) {
 32 | 	            if ($this->auth($this->password) === false) {
 33 | 	                throw new CException('Resque failed to authenticate with redis!');
 34 | 	            }
 35 | 	        }
 36 | 
 37 | 			$this->setOption(\Redis::OPT_PREFIX, self::$defaultNamespace);
 38 | 		}
 39 | 
 40 | 		public function prefix($namespace)
 41 | 		{
 42 | 			if (empty($namespace)) $namespace = self::$defaultNamespace;
 43 | 			if (strpos($namespace, ':') === false) {
 44 | 				$namespace .= ':';
 45 | 			}
 46 | 			self::$defaultNamespace = $namespace;
 47 |                         
 48 | 			$this->setOption(\Redis::OPT_PREFIX, self::$defaultNamespace);
 49 | 		}
 50 | 	}
 51 | }
 52 | else
 53 | {
 54 | 	/**
 55 | 	 * Wrap Credis to add namespace support and various helper methods.
 56 | 	 *
 57 | 	 * @package		Resque/Redis
 58 | 	 * @author		Chris Boulton 
 59 | 	 * @license		http://www.opensource.org/licenses/mit-license.php
 60 | 	 */
 61 | 	class RedisApi
 62 | 	{
 63 | 	    /**
 64 | 	     * Redis namespace
 65 | 	     * @var string
 66 | 	     */
 67 | 	    private static $defaultNamespace = 'resque:';
 68 | 
 69 | 	    private $server;
 70 | 	    private $database;
 71 | 
 72 | 		/**
 73 | 		 * @var array List of all commands in Redis that supply a key as their
 74 | 		 *	first argument. Used to prefix keys with the Resque namespace.
 75 | 		 */
 76 | 		private $keyCommands = array(
 77 | 			'exists',
 78 | 			'del',
 79 | 			'type',
 80 | 			'keys',
 81 | 			'expire',
 82 | 			'ttl',
 83 | 			'move',
 84 | 			'set',
 85 | 			'setex',
 86 | 			'get',
 87 | 			'getset',
 88 | 			'setnx',
 89 | 			'incr',
 90 | 			'incrby',
 91 | 			'decr',
 92 | 			'decrby',
 93 | 			'rpush',
 94 | 			'lpush',
 95 | 			'llen',
 96 | 			'lrange',
 97 | 			'ltrim',
 98 | 			'lindex',
 99 | 			'lset',
100 | 			'lrem',
101 | 			'lpop',
102 | 			'rpop',
103 | 			'sadd',
104 | 			'srem',
105 | 			'spop',
106 | 			'scard',
107 | 			'sismember',
108 | 			'smembers',
109 | 			'srandmember',
110 | 			'zadd',
111 | 			'zrem',
112 | 			'zrange',
113 | 			'zrevrange',
114 | 			'zrangebyscore',
115 | 			'zcard',
116 | 			'zscore',
117 | 			'zremrangebyscore',
118 | 			'sort'
119 | 		);
120 | 		// sinterstore
121 | 		// sunion
122 | 		// sunionstore
123 | 		// sdiff
124 | 		// sdiffstore
125 | 		// sinter
126 | 		// smove
127 | 		// rename
128 | 		// rpoplpush
129 | 		// mget
130 | 		// msetnx
131 | 		// mset
132 | 		// renamenx
133 | 
134 | 		/**
135 | 		 * Set Redis namespace (prefix) default: resque
136 | 		 * @param string $namespace
137 | 		 */
138 | 		public static function prefix($namespace)
139 | 		{
140 | 		    if (strpos($namespace, ':') === false) {
141 | 		        $namespace .= ':';
142 | 		    }
143 | 		    self::$defaultNamespace = $namespace;
144 | 		}
145 | 
146 | 		public function __construct($server, $database = null)
147 | 		{
148 | 			$this->server = $server;
149 | 			$this->database = $database;
150 |                         
151 | 			if (is_array($this->server)) {
152 |                             
153 | 				$this->driver = new Credis_Cluster($server);
154 | 			}
155 | 			else {
156 | 				$port = null;
157 | 				$password = null;
158 | 				$host = $server;
159 | 
160 | 				// If not a UNIX socket path or tcp:// formatted connections string
161 | 				// assume host:port combination.
162 | 				if (strpos($server, '/') === false) {
163 | 					$parts = explode(':', $server);
164 | 					if (isset($parts[1])) {
165 | 						$port = $parts[1];
166 | 					}
167 | 					$host = $parts[0];
168 | 				}else if (strpos($server, 'redis://') !== false){
169 | 					// Redis format is:
170 | 					// redis://[user]:[password]@[host]:[port]
171 | 					list($userpwd,$hostport) = explode('@', $server);
172 | 					$userpwd = substr($userpwd, strpos($userpwd, 'redis://')+8);
173 | 					list($host, $port) = explode(':', $hostport);
174 | 					list($user, $password) = explode(':', $userpwd);
175 | 				}
176 |                                 
177 |        
178 |                                  
179 | 				$this->driver = new Credis_Client($host, $port);
180 |                                 
181 | 				if (isset($password)){
182 | 					$this->driver->auth($password);
183 | 				} 
184 |                                 
185 | 			}
186 |                         if ($this->database !== null) {
187 | 				$this->driver->select($database);
188 | 			}
189 | 		}
190 | 
191 | 		/**
192 | 		 * Magic method to handle all function requests and prefix key based
193 | 		 * operations with the {self::$defaultNamespace} key prefix.
194 | 		 *
195 | 		 * @param string $name The name of the method called.
196 | 		 * @param array $args Array of supplied arguments to the method.
197 | 		 * @return mixed Return value from Resident::call() based on the command.
198 | 		 */
199 | 		public function __call($name, $args) {
200 |                         if(in_array($name, $this->keyCommands)) {
201 | 			    $args[0] = self::$defaultNamespace . $args[0];
202 | 			}
203 |                         try {
204 |                                 return $this->driver->__call($name, $args);
205 | 			}
206 | 			catch(CredisException $e) {
207 | 				return false;
208 | 			}
209 | 		}
210 | 
211 | 	    public static function getPrefix()
212 | 	    {
213 | 	        return self::$defaultNamespace;
214 | 	    }
215 | 
216 | 	    public static function removePrefix($string)
217 | 	    {
218 | 	        $prefix=self::getPrefix();
219 | 
220 | 	        if (substr($string, 0, strlen($prefix)) == $prefix) {
221 | 	            $string = substr($string, strlen($prefix), strlen($string) );
222 | 	        }
223 | 	        return $string;
224 | 	    }
225 | 	}
226 | }
227 | 
228 | class Resque_Redis extends RedisApi {}


--------------------------------------------------------------------------------
/lib/Resque/Stat.php:
--------------------------------------------------------------------------------
 1 | 
 7 |  * @license		http://www.opensource.org/licenses/mit-license.php
 8 |  */
 9 | namespace resque\lib\Resque;
10 | use resque\lib\Resque;
11 | class Resque_Stat
12 | {
13 | 	/**
14 | 	 * Get the value of the supplied statistic counter for the specified statistic.
15 | 	 *
16 | 	 * @param string $stat The name of the statistic to get the stats for.
17 | 	 * @return mixed Value of the statistic.
18 | 	 */
19 | 	public static function get($stat)
20 | 	{
21 | 		return (int)Resque::redis()->get('stat:' . $stat);
22 | 	}
23 | 
24 | 	/**
25 | 	 * Increment the value of the specified statistic by a certain amount (default is 1)
26 | 	 *
27 | 	 * @param string $stat The name of the statistic to increment.
28 | 	 * @param int $by The amount to increment the statistic by.
29 | 	 * @return boolean True if successful, false if not.
30 | 	 */
31 | 	public static function incr($stat, $by = 1)
32 | 	{
33 | 		return (bool)Resque::redis()->incrby('stat:' . $stat, $by);
34 | 	}
35 | 
36 | 	/**
37 | 	 * Decrement the value of the specified statistic by a certain amount (default is 1)
38 | 	 *
39 | 	 * @param string $stat The name of the statistic to decrement.
40 | 	 * @param int $by The amount to decrement the statistic by.
41 | 	 * @return boolean True if successful, false if not.
42 | 	 */
43 | 	public static function decr($stat, $by = 1)
44 | 	{
45 | 		return (bool)Resque::redis()->decrby('stat:' . $stat, $by);
46 | 	}
47 | 
48 | 	/**
49 | 	 * Delete a statistic with the given name.
50 | 	 *
51 | 	 * @param string $stat The name of the statistic to delete.
52 | 	 * @return boolean True if successful, false if not.
53 | 	 */
54 | 	public static function clear($stat)
55 | 	{
56 | 		return (bool)Resque::redis()->del('stat:' . $stat);
57 | 	}
58 | }


--------------------------------------------------------------------------------
/lib/ResqueScheduler/InvalidTimestampException.php:
--------------------------------------------------------------------------------
 1 | 
 7 | * @copyright	(c) 2012 Chris Boulton
 8 | * @license		http://www.opensource.org/licenses/mit-license.php
 9 | */
10 | class ResqueScheduler_InvalidTimestampException extends Resque_Exception
11 | {
12 | 
13 | }


--------------------------------------------------------------------------------
/lib/ResqueScheduler/Worker.php:
--------------------------------------------------------------------------------
  1 | 
  7 |  * @copyright	(c) 2012 Chris Boulton
  8 |  * @license		http://www.opensource.org/licenses/mit-license.php
  9 |  */
 10 | class ResqueScheduler_Worker
 11 | {
 12 | 	const LOG_NONE = 0;
 13 | 	const LOG_NORMAL = 1;
 14 | 	const LOG_VERBOSE = 2;
 15 | 	
 16 | 	/**
 17 | 	 * @var int Current log level of this worker.
 18 | 	 */
 19 | 	public $logLevel = 0;
 20 | 	
 21 | 	/**
 22 | 	 * @var int Interval to sleep for between checking schedules.
 23 | 	 */
 24 | 	protected $interval = 5;
 25 | 	
 26 | 	/**
 27 | 	* The primary loop for a worker.
 28 | 	*
 29 | 	* Every $interval (seconds), the scheduled queue will be checked for jobs
 30 | 	* that should be pushed to Resque.
 31 | 	*
 32 | 	* @param int $interval How often to check schedules.
 33 | 	*/
 34 | 	public function work($interval = null)
 35 | 	{
 36 | 		if ($interval !== null) {
 37 | 			$this->interval = $interval;
 38 | 		}
 39 | 
 40 | 		$this->updateProcLine('Starting');
 41 | 		
 42 | 		while (true) {
 43 | 			$this->handleDelayedItems();
 44 | 			$this->sleep();
 45 | 		}
 46 | 	}
 47 | 	
 48 | 	/**
 49 | 	 * Handle delayed items for the next scheduled timestamp.
 50 | 	 *
 51 | 	 * Searches for any items that are due to be scheduled in Resque
 52 | 	 * and adds them to the appropriate job queue in Resque.
 53 | 	 *
 54 | 	 * @param DateTime|int $timestamp Search for any items up to this timestamp to schedule.
 55 | 	 */
 56 | 	public function handleDelayedItems($timestamp = null)
 57 | 	{
 58 | 		while (($timestamp = ResqueScheduler::nextDelayedTimestamp($timestamp)) !== false) {
 59 | 			$this->updateProcLine('Processing Delayed Items');
 60 | 			$this->enqueueDelayedItemsForTimestamp($timestamp);
 61 | 		}
 62 | 	}
 63 | 	
 64 | 	/**
 65 | 	 * Schedule all of the delayed jobs for a given timestamp.
 66 | 	 *
 67 | 	 * Searches for all items for a given timestamp, pulls them off the list of
 68 | 	 * delayed jobs and pushes them across to Resque.
 69 | 	 *
 70 | 	 * @param DateTime|int $timestamp Search for any items up to this timestamp to schedule.
 71 | 	 */
 72 | 	public function enqueueDelayedItemsForTimestamp($timestamp)
 73 | 	{
 74 | 		$item = null;
 75 | 		while ($item = ResqueScheduler::nextItemForTimestamp($timestamp)) {
 76 | 			$this->log('queueing ' . $item['class'] . ' in ' . $item['queue'] .' [delayed]');
 77 | 			
 78 | 			Resque_Event::trigger('beforeDelayedEnqueue', array(
 79 | 				'queue' => $item['queue'],
 80 | 				'class' => $item['class'],
 81 | 				'args'  => $item['args'],
 82 | 			));
 83 | 
 84 | 			$payload = array_merge(array($item['queue'], $item['class']), $item['args']);
 85 | 			call_user_func_array('Resque::enqueue', $payload);
 86 | 		}
 87 | 	}
 88 | 	
 89 | 	/**
 90 | 	 * Sleep for the defined interval.
 91 | 	 */
 92 | 	protected function sleep()
 93 | 	{
 94 | 		sleep($this->interval);
 95 | 	}
 96 | 	
 97 | 	/**
 98 | 	 * Update the status of the current worker process.
 99 | 	 *
100 | 	 * On supported systems (with the PECL proctitle module installed), update
101 | 	 * the name of the currently running process to indicate the current state
102 | 	 * of a worker.
103 | 	 *
104 | 	 * @param string $status The updated process title.
105 | 	 */
106 | 	private function updateProcLine($status)
107 | 	{
108 | 		if(function_exists('setproctitle')) {
109 | 			setproctitle('resque-scheduler-' . ResqueScheduler::VERSION . ': ' . $status);
110 | 		}
111 | 	}
112 | 	
113 | 	/**
114 | 	 * Output a given log message to STDOUT.
115 | 	 *
116 | 	 * @param string $message Message to output.
117 | 	 */
118 | 	public function log($message)
119 | 	{
120 | 		if($this->logLevel == self::LOG_NORMAL) {
121 | 			fwrite(STDOUT, "*** " . $message . "\n");
122 | 		}
123 | 		else if($this->logLevel == self::LOG_VERBOSE) {
124 | 			fwrite(STDOUT, "** [" . strftime('%T %Y-%m-%d') . "] " . $message . "\n");
125 | 		}
126 | 	}
127 | }
128 | 


--------------------------------------------------------------------------------