On Mon, 21 Apr 2003, Markus Wichmann wrote:
> Hello all,
>
> though I have to admit that I'm a newbie to Ruby I'll try to devise my
> questions intelligently ;-)
i'm *not* a newbie and my questions are generally arcane and un-intelligent so
i wouldn't worry about that.
> I'd like to parse an Apache logfile at regular intervals, say every 15
> minutes. If that part of the logfile that has been added since the last
> parsing contains a certain String, let's say "blueice", I'd like to be
> sent an e-mail.
>
> This is my first real Ruby experience, but I thought I should rather
> start with something practical instead of something academic.
>
> How do I realize the regular-interval-parsing? How can my application
> keep in mind what part of the logfile has already been parsed and which
> part is new? How am I able to send an e-mail using Ruby?
>
> Any hints in any form are greatly appreciated!
i would use ruby's built database, PStore, to store the date of the last run.
that way, you can simply cron the job - or run it by hand - whenever you feel
like it and the program will know the date of the most recently processed line
and can start from there - here's a little example. a couple of things
* the methods are defined in a BEGIN block for clarity/readability only.
although it also works fine i don't generally do this in real code.
* no mailing is going on, but you can read about that in the net/smtp
section of the pickaxe's 'Network and Web Libraries' section. you can
download the book from http://www.rubycentral.com, but i'd reccomend
buying it straight away if you already haven't - one to support the
authors, two to let book companies know their is an audience out there for
ruby books, and three because it is a super book for getting started in
ruby
----CUT----
#!/usr/bin/env ruby
require 'pstore'
ACCESS_LOG = ARGV[0] || "/usr/local/apache/logs/access_log"
PSTORE = ARGV[1] || "./access_log.db"
previous = get_previous_date()
date = nil
File.open(ACCESS_LOG) do |access_log|
access_log.each do |line|
date = parsedate(line)
process_line(line) if(date > previous)
end
end
store_current_date(date)
BEGIN {
DATE_RE = %r"\s\[(\d+)/(\w+)/(\d+):(\d+):(\d+):(\d+)"o
MONTH_MAP = Hash[
%r/^jan/io => 1,
%r/^feb/io => 2,
%r/^mar/io => 3,
%r/^apr/io => 4,
%r/^may/io => 5,
%r/^jun/io => 6,
%r/^jul/io => 7,
%r/^aug/io => 8,
%r/^sep/io => 9,
%r/^oct/io => 10,
%r/^nov/io => 11,
%r/^dec/io => 12,
]
def parsedate(line, re = DATE_RE)
match = re.match(line) or raise (ArgumentError, "LINE HAS NO DATE")
dd, mm, yy, h, m, s = match.to_a[1..-1]
n = nil
MONTH_MAP.map{|mp,mn| mp.match(mm) and n = mn}
n or raise (ArgumentError, "COULD NOT MAP MONTH TO MONTH NUMBER")
return Time.mktime(yy, mm, dd, h, m, s)
end
def get_previous_date()
date = nil
pstore = PStore.new(PSTORE)
pstore.transaction do
date =
begin
pstore[:date]
rescue
Time.at(0)
end
end
return date
end
def process_line(line)
puts(line)
end
def store_current_date(date)
pstore = PStore.new(PSTORE)
pstore.transaction do
pstore[:date] = date
end
end
}
----CUT----
-a
--
====================================
| Ara Howard
| NOAA Forecast Systems Laboratory
| Information and Technology Services
| Data Systems Group
| R/FST 325 Broadway
| Boulder, CO 80305-3328
| Email: ara.t.howard / fsl.noaa.gov
| Phone: 303-497-7238
| Fax: 303-497-7259
====================================