Nothing much to say here, but with absolutely minimal pain and suffering, I have 64-bit linux virtual machines running on top of my 32-bit windows XP install. This pleases me.
The recipe:
- Compatible CPU with VT-x/AMD-V enabled in the BIOS
- Innotek/Oracle/Sun VirtualBox (a current version) with hardware virtualization enabled
- Profit!
The one downside to this? 64-bit VM’s running on 32-bit host OS can’t see multiple cpu’s. Boo. Hoo. I’ll just run more VM’s!

In response to my two-step rotation post earlier this week, I figure I may as well share the logic I use for a more traditional logfile rotation scheme.
I think this is as simple as I can possibly make it:
<?
define( 'MAX_COPIES', 3 );
$back_fname = "/path/to/log/file/abc.log";
function trace( $msg ) {
echo "- $msg\n";
}
exec( "ls -r ${back_fname}*", $copies, $succ );
while( count($copies) >= MAX_COPIES ) {
$fname = array_shift($copies);
trace( "deleting ".$fname );
}
$next = count($copies);
while( $fname = array_shift($copies) ) {
--$next;
trace( "rotating $fname -> $next" );
rename( $fname, "$back_fname.$next" );
}
trace( "creating $back_fname" );
touch( $back_fname );
?>
A sample series of executions might look like this:
ammon@wernstrom:/path/to/log/file$ touch abc.log
ammon@wernstrom:/path/to/log/file$ php rotate.php
- rotating /path/to/log/file/abc.log -> 0
- creating /path/to/log/file/abc.log
ammon@wernstrom:/path/to/log/file$ php rotate.php
- rotating /path/to/log/file/abc.log.0 -> 1
- rotating /path/to/log/file/abc.log -> 0
- creating /path/to/log/file/abc.log
ammon@wernstrom:/path/to/log/file$ php rotate.php
- rotating /path/to/log/file/abc.log.1 -> 2
- rotating /path/to/log/file/abc.log.0 -> 1
- rotating /path/to/log/file/abc.log -> 0
- creating /path/to/log/file/abc.log
ammon@wernstrom:/path/to/log/file$ php rotate.php
- deleting /path/to/log/file/abc.log.2
- rotating /path/to/log/file/abc.log.1 -> 2
- rotating /path/to/log/file/abc.log.0 -> 1
- rotating /path/to/log/file/abc.log -> 0
- creating /path/to/log/file/abc.log
This doesn’t have any failsafes, doesn’t compress anything, depends on an external call to ‘ls’, and it actually deletes old files in stead of overwriting them… but it is the shortest, simplest method I’ve come up with to get the job done.
If I feel like making this a full-fledged series, I might actually post a more thorough implementation later
This is the result of 10 minutes of pounding on the keyboard after yet another disappointing experience with trying to get logrotate to do something vaguely more flexible.
This simple script scans all normal files in a log directory, and if they are older than a certain cutoff, moves them into a holding directory for old logs. Future passes will check files in the old directory for another age setting and will delete them. That’s all there is to it.
Configure your cutoffs, directories of interest, and optionally plug in a better logging mechanism and you’re set. (Oh, and change the #! if necessary, of course).
#!/usr/bin/php
<?
$cutoff_rotate = "3 days";
$cutoff_delete = "7 days";
$dir_log = "/logs";
$dir_old = "/logs.old";
function trace( $msg, $debug = FALSE ) {
// appropriate logging mechanism can be plugged in here
echo "[] $msg\n";
}
// scan old files for deletion
if( is_dir($dir_old) ) {
$dh = opendir( $dir_old );
if( $dh !== FALSE ) {
chdir( $dir_old );
trace( "scanning $dir_old for logs more than $cutoff_delete old" );
$cutoff = strtotime( "-$cutoff_delete" );
trace( "cutoff is ".date('r',$cutoff) );
while( ($file = readdir($dh)) !== FALSE ) {
if( is_dir($file) ) {
trace( "skipping $file", true );
continue;
} else {
$ts = filemtime($file);
if( $ts < $cutoff ) {
trace( "deleting $file, ".date('r',$ts) );
$succ = @unlink($file);
if( !$succ )
trace( "failed to unlink $file!" );
} else {
trace( "ignoring $file, ".date('r',$ts), true );
}
}
}
}
closedir( $dh );
} else {
trace( "no old log dir $dir_old to scan yet" );
}
// scan current files for rotation
if( file_exists($dir_old) ) {
trace( "creating $dir_old" );
$succ = @mkdir( $dir_old, 0775, true );
if( !$succ ) {
trace( "mkdir failed, aborting rotation" );
exit( 1 );
}
}
if( is_dir($dir_log) ) {
$dh = opendir( $dir_log );
if( $dh !== FALSE ) {
chdir( $dir_log );
trace( "scanning $dir_log for logs more than $cutoff_rotate old" );
$cutoff = strtotime( "-$cutoff_delete" );
trace( "cutoff is ".date('r',$cutoff) );
while( ($file = readdir($dh)) !== FALSE ) {
if( is_dir($file) ) {
trace( "skipping $file", true );
continue;
} else {
$ts = filemtime($file);
if( $ts < $cutoff ) {
trace( "rotating $file, ".date('r',$ts), true );
$succ = @rename( $file, $dir_old );
if( !$succ )
trace( "failed to rotate $file!" );
} else {
trace( "ignoring $file, ".date('r',$ts), true );
}
}
}
}
closedir( $dh );
}
?>
Caveman profiling with a side of “where were you at 9pm on the night in question?” As always, season to taste.
<?
$_profile_log = "/tmp/php-profile.log";
function _profile() {
static $fh;
if( !isset($fh) ) {
global $_profile_log;
if( !file_exists($_profile_log) ) {
@touch( $_profile_log );
@chmod( $_profile_log, 0664 );
}
$fh = @fopen( $_profile_log, "a" );
}
if( !$fh )
return false;
$stack = debug_backtrace();
if( $stack[1] )
$base = $stack[1];
else
$base = $stack[0];
$buf = $base['file'].":".$base['line'].", ";
if( $base['class'] )
$buf .= $base['class'].$base['type'];
$buf .= $base['function'];
$buf = sprintf("[%s] %s\n",date("H:i:s"),$buf);
return @fwrite( $fh, $buf );
}
?>
Read the rest of this entry »
I’ve gone through all of my old posts (~260 of them in my 5+ year history) and tagged them.
I’ve got a theme that doesn’t make me want to tear my eyes out, but it’s not what I want yet.
I’ve acknowledged all missing images that I noticed by tagging the post as ‘broken images’, and I’ll be going through them again later to see if I have any remaining local copies of the files in question.
I’ve installed a modern syntax hiliting plugin, so code should be readable again.
Sooo close.
I can’t type. I Just managed to delete my entire blog content dir and plugins. This means all of my images and any uploaded zips are gone.
Also, my company has recently had to make some dramatic changes that I’m still coping with. I am still employed, but I’m not much in the mood to continue with any of my previous article series at present.
On the bright side, this gives me an excuse upgrade to WP2.9 and dig through my 250+ post archive and clean things up.
Please excuse the mess while I unbork everything. Happy new year.