Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

« Newer Snippets
Older Snippets »
Showing 11-20 of 43 total

Rewrite Apache logs that have incorrect dates

// Rewrite Apache logs that have incorrect dates

#!/usr/bin/perl

# $Id$

# Rewrite Apache logs that have incorrect dates.
# Example usage: $0 '28/May/2006:01:17:14 +0200' '19/Jan/2007:08:49:14 +0100' \
#                access_log.* error_log.*

use strict;
use warnings;

## no critic (ValuesAndExpressions::RequireInterpolationOfMetachars)
our ($VERSION) = '$Revision$' =~ m{ \$Revision: \s+ (\S+) }xms;
## use critic

use HTTP::Date;

my @DAYS   = qw(Sun Mon Tue Wed Thu Fri Sat);
my @MONTHS = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);

my $wrong_datetime = shift @ARGV;
my $right_datetime = shift @ARGV;

my ($timezone) = $right_datetime =~ m/ ([+-]\d\d\d\d)\z/xms;

my $seconds_diff = str2time($right_datetime) - str2time($wrong_datetime);

foreach my $file (@ARGV) {
    print "Rewriting $file\n";
    open my $IN,  '<', $file
        or die "Can't open $file: $!\n";
    open my $OUT, '>', "$file.rewritten"
        or die "Can't write to $file.rewritten: $!\n";
    while (<$IN>) {
        if (m{
               \A
               (.+\s+) # Before date and time (if any)
               \[
               (
                   \d\d/\w\w\w/\d\d\d\d # Date
                   :\d\d:\d\d:\d\d      # Time
                   \s
                   [\+\-]\d\d\d\d       # Time zone
               )
               \]
               (\s+.+) # After date and time
               \z
             }xms) {
            print {$OUT} 
              $1, q{[},
              rewrite_access_datetime($2, $seconds_diff, $timezone),
              q{]}, $3;
        }
        elsif (m{
               \A
               \[
               (
                   \w\w\w \s \w\w\w \s \d\d \s # Date
                   \d\d:\d\d:\d\d \s           # Time
                   \d\d\d\d                    # Year
               )
               \]
               (\s+.+) # After date and time
               \z
             }xms) {
            print {$OUT} 
              q{[},
              rewrite_error_datetime($1, $seconds_diff),
              q{]}, $2;
        }
        else {
            print {$OUT} $_;
        }
    }
}

sub rewrite_access_datetime {
    my ($datetime, $seconds_diff, $timezone) = @_;
    
    my ($sign, $hours, $minutes) = $timezone =~ m/\A([+-])(\d\d)(\d\d)\z/xms;
    my $seconds_offset = ($hours * 60 + $minutes) * 60;
    
    $datetime = str2time($datetime) + $seconds_diff;
    if    ($sign eq q{+}) {
        $datetime = $datetime + $seconds_offset;
    }
    elsif ($sign eq q{-}) {
        $datetime = $datetime - $seconds_offset;
    }
    
    my ($sec, $min, $hour, $mday, $mon, $year) = gmtime $datetime;
    return sprintf '%02d/%s/%04d:%02d:%02d:%02d %s',
        $mday, $MONTHS[$mon], $year + 1900, $hour, $min, $sec, $timezone;
}

