traceLevel for targets

Hi,everyone!

I need that each of targets of the log component has own traceLevel.

My config is here




return [

    'traceLevel' => 6,

    'targets' => [


        [

            'class' => 'yii\log\FileTarget',

            'categories' => ['application'],

            'levels' => ['error', 'warning', 'info'],

            'logFile' => "@app/runtime/logs/app.log",

            'logVars' => [],

        ],


        [

            'class' => 'yii\log\FileTarget'

            'categories' => ['catalog-add'],

            'levels' => ['error', 'warning', 'info'],

            'logFile' => '@app/runtime/logs/catalog.log',

            'logVars' => [],

        ]

    ]

]    



Currently trace Level = 6, which means that the trace be displayed in both files: app.log and catalog.log. I need that catalog.log has traceLevel = 0.

How can I do that?

You can prepare your Target class that extends Filetarget and configure the target to use this class.

Inside you can set traceLevel to 0.

Hi, Bizley! Thanks for your answer. Can you explain something? traceLevel is not property of Target class, it is property of Logger class. How exactly i can set traceLevel to 0 in my Target class?

I think adding it in init() method should be enough.




public function init()

{

    parent::init();

    Yii::$app->log->traceLevel = 0;

}



Thank you for your solution. I’ve checked this case. Method init() of all Target classes executed when component Dispatcher in the initialization. This happens only once throughout the application life.

The following sample code:




 \Yii::error('test', 'catalog-add'); // traceLevel = 0 (conformity to the requirements)

 \Yii::error('test'); // ignored 'traceLevel' => 6 in config file, because traceLevel was set to 0 in init method



As a result, both of log files has no trace.

Mmm… right… Looks like you can not do it without modifying the Logger class or adding another log component with different trace level.

Bizley, thanks for your support, I solved my problem in this way:

I created ExtendedFileTarget class that extends FileTarget. In the class I overrided method formatMessage from Target class and added traceLevel as property of class.




class ExtendedFileTarget extends FileTarget 

{


    public $traceLevel = 0;


    public function formatMessage($message)

    {

        list($text, $level, $category, $timestamp) = $message;

        $level = Logger::getLevelName($level);

        if (!is_string($text)) {

            if ($text instanceof \Exception) {

                $text = (string) $text;

            } else {

                $text = VarDumper::export($text);

            }

        }

        $traces = [];

        if (isset($message[4]) && $this->traceLevel > 0) {

            $count = 0;

            foreach ($message[4] as $trace) {

                $traces[] = "in {$trace['file']}:{$trace['line']}";

                if (++$count >= $this->traceLevel) {

                    break;

                }

            }

        }


        $prefix = $this->getMessagePrefix($message);

        return date('Y-m-d H:i:s', $timestamp) . " {$prefix}[$level][$category] $text"

        . (empty($traces) ? '' : "\n    " . implode("\n    ", $traces));

    }

}



With this code I can configurate my log.php file as like that:




return [

    'traceLevel' => 20,

    'targets' => [


        [

            'class' => 'app\components\log\ExtendedFileTarget',

            'categories' => ['application'],

            'levels' => ['error', 'warning', 'info'],

            'logFile' => "@app/runtime/logs/app.log",

            'traceLevel' => 6,

            'logVars' => [],

        ],


        [

            'class' => 'app\components\log\ExtendedFileTarget'

            'categories' => ['catalog-add'],

            'levels' => ['error', 'warning', 'info'],

            'traceLevel' => 0, 

            'logFile' => '@app/runtime/logs/catalog.log',

            'logVars' => [],

        ]

    ]

]    



This case has only one problem: I can’t set value of traceLevel in Target more than traceLevel in Logger class. It means, that value of traceLevel from Logger class is maximum for all targets. But this situation satisfy me in this task

It’s quite interesting approach indeed.

Only problem here might be with the performance - logger gathers all tracelevels first in every case and then it is limited when sending to target #0 but I understand you balance it properly.