MySQL Query Logging in CakePHP - php

I wanted to know if there is way to log the mysql queries in CakePHP being executed when we use the find method on the models, I know that rails database queries, so does Cake do the same, if so how can I enable it or use it?
Shiv

This page has instructions on how to get Cake to log queries the same way as rails.

A Very simple method to log all the queries being executed:
in your cake\libs\model\datasources\dbo\dbo_mysql.php
find the _execute function:
function _execute($sql) {
return mysql_query($sql, $this->connection);
}
add the line "$this->log($sql);" before "return mysql_query($sql, $this->connection);"
function _execute($sql) {
$this->log($sql);
return mysql_query($sql, $this->connection);
}
That's it!!!!! All your SQL Queries gets logged. Make sure the log file is configured properly and have sufficient permission. Enjoy

Assuming you are on a nix os, the best approach would actually to tail the mysql log itself.
You might learn some interesting things out of it.
log in Ubuntu when installing from repository
tail -f /var/log/mysql/mysql.log
As mentioned below, this is a huge performance killer (well, all logs have some performance impact). So, make sure you use it only on your dev/QA machines and only for short periods on your production machine.

CakePHP 1.3 uses the sql_dump element for that.
You can use the element directly when Configure::read('debug') is set to 2:
echo $this->element('sql_dump');
Or take it's code directly if you need to do something else with it (like echo it from a ShellTask)
$sources = ConnectionManager::sourceList();
$logs = array();
foreach ($sources as $source):
$db =& ConnectionManager::getDataSource($source);
if (!$db->isInterfaceSupported('getLog')):
continue;
endif;
$logs[$source] = $db->getLog();
endforeach;
Echo with e.g.:
print_r($logs)

This is what I use (put it in element folder then include in your layout)
<?php
ob_start();
echo $this->element('sql_dump');
$out = ob_get_contents();
ob_end_clean();
CakeLog::write('mysql' , $out);
?>
then you will find the mysql.log file in TMP.logs.DS.mysql.log

Related

PHP non-blocking exclusive lock

I would like to use exclusive/shared, both blocking and non-blocking locks like these found in flock(). How can this be achieved using semaphores?
It depends on the use case.
If you are on only one server, use a lock file.
function doSomething() {
$file = /temp/path/somthing.lock;
if (file_exists($file)) {
return false;
}
touch($file);
// Safely mess with things
unlink($file);
}
If you have multiple web servers, e.g. behind a load balancer, the same thing can be accomplished by using a table in mysql.
function doSomething() {
$query = "SELECT * FROM locks WHERE name='something'");
$res = mysqli_query($query);
if (mysql_num_rows($res) > 0) {
return false;
}
$query = "INSERT INTO locks (name) VALUES ('something')";
mysqli_query($query);
// Safely mess with things
$query = "DELETE FROM locks WHERE name='something'");
mysqli_query($query);
}
Memcache is another obvious candidate with multiple machine support.
You should not use ACP, because it is intended for caching only. This means you do not have control when ACP storage gets deleted, it could happen at any time.
You can also use semaphores, however the same caveats as with lock files apply if you use more than one server.
I would recommend creating lock($key), is_locked($key) and release($key) functions, and then religiously use them throughout your project. That way you can start with lock files (quick to implement), but then upgrade to something better later without editing the rest of your code. If you want to get really fancy, you can implement them as methods of a logger object that you put in a known location of your code.

Query logging for mySQL on shared server

I have a VPS with Dreamhost but the mySQL server is shared. I really want to start producing accessible logs of every mySQL query a particular site issues.
I can hand roll this into my abstraction layer but I was curious is there was something like sql_log_off that can be set at runtime so all queries get logged into files I can rotate and review?
From what I understand of what the question is asking:
What you could do is wrap your queries into some sort of wrapper that logs the queries into a file. This could be a text file or a PHP file that will only allow those with permission to view (a log viewer script could include this so that only those with proper access can view).
That is of course saying if you are able to do so. (If you are wanting to log queries from sites that you have no control over then I am not sure.)
An example of a wrapper you might be interested in:
function sql_query($query, $show=0)
{
global $queries, $debugginglist;
$thequery = mysql_query($query) or print(mysql_error()."<br>Query was: <code>".htmlspecialchars($query)."</code>");
$queries++;
if ($show == 1)
{
print "($queries): Query was: <i><code>".htmlspecialchars($query)."</code></i><br>";
}
$debugginglist .= "$qbr($queries): Query was: <i><code>$query</code></i><br>";
//this is just to give an idea for logging, NOT an exact solution
$logquery = fopen("querylog.txt", "ab+");
fputs($logquery, "\r\n$query");
fclose($logquery);
return $thequery;
}

PHP Performance Measurement

