Craft 3 plugins - Logging in a separate *.log file In Craft 2, it was possible to have your plugin log to a separate file. For example, it would record items to a myplugin.log file. You would simply be able to do it like this...

MyPlugin::log('Lorem ipsum');


However, I can't seem to figure out how this would be done in Craft 3. I've seen this answer, which demonstrates how to log items in Craft 3 in general. But that just dumps items into the shared web.log file.

How can I log items to myplugin.log in Craft 3?
Edit 2

I came up with a far far far better approach after a little brainstorming. I'll keep my old answer here but you should probably just use the first snipped.

In your main Pluginfile.php

public static function log($message){
    Craft::getLogger()-&gt;log($message, \yii\log\Logger::LEVEL_INFO, 'your-plugin-handle');
}

public function init(){
    $fileTarget = new \craft\log\FileTarget([
        'logFile' =&gt; __DIR__ . '/pluginName.log', // &lt;--- path of the log file
        'categories' =&gt; ['your-plugin-handle'] // &lt;--- categories in the file
    ]);
    // include the new target file target to the dispatcher
    Craft::getLogger()-&gt;dispatcher-&gt;targets[] = $fileTarget;
    ....
}


Explanation: categories is an array of all categories that should be in the log file. You usually want to allow only categories of your own plugin (you have to use an unique identifier in case certain other developers try to add the same category). Whenever you want to log something with the Craft/Yii log method that match one of your given categories in the array it will be logged in your file as well.

Old answer

Create this file somewhere in your plugin

FileTarget

class FileTarget extends \yii\log\FileTarget{

    // an array of categories that should be logged
    // note: your target receives all `Yii::log()` messages
    // but you can filter them with this array
    // if you want to track all messages of type 'application' as well
    // just include it in the array
    public $categories = ['a-category-that-you-would-like-to-log']; //&lt;- usually your plugin handle or something

    // set the file path
    public function setLogFile($path = __DIR__){
        // I'm lazy so I just use the current location since it's in my 'src/' folder anyway 
        // you can use Crafts default folders or whatever you like
        $this-&gt;logFile = $path . '/test.log';
        return $this;
    }

    // Optional -&gt; a callback that formats your messages
    // remove this function if there is
    // no formatting needed or if you want to use the default
    public function formatMessage($message)
    {
        list($text, $level, $category, $timestamp) = $message;
        $level = 'Your fancy plugin Name';

        if ($category == 'a-category-that-you-would-like-to-log') {
            return date('Y-m-d H:i:s', $timestamp) . " [$level][$category] $text";
        }
    }
}


In your Plugin main file

public static $_fileTarget;

public static function log($message){
    if(self::$_fileTarget === null){
        /** @var FileTarget _fileTarget */
        self::$_fileTarget = Craft::createObject('namespace\pluginhandle\filetarget');
        // set the path
        self::$_fileTarget-&gt;setLogFile();
        // include your target to the current dispatcher targets 
        // -&gt; all messages are tracked in your target as well. 
        Craft::getLogger()-&gt;dispatcher-&gt;targets[] = self::$_fileTarget;
    }

    // just use the default Craft/Yii logging method but with your category
    Craft::getLogger()-&gt;log($message, \yii\log\Logger::LEVEL_INFO, 'a-category-that-you-would-like-to-log');
}


Usage

Plugin::log('Lorem ipsum');
Craft::getLogger()-&gt;log('Lorem ipsum', \yii\log\Logger::LEVEL_INFO, 'a-category-that-you-would-like-to-log');
Craft::info('Lorem ipsum', 'a-category-that-you-would-like-to-log');


Maybe we could create a feature/pull request in order to create this feature by default. So every Plugin receives it's own category (by plugin handle) and if these categories are recognized the logger logs them in a separate file

Edit (thanks Andrew for mentioning it):

Note with this method I just add an additional target to the dispatcher that creates log files. So you'll insert 2 messages: one in the default storage/logs folder together with all the other requests and one in you custom log folder thus you are still able to use the great Yii2 Debug Toolbar and you can ask clients to hand over their plugin related logs to see what's going on