Logging in Long running Console app

Hi, all

I’ve searched and I can’t seem to find the solution in this forum.

I have a console command running forever for some reason.

And the problem is I want to log something every loop but the log doesn’t show immediately




class EmailCommand extends CConsoleCommand {

    

    public function run($args) {

	for(;<img src='http://www.yiiframework.com/forum/public/style_emoticons/default/wink.gif' class='bbc_emoticon' alt=';)' /> {

		Yii::log('Something');

	}

    }

}



Is there any solution?

You can access the logger object this way:


$log = Yii::getLogger();

Check out the logger API, there you’ll find properties/methods on how to flush the log manually or after x messages.

I have tried both




    public function run($args) {

        Yii::getLogger()->autoFlush = 1;

        for (;<img src='http://www.yiiframework.com/forum/public/style_emoticons/default/wink.gif' class='bbc_emoticon' alt=';)' />{

            Yii::log('Something');

        }

    }



and




    public function run($args) {

        for (;<img src='http://www.yiiframework.com/forum/public/style_emoticons/default/wink.gif' class='bbc_emoticon' alt=';)' />{

            Yii::log('Something');

            Yii::getLogger()->flush();

        }

    }



Still nothing happened.

Alter the autoFlash property or call flush() manually after each log entry. This will trigger the onFlush event of your logger and send the collected log entries to your configured log routes.

EDIT: Sorry, didn’t read that Y!! suggested the same. Sure you’ve configured some log routes in your console config?

Of course I’m sure




    public function run($args) {

        Yii::log('Something');

    }



works perfectly,

have you tried yourself?

Aah, the problem seem to be in CLogRouter::collectLogs(). It calls collectLogs($logger,false) for all log routes. The false parameter tells the route not to process the log entries immediately. So the routes will collect the logs first and only log onEndRequest again. I think, there’s no simple way to circumvent this.

But you could try to write your custom LogRouter (extends CLogRouter) and override the collectLogs() method there. You’ll maybe have to flush the log route’s $log property, too, each time you process the logs.

I just tried alter the CLogRouter::collectLogs(). You mean like this, right?




	public function collectLogs($event)

	{

		$logger=Yii::getLogger();

		foreach($this->_routes as $route)

		{

			if($route->enabled) {

				$route->collectLogs($logger,true);

                                $route->logs = array();

                        }

		}

	}



It’s working quite fine, though.

Yes, looks good to me.

Okay, the problem is solved until some issues are found :lol: :lol:

Just found a problem, the logger didn’t work well if I use more than one logroute (CFileLogRoute and CDbLogRoute). And it didn’t work at all when I use only CDbLogRoute.

Just to make sure: And CDbLogRoute works in the console app if you don’t use the custom code and without the loop?

The original CLogRouter works fine only with




        public function run($args) {

            Yii::log('Something');            

        }



either with CFileLogRoute or CDbLogRoute or both,

but doesn’t work within the infinite loop.

If I use the CFileLogRoute with the custom CLogRouter, the logger works quite fine. But the CDbLogRoute alone doesn’t work not to mention when they’re both used.

Anyone has solution?

You can try and add new method and event to CLogger like


	/**

	 * Custom method

	 */

	public function flushSave()

	{

		$this->onFlushAndWrite(new CEvent($this));

		$this->_logs=array();

		$this->_logCount=0;

	}


	/**

	 * Custom method

	 */

	public function onFlushAndWrite($event)

	{

		$this->raiseEvent('onFlushAndWrite', $event);

	}

Then you can add eventhandler to this new event( in CLogRouter )

like this


Yii::getLogger()->attachEventHandler('onFlushAndWrite',array($this,'processLogs'));

This worked out for me.

Also, you can try it


class TestCommand extends CConsoleCommand

{

	public function run($args)

	{

		Yii::getLogger()->autoFlush = 1;

		Yii::getLogger()->attachEventHandler('onFlush',array(Yii::app()->log,'processLogs'));

		parent::run($args);

	}


}

Unfortunately, my previous solution does not work well.

See updated version:


class TestCommand extends CConsoleCommand

{


	public function run($args)

	{

		Yii::getLogger()->autoFlush = 10;

		Yii::getLogger()->detachEventHandler('onFlush',array(Yii::app()->log,'collectLogs'));

		Yii::getLogger()->attachEventHandler('onFlush',array($this,'processLogs'));

		parent::run($args);

	}


	public function processLogs($event)

	{

		static $routes;

		$logger = Yii::getLogger();

		$routes = isset($routes) ? $routes : Yii::app()->log->getRoutes();

		foreach($routes as $route)

		{

			if($route->enabled)

			{

				$route->collectLogs($logger,true);

				$route->logs = array();

			}

		}

	}

}

does it work on multiple log route?

Yes, the solution works perfectly.

I checked with CFileLogRoute and CDbLogRoute

Note! If using CDbLogRoute [b]YII_DEBUG[/b] must be defined to FALSE and [b]YII_TRACE_LEVEL[/b] set to 0

Vitaliy

Would be great if you’ll share your code via wiki or extension.

samdark

No problem, I’ll write a short article on wiki.