How can I benchmark certain peices of code in PHP? I can use timers to calculate the differences, I'm just not sure if it is the best solution out there.
Have a look at XDebug Profiler to benchmark the performance and more.
Xdebug's Profiler is a powerful tool
that gives you the ability to analyze
your PHP code and determine
bottlenecks or generally see which
parts of your code are slow and could
use a speed boost.
You can use a profiler like the one built into Xdebug.
XDebug is cool but if you dont want to install this library, you could try the following:
What I use to locate possible bottle necks is:
$benchmark_start = microtime(true);
// Code goes here
$benchmark_stop = microtime(true);
$benchmark_total = $benchmark_stop - $benchmark_start;
echo "The script took ". $benchmark_total." seconds";
a bit more sophisticated example of manual profiling using timers
works perfect for me, especially when I am asked to sort things out on some live server with FTP access only.
needless to mention that profiling is way more important (and useful) on live server, rather than on hothouse developer's PC.
$TIMER['start']=microtime(TRUE);
// some code
$query="SELECT ...";
$TIMER['before q']=microtime(TRUE);
$res=mysql_query($query);
$TIMER['after q']=microtime(TRUE);
while ($row = mysql_fetch_array($res)) {
// some code
}
$TIMER['array filled']=microtime(TRUE);
// some code
$TIMER['pagination']=microtime(TRUE);
if ('127.0.0.1' === $_SERVER['REMOTE_ADDR']) { //I set my IP here
echo "<table border=1><tr><td>name</td><td>so far</td><td>delta</td><td>per cent</td></tr>";
reset($TIMER);
$start=$prev=current($TIMER);
$total=end($TIMER)-$start;
foreach($TIMER as $name => $value) {
$sofar=round($value-$start,3);
$delta=round($value-$prev,3);
$percent=round($delta/$total*100);
echo "<tr><td>$name</td><td>$sofar</td><td>$delta</td><td>$percent</td></tr>";
$prev=$value;
}
echo "</table><>";
}

How to do caching in php

I used the following code, but it is taking time. i want to cache without storing in a text file.
$file = 'cache_toppers.txt';
if (file_exists($file) &&
filemtime($file) > (time() - $expire)) {
$records = unserialize(file_get_contents($file));
} else {
include("kalvidbconnect.php");
$query = "SELECT * FROM vpfmsttoppers";
$result = mysql_query($query)
or die (mysql_error());
while ($record = mysql_fetch_array($result) ) {
$records[] = $record;
}
$OUTPUT = serialize($records);
$fp = fopen($file,"w");
fputs($fp, $OUTPUT);
fclose($fp);
}
Thanks,
Kamatchi.D
There are some ready to use PHP extensions providing cache functionality. Some of them:
memcache http://pecl.php.net/package/memcache
APC http://php.net/manual/en/book.apc.php
eAccelerator
XCache
these are the ones I know of, but surely there are many more.
Just a thought, not sure, but how about using CouchDB!?
Here is a good tutorial on IBM http://www.ibm.com/developerworks/opensource/library/os-php-couchdb/index.html?ca=drs-
If you don't want to use file-based caching, then one option is to build a wrapper and store it in shared memory,
http://se.php.net/manual/en/ref.sem.php
Maybe APC utilizes the same technique, I don't know, but if you don't want to install PECL-extensions then building your own cache-handling might be an option.
I would however consider caching rendered content to file, since that would put the least amount of load on the server.
Depending on a very long list of factors, I'd typically expect trying to unserialize the file to take longer than loading it fresh from the database.
Well, use cache then, for example APC - apc_store()/ apc_fetch()

How to do command line from PHP script

I need to write a script that will give users info on a given Unix account (the same Unix server that the script lives on). Mostly thing kinds of things that are in the passwd file or available via finger.
PHP is in safe-mode, so I can't access the passwd file via something built into php like file_get_contents(). Also, because it's in safe mode, various other command-line functions are disabled.
I thought I could get the info via a socket (no clue yet what that means, but I thought I'd try) but I get a fatal error that socket_create() is an unknown function. I pulled up the php-config file (which I can't change, FYI), and sure enough, sockets are not enabled.
However, while I was in there, I saw the line '--with-exec-dir=' with no actual directory set.
So then I remembered that when I was trying EVERY command line function, that some threw "not allowed in safe-mode" type errors, while others did nothing at all. If I put something like:
echo "[[";
exec("finger user");
echo "]]";
I'd end up with [[]]. So no errors, just no results either.
Bottom line:
Is there something I haven't tried? (in general)
Is there a runtime config option I can set to make exec() work?
quick note: I tried passthru() as well, specifically passthru("pwd") with still no output.
update
based on feedback, I tried both of the following:
$stuff = exec("pwd", $return);
echo "stuff=".$stuff."\n";
echo "return=";
print_r($return);
which results in:
stuff=
return=Array
(
)
and
$stuff = passthru("pwd", $return);
echo "stuff=".$stuff."\n";
echo "return=";
print_r($return);
which results in:
stuff=
return=1
The 1 sounds hopeful, but not what I want yet.
Idea
So this is actually an update of an already existing script that (please don't ask) I don't have access to. It's a perl script that's called via cgi. Is there a way to do php via cgi (so I don't have to deal with perl or rely on the older code)?
I'm afraid you can't do that in safe-mode. You have to remove the safe-mode if you have control of the server configuration.
I think you can't rely on sockets to read local files, sockets are used for network related things.
exec doesn't inherently return any data.
Try something like,
exec("finger user",$output);
echo "[[";
foreach($output as $key => $value){
echo $value;
}
echo "]]";
Exec returns a value, so do:
$var = exec("finger user");
and then parse the output to get what you want. You can get return status by adding in an optional variable thus:
exec("finger user", $var, $return_status);
or just:
echo exec("finger user");
if all you want is to see the output.
Thanks to all that responded, the following is what finally worked:
Create a cgi-bin folder
Add the following to the top of the php script:
#!/usr/local/bin/php-cgi
I don't know if this is something special on my server configuration, but I can run exec() and get what I'm after.

Categories