Giter Site home page Giter Site logo

samdark / yii2-psr-log-target Goto Github PK

View Code? Open in Web Editor NEW
77.0 9.0 17.0 41 KB

Yii 2.0 log target that is able to write messages to PSR-3 compatible logger

License: BSD 3-Clause "New" or "Revised" License

PHP 100.00%
yii2 yii2-extension psr-3 log logging logger

yii2-psr-log-target's Introduction

Yii 2 PSR Log Target

Allows you to process logs using any PSR-3 compatible logger such as Monolog.

Latest Stable Version Total Downloads Build Status Code Coverage Scrutinizer Quality Score

Installation

composer require "samdark/yii2-psr-log-target"

Usage

In order to use PsrTarget you should configure your log application component like the following:

// $psrLogger should be an instance of PSR-3 compatible logger.
// As an example, we'll use Monolog to send log to Slack.
$psrLogger = new \Monolog\Logger('my_logger');
$psrLogger->pushHandler(new \Monolog\Handler\SlackHandler('slack_token', 'logs', null, true, null, \Monolog\Logger::DEBUG));

return [
    // ...
    'bootstrap' => ['log'],    
    // ...    
    'components' => [
        // ...        
        'log' => [
            'targets' => [
                [
                    'class' => 'samdark\log\PsrTarget',
                    'logger' => $psrLogger,
                    
                    // It is optional parameter. The message levels that this target is interested in.
                    // The parameter can be an array.
                    'levels' => ['info', yii\log\Logger::LEVEL_WARNING, Psr\Log\LogLevel::CRITICAL],
                    // It is optional parameter. Default value is false. If you use Yii log buffering, you see buffer write time, and not real timestamp.
                    // If you want write real time to logs, you can set addTimestampToContext as true and use timestamp from log event context.
                    'addTimestampToContext' => true,
                ],
                // ...
            ],
        ],
    ],
];

Standard usage:

Yii::info('Info message');
Yii::error('Error message');

Usage with PSR logger levels:

Yii::getLogger()->log('Critical message', Psr\Log\LogLevel::CRITICAL);
Yii::getLogger()->log('Alert message', Psr\Log\LogLevel::ALERT);

Usage with original timestamp from context in the log:

// $psrLogger should be an instance of PSR-3 compatible logger.
// As an example, we'll use Monolog to send log to Slack.
$psrLogger = new \Monolog\Logger('my_logger');

$psrLogger->pushProcessor(function($record) {
    if (isset($record['context']['timestamp'])) {
        $dateTime = DateTime::createFromFormat('U.u', $record['context']['timestamp']);
        $timeZone = $record['datetime']->getTimezone();
        $dateTime->setTimezone($timeZone);
        $record['datetime'] = $dateTime;

        unset($record['context']['timestamp']);
    }

    return $record;
});

You can use PsrMessage instead of regular string messages to add custom context.

Standard usage:

Yii::error(new \samdark\log\PsrMessage("Critical message", [
    'custom' => 'context',
    'key' => 'value',
]));

Usage with PSR logger Levels:

Yii::getLogger()->log(new \samdark\log\PsrMessage("Critical message", [
    'important' => 'context'
]), Psr\Log\LogLevel::CRITICAL);

Usage with PSR-3 log message processing:

$psrLogger = new \Monolog\Logger('my_logger');
$psrLogger->pushProcessor(new \Monolog\Processor\PsrLogMessageProcessor());
Yii::debug(new \samdark\log\PsrMessage("Greetings from {fruit}", [
    'fruit' => 'banana'
]));

Running tests

In order to run tests perform the following commands:

composer install
./vendor/bin/phpunit

yii2-psr-log-target's People

Contributors

arturf avatar de-salvatierra avatar dependabot[bot] avatar gusiushub avatar ilyaplot avatar mrodikov avatar patrick-yi-82 avatar rodion-k avatar samdark avatar terabytesoftw avatar versh23 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

yii2-psr-log-target's Issues

Context message doesn't have memory and trace fields -> causing notice

I see some notices:

