I'd like Symfony to log the Doctrine SQL queries that one of my tasks executes to a log file, much like the web debug toolbar does for non-cli code. Is this possible?
Symfony version: 1.4.12
Doctrine version: 1.2.4
Here's some example code for a task. I would like the SELECT query to be logged in a similar way to how it would be if it was called from an action.
class exampleTask extends sfBaseTask
{
protected function configure()
{
parent::configure();
$this->namespace = 'test';
$this->name = 'example';
}
protected function execute($arguments = array(), $options = array())
{
$databaseManager = new sfDatabaseManager($this->configuration);
$users = Doctrine_Core::getTable('SfGuardUser')
->createQuery('s')
->select('s.first_name')
->execute();
foreach($users as $user) {
print $user->getFirstName()."\n";
}
}
}
Try using the global task option --trace (shortcut -t). Like:
./symfony --trace namespace:task
It logs database queries the moment they are executed.
Don't forget to enable logging in the settings.yml of the application you're running the task in.
So if you're running the task in the dev environment of the backend you would edit apps/backend/config/settings.yml:
dev:
.settings:
logging_enabled: true
Note that this also logs stack traces of exception which might also be very helpful if you need to debug your tasks.
If you turn logging on all queries should be logged to your application log in the log directory. To do this set logging_enabled to true in your settings.yml.
You can then tail -f on the logfile and see what's going on.
The following link contains a nice tutorial on how to enable logging of the Doctrine queries. (translated from the original portuguese to english)
http://translate.google.com/translate?js=n&prev=_t&hl=en&ie=UTF-8&layout=2&eotf=1&sl=pt&tl=en&u=http%3A%2F%2Fwww.michaelpaul.com.br%2Flog-queries-doctrine.html&act=url
Related
I setup a Unit Test in a Shopware custom (static) Plugin following this guide:
Shopware documentation
Everything runs fine and I'm able to run a unit test
class ProductReturnsTest extends TestCase
{
use IntegrationTestBehaviour;
use StorefrontPageTestBehaviour;
public function testConfirmPageSubscriber(): void
{
$container = $this->getKernel()->getContainer();
$dd = $container->get(CustomDataService::class); <== IT BREAKS HERE ServiceNotFoundException: You have requested a non-existent service
$dd = $container->get('event_dispatcher'); // WORKS WITH SHOPWARE ALIASES NOT WITH PLUGINS
}
}
I can make container->get on any shopware alias but as soon I try to recall and get from the container any service decleared in any xml of any 3th party plugin, i get
ServiceNotFoundException: You have requested a non-existent service "blabla"
What is wrong ?
Take a look at the answer given here: https://stackoverflow.com/a/70171394/10064036.
Probably your plugin is not marked as active in the DB your tests run against.
The test environment has a mostly unpopulated database to allow tests to to run unaffected with their own fixtures only. Therefore after each test there should be a rollback to all transactions made within the test. This principle also includes plugin installations and database transactions they may execute in their lifecycle events.
You may want to install your plugin properly before your tests, so you get a representative state of the environment with the plugins lifecycle events getting dispatched and thereby caused possible changes.
public function setUp(): void
{
$this->installPlugin();
}
private function installPlugin(): void
{
$application = new Application($this->getKernel());
$installCommand = $application->find('plugin:install');
$args = [
'--activate' => true,
'--reinstall' => false,
'plugins' => ['YourPluginName'],
];
$installCommand->run(new ArrayInput($args, $installCommand->getDefinition()), new NullOutput());
}
There are two noisy console commands in my Laravel 5.3 app that I want to keep logs for but would prefer to have them write to a different log file from the rest of the system.
Currently my app writes logs to a file configured in bootstrap/app.php using $app->configureMonologUsing(function($monolog) { ...
Second prize is writing all console commands to another log file, but ideally just these two.
I tried following these instructions (https://blog.muya.co.ke/configure-custom-logging-in-laravel-5/ and https://laracasts.com/discuss/channels/general-discussion/advance-logging-with-laravel-and-monolog) to reroute all console logs to another file but it did not work and just caused weird issues in the rest of the code.
If this is still the preferred method in 5.3 then I will keep trying, but was wondering if there was newer method or a method to only change the file for those two console commands.
They are two approaches you could take
First, you could use Log::useFiles or Log::useDailyFiles like suggests here.
Log::useDailyFiles(storage_path().'/logs/name-of-log.log');
Log::info([info to log]);
The downside of this approach is that everything will still be log in your default log file because the default Monolog is executed before your code.
Second, to avoid to have everything in your default log, you could overwrite the default logging class. An exemple of this is given here. You could have a specific log file for let's say Log::info() and all the others logs could be written in your default file. The obvious downside of this approach is that it requires more work and code maintenance.
This is possible but first you need to remove existing handlers.
Monolog already has had some logging handlers set, so you need to get rid of those with $monolog->popHandler();. Then using Wistar's suggestion a simple way of adding a new log is with $log->useFiles('/var/log/nginx/ds.console.log', $level='info');.
public function fire (Writer $log)
{
$monolog = $log->getMonolog();
$monolog->popHandler();
$log->useFiles('/var/log/nginx/ds.console.log', $level='info');
$log->useFiles('/var/log/nginx/ds.console.log', $level='error');
...
For multiple handlers
If you have more than one log handler set (if for example you are using Sentry) you may need to pop more than one before the handlers are clear. If you want to keep a handler, you need to loop through all of them and then readd the ones you wanted to keep.
$monolog->popHandler() will throw an exception if you try to pop a non-existant handler so you have to jump through hoops to get it working.
public function fire (Writer $log)
{
$monolog = $log->getMonolog();
$handlers = $monolog->getHandlers();
$numberOfHandlers = count($handlers);
$saveHandlers = [];
for ($idx=0; $idx<$numberOfHandlers; $idx++)
{
$handler = $monolog->popHandler();
if (get_class($handler) !== 'Monolog\Handler\StreamHandler')
{
$saveHandlers[] = $handler;
}
}
foreach ($saveHandlers as $handler)
{
$monolog->pushHandler($handler);
}
$log->useFiles('/var/log/nginx/ds.console.log', $level='info');
$log->useFiles('/var/log/nginx/ds.console.log', $level='error');
...
For more control over the log file, instead of $log->useFiles() you can use something like this:
$logStreamHandler = new \Monolog\Handler\StreamHandler('/var/log/nginx/ds.console.log');
$pid = getmypid();
$logFormat = "%datetime% $pid [%level_name%]: %message%\n";
$formatter = new \Monolog\Formatter\LineFormatter($logFormat, null, true);
$logStreamHandler->setFormatter($formatter);
$monolog->pushHandler($logStreamHandler);
I am currently experimenting with the Phalcon Framework, and running into some complications when I attempt to save content into the Mongo Database. I can correctly setup the MySQL database without issues. Whenever I send the simple request through I get a 500 Internal server error (checking devTools). I have setup everything accordingly as the documentation specifies.
This is my simple index.php bootstrap Mongo initialisation along with the collection manager:
// Setting Mongo Connection
$di->set('mongo', function() {
$mongo = new Mongo();
return $mongo->selectDb("phalcon");
}, true);
// Setting up the collection Manager
$di->set('collectionManager', function(){
return new Phalcon\Mvc\Collection\Manager();
}, true);
This is my controller handling the request:
public function createAction() {
$user = new User();
$user->firstname = "Test ACC";
$user->lastname = "tester";
$user->password = "password";
$user->email = "testing#example.com";
if($user->create() == false) {
echo 'Failed to insert into the database' . "\n";
foreach($user->getMessages as $message) {
echo $message . "\n";
}
} else {
echo 'Happy Days, it worked';
}
}
And finally my simple User class:
class User extends \Phalcon\Mvc\Collection {
public $firstname;
public $lastname;
public $email;
public $password;
public $created_at = date('Y-m-d H:i:s');
}
Much appreciated for everyones input/suggestions.
i think it's because your installation of Mongo is not valid.
try printing phpinfo() and check if mongo is loaded at all, if not - install it, add to ini files (if you use cli, don't forget to add to cli ini too) and reach the moment, when mongo is fully loaded.
try mongo w/o phalcon. any simple connection/insertation. you can see here: Fatal Error - 'Mongo' class not found that there are problems with apache module version for some people. Try reinstalling different mongo version.
if you can print this out:
echo Phalcon\Version::get();
there should be no problems with phalcon instalation
to validate mongo installation, try any of examples from php.net:
http://www.php.net/manual/en/mongo.tutorial.php
A little bit late, but for anyone else facing this issue, it would be a good idea to try and connect to mongo (run "mongo" in your terminal) to ensure that mongo is setup correctly in your dev environment.
Also, I usually find in this sort of situation, that adding a collection to a database in mongo and then testing the CRUD process with a simple read helps move things along. If all is well at this stage, then you know your app is able to connect and you can proceed to writes, and so on.
This looks useful.
I'm building a monitoring solution for logging PHP errors, uncaught exceptions and anything else the user wants to log to a database table. Kind of a replacement for the Monitoring solution in the commercial Zend Server.
I've written a Monitor class which extends Zend_Log and can handle all the mentioned cases.
My aim is to reduce configuration to one place, which would be the Bootstrap. At the moment I'm initializing the monitor like this:
protected function _initMonitor()
{
$config = Zend_Registry::get('config');
$monitorDb = Zend_Db::factory($config->resources->db->adapter, $config->resources->db->params);
$monitor = new Survey_Monitor(new Zend_Log_Writer_Db($monitorDb, 'logEntries'), $config->projectName);
$monitor->registerErrorHandler()->logExceptions();
}
The registerErrorHandler() method enables php error logging to the DB, the logExceptions() method is an extension and just sets a protected flag.
In the ErrorController errorAction I add the following lines:
//use the monitor to log exceptions, if enabled
$monitor = Zend_Registry::get('monitor');
if (TRUE == $monitor->loggingExceptions)
{
$monitor->log($errors->exception);
}
I would like to avoid adding code to the ErrorController though, I'd rather register a plugin dynamically. That would make integration into existing projects easier for the user.
Question: Can I register a controller plugin that uses the postDispatch hook and achieve the same effect? I don't understand what events trigger the errorAction, if there are multiple events at multiple stages of the circuit, would I need to use several hooks?
Register your plugin with stack index 101. Check for exceptions in response object on routeShutdown and postDispatch.
$response = $this->getResponse();
if ($response->isException()) {
$exceptions = $response->getException();
}
to check if exception was thrown inside error handler loop you must place dispatch() in a try-catch block
The accepted answer by Xerkus got me on the right track. I would like to add some more information about my solution, though.
I wrote a Controller Plugin which looks like that:
class Survey_Controller_Plugin_MonitorExceptions extends Zend_Controller_Plugin_Abstract
{
public function postDispatch(Zend_Controller_Request_Abstract $request)
{
$response = $this->getResponse();
$monitor = Zend_Registry::get('monitor');
if ($response->isException())
{
$monitor->log($response);
}
}
}
Note that you get an Array of Zend_Exception instances if you use $response->getException(). After I had understood that, I simply added a foreach loop to my logger method that writes each Exception to log separately.
Now almost everything works as expected. At the moment I still get two identical exceptions logged, which is not what I would expect. I'll have to look into that via another question on SO.
I'm using symfony 1.4 with Doctrine.
I'm trying to find a way to enable debug mode only if the current sfUser has a special debugger credential.
I already created a filter that deactivates the symfony debug bar if the sfUser has not this credential (the web_debug is set to true in my settings.yml file):
class checkWebDebugFilter extends sfFilter
{
public function execute($filterChain)
{
if(!$this->getContext()->getUser()->hasCredential('debugger'))
{
sfConfig::set('sf_web_debug', false);
}
$filterChain->execute();
}
}
The code of my index.php file is:
require_once(dirname(__FILE__).'/../config/ProjectConfiguration.class.php');
$configuration = ProjectConfiguration::getApplicationConfiguration('frontend', 'prod', false));
sfContext::createInstance($configuration)->dispatch();
The problem is, as the debug mode is hardcoded to false in my index.php, it is also disabled for debuggers; therefore the Web debug bar does not show Doctrine statements nor timing indications.
Is there a way to enable debug mode only if the current sfUser has a precise credential?
I tried to add sfConfig::set('sf_debug', true); to my checkWebDebugFilter::execute() method but as the filter is executed after Doctrine statements, they are not recorded.
I also tried to add session_start(); in my index.php file, then browsing through the $_SESSION variable to check whether the current user has the debugger credential, but it did not work (and it was not in the spirit of symfony either).
Thanks in advance for your answers.
When you pass the debug parameter in the index.php file, it actually is passed down to the sfApplicationConfiguration class of your application. In your case it can be found in the /apps/frontend/config/frontendConfiguration.class.php file. frontendConfiguration class extends sfApplicationConfiguration, and here you can add your code.
Debug parameter is stored in a protected variable of this class, so you wont be able to change it from filter, but you can create a function for example:
setDebug($mode) {
$this->debug = $mode;
}
And call it in your filter:
$this->context->getConfiguration()->setDebug(true);
You also could override isDebug() function in frontendConfiguration class, because that is used in the initConfiguration() function to initialize timing indicators and other debugging stuff.
if ($this->isDebug() && !sfWebDebugPanelTimer::isStarted())
{
sfWebDebugPanelTimer::startTime();
}
But you won't be able to check user permissions here, as sfUser class won't be initialized in this stage yet. But you can check $_COOKIES or $_SESSION global variables for a value that you can set when user is logging in. Or you can call sfWebDebugPanelTimer::startTime() in your Filter, but will miss a few microseconds.
I have not tested this, but that's how I would do it.
Try this
if you want to enable web_debug panel (dev) mode then
http://host_url/frontend_dev.php
or
write in your index.php 'frontend','dev',true.
require_once(dirname(FILE).'/../config/ProjectConfiguration.class.php');
$configuration = ProjectConfiguration::getApplicationConfiguration('frontend', 'dev', true));
sfContext::createInstance($configuration)->dispatch();