├── .dockerignore ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── Bug_report.md │ └── Feature_request.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .php_cs.dist ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── build ├── cov │ └── .gitignore └── logs │ └── .gitignore ├── composer.json ├── composer.lock ├── docker-compose.yml ├── docker ├── Dockerfile └── config │ ├── docker-php-ext-xdebug.ini │ └── php.ini ├── phpunit.xml ├── src └── PhpJsonLogger │ ├── ErrorsContextFormatter.php │ ├── InvalidArgumentException.php │ ├── JsonFormatter.php │ ├── Logger.php │ ├── LoggerBuilder.php │ ├── MonologCreator.php │ ├── ServerEnvExtractor.php │ └── SlackHandlerBuilder.php └── tests ├── ExtendedMonologTest.php ├── Logger ├── AlertTest.php ├── CriticalTest.php ├── DebugTest.php ├── EmergencyTest.php ├── ErrorTest.php ├── InfoTest.php ├── LoggerTest.php ├── NoticeTest.php ├── SlackNotificationTest.php └── WarningTest.php └── UseInDockerTest.php /.dockerignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | .github 3 | .idea 4 | php-json-logger.iml 5 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Please confirm before creating PR 2 | 3 | Let's confirm before creating PR🐱! 4 | 5 | - Please give me an easy-to-understand title. 6 | - You have cleared check items written in README.md. 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Bug Report Template 4 | 5 | --- 6 | 7 | # Summary 8 | [required] 9 | 10 | # Steps to Reproduce 11 | [required] 12 | 13 | # Environment 14 | [required] 15 | 16 | # Problem 17 | [optional] 18 | 19 | # Repletion 20 | [optional] 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature 3 | about: New Feature Template 4 | 5 | --- 6 | 7 | # Done 8 | [required] 9 | 10 | # Repletion 11 | [optional] 12 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # issueURL 2 | [required] 3 | 4 | # Done 5 | [required] 6 | 7 | # Summary of Changes 8 | 9 | # What you want to see in the reviewer 10 | [optional] 11 | 12 | # Repletion 13 | [optional] 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | composer.phar 2 | /vendor/ 3 | 4 | # Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control 5 | # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file 6 | # composer.lock 7 | 8 | # IDEA Setting Files 9 | .idea 10 | php-json-logger.iml 11 | 12 | # PHPUnit Coverage dir 13 | coverage 14 | 15 | # Debug Log Files 16 | src/*.log 17 | *.log 18 | -------------------------------------------------------------------------------- /.php_cs.dist: -------------------------------------------------------------------------------- 1 | 6 | * @since 2018-05-28 7 | * @link https://github.com/FriendsOfPHP/PHP-CS-Fixer 8 | */ 9 | $finder = PhpCsFixer\Finder::create() 10 | ->exclude('bootstrap/cache') 11 | ->exclude('storage') 12 | ->exclude('vendor') 13 | ->in(__DIR__); 14 | $config = PhpCsFixer\Config::create(); 15 | $rules = [ 16 | '@PSR1' => false, 17 | '@PSR2' => true, 18 | 'array_syntax' => ['syntax' => 'short'], 19 | 'no_multiline_whitespace_around_double_arrow' => true, 20 | 'no_multiline_whitespace_before_semicolons' => true, 21 | 'blank_line_after_namespace' => true, 22 | 'no_unused_imports' => true, 23 | 'ordered_imports' => true, 24 | 'single_quote' => true, 25 | // = , => を整列する 26 | 'binary_operator_spaces' => [ 27 | 'align_double_arrow' => true, 28 | ], 29 | ]; 30 | $config->setRules($rules) 31 | ->setUsingCache(false) 32 | ->setFinder($finder); 33 | return $config; 34 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - '7.1' 5 | - '7.2' 6 | - '7.3' 7 | 8 | before_script: 9 | - composer install 10 | 11 | script: 12 | - vendor/bin/phpunit 13 | 14 | after_success: 15 | - travis_retry php vendor/bin/php-coveralls -v 16 | 17 | env: 18 | global: 19 | secure: "i44lDLUcbe719n7Gya3y1iwC+RJbCGarV9OFxY/dSoufDEzd9X0YzqHXg5myvpeDJbp7E1X2rR7Hq5tfB655v6fBDF/gc8KY2zsuswPGRPGAXoT/eRBwUrt0MB9JyC5gxuMvcKBTChWOWGb9QsT7+FQwWthJ+PtrznOQvmAzx73kijXGO9+/PRgpiV6lSpVobmFpDJP9LAuAscrBRpDA/w99d38cNrKgP8E0HX30v8ooMhdumcSmaG2HSD66LE6m1vSPywPlzddb4rAnNczKgx3Bj/buQOGzWjWANROqAleImcGqSIqkdolY0ugQFQlxTkG4Ti8BD+Mka+dQeEjVQGeSBAo8lYjk1ZpFi0n360yhuJDkPPKCSJQsF2rJ+OuYqH3ht7GCtlpX2Tm3Bxgy6opJbSJ7NQVSgcaRPhzYI+eXNCPpYotdRLeCq+1YJ0OmT2VAH5ydA0Qgo7qORLp3KxZqro1A1fcNK7Z1exer1fud9j3UQ8Rqy9RzMyNQbJ8X4sgQqSocjMPt0oBC3mTmfdFywJcFGVGcRvMZrP+lZ2hCz4/n5DxV1QwDcuuOemsdQfvK4iOiHraDHpsHcL5HMIe8Q6hsIBsDneIG1kjL1g62L4dMv8KWb5HvrB1oa88boTd988pUoj2bL3gZh4kp+LKmuaLacOC2FzJhAO7zWP0=" 20 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.3.1 - 2019-02-18 4 | Bug Fix 5 | - Since the wrong sample code was on `README.md`, delete it. 6 | 7 | ## 1.3.0 - 2019-02-18 8 | Feature 9 | - [Enable to specify `stdout` as log output destination](https://github.com/nekonomokochan/php-json-logger/pull/64) 10 | 11 | ## 1.2.0 - 2018-07-05 12 | Feature 13 | - [Changed `Nekonomokochan\PhpJsonLogger\Logger` to a class extended `\Monolog\Logger`](https://github.com/nekonomokochan/php-json-logger/pull/60) 14 | 15 | ## 1.1.0 - 2018-06-19 16 | Feature 17 | - [Added `server_ip_address` to log output](https://github.com/nekonomokochan/php-json-logger/pull/55) 18 | 19 | ## 1.0.0 - 2018-06-17 20 | Feature 21 | - [Make it possible to notify Slack.](https://github.com/nekonomokochan/php-json-logger/pull/49) 22 | 23 | ## 0.1.1 - 2018-06-09 24 | Bug Fix 25 | - [Calculation of `process_time` was wrong so we fixed it](https://github.com/nekonomokochan/php-json-logger/pull/45) 26 | 27 | ## 0.1.0 - 2018-06-07 28 | - [Add channel to contents of log output](https://github.com/nekonomokochan/php-json-logger/pull/42). 29 | - Changed to rotate logs using RotatingFileHandler. 30 | - Minor Bug Fixes 31 | 32 | ## 0.0.3 - 2018-06-01 33 | Refactoring 34 | - https://github.com/nekonomokochan/php-json-logger/pull/25 35 | 36 | Feature 37 | - Changed to extend `JsonFormatter` for use. 38 | 39 | ## 0.0.2 - 2018-05-31 40 | Bug fix 41 | - https://github.com/nekonomokochan/php-json-logger/issues/23 42 | 43 | ## 0.0.1 - 2018-05-24 44 | Initial release 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2019 nekonomokochan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # php-json-logger 2 | [![Latest Stable Version](https://poser.pugx.org/nekonomokochan/php-json-logger/v/stable)](https://packagist.org/packages/nekonomokochan/php-json-logger) 3 | [![Total Downloads](https://poser.pugx.org/nekonomokochan/php-json-logger/downloads)](https://packagist.org/packages/nekonomokochan/php-json-logger) 4 | [![Latest Unstable Version](https://poser.pugx.org/nekonomokochan/php-json-logger/v/unstable)](https://packagist.org/packages/nekonomokochan/php-json-logger) 5 | [![License](https://poser.pugx.org/nekonomokochan/php-json-logger/license)](https://packagist.org/packages/nekonomokochan/php-json-logger) 6 | [![Monthly Downloads](https://poser.pugx.org/nekonomokochan/php-json-logger/d/monthly)](https://packagist.org/packages/nekonomokochan/php-json-logger) 7 | [![Daily Downloads](https://poser.pugx.org/nekonomokochan/php-json-logger/d/daily)](https://packagist.org/packages/nekonomokochan/php-json-logger) 8 | [![composer.lock](https://poser.pugx.org/nekonomokochan/php-json-logger/composerlock)](https://packagist.org/packages/nekonomokochan/php-json-logger) 9 | [![Build Status](https://travis-ci.org/nekonomokochan/php-json-logger.svg?branch=master)](https://travis-ci.org/nekonomokochan/php-json-logger) 10 | [![Coverage Status](https://coveralls.io/repos/github/nekonomokochan/php-json-logger/badge.svg?branch=master)](https://coveralls.io/github/nekonomokochan/php-json-logger?branch=master) 11 | 12 | LoggingLibrary for PHP. Output by JSON Format 13 | 14 | This Library is mainly intended for use in web applications. 15 | 16 | ## Getting Started 17 | 18 | ### Install composer package 19 | 20 | ``` 21 | composer require nekonomokochan/php-json-logger 22 | ``` 23 | 24 | ## How To Use 25 | 26 | ### Basic usage 27 | 28 | ```php 29 | 'Test', 34 | 'price' => 4000, 35 | 'list' => [1, 2, 3], 36 | 'user' => [ 37 | 'id' => 100, 38 | 'name' => 'keitakn', 39 | ], 40 | ]; 41 | 42 | $loggerBuilder = new LoggerBuilder(); 43 | $logger = $loggerBuilder->build(); 44 | $logger->info('🐱', $context); 45 | ``` 46 | 47 | It is output as follows. 48 | 49 | ```json 50 | { 51 | "log_level": "INFO", 52 | "message": "🐱", 53 | "channel": "PhpJsonLogger", 54 | "trace_id": "35b627ce-55e0-4729-9da0-fbda2a7d817d", 55 | "file": "\/home\/vagrant\/php-json-logger\/tests\/LoggerTest.php", 56 | "line": 42, 57 | "context": { 58 | "title": "Test", 59 | "price": 4000, 60 | "list": [ 61 | 1, 62 | 2, 63 | 3 64 | ], 65 | "user": { 66 | "id": 100, 67 | "name": "keitakn" 68 | } 69 | }, 70 | "remote_ip_address": "127.0.0.1", 71 | "server_ip_address": "127.0.0.1", 72 | "user_agent": "unknown", 73 | "datetime": "2018-06-04 17:21:03.631409", 74 | "timezone": "Asia\/Tokyo", 75 | "process_time": 631.50811195373535 76 | } 77 | ``` 78 | 79 | The unit of `process_time` is ms(millisecond). 80 | 81 | #### How to change output filepath 82 | 83 | Default output filepath is `/tmp/php-json-logger-yyyy-mm-dd.log` . 84 | 85 | If you want to change the output filepath, please set the output filepath to the builder class. 86 | 87 | ```php 88 | '🐱', 95 | 'dog' => '🐶', 96 | 'rabbit' => '🐰', 97 | ]; 98 | 99 | $loggerBuilder = new LoggerBuilder(); 100 | $loggerBuilder->setFileName($fileName); 101 | $logger = $loggerBuilder->build(); 102 | $logger->info('testSetLogFileName', $context); 103 | ``` 104 | 105 | The output filepath is `/tmp/test-php-json-logger-yyyy-mm-dd.log` . 106 | 107 | It is output as follows. 108 | 109 | ```json 110 | { 111 | "log_level": "INFO", 112 | "message": "testSetLogFileName", 113 | "channel": "PhpJsonLogger", 114 | "trace_id": "20f39cdb-dbd8-470c-babd-093a2974d169", 115 | "file": "\/home\/vagrant\/php-json-logger\/tests\/LoggerTest.php", 116 | "line": 263, 117 | "context": { 118 | "cat": "🐱", 119 | "dog": "🐶", 120 | "rabbit": "🐰" 121 | }, 122 | "remote_ip_address": "127.0.0.1", 123 | "server_ip_address": "127.0.0.1", 124 | "user_agent": "unknown", 125 | "datetime": "2018-06-05 11:28:03.214995", 126 | "timezone": "Asia\/Tokyo", 127 | "process_time": 215.09790420532227 128 | } 129 | ``` 130 | 131 | #### How to Set `trace_id` 132 | 133 | Any value can be set for `trace_id`. 134 | 135 | This will help you when looking for logs you want. 136 | 137 | ```php 138 | 'keitakn', 143 | ]; 144 | 145 | $loggerBuilder = new LoggerBuilder(); 146 | $loggerBuilder->setTraceId('MyTraceID'); 147 | $logger = $loggerBuilder->build(); 148 | $logger->info('testSetTraceIdIsOutput', $context); 149 | ``` 150 | 151 | It is output as follows. 152 | 153 | ```json 154 | { 155 | "log_level": "INFO", 156 | "message": "testSetTraceIdIsOutput", 157 | "channel": "PhpJsonLogger", 158 | "trace_id": "MyTraceID", 159 | "file": "\/home\/vagrant\/php-json-logger\/tests\/LoggerTest.php", 160 | "line": 214, 161 | "context": { 162 | "name": "keitakn" 163 | }, 164 | "remote_ip_address": "127.0.0.1", 165 | "server_ip_address": "127.0.0.1", 166 | "user_agent": "unknown", 167 | "datetime": "2018-06-05 11:36:02.394269", 168 | "timezone": "Asia\/Tokyo", 169 | "process_time": 394.35911178588867 170 | } 171 | ``` 172 | 173 | #### How to change logLevel 174 | 175 | Please use `\Nekonomokochan\PhpJsonLogger\LoggerBuilder::setLogLevel()` . 176 | 177 | For example, the following code does not output logs. 178 | 179 | Because the level is set to `CRITICAL`. 180 | 181 | ```php 182 | '🐱', 187 | 'dog' => '🐶', 188 | 'rabbit' => '🐰', 189 | ]; 190 | 191 | $loggerBuilder = new LoggerBuilder(); 192 | $loggerBuilder->setLogLevel(LoggerBuilder::CRITICAL); 193 | $logger = $loggerBuilder->build(); 194 | $logger->info('testSetLogLevel', $context); 195 | ``` 196 | 197 | You can set the following values for `logLevel` . 198 | 199 | These are the same as `logLevel` defined in [Monolog](https://github.com/Seldaek/monolog). 200 | 201 | - DEBUG = 100 202 | - INFO = 200 203 | - NOTICE = 250 204 | - WARNING = 300 205 | - ERROR = 400 206 | - CRITICAL = 500 207 | - ALERT = 550 208 | - EMERGENCY = 600 209 | 210 | #### How to change channel 211 | 212 | Default channel is `PhpJsonLogger`. 213 | 214 | If you want to change the channel, you can change it with the following code. 215 | 216 | ```php 217 | $loggerBuilder = new LoggerBuilder(); 218 | $loggerBuilder->setChannel('My Favorite Animals'); 219 | ``` 220 | 221 | For example, the output is as follows. 222 | 223 | ```json 224 | { 225 | "log_level": "INFO", 226 | "message": "testCanSetChannel", 227 | "channel": "My Favorite Animals", 228 | "trace_id": "4b8aa070-a533-4376-9bf5-270c8fcc6d87", 229 | "file": "\/home\/vagrant\/php-json-logger\/tests\/Logger\/LoggerTest.php", 230 | "line": 347, 231 | "context": { 232 | "animals": "🐱🐶🐰🐱🐹" 233 | }, 234 | "remote_ip_address": "127.0.0.1", 235 | "server_ip_address": "127.0.0.1", 236 | "user_agent": "unknown", 237 | "datetime": "2018-06-07 17:56:48.538117", 238 | "timezone": "Asia\/Tokyo", 239 | "process_time": 538.48695755004883 240 | } 241 | ``` 242 | 243 | #### How to change Log Rotation Date 244 | 245 | This is the default setting to save logs for 7 days. 246 | 247 | If you want to change the log Rotation date, you can change it with the following code. 248 | 249 | The following code sets the log retention period to 2 days. 250 | 251 | ```php 252 | $loggerBuilder = new LoggerBuilder(); 253 | $loggerBuilder->setMaxFiles(2); 254 | ``` 255 | 256 | ### Extend and use `\Nekonomokochan\PhpJsonLogger\JsonFormatter` 257 | 258 | You can make your own `\Monolog\Logger` using only `\Nekonomokochan\PhpJsonLogger\JsonFormatter`. 259 | 260 | This method is useful when you need `\Monolog\Logger` in web application framework(e.g. [Laravel](https://github.com/laravel/laravel)). 261 | 262 | The following is sample code. 263 | 264 | ```php 265 | setFormatter($formatter); 282 | 283 | $introspection = new IntrospectionProcessor( 284 | Logger::INFO, 285 | ['Nekonomokochan\\PhpJsonLogger\\'], 286 | 0 287 | ); 288 | 289 | $extraRecords = function ($record) { 290 | $record['extra']['trace_id'] = 'ExtendedMonologTestTraceId'; 291 | $record['extra']['created_time'] = microtime(true); 292 | 293 | return $record; 294 | }; 295 | 296 | $extendedMonolog = new Logger( 297 | 'ExtendedMonolog', 298 | [$rotating], 299 | [$introspection, $extraRecords] 300 | ); 301 | 302 | // output info log 303 | $context = [ 304 | 'cat' => '🐱', 305 | 'dog' => '🐶', 306 | 'rabbit' => '🐰', 307 | ]; 308 | 309 | $extendedMonolog->info('outputInfoLogTest', $context); 310 | ``` 311 | 312 | It is output to `extended-monolog-test-yyyy-mm-dd.log` as follows 313 | 314 | ```json 315 | { 316 | "log_level": "INFO", 317 | "message": "outputInfoLogTest", 318 | "channel": "ExtendedMonolog", 319 | "trace_id": "ExtendedMonologTestTraceId", 320 | "file": "\/home\/vagrant\/php-json-logger\/tests\/ExtendedMonologTest.php", 321 | "line": 85, 322 | "context": { 323 | "cat": "🐱", 324 | "dog": "🐶", 325 | "rabbit": "🐰" 326 | }, 327 | "remote_ip_address": "127.0.0.1", 328 | "server_ip_address": "127.0.0.1", 329 | "user_agent": "unknown", 330 | "datetime": "2018-06-06 17:14:26.042013", 331 | "timezone": "Asia\/Tokyo", 332 | "process_time": 0.1678466796875 333 | } 334 | ``` 335 | 336 | The following code is necessary to output `trace_id` and `process_time`. 337 | 338 | ```php 339 | '🐱(=^・^=)🐱', 366 | 'dog' => '🐶Uo・ェ・oU🐶', 367 | 'rabbit' => '🐰🐰🐰', 368 | ]; 369 | 370 | $extendedMonolog->error( 371 | get_class($exception), 372 | $this->formatPhpJsonLoggerErrorsContext($exception, $context) 373 | ); 374 | ``` 375 | 376 | Please pay attention to the part `$this->formatPhpJsonLoggerErrorsContext($exception, $context)`. 377 | 378 | This is necessary processing to format the error log into JSON and output it. 379 | 380 | This is the method implemented in `\Nekonomokochan\PhpJsonLogger\ErrorsContextFormat`. 381 | 382 | It is output to `extended-monolog-test-yyyy-mm-dd.log` as follows. 383 | 384 | If you want to know more detailed usage, please look at `php-json-logger/tests/ExtendedMonologTest.php`. 385 | 386 | ```json 387 | { 388 | "log_level": "ERROR", 389 | "message": "Exception", 390 | "channel": "PhpJsonLogger", 391 | "trace_id": "ExtendedMonologTestTraceId", 392 | "file": "\/home\/vagrant\/php-json-logger\/tests\/ExtendedMonologTest.php", 393 | "line": 126, 394 | "context": { 395 | "cat": "🐱(=^・^=)🐱", 396 | "dog": "🐶Uo・ェ・oU🐶", 397 | "rabbit": "🐰🐰🐰" 398 | }, 399 | "remote_ip_address": "127.0.0.1", 400 | "server_ip_address": "127.0.0.1", 401 | "user_agent": "unknown", 402 | "datetime": "2018-06-06 17:37:57.440757", 403 | "timezone": "Asia\/Tokyo", 404 | "process_time": 0.16093254089355469, 405 | "errors": { 406 | "message": "ExtendedMonologTest.outputErrorLog", 407 | "code": 500, 408 | "file": "\/home\/vagrant\/php-json-logger\/tests\/ExtendedMonologTest.php", 409 | "line": 117, 410 | "trace": [ 411 | "#0 \/home\/vagrant\/php-json-logger\/vendor\/phpunit\/phpunit\/src\/Framework\/TestCase.php(1145): Nekonomokochan\\Tests\\ExtendedMonologTest->outputErrorLog()", 412 | "#1 \/home\/vagrant\/php-json-logger\/vendor\/phpunit\/phpunit\/src\/Framework\/TestCase.php(840): PHPUnit\\Framework\\TestCase->runTest()", 413 | "#2 \/home\/vagrant\/php-json-logger\/vendor\/phpunit\/phpunit\/src\/Framework\/TestResult.php(645): PHPUnit\\Framework\\TestCase->runBare()", 414 | "#3 \/home\/vagrant\/php-json-logger\/vendor\/phpunit\/phpunit\/src\/Framework\/TestCase.php(798): PHPUnit\\Framework\\TestResult->run()", 415 | "#4 \/home\/vagrant\/php-json-logger\/vendor\/phpunit\/phpunit\/src\/Framework\/TestSuite.php(776): PHPUnit\\Framework\\TestCase->run()", 416 | "#5 \/home\/vagrant\/php-json-logger\/vendor\/phpunit\/phpunit\/src\/TextUI\/TestRunner.php(529): PHPUnit\\Framework\\TestSuite->run()", 417 | "#6 \/home\/vagrant\/php-json-logger\/vendor\/phpunit\/phpunit\/src\/TextUI\/Command.php(198): PHPUnit\\TextUI\\TestRunner->doRun()", 418 | "#7 \/home\/vagrant\/php-json-logger\/vendor\/phpunit\/phpunit\/src\/TextUI\/Command.php(151): PHPUnit\\TextUI\\Command->run()", 419 | "#8 \/home\/vagrant\/php-json-logger\/vendor\/phpunit\/phpunit\/phpunit(53): PHPUnit\\TextUI\\Command::main()" 420 | ] 421 | } 422 | } 423 | ``` 424 | 425 | ### Notification To Slack 426 | 427 | To send the log to Slack please execute the following code. 428 | 429 | This code will be sent to slack if the log level is `CRITICAL` or higher. 430 | 431 | ```php 432 | 'keitakn', 439 | 'email' => 'dummy@email.com', 440 | ]; 441 | 442 | $slackToken = 'YOUR_SLACK_TOKEN'; 443 | $slackChannel = 'YOUR_SLACK_CHANNEL'; 444 | 445 | $slackHandlerBuilder = new SlackHandlerBuilder($slackToken, $slackChannel); 446 | $slackHandlerBuilder->setLevel(LoggerBuilder::CRITICAL); 447 | 448 | $loggerBuilder = new LoggerBuilder(); 449 | $loggerBuilder->setFileName($this->outputFileBaseName); 450 | $loggerBuilder->setSlackHandler($slackHandlerBuilder->build()); 451 | $logger = $loggerBuilder->build(); 452 | $logger->critical($exception, $context); 453 | ``` 454 | 455 | ### Use in Docker 456 | 457 | Please use `LoggerBuilder.setUseInDocker` in order to use it on Docker. 458 | 459 | When setUseInDocker is set to true, no file output is done and the log is output as `stdout`. 460 | 461 | ```php 462 | 'keitakn', 468 | 'email' => 'dummy@email.com', 469 | ]; 470 | 471 | $loggerBuilder = new LoggerBuilder(); 472 | $loggerBuilder->setFileName($this->outputFileBaseName); 473 | $loggerBuilder->setUseInDocker(true); 474 | $logger = $loggerBuilder->build(); 475 | $logger->critical($exception, $context); 476 | ``` 477 | 478 | ### Caution 479 | 480 | `\Nekonomokochan\PhpJsonLogger\Logger` is a subclass that extends `\Monolog\Logger` 481 | 482 | You can use it like `\Monolog\Logger`. 483 | 484 | However, for the following methods, you can pass only classes that extend `\Exception` or `\Error` as arguments. 485 | 486 | - `\Nekonomokochan\PhpJsonLogger\Logger::error()` 487 | - `\Nekonomokochan\PhpJsonLogger\Logger::critical()` 488 | - `\Nekonomokochan\PhpJsonLogger\Logger::alert()` 489 | - `\Nekonomokochan\PhpJsonLogger\Logger::emergency()` 490 | 491 | In case of violation, `\Nekonomokochan\PhpJsonLogger\Logger` will Throw `\Nekonomokochan\PhpJsonLogger\InvalidArgumentException` 492 | 493 | ## License 494 | MIT 495 | -------------------------------------------------------------------------------- /build/cov/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /build/logs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nekonomokochan/php-json-logger", 3 | "description": "LoggingLibrary for PHP. Output by JSON Format", 4 | "type": "library", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "keitakn", 9 | "email": "keita.koga.work@gmail.com" 10 | } 11 | ], 12 | "autoload": { 13 | "psr-4": { 14 | "Nekonomokochan\\PhpJsonLogger\\": "src/PhpJsonLogger" 15 | } 16 | }, 17 | "autoload-dev": { 18 | "psr-4": { 19 | "Nekonomokochan\\PhpJsonLogger\\": "src/PhpJsonLogger", 20 | "Nekonomokochan\\Tests\\": "tests/" 21 | } 22 | }, 23 | "require": { 24 | "php": "~7.1", 25 | "monolog/monolog": "^1.24", 26 | "ramsey/uuid": "^3.8" 27 | }, 28 | "require-dev": { 29 | "php": "~7.1", 30 | "phpunit/phpunit": "^7.5", 31 | "friendsofphp/php-cs-fixer": "^2.14", 32 | "php-coveralls/php-coveralls": "^2.1", 33 | "phpunit/phpcov": "^5.0" 34 | }, 35 | "scripts": { 36 | "test": "phpunit", 37 | "test:coverage:html": "phpunit --coverage-html coverage", 38 | "format": "php-cs-fixer fix --diff -v --config .php_cs.dist" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.5' 2 | services: 3 | app: 4 | container_name: php_json_logger_app 5 | build: 6 | context: . 7 | dockerfile: ./docker/Dockerfile 8 | environment: 9 | PHP_JSON_LOGGER_SLACK_TOKEN: ${PHP_JSON_LOGGER_SLACK_TOKEN} 10 | PHP_JSON_LOGGER_SLACK_CHANNEL: ${PHP_JSON_LOGGER_SLACK_CHANNEL} 11 | volumes: 12 | - .:/app/php-json-logger 13 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.3.2-cli-alpine3.9 2 | 3 | RUN set -x && \ 4 | apk update && \ 5 | apk add --no-cache libxml2 libxml2-dev curl curl-dev autoconf $PHPIZE_DEPS && \ 6 | docker-php-ext-install mysqli pdo pdo_mysql xml mbstring curl session tokenizer json && \ 7 | pecl install xdebug-2.7.0beta1 && \ 8 | docker-php-ext-enable xdebug && \ 9 | curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin --filename=composer && \ 10 | composer global require hirak/prestissimo 11 | 12 | COPY ./docker/config/php.ini /usr/local/etc/php/php.ini 13 | COPY ./docker/config/docker-php-ext-xdebug.ini /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini 14 | 15 | ADD . /app/php-json-logger/ 16 | WORKDIR /app/php-json-logger 17 | 18 | ENTRYPOINT ["/bin/sh", "-c", "while true; do echo hello world; sleep 1; done"] 19 | -------------------------------------------------------------------------------- /docker/config/docker-php-ext-xdebug.ini: -------------------------------------------------------------------------------- 1 | zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20180731/xdebug.so 2 | 3 | xdebug.remote_enable=1 4 | xdebug.remote_autostart=1 5 | xdebug.remote_connect_back=1 6 | xdebug.remote_port=9090 7 | -------------------------------------------------------------------------------- /docker/config/php.ini: -------------------------------------------------------------------------------- 1 | [PHP] 2 | engine = On 3 | short_open_tag = Off 4 | precision = 14 5 | output_buffering = 4096 6 | zlib.output_compression = Off 7 | implicit_flush = Off 8 | unserialize_callback_func = 9 | serialize_precision = -1 10 | disable_functions = 11 | disable_classes = 12 | zend.enable_gc = On 13 | expose_php = Off 14 | max_execution_time = 30 15 | max_input_time = 60 16 | memory_limit = 128M 17 | error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT 18 | display_errors = Off 19 | display_startup_errors = Off 20 | log_errors = On 21 | log_errors_max_len = 1024 22 | ignore_repeated_errors = Off 23 | ignore_repeated_source = Off 24 | report_memleaks = On 25 | html_errors = On 26 | error_log = /var/log/php-error.log 27 | variables_order = "GPCS" 28 | request_order = "GP" 29 | register_argc_argv = Off 30 | auto_globals_jit = On 31 | post_max_size = 8M 32 | auto_prepend_file = 33 | auto_append_file = 34 | default_mimetype = "text/html" 35 | default_charset = "UTF-8" 36 | doc_root = 37 | user_dir = 38 | enable_dl = Off 39 | file_uploads = On 40 | upload_max_filesize = 2M 41 | max_file_uploads = 20 42 | allow_url_fopen = On 43 | allow_url_include = Off 44 | default_socket_timeout = 60 45 | 46 | [CLI Server] 47 | cli_server.color = On 48 | 49 | [Date] 50 | date.timezone = Asia/Tokyo 51 | 52 | [filter] 53 | 54 | [iconv] 55 | 56 | [intl] 57 | 58 | [sqlite3] 59 | 60 | [Pcre] 61 | pcre.jit=0 62 | 63 | [Pdo] 64 | 65 | [Pdo_mysql] 66 | pdo_mysql.cache_size = 2000 67 | pdo_mysql.default_socket= 68 | 69 | [Phar] 70 | 71 | [mail function] 72 | sendmail_path = /usr/sbin/sendmail -t -i 73 | mail.add_x_header = On 74 | 75 | [ODBC] 76 | odbc.allow_persistent = On 77 | odbc.check_persistent = On 78 | odbc.max_persistent = -1 79 | odbc.max_links = -1 80 | odbc.defaultlrl = 4096 81 | odbc.defaultbinmode = 1 82 | 83 | [Interbase] 84 | ibase.allow_persistent = 1 85 | ibase.max_persistent = -1 86 | ibase.max_links = -1 87 | ibase.timestampformat = "%Y-%m-%d %H:%M:%S" 88 | ibase.dateformat = "%Y-%m-%d" 89 | ibase.timeformat = "%H:%M:%S" 90 | 91 | [MySQLi] 92 | mysqli.max_persistent = -1 93 | mysqli.allow_persistent = On 94 | mysqli.max_links = -1 95 | mysqli.cache_size = 2000 96 | mysqli.default_port = 3306 97 | mysqli.default_socket = 98 | mysqli.default_host = 99 | mysqli.default_user = 100 | mysqli.default_pw = 101 | mysqli.reconnect = Off 102 | 103 | [mysqlnd] 104 | mysqlnd.collect_statistics = On 105 | mysqlnd.collect_memory_statistics = Off 106 | 107 | [PostgreSQL] 108 | pgsql.allow_persistent = On 109 | pgsql.auto_reset_persistent = Off 110 | pgsql.max_persistent = -1 111 | pgsql.max_links = -1 112 | pgsql.ignore_notice = 0 113 | pgsql.log_notice = 0 114 | 115 | [bcmath] 116 | bcmath.scale = 0 117 | 118 | [browscap] 119 | 120 | [Session] 121 | session.save_handler = files 122 | session.use_strict_mode = 0 123 | session.use_cookies = 1 124 | session.use_only_cookies = 1 125 | session.name = PHPSESSID 126 | session.auto_start = 0 127 | session.cookie_lifetime = 0 128 | session.cookie_path = / 129 | session.cookie_domain = 130 | session.cookie_httponly = 131 | session.serialize_handler = php 132 | session.gc_probability = 1 133 | session.gc_divisor = 1000 134 | session.gc_maxlifetime = 1440 135 | session.referer_check = 136 | session.cache_limiter = nocache 137 | session.cache_expire = 180 138 | session.use_trans_sid = 0 139 | session.sid_length = 26 140 | session.trans_sid_tags = "a=href,area=href,frame=src,form=" 141 | session.sid_bits_per_character = 5 142 | 143 | [Assertion] 144 | zend.assertions = -1 145 | 146 | [mbstring] 147 | mbstring.language = Japanese 148 | mbstring.encoding_translation = Off 149 | mbstring.detect_order = UTF-8,SJIS,EUC-JP,JIS,ASCII 150 | 151 | [gd] 152 | 153 | [exif] 154 | 155 | [Tidy] 156 | tidy.clean_output = Off 157 | 158 | [soap] 159 | soap.wsdl_cache_enabled=1 160 | soap.wsdl_cache_dir="/tmp" 161 | soap.wsdl_cache_ttl=86400 162 | soap.wsdl_cache_limit = 5 163 | 164 | [sysvshm] 165 | 166 | [ldap] 167 | ldap.max_links = -1 168 | 169 | [dba] 170 | 171 | [curl] 172 | 173 | [openssl] 174 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | tests 6 | 7 | 8 | 9 | 10 | src/ 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/PhpJsonLogger/ErrorsContextFormatter.php: -------------------------------------------------------------------------------- 1 | getMessage(); 19 | $context['php_json_logger']['errors']['code'] = $e->getCode(); 20 | $context['php_json_logger']['errors']['file'] = $e->getFile(); 21 | $context['php_json_logger']['errors']['line'] = $e->getLine(); 22 | $context['php_json_logger']['errors']['trace'] = $this->formatStackTrace($e->getTrace()); 23 | 24 | return $context; 25 | } 26 | 27 | /** 28 | * @param array $traces 29 | * @return array 30 | */ 31 | protected function formatStackTrace(array $traces): array 32 | { 33 | $formattedTraces = []; 34 | $length = count($traces); 35 | 36 | for ($i = 0; $i < $length; $i++) { 37 | $format = sprintf( 38 | '#%s %s(%s): %s%s%s()', 39 | $i, 40 | $traces[$i]['file'] ?? '', 41 | $traces[$i]['line'] ?? '', 42 | $traces[$i]['class'] ?? '', 43 | $traces[$i]['type'] ?? '', 44 | $traces[$i]['function'] ?? '' 45 | ); 46 | 47 | $formattedTraces[] = $format; 48 | } 49 | 50 | return $formattedTraces; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/PhpJsonLogger/InvalidArgumentException.php: -------------------------------------------------------------------------------- 1 | $record['level_name'], 23 | 'message' => $record['message'], 24 | 'channel' => $record['channel'], 25 | 'trace_id' => $record['extra']['trace_id'], 26 | 'file' => $record['extra']['file'], 27 | 'line' => $record['extra']['line'], 28 | 'context' => $record['context'], 29 | 'remote_ip_address' => $this->extractRemoteIpAddress(), 30 | 'server_ip_address' => $this->extractServerIpAddress(), 31 | 'user_agent' => $this->extractUserAgent(), 32 | 'datetime' => $record['datetime']->format('Y-m-d H:i:s.u'), 33 | 'timezone' => $record['datetime']->getTimezone()->getName(), 34 | 'process_time' => $this->calculateProcessTime($record['extra']['created_time']), 35 | ]; 36 | 37 | unset($formattedRecord['context']['php_json_logger']); 38 | 39 | if (isset($record['context']['php_json_logger']['errors'])) { 40 | $formattedRecord['errors'] = $record['context']['php_json_logger']['errors']; 41 | } 42 | 43 | $json = $this->toJson($this->normalize($formattedRecord), true) . ($this->appendNewline ? "\n" : ''); 44 | 45 | return $json; 46 | } 47 | 48 | /** 49 | * @param float $createdTime 50 | * @return float 51 | */ 52 | private function calculateProcessTime(float $createdTime): float 53 | { 54 | $time = microtime(true); 55 | 56 | return ($time - $createdTime) * 1000; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/PhpJsonLogger/Logger.php: -------------------------------------------------------------------------------- 1 | traceId = $builder->getTraceId(); 53 | $this->generateTraceIdIfNeeded(); 54 | $this->channel = $builder->getChannel(); 55 | $this->logFileName = $builder->getFileName(); 56 | $this->logLevel = $builder->getLogLevel(); 57 | $this->maxFiles = $builder->getMaxFiles(); 58 | 59 | $constructParams = $this->createConstructParams($this->traceId, $builder); 60 | 61 | parent::__construct( 62 | $constructParams['channel'], 63 | $constructParams['handlers'], 64 | $constructParams['processors'] 65 | ); 66 | } 67 | 68 | /** 69 | * @param $message 70 | * @param $context 71 | */ 72 | public function debug($message, array $context = []) 73 | { 74 | $this->addDebug($message, $context); 75 | } 76 | 77 | /** 78 | * @param $message 79 | * @param array $context 80 | */ 81 | public function info($message, array $context = []) 82 | { 83 | $this->addInfo($message, $context); 84 | } 85 | 86 | /** 87 | * @param $message 88 | * @param array $context 89 | */ 90 | public function notice($message, array $context = []) 91 | { 92 | $this->addNotice($message, $context); 93 | } 94 | 95 | /** 96 | * @param $message 97 | * @param array $context 98 | */ 99 | public function warning($message, array $context = []) 100 | { 101 | $this->addWarning($message, $context); 102 | } 103 | 104 | /** 105 | * @param \Throwable $e 106 | * @param array $context 107 | */ 108 | public function error($e, array $context = []) 109 | { 110 | if ($this->isErrorObject($e) === false) { 111 | throw new \InvalidArgumentException( 112 | $this->generateInvalidArgumentMessage(__METHOD__) 113 | ); 114 | } 115 | 116 | $this->addError(get_class($e), $this->formatPhpJsonLoggerErrorsContext($e, $context)); 117 | } 118 | 119 | /** 120 | * @param \Throwable $e 121 | * @param array $context 122 | */ 123 | public function critical($e, array $context = []) 124 | { 125 | if ($this->isErrorObject($e) === false) { 126 | throw new \InvalidArgumentException( 127 | $this->generateInvalidArgumentMessage(__METHOD__) 128 | ); 129 | } 130 | 131 | $this->addCritical(get_class($e), $this->formatPhpJsonLoggerErrorsContext($e, $context)); 132 | } 133 | 134 | /** 135 | * @param \Throwable $e 136 | * @param array $context 137 | */ 138 | public function alert($e, array $context = []) 139 | { 140 | if ($this->isErrorObject($e) === false) { 141 | throw new \InvalidArgumentException( 142 | $this->generateInvalidArgumentMessage(__METHOD__) 143 | ); 144 | } 145 | 146 | $this->addAlert(get_class($e), $this->formatPhpJsonLoggerErrorsContext($e, $context)); 147 | } 148 | 149 | /** 150 | * @param \Throwable $e 151 | * @param array $context 152 | */ 153 | public function emergency($e, array $context = []) 154 | { 155 | if ($this->isErrorObject($e) === false) { 156 | throw new \InvalidArgumentException( 157 | $this->generateInvalidArgumentMessage(__METHOD__) 158 | ); 159 | } 160 | 161 | $this->addEmergency(get_class($e), $this->formatPhpJsonLoggerErrorsContext($e, $context)); 162 | } 163 | 164 | /** 165 | * @return string 166 | */ 167 | public function getTraceId(): string 168 | { 169 | return $this->traceId; 170 | } 171 | 172 | /** 173 | * @return string 174 | */ 175 | public function getChannel(): string 176 | { 177 | return $this->channel; 178 | } 179 | 180 | /** 181 | * @return int 182 | */ 183 | public function getLogLevel(): int 184 | { 185 | return $this->logLevel; 186 | } 187 | 188 | /** 189 | * @return string 190 | */ 191 | public function getLogFileName(): string 192 | { 193 | return $this->logFileName; 194 | } 195 | 196 | /** 197 | * @return int 198 | */ 199 | public function getMaxFiles(): int 200 | { 201 | return $this->maxFiles; 202 | } 203 | 204 | /** 205 | * Generate if TraceID is empty 206 | */ 207 | private function generateTraceIdIfNeeded() 208 | { 209 | if (empty($this->traceId)) { 210 | $this->traceId = Uuid::uuid4()->toString(); 211 | } 212 | } 213 | 214 | /** 215 | * @param $value 216 | * @return bool 217 | */ 218 | private function isErrorObject($value): bool 219 | { 220 | if ($value instanceof \Exception || $value instanceof \Error) { 221 | return true; 222 | } 223 | 224 | return false; 225 | } 226 | 227 | /** 228 | * @param string $method 229 | * @return string 230 | */ 231 | private function generateInvalidArgumentMessage(string $method) 232 | { 233 | return 'Please give the exception class to the ' . $method; 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /src/PhpJsonLogger/LoggerBuilder.php: -------------------------------------------------------------------------------- 1 | traceId = $traceId; 138 | $this->setChannel(self::DEFAULT_CHANNEL); 139 | $this->setLogLevel(self::INFO); 140 | $this->setFileName('/tmp/php-json-logger.log'); 141 | $this->setSkipClassesPartials(self::DEFAULT_SKIP_CLASSES_PARTIALS); 142 | $this->setSkipStackFramesCount(self::DEFAULT_SKIP_STACK_FRAMES_COUNT); 143 | $this->setMaxFiles(self::DEFAULT_MAX_FILES); 144 | } 145 | 146 | /** 147 | * @return string 148 | */ 149 | public function getTraceId(): string 150 | { 151 | return $this->traceId; 152 | } 153 | 154 | /** 155 | * @param string $traceId 156 | */ 157 | public function setTraceId(string $traceId) 158 | { 159 | $this->traceId = $traceId; 160 | } 161 | 162 | /** 163 | * @return string 164 | */ 165 | public function getChannel(): string 166 | { 167 | return $this->channel; 168 | } 169 | 170 | /** 171 | * @param string $channel 172 | */ 173 | public function setChannel(string $channel) 174 | { 175 | $this->channel = $channel; 176 | } 177 | 178 | /** 179 | * @return int 180 | */ 181 | public function getLogLevel(): int 182 | { 183 | return $this->logLevel; 184 | } 185 | 186 | /** 187 | * @param int $logLevel 188 | */ 189 | public function setLogLevel(int $logLevel) 190 | { 191 | $this->logLevel = $logLevel; 192 | } 193 | 194 | /** 195 | * @return string 196 | */ 197 | public function getFileName(): string 198 | { 199 | return $this->fileName; 200 | } 201 | 202 | /** 203 | * @param string $fileName 204 | */ 205 | public function setFileName(string $fileName) 206 | { 207 | $this->fileName = $fileName; 208 | } 209 | 210 | /** 211 | * @return array 212 | */ 213 | public function getSkipClassesPartials(): array 214 | { 215 | return $this->skipClassesPartials; 216 | } 217 | 218 | /** 219 | * @param array $skipClassesPartials 220 | */ 221 | public function setSkipClassesPartials(array $skipClassesPartials) 222 | { 223 | $this->skipClassesPartials = array_merge($this->skipClassesPartials, $skipClassesPartials); 224 | } 225 | 226 | /** 227 | * @return int 228 | */ 229 | public function getSkipStackFramesCount(): int 230 | { 231 | return $this->skipStackFramesCount; 232 | } 233 | 234 | /** 235 | * @param int $skipStackFramesCount 236 | */ 237 | public function setSkipStackFramesCount(int $skipStackFramesCount) 238 | { 239 | $this->skipStackFramesCount = $skipStackFramesCount; 240 | } 241 | 242 | /** 243 | * @return int 244 | */ 245 | public function getMaxFiles(): int 246 | { 247 | return $this->maxFiles; 248 | } 249 | 250 | /** 251 | * @param int $maxFiles 252 | */ 253 | public function setMaxFiles(int $maxFiles) 254 | { 255 | $this->maxFiles = $maxFiles; 256 | } 257 | 258 | /** 259 | * @return \Monolog\Handler\SlackHandler 260 | */ 261 | public function getSlackHandler():? \Monolog\Handler\SlackHandler 262 | { 263 | return $this->slackHandler; 264 | } 265 | 266 | /** 267 | * @param \Monolog\Handler\SlackHandler $slackHandler 268 | */ 269 | public function setSlackHandler(\Monolog\Handler\SlackHandler $slackHandler) 270 | { 271 | $this->slackHandler = $slackHandler; 272 | } 273 | 274 | /** 275 | * @return bool 276 | */ 277 | public function isUseInDocker(): bool 278 | { 279 | return $this->useInDocker; 280 | } 281 | 282 | /** 283 | * @param bool $useInDocker 284 | */ 285 | public function setUseInDocker(bool $useInDocker): void 286 | { 287 | $this->useInDocker = $useInDocker; 288 | } 289 | 290 | /** 291 | * @return Logger 292 | * @throws \Exception 293 | */ 294 | public function build() 295 | { 296 | return new Logger($this); 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /src/PhpJsonLogger/MonologCreator.php: -------------------------------------------------------------------------------- 1 | getFileName(), 30 | $loggerBuilder->getMaxFiles(), 31 | $loggerBuilder->getLogLevel() 32 | ); 33 | $rotating->setFormatter($formatter); 34 | 35 | if ($loggerBuilder->isUseInDocker()) { 36 | $streamHandler = new StreamHandler('php://stdout', $loggerBuilder->getLogLevel()); 37 | $streamHandler->setFormatter($formatter); 38 | array_push($handlers, $streamHandler); 39 | } else { 40 | $rotating = new RotatingFileHandler( 41 | $loggerBuilder->getFileName(), 42 | $loggerBuilder->getMaxFiles(), 43 | $loggerBuilder->getLogLevel() 44 | ); 45 | $rotating->setFormatter($formatter); 46 | array_push($handlers, $rotating); 47 | } 48 | 49 | $introspection = new IntrospectionProcessor( 50 | $loggerBuilder->getLogLevel(), 51 | $loggerBuilder->getSkipClassesPartials(), 52 | $loggerBuilder->getSkipStackFramesCount() 53 | ); 54 | 55 | $extraRecords = function ($record) use ($traceId) { 56 | $record['extra']['trace_id'] = $traceId; 57 | $record['extra']['created_time'] = microtime(true); 58 | 59 | return $record; 60 | }; 61 | 62 | $processors = [ 63 | $introspection, 64 | $extraRecords, 65 | ]; 66 | 67 | if ($loggerBuilder->getSlackHandler() instanceof SlackHandler) { 68 | $slack = $loggerBuilder->getSlackHandler(); 69 | $slack->setFormatter($formatter); 70 | 71 | array_push( 72 | $handlers, 73 | $slack 74 | ); 75 | 76 | $webProcessor = new WebProcessor(); 77 | $webProcessor->addExtraField('server_ip_address', 'SERVER_ADDR'); 78 | $webProcessor->addExtraField('user_agent', 'HTTP_USER_AGENT'); 79 | array_push($processors, $webProcessor); 80 | } 81 | 82 | return [ 83 | 'channel' => $loggerBuilder->getChannel(), 84 | 'handlers' => $handlers, 85 | 'processors' => $processors 86 | ]; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/PhpJsonLogger/ServerEnvExtractor.php: -------------------------------------------------------------------------------- 1 | setToken($token); 70 | $this->setChannel($channel); 71 | $this->setUsername('nekonomokochan/php-json-logger'); 72 | $this->setUseAttachment(true); 73 | $this->setIconEmoji(':cat:'); 74 | $this->setLevel(LoggerBuilder::CRITICAL); 75 | $this->setBubble(true); 76 | $this->setUseShortAttachment(false); 77 | $this->setIncludeContextAndExtra(true); 78 | $this->setExcludeFields([]); 79 | } 80 | 81 | /** 82 | * @return string 83 | */ 84 | public function getToken(): string 85 | { 86 | return $this->token; 87 | } 88 | 89 | /** 90 | * @param string $token 91 | */ 92 | public function setToken(string $token) 93 | { 94 | $this->token = $token; 95 | } 96 | 97 | /** 98 | * @return string 99 | */ 100 | public function getChannel(): string 101 | { 102 | return $this->channel; 103 | } 104 | 105 | /** 106 | * @param string $channel 107 | */ 108 | public function setChannel(string $channel) 109 | { 110 | $this->channel = $channel; 111 | } 112 | 113 | /** 114 | * @return string 115 | */ 116 | public function getUsername(): string 117 | { 118 | return $this->username; 119 | } 120 | 121 | /** 122 | * @param string $username 123 | */ 124 | public function setUsername(string $username) 125 | { 126 | $this->username = $username; 127 | } 128 | 129 | /** 130 | * @return bool 131 | */ 132 | public function isUseAttachment(): bool 133 | { 134 | return $this->useAttachment; 135 | } 136 | 137 | /** 138 | * @param bool $useAttachment 139 | */ 140 | private function setUseAttachment(bool $useAttachment) 141 | { 142 | $this->useAttachment = $useAttachment; 143 | } 144 | 145 | /** 146 | * @return string 147 | */ 148 | public function getIconEmoji(): string 149 | { 150 | return $this->iconEmoji; 151 | } 152 | 153 | /** 154 | * @param string $iconEmoji 155 | */ 156 | private function setIconEmoji(string $iconEmoji) 157 | { 158 | $this->iconEmoji = $iconEmoji; 159 | } 160 | 161 | /** 162 | * @return int 163 | */ 164 | public function getLevel(): int 165 | { 166 | return $this->level; 167 | } 168 | 169 | /** 170 | * @param int $level 171 | */ 172 | public function setLevel(int $level) 173 | { 174 | $this->level = $level; 175 | } 176 | 177 | /** 178 | * @return bool 179 | */ 180 | public function isBubble(): bool 181 | { 182 | return $this->bubble; 183 | } 184 | 185 | /** 186 | * @param bool $bubble 187 | */ 188 | private function setBubble(bool $bubble) 189 | { 190 | $this->bubble = $bubble; 191 | } 192 | 193 | /** 194 | * @return bool 195 | */ 196 | public function isUseShortAttachment(): bool 197 | { 198 | return $this->useShortAttachment; 199 | } 200 | 201 | /** 202 | * @param bool $useShortAttachment 203 | */ 204 | private function setUseShortAttachment(bool $useShortAttachment) 205 | { 206 | $this->useShortAttachment = $useShortAttachment; 207 | } 208 | 209 | /** 210 | * @return bool 211 | */ 212 | public function isIncludeContextAndExtra(): bool 213 | { 214 | return $this->includeContextAndExtra; 215 | } 216 | 217 | /** 218 | * @param bool $includeContextAndExtra 219 | */ 220 | private function setIncludeContextAndExtra(bool $includeContextAndExtra) 221 | { 222 | $this->includeContextAndExtra = $includeContextAndExtra; 223 | } 224 | 225 | /** 226 | * @return array 227 | */ 228 | public function getExcludeFields(): array 229 | { 230 | return $this->excludeFields; 231 | } 232 | 233 | /** 234 | * @param array $excludeFields 235 | */ 236 | private function setExcludeFields(array $excludeFields) 237 | { 238 | $this->excludeFields = $excludeFields; 239 | } 240 | 241 | /** 242 | * @return \Monolog\Handler\SlackHandler 243 | * @throws \Monolog\Handler\MissingExtensionException 244 | */ 245 | public function build() 246 | { 247 | return new \Monolog\Handler\SlackHandler( 248 | $this->getToken(), 249 | $this->getChannel(), 250 | $this->getUsername(), 251 | $this->isUseAttachment(), 252 | $this->getIconEmoji(), 253 | $this->getLevel(), 254 | $this->isBubble(), 255 | $this->isUseShortAttachment(), 256 | $this->isIncludeContextAndExtra(), 257 | $this->getExcludeFields() 258 | ); 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /tests/ExtendedMonologTest.php: -------------------------------------------------------------------------------- 1 | logFileName, 49 | 7, 50 | Logger::INFO 51 | ); 52 | $rotating->setFormatter($formatter); 53 | 54 | $introspection = new IntrospectionProcessor( 55 | Logger::INFO, 56 | ['Nekonomokochan\\PhpJsonLogger\\'], 57 | 0 58 | ); 59 | 60 | $extraRecords = function ($record) { 61 | $record['extra']['trace_id'] = 'ExtendedMonologTestTraceId'; 62 | $record['extra']['created_time'] = microtime(true); 63 | 64 | return $record; 65 | }; 66 | 67 | $this->extendedMonolog = new Logger( 68 | 'ExtendedMonolog', 69 | [$rotating], 70 | [$introspection, $extraRecords] 71 | ); 72 | } 73 | 74 | /** 75 | * @test 76 | */ 77 | public function outputInfoLog() 78 | { 79 | $context = [ 80 | 'cat' => '🐱', 81 | 'dog' => '🐶', 82 | 'rabbit' => '🐰', 83 | ]; 84 | 85 | $this->extendedMonolog->info('outputInfoLogTest', $context); 86 | 87 | $resultJson = file_get_contents('/tmp/extended-monolog-test-' . date('Y-m-d') . '.log'); 88 | $resultArray = json_decode($resultJson, true); 89 | 90 | echo "\n ---- Output Log Begin ---- \n"; 91 | echo json_encode($resultArray, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); 92 | echo "\n ---- Output Log End ---- \n"; 93 | 94 | $expectedLog = [ 95 | 'log_level' => 'INFO', 96 | 'message' => 'outputInfoLogTest', 97 | 'channel' => 'ExtendedMonolog', 98 | 'trace_id' => 'ExtendedMonologTestTraceId', 99 | 'file' => __FILE__, 100 | 'line' => 85, 101 | 'context' => $context, 102 | 'remote_ip_address' => '127.0.0.1', 103 | 'server_ip_address' => '127.0.0.1', 104 | 'user_agent' => 'unknown', 105 | 'datetime' => $resultArray['datetime'], 106 | 'timezone' => date_default_timezone_get(), 107 | 'process_time' => $resultArray['process_time'], 108 | ]; 109 | 110 | $this->assertSame('ExtendedMonolog', $this->extendedMonolog->getName()); 111 | $this->assertSame($expectedLog, $resultArray); 112 | } 113 | 114 | /** 115 | * @test 116 | */ 117 | public function outputErrorLog() 118 | { 119 | $exception = new \Exception('ExtendedMonologTest.outputErrorLog', 500); 120 | $context = [ 121 | 'cat' => '🐱(=^・^=)🐱', 122 | 'dog' => '🐶Uo・ェ・oU🐶', 123 | 'rabbit' => '🐰🐰🐰', 124 | ]; 125 | 126 | $this->extendedMonolog->error( 127 | get_class($exception), 128 | $this->formatPhpJsonLoggerErrorsContext($exception, $context) 129 | ); 130 | 131 | $resultJson = file_get_contents('/tmp/extended-monolog-test-' . date('Y-m-d') . '.log'); 132 | $resultArray = json_decode($resultJson, true); 133 | 134 | echo "\n ---- Output Log Begin ---- \n"; 135 | echo json_encode($resultArray, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); 136 | echo "\n ---- Output Log End ---- \n"; 137 | 138 | $expectedLog = [ 139 | 'log_level' => 'ERROR', 140 | 'message' => get_class($exception), 141 | 'channel' => 'ExtendedMonolog', 142 | 'trace_id' => 'ExtendedMonologTestTraceId', 143 | 'file' => __FILE__, 144 | 'line' => 128, 145 | 'context' => $context, 146 | 'remote_ip_address' => '127.0.0.1', 147 | 'server_ip_address' => '127.0.0.1', 148 | 'user_agent' => 'unknown', 149 | 'datetime' => $resultArray['datetime'], 150 | 'timezone' => date_default_timezone_get(), 151 | 'process_time' => $resultArray['process_time'], 152 | 'errors' => [ 153 | 'message' => $exception->getMessage(), 154 | 'code' => $exception->getCode(), 155 | 'file' => $exception->getFile(), 156 | 'line' => $exception->getLine(), 157 | 'trace' => $resultArray['errors']['trace'], 158 | ], 159 | ]; 160 | 161 | $this->assertSame('ExtendedMonolog', $this->extendedMonolog->getName()); 162 | $this->assertSame($expectedLog, $resultArray); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /tests/Logger/AlertTest.php: -------------------------------------------------------------------------------- 1 | outputFileBaseName = '/tmp/alert-log-test.log'; 33 | $this->outputFileName = '/tmp/alert-log-test-' . date('Y-m-d') . '.log'; 34 | 35 | if (file_exists($this->outputFileName)) { 36 | unlink($this->outputFileName); 37 | } 38 | } 39 | 40 | /** 41 | * @test 42 | */ 43 | public function outputAlertLog() 44 | { 45 | $exception = new \ErrorException('TestCritical', 500); 46 | $context = [ 47 | 'name' => 'keitakn', 48 | 'email' => 'dummy@email.com', 49 | ]; 50 | 51 | $loggerBuilder = new LoggerBuilder(); 52 | $loggerBuilder->setFileName($this->outputFileBaseName); 53 | $logger = $loggerBuilder->build(); 54 | $logger->alert($exception, $context); 55 | 56 | $resultJson = file_get_contents($this->outputFileName); 57 | $resultArray = json_decode($resultJson, true); 58 | 59 | echo "\n ---- Output Log Begin ---- \n"; 60 | echo json_encode($resultArray, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); 61 | echo "\n ---- Output Log End ---- \n"; 62 | 63 | $expectedLog = [ 64 | 'log_level' => 'ALERT', 65 | 'message' => 'ErrorException', 66 | 'channel' => 'PhpJsonLogger', 67 | 'trace_id' => $logger->getTraceId(), 68 | 'file' => __FILE__, 69 | 'line' => 54, 70 | 'context' => $context, 71 | 'remote_ip_address' => '127.0.0.1', 72 | 'server_ip_address' => '127.0.0.1', 73 | 'user_agent' => 'unknown', 74 | 'datetime' => $resultArray['datetime'], 75 | 'timezone' => date_default_timezone_get(), 76 | 'process_time' => $resultArray['process_time'], 77 | 'errors' => [ 78 | 'message' => 'TestCritical', 79 | 'code' => 500, 80 | 'file' => __FILE__, 81 | 'line' => 45, 82 | 'trace' => $resultArray['errors']['trace'], 83 | ], 84 | ]; 85 | 86 | $this->assertSame('PhpJsonLogger', $logger->getChannel()); 87 | $this->assertSame($expectedLog, $resultArray); 88 | } 89 | 90 | /** 91 | * @test 92 | * @expectedException InvalidArgumentException 93 | * @expectedExceptionMessage Please give the exception class to the Nekonomokochan\PhpJsonLogger\Logger::alert 94 | */ 95 | public function invalidArgumentException() 96 | { 97 | $message = ''; 98 | 99 | $context = [ 100 | 'name' => 'keitakn', 101 | 'email' => 'dummy@email.com', 102 | ]; 103 | 104 | $loggerBuilder = new LoggerBuilder(); 105 | $loggerBuilder->setFileName($this->outputFileBaseName); 106 | $logger = $loggerBuilder->build(); 107 | $logger->alert($message, $context); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /tests/Logger/CriticalTest.php: -------------------------------------------------------------------------------- 1 | outputFileBaseName = '/tmp/critical-log-test.log'; 33 | $this->outputFileName = '/tmp/critical-log-test-' . date('Y-m-d') . '.log'; 34 | 35 | if (file_exists($this->outputFileName)) { 36 | unlink($this->outputFileName); 37 | } 38 | } 39 | 40 | /** 41 | * @test 42 | */ 43 | public function outputCriticalLog() 44 | { 45 | $exception = new \ErrorException('TestCritical', 500); 46 | $context = [ 47 | 'name' => 'keitakn', 48 | 'email' => 'dummy@email.com', 49 | ]; 50 | 51 | $loggerBuilder = new LoggerBuilder(); 52 | $loggerBuilder->setFileName($this->outputFileBaseName); 53 | $logger = $loggerBuilder->build(); 54 | $logger->critical($exception, $context); 55 | 56 | $resultJson = file_get_contents($this->outputFileName); 57 | $resultArray = json_decode($resultJson, true); 58 | 59 | echo "\n ---- Output Log Begin ---- \n"; 60 | echo json_encode($resultArray, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); 61 | echo "\n ---- Output Log End ---- \n"; 62 | 63 | $expectedLog = [ 64 | 'log_level' => 'CRITICAL', 65 | 'message' => 'ErrorException', 66 | 'channel' => 'PhpJsonLogger', 67 | 'trace_id' => $logger->getTraceId(), 68 | 'file' => __FILE__, 69 | 'line' => 54, 70 | 'context' => $context, 71 | 'remote_ip_address' => '127.0.0.1', 72 | 'server_ip_address' => '127.0.0.1', 73 | 'user_agent' => 'unknown', 74 | 'datetime' => $resultArray['datetime'], 75 | 'timezone' => date_default_timezone_get(), 76 | 'process_time' => $resultArray['process_time'], 77 | 'errors' => [ 78 | 'message' => 'TestCritical', 79 | 'code' => 500, 80 | 'file' => __FILE__, 81 | 'line' => 45, 82 | 'trace' => $resultArray['errors']['trace'], 83 | ], 84 | ]; 85 | 86 | $this->assertSame('PhpJsonLogger', $logger->getChannel()); 87 | $this->assertSame($expectedLog, $resultArray); 88 | } 89 | 90 | /** 91 | * @test 92 | * @expectedException InvalidArgumentException 93 | * @expectedExceptionMessage Please give the exception class to the Nekonomokochan\PhpJsonLogger\Logger::critical 94 | */ 95 | public function invalidArgumentException() 96 | { 97 | $message = ''; 98 | 99 | $context = [ 100 | 'name' => 'keitakn', 101 | 'email' => 'dummy@email.com', 102 | ]; 103 | 104 | $loggerBuilder = new LoggerBuilder(); 105 | $loggerBuilder->setFileName($this->outputFileBaseName); 106 | $logger = $loggerBuilder->build(); 107 | $logger->critical($message, $context); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /tests/Logger/DebugTest.php: -------------------------------------------------------------------------------- 1 | outputFileBaseName = '/tmp/debug-log-test.log'; 32 | $this->outputFileName = '/tmp/debug-log-test-' . date('Y-m-d') . '.log'; 33 | 34 | if (file_exists($this->outputFileName)) { 35 | unlink($this->outputFileName); 36 | } 37 | } 38 | 39 | /** 40 | * @test 41 | */ 42 | public function outputDebugLog() 43 | { 44 | $context = [ 45 | 'title' => 'Test', 46 | ]; 47 | 48 | $loggerBuilder = new LoggerBuilder(); 49 | $loggerBuilder->setFileName($this->outputFileBaseName); 50 | $loggerBuilder->setLogLevel(LoggerBuilder::DEBUG); 51 | $logger = $loggerBuilder->build(); 52 | $logger->debug('🐶', $context); 53 | 54 | $resultJson = file_get_contents($this->outputFileName); 55 | $resultArray = json_decode($resultJson, true); 56 | 57 | echo "\n ---- Output Log Begin ---- \n"; 58 | echo json_encode($resultArray, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); 59 | echo "\n ---- Output Log End ---- \n"; 60 | 61 | $expectedLog = [ 62 | 'log_level' => 'DEBUG', 63 | 'message' => '🐶', 64 | 'channel' => 'PhpJsonLogger', 65 | 'trace_id' => $logger->getTraceId(), 66 | 'file' => __FILE__, 67 | 'line' => 52, 68 | 'context' => $context, 69 | 'remote_ip_address' => '127.0.0.1', 70 | 'server_ip_address' => '127.0.0.1', 71 | 'user_agent' => 'unknown', 72 | 'datetime' => $resultArray['datetime'], 73 | 'timezone' => date_default_timezone_get(), 74 | 'process_time' => $resultArray['process_time'], 75 | ]; 76 | 77 | $this->assertSame('PhpJsonLogger', $logger->getChannel()); 78 | $this->assertSame($expectedLog, $resultArray); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /tests/Logger/EmergencyTest.php: -------------------------------------------------------------------------------- 1 | outputFileBaseName = '/tmp/emergency-log-test.log'; 33 | $this->outputFileName = '/tmp/emergency-log-test-' . date('Y-m-d') . '.log'; 34 | 35 | if (file_exists($this->outputFileName)) { 36 | unlink($this->outputFileName); 37 | } 38 | } 39 | 40 | /** 41 | * @test 42 | * @throws \Exception 43 | */ 44 | public function outputEmergencyLog() 45 | { 46 | $exception = new \ErrorException('TestEmergency', 500); 47 | $context = [ 48 | 'name' => 'keitakn', 49 | 'email' => 'dummy@email.com', 50 | ]; 51 | 52 | $loggerBuilder = new LoggerBuilder(); 53 | $loggerBuilder->setFileName($this->outputFileBaseName); 54 | $logger = $loggerBuilder->build(); 55 | $logger->emergency($exception, $context); 56 | 57 | $resultJson = file_get_contents($this->outputFileName); 58 | $resultArray = json_decode($resultJson, true); 59 | 60 | echo "\n ---- Output Log Begin ---- \n"; 61 | echo json_encode($resultArray, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); 62 | echo "\n ---- Output Log End ---- \n"; 63 | 64 | $expectedLog = [ 65 | 'log_level' => 'EMERGENCY', 66 | 'message' => 'ErrorException', 67 | 'channel' => 'PhpJsonLogger', 68 | 'trace_id' => $logger->getTraceId(), 69 | 'file' => __FILE__, 70 | 'line' => 55, 71 | 'context' => $context, 72 | 'remote_ip_address' => '127.0.0.1', 73 | 'server_ip_address' => '127.0.0.1', 74 | 'user_agent' => 'unknown', 75 | 'datetime' => $resultArray['datetime'], 76 | 'timezone' => date_default_timezone_get(), 77 | 'process_time' => $resultArray['process_time'], 78 | 'errors' => [ 79 | 'message' => 'TestEmergency', 80 | 'code' => 500, 81 | 'file' => __FILE__, 82 | 'line' => 46, 83 | 'trace' => $resultArray['errors']['trace'], 84 | ], 85 | ]; 86 | 87 | $this->assertSame('PhpJsonLogger', $logger->getChannel()); 88 | $this->assertSame($expectedLog, $resultArray); 89 | } 90 | 91 | /** 92 | * @test 93 | * @expectedException InvalidArgumentException 94 | * @expectedExceptionMessage Please give the exception class to the Nekonomokochan\PhpJsonLogger\Logger::emergency 95 | */ 96 | public function invalidArgumentException() 97 | { 98 | $message = ''; 99 | 100 | $context = [ 101 | 'name' => 'keitakn', 102 | 'email' => 'dummy@email.com', 103 | ]; 104 | 105 | $loggerBuilder = new LoggerBuilder(); 106 | $loggerBuilder->setFileName($this->outputFileBaseName); 107 | $logger = $loggerBuilder->build(); 108 | $logger->emergency($message, $context); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /tests/Logger/ErrorTest.php: -------------------------------------------------------------------------------- 1 | outputFileBaseName = '/tmp/error-log-test.log'; 33 | $this->outputFileName = '/tmp/error-log-test-' . date('Y-m-d') . '.log'; 34 | 35 | if (file_exists($this->outputFileName)) { 36 | unlink($this->outputFileName); 37 | } 38 | } 39 | 40 | /** 41 | * @test 42 | */ 43 | public function outputErrorLog() 44 | { 45 | $exception = new \Exception('TestException', 500); 46 | $context = [ 47 | 'name' => 'keitakn', 48 | 'email' => 'dummy@email.com', 49 | ]; 50 | 51 | $loggerBuilder = new LoggerBuilder(); 52 | $loggerBuilder->setFileName($this->outputFileBaseName); 53 | $logger = $loggerBuilder->build(); 54 | $logger->error($exception, $context); 55 | 56 | $resultJson = file_get_contents($this->outputFileName); 57 | $resultArray = json_decode($resultJson, true); 58 | 59 | echo "\n ---- Output Log Begin ---- \n"; 60 | echo json_encode($resultArray, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); 61 | echo "\n ---- Output Log End ---- \n"; 62 | 63 | $expectedLog = [ 64 | 'log_level' => 'ERROR', 65 | 'message' => 'Exception', 66 | 'channel' => 'PhpJsonLogger', 67 | 'trace_id' => $logger->getTraceId(), 68 | 'file' => __FILE__, 69 | 'line' => 54, 70 | 'context' => $context, 71 | 'remote_ip_address' => '127.0.0.1', 72 | 'server_ip_address' => '127.0.0.1', 73 | 'user_agent' => 'unknown', 74 | 'datetime' => $resultArray['datetime'], 75 | 'timezone' => date_default_timezone_get(), 76 | 'process_time' => $resultArray['process_time'], 77 | 'errors' => [ 78 | 'message' => 'TestException', 79 | 'code' => 500, 80 | 'file' => __FILE__, 81 | 'line' => 45, 82 | 'trace' => $resultArray['errors']['trace'], 83 | ], 84 | ]; 85 | 86 | $this->assertSame('PhpJsonLogger', $logger->getChannel()); 87 | $this->assertSame($expectedLog, $resultArray); 88 | } 89 | 90 | /** 91 | * @test 92 | * @expectedException InvalidArgumentException 93 | * @expectedExceptionMessage Please give the exception class to the Nekonomokochan\PhpJsonLogger\Logger::error 94 | */ 95 | public function invalidArgumentException() 96 | { 97 | $message = ''; 98 | 99 | $context = [ 100 | 'name' => 'keitakn', 101 | 'email' => 'dummy@email.com', 102 | ]; 103 | 104 | $loggerBuilder = new LoggerBuilder(); 105 | $loggerBuilder->setFileName($this->outputFileBaseName); 106 | $logger = $loggerBuilder->build(); 107 | $logger->error($message, $context); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /tests/Logger/InfoTest.php: -------------------------------------------------------------------------------- 1 | outputFileBaseName = '/tmp/info-log-test.log'; 32 | $this->outputFileName = '/tmp/info-log-test-' . date('Y-m-d') . '.log'; 33 | 34 | if (file_exists($this->outputFileName)) { 35 | unlink($this->outputFileName); 36 | } 37 | } 38 | 39 | /** 40 | * @test 41 | */ 42 | public function outputInfoLog() 43 | { 44 | $context = [ 45 | 'title' => 'Test', 46 | 'price' => 4000, 47 | 'list' => [1, 2, 3], 48 | 'user' => [ 49 | 'id' => 100, 50 | 'name' => 'keitakn', 51 | ], 52 | ]; 53 | 54 | $loggerBuilder = new LoggerBuilder(); 55 | $loggerBuilder->setFileName($this->outputFileBaseName); 56 | $logger = $loggerBuilder->build(); 57 | $logger->info('🐱', $context); 58 | 59 | $resultJson = file_get_contents($this->outputFileName); 60 | $resultArray = json_decode($resultJson, true); 61 | 62 | echo "\n ---- Output Log Begin ---- \n"; 63 | echo json_encode($resultArray, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); 64 | echo "\n ---- Output Log End ---- \n"; 65 | 66 | $expectedLog = [ 67 | 'log_level' => 'INFO', 68 | 'message' => '🐱', 69 | 'channel' => 'PhpJsonLogger', 70 | 'trace_id' => $logger->getTraceId(), 71 | 'file' => __FILE__, 72 | 'line' => 57, 73 | 'context' => $context, 74 | 'remote_ip_address' => '127.0.0.1', 75 | 'server_ip_address' => '127.0.0.1', 76 | 'user_agent' => 'unknown', 77 | 'datetime' => $resultArray['datetime'], 78 | 'timezone' => date_default_timezone_get(), 79 | 'process_time' => $resultArray['process_time'], 80 | ]; 81 | 82 | $this->assertSame('PhpJsonLogger', $logger->getChannel()); 83 | $this->assertSame($expectedLog, $resultArray); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /tests/Logger/LoggerTest.php: -------------------------------------------------------------------------------- 1 | defaultOutputFileBaseName = '/tmp/php-json-logger.log'; 33 | $this->defaultOutputFileName = '/tmp/php-json-logger-' . date('Y-m-d') . '.log'; 34 | 35 | if (file_exists($this->defaultOutputFileName)) { 36 | unlink($this->defaultOutputFileName); 37 | } 38 | } 39 | 40 | /** 41 | * @test 42 | */ 43 | public function outputUserAgent() 44 | { 45 | $userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'; 46 | $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'; 47 | 48 | $context = [ 49 | 'name' => 'keitakn', 50 | ]; 51 | 52 | $loggerBuilder = new LoggerBuilder(); 53 | $logger = $loggerBuilder->build(); 54 | $logger->info('testOutputUserAgent', $context); 55 | 56 | unset($_SERVER['HTTP_USER_AGENT']); 57 | 58 | $resultJson = file_get_contents($this->defaultOutputFileName); 59 | $resultArray = json_decode($resultJson, true); 60 | 61 | echo "\n ---- Output Log Begin ---- \n"; 62 | echo json_encode($resultArray, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); 63 | echo "\n ---- Output Log End ---- \n"; 64 | 65 | $expectedLog = [ 66 | 'log_level' => 'INFO', 67 | 'message' => 'testOutputUserAgent', 68 | 'channel' => 'PhpJsonLogger', 69 | 'trace_id' => $logger->getTraceId(), 70 | 'file' => __FILE__, 71 | 'line' => 54, 72 | 'context' => $context, 73 | 'remote_ip_address' => '127.0.0.1', 74 | 'server_ip_address' => '127.0.0.1', 75 | 'user_agent' => $userAgent, 76 | 'datetime' => $resultArray['datetime'], 77 | 'timezone' => date_default_timezone_get(), 78 | 'process_time' => $resultArray['process_time'], 79 | ]; 80 | 81 | $this->assertSame('PhpJsonLogger', $logger->getChannel()); 82 | $this->assertSame($expectedLog, $resultArray); 83 | } 84 | 85 | /** 86 | * @test 87 | */ 88 | public function outputRemoteIpAddress() 89 | { 90 | $remoteIpAddress = '192.168.10.20'; 91 | $_SERVER['REMOTE_ADDR'] = $remoteIpAddress; 92 | 93 | $context = [ 94 | 'name' => 'keitakn', 95 | ]; 96 | 97 | $loggerBuilder = new LoggerBuilder(); 98 | $logger = $loggerBuilder->build(); 99 | $logger->info('testOutputRemoteIpAddress', $context); 100 | 101 | unset($_SERVER['REMOTE_ADDR']); 102 | 103 | $resultJson = file_get_contents($this->defaultOutputFileName); 104 | $resultArray = json_decode($resultJson, true); 105 | 106 | echo "\n ---- Output Log Begin ---- \n"; 107 | echo json_encode($resultArray, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); 108 | echo "\n ---- Output Log End ---- \n"; 109 | 110 | $expectedLog = [ 111 | 'log_level' => 'INFO', 112 | 'message' => 'testOutputRemoteIpAddress', 113 | 'channel' => 'PhpJsonLogger', 114 | 'trace_id' => $logger->getTraceId(), 115 | 'file' => __FILE__, 116 | 'line' => 99, 117 | 'context' => $context, 118 | 'remote_ip_address' => $remoteIpAddress, 119 | 'server_ip_address' => '127.0.0.1', 120 | 'user_agent' => 'unknown', 121 | 'datetime' => $resultArray['datetime'], 122 | 'timezone' => date_default_timezone_get(), 123 | 'process_time' => $resultArray['process_time'], 124 | ]; 125 | 126 | $this->assertSame('PhpJsonLogger', $logger->getChannel()); 127 | $this->assertSame($expectedLog, $resultArray); 128 | } 129 | 130 | /** 131 | * @test 132 | */ 133 | public function setTraceIdIsOutput() 134 | { 135 | $context = [ 136 | 'name' => 'keitakn', 137 | ]; 138 | 139 | $loggerBuilder = new LoggerBuilder(); 140 | $loggerBuilder->setTraceId('MyTraceID'); 141 | $logger = $loggerBuilder->build(); 142 | $logger->info('testSetTraceIdIsOutput', $context); 143 | 144 | $resultJson = file_get_contents($this->defaultOutputFileName); 145 | $resultArray = json_decode($resultJson, true); 146 | 147 | echo "\n ---- Output Log Begin ---- \n"; 148 | echo json_encode($resultArray, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); 149 | echo "\n ---- Output Log End ---- \n"; 150 | 151 | $expectedLog = [ 152 | 'log_level' => 'INFO', 153 | 'message' => 'testSetTraceIdIsOutput', 154 | 'channel' => 'PhpJsonLogger', 155 | 'trace_id' => 'MyTraceID', 156 | 'file' => __FILE__, 157 | 'line' => 142, 158 | 'context' => $context, 159 | 'remote_ip_address' => '127.0.0.1', 160 | 'server_ip_address' => '127.0.0.1', 161 | 'user_agent' => 'unknown', 162 | 'datetime' => $resultArray['datetime'], 163 | 'timezone' => date_default_timezone_get(), 164 | 'process_time' => $resultArray['process_time'], 165 | ]; 166 | 167 | $this->assertSame('PhpJsonLogger', $logger->getChannel()); 168 | $this->assertSame('MyTraceID', $logger->getTraceId()); 169 | $this->assertSame($expectedLog, $resultArray); 170 | } 171 | 172 | /** 173 | * @test 174 | */ 175 | public function setLogFileName() 176 | { 177 | $outputFileBaseName = '/tmp/test-php-json-logger.log'; 178 | $outputFileName = '/tmp/test-php-json-logger-' . date('Y-m-d') . '.log'; 179 | if (file_exists($outputFileName)) { 180 | unlink($outputFileName); 181 | } 182 | 183 | $context = [ 184 | 'cat' => '🐱', 185 | 'dog' => '🐶', 186 | 'rabbit' => '🐰', 187 | ]; 188 | 189 | $loggerBuilder = new LoggerBuilder(); 190 | $loggerBuilder->setFileName($outputFileBaseName); 191 | $logger = $loggerBuilder->build(); 192 | $logger->info('testSetLogFileName', $context); 193 | 194 | $resultJson = file_get_contents($outputFileName); 195 | $resultArray = json_decode($resultJson, true); 196 | 197 | echo "\n ---- Output Log Begin ---- \n"; 198 | echo json_encode($resultArray, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); 199 | echo "\n ---- Output Log End ---- \n"; 200 | 201 | $expectedLog = [ 202 | 'log_level' => 'INFO', 203 | 'message' => 'testSetLogFileName', 204 | 'channel' => 'PhpJsonLogger', 205 | 'trace_id' => $logger->getTraceId(), 206 | 'file' => __FILE__, 207 | 'line' => 192, 208 | 'context' => $context, 209 | 'remote_ip_address' => '127.0.0.1', 210 | 'server_ip_address' => '127.0.0.1', 211 | 'user_agent' => 'unknown', 212 | 'datetime' => $resultArray['datetime'], 213 | 'timezone' => date_default_timezone_get(), 214 | 'process_time' => $resultArray['process_time'], 215 | ]; 216 | 217 | $this->assertSame('PhpJsonLogger', $logger->getChannel()); 218 | $this->assertSame( 219 | $outputFileBaseName, 220 | $logger->getLogFileName() 221 | ); 222 | $this->assertSame($expectedLog, $resultArray); 223 | } 224 | 225 | /** 226 | * @test 227 | */ 228 | public function setLogLevel() 229 | { 230 | $context = [ 231 | 'cat' => '🐱', 232 | 'dog' => '🐶', 233 | 'rabbit' => '🐰', 234 | ]; 235 | 236 | $loggerBuilder = new LoggerBuilder(); 237 | $loggerBuilder->setLogLevel(LoggerBuilder::CRITICAL); 238 | $logger = $loggerBuilder->build(); 239 | $logger->info('testSetLogLevel', $context); 240 | 241 | $this->assertFalse( 242 | file_exists($this->defaultOutputFileName) 243 | ); 244 | 245 | $this->assertSame('PhpJsonLogger', $logger->getChannel()); 246 | $this->assertSame(500, $logger->getLogLevel()); 247 | } 248 | 249 | /** 250 | * @test 251 | */ 252 | public function outputHttpXForwardedFor() 253 | { 254 | $_SERVER['HTTP_X_FORWARDED_FOR'] = '10.0.0.0,10.1.1.1'; 255 | $_SERVER['REMOTE_ADDR'] = '192.168.10.20'; 256 | 257 | $expectedRemoteIpAddress = '10.0.0.0'; 258 | 259 | $context = [ 260 | 'name' => 'keitakn', 261 | ]; 262 | 263 | $loggerBuilder = new LoggerBuilder(); 264 | $logger = $loggerBuilder->build(); 265 | $logger->info('testOutputHttpXForwardedFor', $context); 266 | 267 | unset($_SERVER['REMOTE_ADDR']); 268 | unset($_SERVER['HTTP_X_FORWARDED_FOR']); 269 | 270 | $resultJson = file_get_contents($this->defaultOutputFileName); 271 | $resultArray = json_decode($resultJson, true); 272 | 273 | echo "\n ---- Output Log Begin ---- \n"; 274 | echo json_encode($resultArray, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); 275 | echo "\n ---- Output Log End ---- \n"; 276 | 277 | $expectedLog = [ 278 | 'log_level' => 'INFO', 279 | 'message' => 'testOutputHttpXForwardedFor', 280 | 'channel' => 'PhpJsonLogger', 281 | 'trace_id' => $logger->getTraceId(), 282 | 'file' => __FILE__, 283 | 'line' => 265, 284 | 'context' => $context, 285 | 'remote_ip_address' => $expectedRemoteIpAddress, 286 | 'server_ip_address' => '127.0.0.1', 287 | 'user_agent' => 'unknown', 288 | 'datetime' => $resultArray['datetime'], 289 | 'timezone' => date_default_timezone_get(), 290 | 'process_time' => $resultArray['process_time'], 291 | ]; 292 | 293 | $this->assertSame('PhpJsonLogger', $logger->getChannel()); 294 | $this->assertSame($expectedLog, $resultArray); 295 | } 296 | 297 | /** 298 | * @test 299 | */ 300 | public function canSetMaxFiles() 301 | { 302 | $context = [ 303 | 'name' => 'keitakn', 304 | ]; 305 | 306 | $loggerBuilder = new LoggerBuilder(); 307 | $loggerBuilder->setMaxFiles(2); 308 | $logger = $loggerBuilder->build(); 309 | $logger->info('testCanSetMaxFiles', $context); 310 | 311 | $resultJson = file_get_contents($this->defaultOutputFileName); 312 | $resultArray = json_decode($resultJson, true); 313 | 314 | echo "\n ---- Output Log Begin ---- \n"; 315 | echo json_encode($resultArray, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); 316 | echo "\n ---- Output Log End ---- \n"; 317 | 318 | $expectedLog = [ 319 | 'log_level' => 'INFO', 320 | 'message' => 'testCanSetMaxFiles', 321 | 'channel' => 'PhpJsonLogger', 322 | 'trace_id' => $logger->getTraceId(), 323 | 'file' => __FILE__, 324 | 'line' => 309, 325 | 'context' => $context, 326 | 'remote_ip_address' => '127.0.0.1', 327 | 'server_ip_address' => '127.0.0.1', 328 | 'user_agent' => 'unknown', 329 | 'datetime' => $resultArray['datetime'], 330 | 'timezone' => date_default_timezone_get(), 331 | 'process_time' => $resultArray['process_time'], 332 | ]; 333 | 334 | $this->assertSame('PhpJsonLogger', $logger->getChannel()); 335 | $this->assertSame(2, $logger->getMaxFiles()); 336 | $this->assertSame($expectedLog, $resultArray); 337 | } 338 | 339 | /** 340 | * @test 341 | */ 342 | public function canSetChannel() 343 | { 344 | $context = [ 345 | 'animals' => '🐱🐶🐰🐱🐹', 346 | ]; 347 | 348 | $expectedChannel = 'My Favorite Animals'; 349 | 350 | $loggerBuilder = new LoggerBuilder(); 351 | $loggerBuilder->setChannel($expectedChannel); 352 | $logger = $loggerBuilder->build(); 353 | $logger->info('testCanSetChannel', $context); 354 | 355 | $resultJson = file_get_contents($this->defaultOutputFileName); 356 | $resultArray = json_decode($resultJson, true); 357 | 358 | echo "\n ---- Output Log Begin ---- \n"; 359 | echo json_encode($resultArray, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); 360 | echo "\n ---- Output Log End ---- \n"; 361 | 362 | $expectedLog = [ 363 | 'log_level' => 'INFO', 364 | 'message' => 'testCanSetChannel', 365 | 'channel' => $expectedChannel, 366 | 'trace_id' => $logger->getTraceId(), 367 | 'file' => __FILE__, 368 | 'line' => 353, 369 | 'context' => $context, 370 | 'remote_ip_address' => '127.0.0.1', 371 | 'server_ip_address' => '127.0.0.1', 372 | 'user_agent' => 'unknown', 373 | 'datetime' => $resultArray['datetime'], 374 | 'timezone' => date_default_timezone_get(), 375 | 'process_time' => $resultArray['process_time'], 376 | ]; 377 | 378 | $this->assertSame($expectedChannel, $logger->getChannel()); 379 | $this->assertSame($expectedLog, $resultArray); 380 | } 381 | } 382 | -------------------------------------------------------------------------------- /tests/Logger/NoticeTest.php: -------------------------------------------------------------------------------- 1 | outputFileBaseName = '/tmp/notice-log-test.log'; 32 | $this->outputFileName = '/tmp/notice-log-test-' . date('Y-m-d') . '.log'; 33 | 34 | if (file_exists($this->outputFileName)) { 35 | unlink($this->outputFileName); 36 | } 37 | } 38 | 39 | /** 40 | * @test 41 | * @throws \Exception 42 | */ 43 | public function outputNoticeLog() 44 | { 45 | $context = [ 46 | 'title' => 'Test', 47 | ]; 48 | 49 | $loggerBuilder = new LoggerBuilder(); 50 | $loggerBuilder->setFileName($this->outputFileBaseName); 51 | $loggerBuilder->setLogLevel(LoggerBuilder::DEBUG); 52 | $logger = $loggerBuilder->build(); 53 | $logger->notice('🐶', $context); 54 | 55 | $resultJson = file_get_contents($this->outputFileName); 56 | $resultArray = json_decode($resultJson, true); 57 | 58 | echo "\n ---- Output Log Begin ---- \n"; 59 | echo json_encode($resultArray, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); 60 | echo "\n ---- Output Log End ---- \n"; 61 | 62 | $expectedLog = [ 63 | 'log_level' => 'NOTICE', 64 | 'message' => '🐶', 65 | 'channel' => 'PhpJsonLogger', 66 | 'trace_id' => $logger->getTraceId(), 67 | 'file' => __FILE__, 68 | 'line' => 53, 69 | 'context' => $context, 70 | 'remote_ip_address' => '127.0.0.1', 71 | 'server_ip_address' => '127.0.0.1', 72 | 'user_agent' => 'unknown', 73 | 'datetime' => $resultArray['datetime'], 74 | 'timezone' => date_default_timezone_get(), 75 | 'process_time' => $resultArray['process_time'], 76 | ]; 77 | 78 | $this->assertSame('PhpJsonLogger', $logger->getChannel()); 79 | $this->assertSame($expectedLog, $resultArray); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /tests/Logger/SlackNotificationTest.php: -------------------------------------------------------------------------------- 1 | outputFileBaseName = '/tmp/slack-log-test.log'; 32 | $this->outputFileName = '/tmp/slack-log-test-' . date('Y-m-d') . '.log'; 33 | 34 | if (file_exists($this->outputFileName)) { 35 | unlink($this->outputFileName); 36 | } 37 | } 38 | 39 | /** 40 | * @test 41 | */ 42 | public function notificationToSlack() 43 | { 44 | $exception = new \Exception('TestException', 500); 45 | $context = [ 46 | 'name' => 'keitakn', 47 | 'email' => 'dummy@email.com', 48 | ]; 49 | 50 | $slackToken = getenv('PHP_JSON_LOGGER_SLACK_TOKEN', true) ?: getenv('PHP_JSON_LOGGER_SLACK_TOKEN'); 51 | $slackChannel = getenv('PHP_JSON_LOGGER_SLACK_CHANNEL', true) ?: getenv('PHP_JSON_LOGGER_SLACK_CHANNEL'); 52 | 53 | $slackHandlerBuilder = new SlackHandlerBuilder($slackToken, $slackChannel); 54 | $slackHandlerBuilder->setLevel(LoggerBuilder::CRITICAL); 55 | 56 | $_SERVER['REQUEST_URI'] = '/tests/notifications'; 57 | $_SERVER['REMOTE_ADDR'] = '192.168.10.10'; 58 | $_SERVER['REQUEST_METHOD'] = 'POST'; 59 | $_SERVER['SERVER_NAME'] = 'cat-moko.localhost'; 60 | $_SERVER['HTTP_REFERER'] = 'https://github.com/nekonomokochan/php-json-logger/issues/50'; 61 | $_SERVER['SERVER_ADDR'] = '10.0.0.11'; 62 | $_SERVER['HTTP_USER_AGENT'] = 'Chrome'; 63 | 64 | $loggerBuilder = new LoggerBuilder(); 65 | $loggerBuilder->setFileName($this->outputFileBaseName); 66 | $loggerBuilder->setSlackHandler($slackHandlerBuilder->build()); 67 | $logger = $loggerBuilder->build(); 68 | $logger->critical($exception, $context); 69 | 70 | unset($_SERVER['REQUEST_URI']); 71 | unset($_SERVER['REMOTE_ADDR']); 72 | unset($_SERVER['REQUEST_METHOD']); 73 | unset($_SERVER['SERVER_NAME']); 74 | unset($_SERVER['HTTP_REFERER']); 75 | unset($_SERVER['SERVER_ADDR']); 76 | unset($_SERVER['HTTP_USER_AGENT']); 77 | 78 | $resultJson = file_get_contents($this->outputFileName); 79 | $resultArray = json_decode($resultJson, true); 80 | 81 | echo "\n ---- Output Log Begin ---- \n"; 82 | echo json_encode($resultArray, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); 83 | echo "\n ---- Output Log End ---- \n"; 84 | 85 | $expectedLog = [ 86 | 'log_level' => 'CRITICAL', 87 | 'message' => 'Exception', 88 | 'channel' => 'PhpJsonLogger', 89 | 'trace_id' => $logger->getTraceId(), 90 | 'file' => __FILE__, 91 | 'line' => 68, 92 | 'context' => $context, 93 | 'remote_ip_address' => '192.168.10.10', 94 | 'server_ip_address' => '10.0.0.11', 95 | 'user_agent' => 'Chrome', 96 | 'datetime' => $resultArray['datetime'], 97 | 'timezone' => date_default_timezone_get(), 98 | 'process_time' => $resultArray['process_time'], 99 | 'errors' => [ 100 | 'message' => 'TestException', 101 | 'code' => 500, 102 | 'file' => __FILE__, 103 | 'line' => 44, 104 | 'trace' => $resultArray['errors']['trace'], 105 | ], 106 | ]; 107 | 108 | $this->assertSame('PhpJsonLogger', $logger->getChannel()); 109 | $this->assertSame($expectedLog, $resultArray); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /tests/Logger/WarningTest.php: -------------------------------------------------------------------------------- 1 | outputFileBaseName = '/tmp/warning-log-test.log'; 32 | $this->outputFileName = '/tmp/warning-log-test-' . date('Y-m-d') . '.log'; 33 | 34 | if (file_exists($this->outputFileName)) { 35 | unlink($this->outputFileName); 36 | } 37 | } 38 | 39 | /** 40 | * @test 41 | * @throws \Exception 42 | */ 43 | public function outputWarningLog() 44 | { 45 | $context = [ 46 | 'title' => 'Test', 47 | ]; 48 | 49 | $loggerBuilder = new LoggerBuilder(); 50 | $loggerBuilder->setFileName($this->outputFileBaseName); 51 | $loggerBuilder->setLogLevel(LoggerBuilder::DEBUG); 52 | $logger = $loggerBuilder->build(); 53 | $logger->warning('🐶', $context); 54 | 55 | $resultJson = file_get_contents($this->outputFileName); 56 | $resultArray = json_decode($resultJson, true); 57 | 58 | echo "\n ---- Output Log Begin ---- \n"; 59 | echo json_encode($resultArray, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); 60 | echo "\n ---- Output Log End ---- \n"; 61 | 62 | $expectedLog = [ 63 | 'log_level' => 'WARNING', 64 | 'message' => '🐶', 65 | 'channel' => 'PhpJsonLogger', 66 | 'trace_id' => $logger->getTraceId(), 67 | 'file' => __FILE__, 68 | 'line' => 53, 69 | 'context' => $context, 70 | 'remote_ip_address' => '127.0.0.1', 71 | 'server_ip_address' => '127.0.0.1', 72 | 'user_agent' => 'unknown', 73 | 'datetime' => $resultArray['datetime'], 74 | 'timezone' => date_default_timezone_get(), 75 | 'process_time' => $resultArray['process_time'], 76 | ]; 77 | 78 | $this->assertSame('PhpJsonLogger', $logger->getChannel()); 79 | $this->assertSame($expectedLog, $resultArray); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /tests/UseInDockerTest.php: -------------------------------------------------------------------------------- 1 | outputFileBaseName = '/tmp/docker-log-test.log'; 31 | $this->outputFileName = '/tmp/docker-log-test-' . date('Y-m-d') . '.log'; 32 | 33 | if (file_exists($this->outputFileName)) { 34 | unlink($this->outputFileName); 35 | } 36 | } 37 | 38 | /** 39 | * @test 40 | * @throws \Monolog\Handler\MissingExtensionException 41 | */ 42 | public function outputStdLogWithSetFileName() 43 | { 44 | $exception = new \Exception('testOutputStdLogWithSetFileName', 500); 45 | $context = [ 46 | 'name' => 'keitakn', 47 | 'email' => 'dummy@email.com', 48 | 'message' => 'testOutputStdLogWithSetFileName', 49 | ]; 50 | 51 | $slackToken = getenv('PHP_JSON_LOGGER_SLACK_TOKEN', true) ?: getenv('PHP_JSON_LOGGER_SLACK_TOKEN'); 52 | $slackChannel = getenv('PHP_JSON_LOGGER_SLACK_CHANNEL', true) ?: getenv('PHP_JSON_LOGGER_SLACK_CHANNEL'); 53 | 54 | $slackHandlerBuilder = new SlackHandlerBuilder($slackToken, $slackChannel); 55 | $slackHandlerBuilder->setLevel(LoggerBuilder::CRITICAL); 56 | 57 | $_SERVER['REQUEST_URI'] = '/tests/notifications'; 58 | $_SERVER['REMOTE_ADDR'] = '192.168.10.10'; 59 | $_SERVER['REQUEST_METHOD'] = 'POST'; 60 | $_SERVER['SERVER_NAME'] = 'cat-moko.localhost'; 61 | $_SERVER['HTTP_REFERER'] = 'https://github.com/nekonomokochan/php-json-logger/issues/50'; 62 | $_SERVER['SERVER_ADDR'] = '10.0.0.11'; 63 | $_SERVER['HTTP_USER_AGENT'] = 'Chrome'; 64 | 65 | $loggerBuilder = new LoggerBuilder(); 66 | $loggerBuilder->setFileName($this->outputFileBaseName); 67 | $loggerBuilder->setSlackHandler($slackHandlerBuilder->build()); 68 | $loggerBuilder->setUseInDocker(true); 69 | $logger = $loggerBuilder->build(); 70 | $logger->critical($exception, $context); 71 | 72 | unset($_SERVER['REQUEST_URI']); 73 | unset($_SERVER['REMOTE_ADDR']); 74 | unset($_SERVER['REQUEST_METHOD']); 75 | unset($_SERVER['SERVER_NAME']); 76 | unset($_SERVER['HTTP_REFERER']); 77 | unset($_SERVER['SERVER_ADDR']); 78 | unset($_SERVER['HTTP_USER_AGENT']); 79 | 80 | $this->assertFalse(file_exists($this->outputFileName)); 81 | } 82 | 83 | /** 84 | * @test 85 | * @throws \Monolog\Handler\MissingExtensionException 86 | */ 87 | public function outputStdLogWithNoSetFileName() 88 | { 89 | $exception = new \Exception('testOutputStdLogWithNoSetFileName', 500); 90 | $context = [ 91 | 'name' => 'keitakn', 92 | 'email' => 'dummy@email.com', 93 | 'message' => 'testOutputStdLogWithNoSetFileName', 94 | ]; 95 | 96 | $slackToken = getenv('PHP_JSON_LOGGER_SLACK_TOKEN', true) ?: getenv('PHP_JSON_LOGGER_SLACK_TOKEN'); 97 | $slackChannel = getenv('PHP_JSON_LOGGER_SLACK_CHANNEL', true) ?: getenv('PHP_JSON_LOGGER_SLACK_CHANNEL'); 98 | 99 | $slackHandlerBuilder = new SlackHandlerBuilder($slackToken, $slackChannel); 100 | $slackHandlerBuilder->setLevel(LoggerBuilder::CRITICAL); 101 | 102 | $_SERVER['REQUEST_URI'] = '/tests/notifications'; 103 | $_SERVER['REMOTE_ADDR'] = '192.168.10.10'; 104 | $_SERVER['REQUEST_METHOD'] = 'POST'; 105 | $_SERVER['SERVER_NAME'] = 'cat-moko.localhost'; 106 | $_SERVER['HTTP_REFERER'] = 'https://github.com/nekonomokochan/php-json-logger/issues/50'; 107 | $_SERVER['SERVER_ADDR'] = '10.0.0.11'; 108 | $_SERVER['HTTP_USER_AGENT'] = 'Chrome'; 109 | 110 | $loggerBuilder = new LoggerBuilder(); 111 | $loggerBuilder->setSlackHandler($slackHandlerBuilder->build()); 112 | $loggerBuilder->setUseInDocker(true); 113 | $logger = $loggerBuilder->build(); 114 | $logger->critical($exception, $context); 115 | 116 | unset($_SERVER['REQUEST_URI']); 117 | unset($_SERVER['REMOTE_ADDR']); 118 | unset($_SERVER['REQUEST_METHOD']); 119 | unset($_SERVER['SERVER_NAME']); 120 | unset($_SERVER['HTTP_REFERER']); 121 | unset($_SERVER['SERVER_ADDR']); 122 | unset($_SERVER['HTTP_USER_AGENT']); 123 | 124 | $this->assertFalse(file_exists($this->outputFileName)); 125 | } 126 | } 127 | --------------------------------------------------------------------------------