├── .gitignore ├── LICENSE ├── README.md ├── application ├── config │ └── monolog.php └── core │ └── Log.php └── composer.json /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | composer.lock 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) Andreas Pfotenhauer 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Codeigniter-Monolog-Plus 2 | =================== 3 | 4 | Simple integration of the Monolog Package (https://github.com/Seldaek/monolog) into CodeIgniter by overwriting the CI_Log class. 5 | 6 | Based on https://github.com/stevethomas/codeigniter-monolog but updating to support Codeigniter 3, monolog ^1.22, and supporting file logging more akin to native CodeIgniter logging. 7 | 8 | This library registers Monolog as the PHP error handler to catch all errors and adds support for IntrospectionProcessor for additional meta data. 9 | 10 | Supports CI-File (native style Codeigniter errors), File (RotatingFileHandler), New Relic (NewRelicHandler), HipChat (HipChatHandler), stderr (for use with Heroku), papertrail (log directly to papertrailapp.com), and graylog.org 11 | 12 | Support now included to multi-line output into logs 13 | 14 | Installation 15 | ------------ 16 | * Install monolog with ```composer require monolog/monolog``` 17 | * Make sure your config.php contains has the ```$config['composer_autoload']``` setting updated to point to ```/vendor/autoload.php``` 18 | * Copy application/core/Log.php and application/config/monolog.php into your Codeigniter application 19 | 20 | Usage 21 | ----- 22 | Use log_message() as normal in CodeIgniter to log error, debug and info messages. Log files are stored in the application/logs folder. 23 | 24 | License 25 | ------- 26 | codeigniter-monolog-plus is licensed under the MIT License - see the LICENSE file for details 27 | -------------------------------------------------------------------------------- /application/config/monolog.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | 14 | /* GENERAL OPTIONS */ 15 | $config['handlers'] = array('ci_file', 'file'); // valid handlers are ci_file | file | new_relic | hipchat | stderr | papertrail | gelf 16 | $config['channel'] = ENVIRONMENT; // channel name which appears on each line of log 17 | $config['threshold'] = '1'; // 'ERROR' => '1', 'DEBUG' => '2', 'INFO' => '3', 'ALL' => '4' 18 | $config['introspection_processor'] = TRUE; // add some meta data such as controller and line number to log messages 19 | 20 | /* CI FILE - DEFAULT CODEIGNITER LOG FILE STRUCTURE 21 | * Log to default CI log directory (must be writable ie. chmod 757). 22 | * Filename will be encoded to current system date, ie. YYYY-MM-DD-ci.log 23 | */ 24 | $config['ci_file_logfile'] = '/application/logs/log.php'; 25 | $config['ci_file_multiline'] = TRUE; //add newlines to the output 26 | 27 | /* FILE HANDLER OPTIONS 28 | * Log to default CI log directory (must be writable ie. chmod 757). 29 | * Filename will be encoded to current system date, ie. YYYY-MM-DD-ci.log 30 | */ 31 | $config['file_logfile'] = '/application/logs/ci.log'; 32 | $config['file_multiline'] = TRUE; //add newlines to the output 33 | 34 | /* NEW RELIC OPTIONS */ 35 | $config['new_relic_app_name'] = 'APP NAME - ' . ENVIRONMENT; 36 | 37 | /* HIPCHAT OPTIONS */ 38 | $config['hipchat_app_token'] = ''; //HipChat API Token 39 | $config['hipchat_app_room_id'] = ''; //The room that should be alerted of the message (Id or Name) 40 | $config['hipchat_app_notification_name'] = 'Monolog'; //Name used in the "from" field 41 | $config['hipchat_app_notify'] = false; //Trigger a notification in clients or not 42 | $config['hipchat_app_loglevel'] = 'WARNING'; //The minimum logging level at which this handler will be triggered 43 | 44 | /* PAPER TRAIL OPTIONS */ 45 | $config['papertrail_host'] = ''; //xxxx.papertrailapp.com 46 | $config['papertrail_port'] = ''; //port number 47 | $config['papertrail_multiline'] = TRUE; //add newlines to the output 48 | 49 | /* GELF OPTIONS */ 50 | $config['gelf_host'] = ''; //xxxx.papertrailapp.com 51 | $config['gelf_port'] = ''; //port number 52 | 53 | // exclusion list for pesky messages which you may wish to temporarily suppress with strpos() match 54 | $config['exclusion_list'] = array(); 55 | -------------------------------------------------------------------------------- /application/core/Log.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * For the full copyright and license information, please view the LICENSE 11 | * file that was distributed with this source code. 12 | */ 13 | 14 | use Monolog\Logger; 15 | use Monolog\ErrorHandler; 16 | use Monolog\Formatter\LineFormatter; 17 | use Monolog\Handler\RotatingFileHandler; 18 | use Monolog\Handler\NewRelicHandler; 19 | use Monolog\Handler\HipChatHandler; 20 | use Monolog\Handler\StreamHandler; 21 | use Monolog\Handler\SyslogUdpHandler; 22 | use Monolog\Processor\IntrospectionProcessor; 23 | 24 | // Make sure to install graylog2/gelf-php - composer require graylog2/gelf-php 25 | use Gelf\Transport\UdpTransport; 26 | use Gelf\Publisher; 27 | 28 | 29 | /** 30 | * replaces CI's Logger class, use Monolog instead 31 | * 32 | * see https://github.com/stevethomas/codeigniter-monolog & https://github.com/Seldaek/monolog 33 | * 34 | */ 35 | class CI_Log 36 | { 37 | // CI log levels 38 | protected $_levels = array( 39 | 'OFF' => '0', 40 | 'ERROR' => '1', 41 | 'DEBUG' => '2', 42 | 'INFO' => '3', 43 | 'ALL' => '4' 44 | ); 45 | 46 | // config placeholder 47 | protected $config = array(); 48 | 49 | 50 | /** 51 | * prepare logging environment with configuration variables 52 | */ 53 | public function __construct() 54 | { 55 | // copied functionality from system/core/Common.php, as the whole CI infrastructure is not available yet 56 | if (!defined('ENVIRONMENT') OR !file_exists($file_path = APPPATH . 'config/' . ENVIRONMENT . '/monolog.php')) 57 | { 58 | $file_path = APPPATH . 'config/monolog.php'; 59 | } 60 | 61 | // Fetch the config file 62 | if (file_exists($file_path)) 63 | { 64 | require($file_path); 65 | } 66 | else 67 | { 68 | exit('monolog.php config does not exist'); 69 | } 70 | 71 | // make $config from config/monolog.php accessible to $this->write_log() 72 | $this->config = $config; 73 | 74 | $this->log = new Logger($this->config['channel']); 75 | // detect and register all PHP errors in this log hence forth 76 | ErrorHandler::register($this->log); 77 | 78 | if ($this->config['introspection_processor']) 79 | { 80 | // add controller and line number info to each log message 81 | $this->log->pushProcessor(new IntrospectionProcessor()); 82 | } 83 | 84 | // decide which handler(s) to use 85 | foreach ($this->config['handlers'] as $value) 86 | { 87 | switch ($value) 88 | { 89 | case 'file': 90 | $handler = new RotatingFileHandler($this->config['file_logfile']); 91 | $formatter = new LineFormatter(null, null, $this->config['file_multiline']); 92 | $handler->setFormatter($formatter); 93 | break; 94 | 95 | case 'ci_file': 96 | $handler = new RotatingFileHandler($this->config['ci_file_logfile']); 97 | $formatter = new LineFormatter("%level_name% - %datetime% --> %message% %extra%\n", null, $this->config['ci_file_multiline']); 98 | $handler->setFormatter($formatter); 99 | break; 100 | 101 | case 'new_relic': 102 | $handler = new NewRelicHandler(Logger::ERROR, true, $this->config['new_relic_app_name']); 103 | break; 104 | 105 | case 'hipchat': 106 | $handler = new HipChatHandler( 107 | $this->config['hipchat_app_token'], 108 | $this->config['hipchat_app_room_id'], 109 | $this->config['hipchat_app_notification_name'], 110 | $this->config['hipchat_app_notify'], 111 | $this->config['hipchat_app_loglevel'] 112 | ); 113 | break; 114 | 115 | case 'stderr': 116 | $handler = new StreamHandler('php://stderr'); 117 | break; 118 | 119 | case 'papertrail': 120 | $handler = new SyslogUdpHandler($this->config['papertrail_host'], $this->config['papertrail_port']); 121 | $formatter = new LineFormatter("%channel%.%level_name%: %message% %extra%", null, $this->config['papertrail_multiline']); 122 | $handler->setFormatter($formatter); 123 | break; 124 | 125 | case 'gelf': 126 | $transport = new UdpTransport($this->config['gelf_host'], $this->config['gelf_port']); 127 | $publisher = new Publisher($transport); 128 | $formatter = new GelfMessageFormatter(); 129 | $handler = new GelfHandler($publisher); 130 | $handler->setFormatter($formatter); 131 | break; 132 | 133 | 134 | default: 135 | exit('log handler not supported: ' . $value . "\n"); 136 | } 137 | 138 | $this->log->pushHandler($handler); 139 | } 140 | 141 | $this->write_log('DEBUG', 'Monolog replacement logger initialized'); 142 | } 143 | 144 | 145 | /** 146 | * Write to defined logger. Is called from CodeIgniters native log_message() 147 | * 148 | * @param string $level 149 | * @param $msg 150 | * @return bool 151 | */ 152 | public function write_log($level = 'error', $msg) 153 | { 154 | $level = strtoupper($level); 155 | 156 | // verify error level 157 | if (!isset($this->_levels[$level])) 158 | { 159 | $this->log->addError('unknown error level: ' . $level); 160 | $level = 'ALL'; 161 | } 162 | 163 | // filter out anything in $this->config['exclusion_list'] 164 | if (!empty($this->config['exclusion_list'])) 165 | { 166 | foreach ($this->config['exclusion_list'] as $findme) 167 | { 168 | $pos = strpos($msg, $findme); 169 | if ($pos !== false) 170 | { 171 | // just exit now - we don't want to log this error 172 | return true; 173 | } 174 | } 175 | } 176 | 177 | if ($this->_levels[$level] <= $this->config['threshold']) 178 | { 179 | switch ($level) 180 | { 181 | case 'ERROR': 182 | $this->log->addError($msg); 183 | break; 184 | 185 | case 'DEBUG': 186 | $this->log->addDebug($msg); 187 | break; 188 | 189 | case 'ALL': 190 | case 'INFO': 191 | $this->log->addInfo($msg); 192 | break; 193 | } 194 | } 195 | return true; 196 | } 197 | 198 | } //end class 199 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "graylog2/gelf-php": "^1.5", 4 | "monolog/monolog": "^1.23" 5 | } 6 | } 7 | 8 | --------------------------------------------------------------------------------