[Thu Mar 16 12:51:57.852657 2017] [php7:notice] [pid 7] [client 172.22.0.1:42976] PHP Notice:  Undefined offset: 5 in /var/www/html/vendor/samdark/yii2-psr-log-target/src/PsrTarget.php on line 57
[Thu Mar 16 12:51:57.852694 2017] [php7:notice] [pid 7] [client 172.22.0.1:42976] PHP Notice:  Undefined offset: 4 in /var/www/html/vendor/samdark/yii2-psr-log-target/src/PsrTarget.php on line 58

Allow to pass closure as logger configuration option

currently you need to pass monolog logger instance inside config file. this is unfortunate as logger is created for each request even in situations where nothing is logged. also you cannot use Yii aliases to configure monolog handlers.

Context message get lost

With the following config:

[
    'class' => \samdark\log\PsrTarget::class,
    'logger' => $psrLogger,
    'levels' => ['error', 'warning'],
]

I want to receive only errors and warnings, but also context message, as I receive to email (\yii\log\EmailTarget) with same config.
Now errors and warnings are sent to prsLogger, but context message filtered by the following line:

if (!isset($this->_levels[$level])) {
    continue;
}

because it has info level

More readable message for exceptions

Right now log messages are a bit verbose. My propose is to update export method with next change:

-- $text = (string)$text;
++ $context['trace'] = explode(PHP_EOL, $text->getTraceAsString());
++ $text = $text->getMessage();

getTrace()does not work in some cases.

Before:

{
  "message": "yii\\db\\Exception: Some exception message in /home/app/components/Registry.php:64\nStack trace:\n#0 /home/vendor/yiisoft/yii2/base/BaseObject.php(109): app\\components\\Registry->init()\n#1 [internal function]: yii\\base\\BaseObject->__construct(Array)\n#2 /home/vendor/yiisoft/yii2/di/Container.php(392): ReflectionClass->newInstanceArgs(Array)\n#3 /home/vendor/yiisoft/yii2/di/Container.php(159): yii\\di\\Container->build('app\\\\components\\\\...', Array, Array)\n#4 /home/vendor/yiisoft/yii2/BaseYii.php(351): yii\\di\\Container->get('app\\\\components\\\\...', Array, Array)\n#5 /home/vendor/yiisoft/yii2/di/ServiceLocator.php(137): yii\\BaseYii::createObject(Array)\n#6 /home/vendor/yiisoft/yii2/base/Module.php(742): yii\\di\\ServiceLocator->get('registry', true)\n#7 /home/vendor/yiisoft/yii2/di/ServiceLocator.php(74): yii\\base\\Module->get('registry')\n#8 /home/app/modules/api/controllers/RegistryController.php(21): yii\\di\\ServiceLocator->__get('registry')\n#9 [internal function]: app\\modules\\api\\controllers\\RegistryController->actionIndex()\n#10 /home/vendor/yiisoft/yii2/base/InlineAction.php(57): call_user_func_array(Array, Array)\n#11 /home/vendor/yiisoft/yii2/base/Controller.php(157): yii\\base\\InlineAction->runWithParams(Array)\n#12 /home/vendor/yiisoft/yii2/base/Module.php(528): yii\\base\\Controller->runAction('', Array)\n#13 /home/vendor/yiisoft/yii2/web/Application.php(103): yii\\base\\Module->runAction('api/registry', Array)\n#14 /home/vendor/yiisoft/yii2/base/Application.php(386): yii\\web\\Application->handleRequest(Object(yii\\web\\Request))\n#15 /home/web/index.php(20): yii\\base\\Application->run()\n#16 {main}\nAdditional Information:\nArray\n(\n)\n",
  "context": {
    "trace": []
}
}

After:

