8

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?

10

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

  • 1
    Niiiiice. A PR for this would be awesome. There are support cases where asking the user to send you just your plugin's log file would be very useful. – andrew.welch Apr 1 '18 at 21:46
  • Hi Robin. Thanks for this. I must be missing something - I add the static log function in the main plugin file, then in init() I add the new log location to the dispatcher (and it shows up in the dispatcher targets array) but then calling it with (in my case) NewsletterSignup::log(); results in it being written to the web log only... not the new plugin log. Is there something missing from your static log method? It doesn't look like it does anything other than write to the Craft log? Thanks in advance! – JamesNZ Jun 19 '18 at 3:01
  • What is your file location? Maybe you didn't specify a valid path? – Robin Schambach Jun 19 '18 at 4:53
  • Hi Robin. The file location is the same as the example, which maps to /Users/me/Projects/project-name/src/plugins/newslettersignup/src/NewsletterSignup.log. I tried creating the file and setting it to 777 just to rule out permissions. Didn't make a difference. The path is definitely correct and points to a file (despite me having had created it). Thanks. – JamesNZ Jun 19 '18 at 22:56
  • 2
    Rather than writing to your plugin's directory you can write to Craft's storage directory: 'logFile' => Craft::getAlias('@storage/logs/pluginhandle.log'), – John D Wells Aug 21 '18 at 14:22
5

Another perhaps simpler approach is to write to your own log file without using the Craft logger at all.

$file = Craft::getAlias('@storage/logs/pluginhandle.log');
$log = date('Y-m-d H:i:s').' '.$message."\n";

\craft\helpers\FileHelper::writeToFile($file, $log, ['append' => true]);
  • That's pretty slick! Just circumvent the whole system. – Lindsey D Oct 5 '18 at 22:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.