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()->log($message, \yii\log\Logger::LEVEL_INFO, 'your-plugin-handle');
}
public function init(){
$fileTarget = new \craft\log\FileTarget([
'logFile' => __DIR__ . '/pluginName.log', // <--- path of the log file
'categories' => ['your-plugin-handle'] // <--- categories in the file
]);
// include the new target file target to the dispatcher
Craft::getLogger()->dispatcher->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']; //<- 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->logFile = $path . '/test.log';
return $this;
}
// Optional -> 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->setLogFile();
// include your target to the current dispatcher targets
// -> all messages are tracked in your target as well.
Craft::getLogger()->dispatcher->targets[] = self::$_fileTarget;
}
// just use the default Craft/Yii logging method but with your category
Craft::getLogger()->log($message, \yii\log\Logger::LEVEL_INFO, 'a-category-that-you-would-like-to-log');
}
Usage
Plugin::log('Lorem ipsum');
Craft::getLogger()->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