sub rewrite_error_datetime {
    my ($datetime, $seconds_diff) = @_;
    
    $datetime = str2time($datetime) + $seconds_diff;
    
    my ($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime $datetime;
    return sprintf '%s %s %02d %02d:%02d:%02d %04d',
        $DAYS[$wday], $MONTHS[$mon], $mday, $hour, $min, $sec, $year + 1900;
}

Ruby On Rails With Apache and mod_proxy using .htaccess

If you want your rails app in the same apache html directory, use a .htaccess like this :

RewriteEngine   on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule     (.*) http://localhost:3000/$1 [P]


All resources that don't exist in your html directory will be requested ( using proxy) from mongrel.

convert apache http combined logs into sql (and import it into a mysql database eventually)

you need to extract the data in your http server log files and put it in a database to query it with your usual tools using SQL. this perl script does just this.

it was hard to find it, that's why i put it here.

#!/usr/bin/perl -w
# Written by Aaron Jenson.
# Original source: http://www.visualprose.com/software.php
# Updated to work under Perl 5.6.1 by Edward Rudd
# Updated 24 march 2007 by Slim Amamou <slim.amamou@alpha-studios.com>
#  - output SQL with the option '--sql'
#  - added SQL create table script to the HELP
#
#  NOTE : you need the TimeDate library (http://search.cpan.org/dist/TimeDate/)
#
use strict;
use Getopt::Long qw(:config bundling);
use DBI;
use Date::Parse;

my %options = ();
my $i = 0;
my $sql = '';
my $valuesSql = '';
my $line = '';
my $dbh = 0;
my $sth = 0;
my @parts = ();
my $part;
my $TIMESTAMP = 3;
my $REQUEST_LINE = 4;
my @cols = (
	'remote_host',			## 0
	'remote_logname',		## 1
	'remote_user',			## 2
	'request_time',			## 3.string
	'time_stamp',			## 3.posix
	'request_line',			## 5
	'request_method',		## 6
	'request_uri',			## 7
	'request_args',			## 8
	'request_protocol',		## 9
	'status',				## 10
	'bytes_sent',			## 11
	'referer',				## 12
	'agent'					## 13
);
my $col = '';

GetOptions (\%options,
		"version" => sub { VERSION_MESSAGE(); exit 0; },
		"help|?" => sub { HELP_MESSAGE(); exit 0; },
		"host|h=s",
		"database|d=s",
		"table|t=s",
		"username|u=s",
		"password|p=s",
		"logfile|f=s",
		"sql");

$options{host} ||= 'localhost';
$options{database} ||= '';
$options{username} ||= '';
$options{password} ||= '';
$options{logfile} ||= '';
$options{sql} ||= '';

if( ! ($options{database} || $options{sql}))
{
	HELP_MESSAGE();
	print "Must supply a database to connect to.\n";
	exit 1;
}

if( ! $options{table} )
{
	HELP_MESSAGE();
	print "Must supply table name.\n";
	exit 1;
}

if( $options{logfile} )
{
	if( ! -e $options{logfile} )
	{
		print  "File '$options{logfile}' doesn't exist.\n";
		exit 1;
	}
	open(STDIN, "<$options{logfile}") || die "Can't open $options{logfile} for reading.";
}

if( $options{database} )
{
	$dbh = Connect();
	if (! $dbh) {
		exit 1;
	}
}

$sql = "INSERT INTO $options{table} (";
foreach $col (@cols)
{
	$sql .= "$col," if( $col );
}
chop($sql);
$sql .= ') VALUES (';
my ($linecount,$insertcount) = (0,0);
while($line = <STDIN>)
{
	$linecount++;
	@parts = SplitLogLine( $line );
	next if( $parts[$TIMESTAMP+1] == 0 );
	$valuesSql = '';
	for( $i = 0; $i < @cols; ++$i )
	{
		$parts[$i] =~ s/\\/\\\\/g;
		$parts[$i] =~ s/'/\\'/g;
		$valuesSql .= "'$parts[$i]'," if( $cols[$i] );
	}
	chop($valuesSql);

	if( $options{database} )
	{
		$sth  = $dbh->prepare("$sql$valuesSql)");
		if( ! $sth->execute() )
		{
			print "Unable to perform specified query.\n$sql$valuesSql\n" . $sth->errstr() . "\n";
		} else {
			$insertcount++;
		}
		$sth->finish();
	}
	if( $options{sql} )
	{
		print "$sql$valuesSql);\n";
	}
}
if( ! $options{sql} )
{
	print "Parsed $linecount Log lines\n";
	print "Inserted $insertcount records\n";
	print "to table '$options{table}' in database '$options{database}' on '$options{host}'\n";
}

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
# Connects to a MySQL database and returns the connection.
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
sub Connect
{
	my $dsn = "DBI:mysql:$options{database};hostname=$options{host}";
	return DBI->connect( $dsn, $options{username}, $options{password} );
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
# Splits up a log line into its parts.
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
sub SplitLogLine
{
	my $line = shift;
	my $i = 0;
	my $inQuote = 0;
	my $char = '';
	my $part = '';
	my @parts = ();
	my $count = 0;
	chomp($line);
	for( $i = 0; $i < length($line); ++$i )
	{
		$char = substr($line, $i, 1);
		if( $char eq ' ' && ! $inQuote )
		{
			## print "Found part $part.\n";
			if( $count == $TIMESTAMP )
			{
				push(@parts, "[".$part."]");
				$part = str2time($part);
			}
			push(@parts, $part);
			if( $count == $REQUEST_LINE )
			{
				my @request = split(/[ ?]/, $part);
				push(@parts, $request[0]);
				push(@parts, $request[1]);
				if( $request[3] )
				{
					push(@parts, $request[2]);
					push(@parts, $request[3]);
				}
				else
				{
					push(@parts, '');
					push(@parts, $request[2]);
				}
				$count += 5;
			}
			else
			{
				++$count;
			}
			$part = '';
		}
		elsif( $char eq '"' || $char eq '[' || $char eq ']' )
		{
			$inQuote = !$inQuote;
		}
		else
		{
			$part .= $char;
		}
	}
	push(@parts,$part) if $part;

	return @parts;
}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
# Prints the usage/help message for this program.
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
sub HELP_MESSAGE
{
	print<<EOF;
Imports an Apache combined log into a MySQL database.
Usage: mysql_import_combined_log.pl -d <database name> -t <table name> [-h <hostname>] [-u <username>] [-p <password>] [-f <filename]
 --host|-h <host name>         The host to connect to.  Default is localhost.
 --database|-d <database name> The database to use.  Required.
 --username|-u <username>      The user to connect as.
 --password|-p <password>      The user's password.
 --table|-t <table name>       The name of the table in which to insert data.
 --logfile|-f <file name>      The file to read from.  If not given, data is read from stdin.
 --sql                         Output SQL
 --help|-?                     Print out this help message.
 --version                     Print out the version of this software.

----------------------------------
-- SQL create statements for the table
--

create table <TABLE_NAME> (
    remote_host varchar(50) ,
    remote_logname varchar(50) ,
    remote_user varchar(50) ,
    request_time char(28),
    time_stamp varchar(10) ,
    request_line varchar(255),
    request_method varchar(10) ,
    request_uri varchar(255),
    request_args varchar(255),
    request_protocol varchar(10) ,
    status varchar(10) ,
    bytes_sent varchar(10) ,
    referer varchar(255) ,
    agent varchar(255)
);

EOF
}



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
# Prints the version information for this program
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
sub VERSION_MESSAGE
{
	print "mysql_import_combined_log.pl version 1.2\n";
	print "Version 1.0 Written by Aaron Jenson.\n";
	print "Update to work with perl 5.6.1 by Edward Rudd\n";
}

1;

Add a fake host for development purposes

I don't like all these "localhost:3001", "localhost:3001", etc. urls so I use vhosts in apache (that is a proxy balancer for a mongrel cluster on my machine. This script helps me to add required information for my fake domain in the /etc/hosts and apache configs

#!/usr/local/bin/ruby

HOSTS_FILE = "/etc/hosts"
VHOSTS_FILE = "/Library/Apache2/conf/extra/httpd-vhosts.conf"

if $*.size < 2
  puts %{addhost.rb - creates a fake domain and bind it to the working rails app
    
USAGE: addhost development_hostname mongrel_port

Example: if you have a rails app on a localhost:3002 and you want
         to bind it to the myrailsapp.dev than run:
         addhost myrailsapp.dev 3002
  }
  
  exit 1
end

dev_host = $*[0]
mongrel_port = $*[1]

# Adding to the hosts file (absolute path must be in the HOSTS_FILE; usually /etc/hosts)
unless IO.read(HOSTS_FILE) =~ /^127.0.0.1\t#{dev_host}$/
  File.open(HOSTS_FILE, "a") do |file|
    file << "\n127.0.0.1\t#{dev_host}"
  end
end

unless IO.read(VHOSTS_FILE) =~ /^\tServerName #{dev_host}$/
  File.open(VHOSTS_FILE, "a") do |file|
    file << %{
<VirtualHost *:80>
  ServerName #{dev_host}
  
  ProxyPass / http://#{dev_host}:#{mongrel_port}/
  ProxyPassReverse / http://#{dev_host}:#{mongrel_port}
  ProxyPreserveHost on
</VirtualHost>
    }
  end
end

.htaccess That Fixes The Trailing Slash Error

// This .htaccess file is for use with a Rails application that is accessed by a symbolic link. This fixes an error in which the directory URL must have a trailing slash. Otherwise, the user receives a 400 Bad Request error.

Options +FollowSymLinks +ExecCGI

RewriteEngine On

RewriteCond %{SCRIPT_FILENAME}    -d
RewriteCond %{SCRIPT_FILENAME}      ^.*[^\/]$
RewriteRule ^(.*)$ $1/ [N]

#Put the directory your Rails app is in here.
RewriteBase /directory

RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ dispatch.cgi?$1 [QSA,L]

.htaccess error404.php

// This goes in .htaccess in the web root.

# error docs
ErrorDocument 404 /error404.php


// Use existing site template to start 404 page then add this code in your main content div.

<h1>Page not found</h1>
<?php
/* Error 404 code for ***** website */

$webmaster = "webmaster@camrider.com";
$host     = getenv("REMOTE_HOST");
$referrer = getenv("HTTP_REFERER"); 
$path     = getenv("REQUEST_URI"); 

// time in this format: 13/Nov/2000:10:50:38
$time = strftime("%d/%b/%Y:%T");

if ($referrer == "") {
  $referrer = "";
} else {
  $referrer = "<p>You came to this page from $referrer, this could be a broken link so please <a href=\"mailto:$webmaster?subject=Error 404 on $path from $referrer\">email the webmaster</a> to inform us of this.</p>";
}


?>
<h2>Sorry, we couldn't find the page <?php echo $path ?> on this website</h2>
<?php echo $referrer; ?>
<p>Please use the navigation links to help locate what you're looking for.</p>

replace file extension with apache rewrite

// in this example *.html is replaced by *.php
// its a redirect [R] and it is is permanent (code is 301)

RewriteEngine On
RewriteBase   /the_directory

RewriteRule  ^(.*).html$ $1.php [R=301]

rewrite rules

// if cms has cryptic urls
// in apache url-rewriting with .htaccess can help

RewriteRule cms/fest$ cms/index.php?option=content&task=view&id=176&Itemid=202 [NC]


// [NC] = not case-sensitive

Exempt directories from Apache's ProxyPass directive

Very useful if forwarding to Mongrel, etc.

        ProxyPass /stylesheets !
        ProxyPass /javascripts !
        ProxyPass /images !     
        ProxyPass / http://127.0.0.1:3010/
        ProxyPassReverse / http://127.0.0.1:3010/  

A tool to split log files by hostname

This script can be used to split a log file by the hostname in the request. It is designed for use with lighttpd virtual hosting, to prepare the log for Webalizer. It should be run with a cron job and CLI PHP.

<?php
// Copyright (C) 2006 Craig Spurrier
// Released under the terms of the MIT/expat license.

$serverip = "127.0.0.1"; //Set to your IP address or default hostname, so requests without hostnames can be sorted 
$log = file_get_contents("/var/log/lighttpd/access.log"); //Log location
$fh = fopen("/var/log/lighttpd/access.log", 'w'); //Clear the log file
fclose($fh);
$lines = explode ("\n", $log);
foreach ($lines as $line){
$parts = explode (" ", $line);
$hostname = strtolower($parts[1]);
if (substr($hostname, 0, 4) == 'www.'){$hostname = substr($hostname, 4);} //Treat www. as the same as the www-less version
if ($hostname == '-'){$hostname = $serverip;} //Set a hostname for request without hostnames
$fh = fopen("/var/log/lighttpd/users/$hostname.access.log", 'a'); //Add the entry to the log for that hostname. Make sure this script can write to this location.
fwrite($fh, "$line\n");
fclose($fh);
}
?>
« Newer Snippets
Older Snippets »
Showing 11-20 of 43 total