{
  "message": "Some exception message",
  "context": {
    "trace": [
      "#0 /home/vendor/yiisoft/yii2/base/BaseObject.php(109): app\\components\\Registry->init()",
      "#1 [internal function]: yii\\base\\BaseObject->__construct(Array)",
      "#2 /home/vendor/yiisoft/yii2/di/Container.php(392): ReflectionClass->newInstanceArgs(Array)",
      "#3 /home/vendor/yiisoft/yii2/di/Container.php(159): yii\\di\\Container->build('app\\\\components\\\\...', Array, Array)",
      "#4 /home/vendor/yiisoft/yii2/BaseYii.php(351): yii\\di\\Container->get('app\\\\components\\\\...', Array, Array)",
      "#5 /home/vendor/yiisoft/yii2/di/ServiceLocator.php(137): yii\\BaseYii::createObject(Array)",
      "#6 /home/vendor/yiisoft/yii2/base/Module.php(742): yii\\di\\ServiceLocator->get('registry', true)",
      "#7 /home/vendor/yiisoft/yii2/di/ServiceLocator.php(74): yii\\base\\Module->get('registry')",
      "#8 /home/app/modules/api/controllers/RegistryController.php(21): yii\\di\\ServiceLocator->__get('registry')",
      "#9 [internal function]: app\\modules\\api\\controllers\\RegistryController->actionIndex()",
      "#10 /home/vendor/yiisoft/yii2/base/InlineAction.php(57): call_user_func_array(Array, Array)",
      "#11 /home/vendor/yiisoft/yii2/base/Controller.php(157): yii\\base\\InlineAction->runWithParams(Array)",
      "#12 /home/vendor/yiisoft/yii2/base/Module.php(528): yii\\base\\Controller->runAction('', Array)",
      "#13 /home/vendor/yiisoft/yii2/web/Application.php(103): yii\\base\\Module->runAction('api/registry', Array)",
      "#14 /home/vendor/yiisoft/yii2/base/Application.php(386): yii\\web\\Application->handleRequest(Object(yii\\web\\Request))",
      "#15 /home/web/index.php(20): yii\\base\\Application->run()",
      "#16 {main}"
    ]
}

What do you think about this? If ok, I'll create a pull request.

Logging with PSR log levels breaks built-in log targets

What steps will reproduce the problem?

  1. Configure logging with a built-in target such as yii\log\FileTarget set to handle built-in log levels ['error', 'warning', 'info', 'trace']
  2. Then add a PsrTarget that handles some built-ins as well as a level that is not built-in, such as ['error', 'warning', \Psr\Log\LogLevel::NOTICE]
  3. Call Yii::getLogger()->log('some message', \Psr\Log\LogLevel::NOTICE);

What is the expected result?

  • The FileTarget is skipped because it does not handle the level of \Psr\Log\LogLevel::NOTICE
  • The PsrTarget gets a NOTICE log containing 'some message'

What do you get instead?

The PsrTarget receives the following warning-level log:

WARNING: Unable to send log via yii\log\FileTarget: PHP Warning 'yii\base\ErrorException' with message 'A non-numeric value encountered' 
in /app/vendor/yiisoft/yii2/log/Target.php:256
Stack trace:
#0 /app/vendor/yiisoft/yii2/log/Target.php(256): yii\base\ErrorHandler->handleError(2, 'A non-numeric v...', '/app/vendor/yii...', 256, Array)
#1 /app/vendor/yiisoft/yii2/log/Target.php(148): yii\log\Target::filterMessages(Array, 15, Array, Array)
#2 /app/vendor/yiisoft/yii2/log/Dispatcher.php(191): yii\log\Target->collect(Array, false)
#3 /app/vendor/yiisoft/yii2/log/Logger.php(227): yii\log\Dispatcher->dispatch(Array, false)
#4 /app/vendor/yiisoft/yii2/log/Logger.php(138): yii\log\Logger->flush()
#5 [internal function]: yii\log\Logger->yii\log\{closure}()
#6 {main}

This is because yii\log\Target::filterMessages() is expecting the message's level value ($message[1] in that function) to be a numeric like one of the built-in level constants, but some of the PSR levels are strings that it does not have a numeric equivalent for, therefore the & operator errors out.

Additional info

Q A
Version 1.1.3
PHP version 7.3
Yii version 2.0.43
Operating system Ubuntu

I realize the workaround would be to use only PsrTargets -- for example, replacing FileTarget with the equivalent file handler in Monolog -- but this shouldn't be necessary. However, this is the solution I've gone with for now.

I did consider that this bug might should be filed on the main Yii project -- however the built-in logging functionality isn't broken until this library comes into the picture. So I wasn't sure.

In my opinion, a good fix that doesn't involve adding core support for all PSR levels would be support for arbitrary log levels (targeted in userland code using Yii::getLogger()->log()), and maybe only translate the built-in ones to binary values. Or only use & on the levels if $message[1] is numeric, and do something else if not.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.