logmerge 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +28 -0
- data/Manifest.txt +14 -0
- data/README +35 -0
- data/Rakefile +63 -0
- data/bin/ip2name +8 -0
- data/bin/logmerge +6 -0
- data/lib/logmerge/merger.rb +74 -0
- data/lib/logmerge/resolv.rb +1892 -0
- data/lib/logmerge/resolver.rb +162 -0
- data/lib/logmerge.rb +13 -0
- data/resolv_test +26 -0
- data/test/access.log +10 -0
- data/test/test_merger.rb +86 -0
- data/test/test_resolver.rb +234 -0
- metadata +59 -0
data/LICENSE
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
All original code copyright 2005 Eric Hodel, The Robot Co-op. All rights
|
2
|
+
reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions
|
6
|
+
are met:
|
7
|
+
|
8
|
+
1. Redistributions of source code must retain the above copyright
|
9
|
+
notice, this list of conditions and the following disclaimer.
|
10
|
+
2. Redistributions in binary form must reproduce the above copyright
|
11
|
+
notice, this list of conditions and the following disclaimer in the
|
12
|
+
documentation and/or other materials provided with the distribution.
|
13
|
+
3. Neither the names of the authors nor the names of their contributors
|
14
|
+
may be used to endorse or promote products derived from this software
|
15
|
+
without specific prior written permission.
|
16
|
+
|
17
|
+
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
|
18
|
+
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
19
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
20
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
|
21
|
+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
22
|
+
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
23
|
+
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
24
|
+
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
25
|
+
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
26
|
+
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
27
|
+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
28
|
+
|
data/Manifest.txt
ADDED
data/README
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
= logmerge
|
2
|
+
|
3
|
+
Rubyforge Project:
|
4
|
+
|
5
|
+
http://rubyforge.org/projects/rctools/
|
6
|
+
|
7
|
+
== About
|
8
|
+
|
9
|
+
Logmerge contains two utilities logmerge and ip2name. logmerge merges Apache
|
10
|
+
access logs into one log ordered by date. ip2name performs DNS lookups on
|
11
|
+
Apache access logs using multiple threads and Ruby's DNS resolver library to
|
12
|
+
speed through log files.
|
13
|
+
|
14
|
+
== Using logmerge
|
15
|
+
|
16
|
+
Simply pass in all the logs you want to merge on the command line. logmerge
|
17
|
+
gives you the merged log on STDOUT.
|
18
|
+
|
19
|
+
logmerge hal/access.log nestor/access.log herbie/access.log > merged.log
|
20
|
+
|
21
|
+
Note that logmerge expects the input log files to be ordered by date.
|
22
|
+
|
23
|
+
== Using ip2name
|
24
|
+
|
25
|
+
Simply pass in the log files you want to perform DNS lookups on the command
|
26
|
+
line or via STDIN. ip2name gives you the looked-up log lines on STDOUT.
|
27
|
+
|
28
|
+
ip2name < merged.log > resolved.log
|
29
|
+
|
30
|
+
ip2name merged.log > resolved.log
|
31
|
+
|
32
|
+
In order to speed DNS lookups, ip2name creates a .name_cache file in the
|
33
|
+
current directory. ip2name uses double the DNS record TTL value so
|
34
|
+
rapidly-changing names may not be correctly resolved.
|
35
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
|
6
|
+
$VERBOSE = nil
|
7
|
+
|
8
|
+
spec = Gem::Specification.new do |s|
|
9
|
+
s.name = 'logmerge'
|
10
|
+
s.version = '1.0.0'
|
11
|
+
s.summary = 'Resolves IP addresses and merges Apache access logs.'
|
12
|
+
s.author = 'Eric Hodel'
|
13
|
+
s.email = 'eric@robotcoop.com'
|
14
|
+
|
15
|
+
s.files = File.read('Manifest.txt').split($/)
|
16
|
+
s.require_path = 'lib'
|
17
|
+
|
18
|
+
s.executables = %w[ip2name logmerge]
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'Run tests'
|
22
|
+
task :default => [ :test ]
|
23
|
+
|
24
|
+
Rake::TestTask.new('test') do |t|
|
25
|
+
t.libs << 'test'
|
26
|
+
t.verbose = true
|
27
|
+
end
|
28
|
+
|
29
|
+
desc 'Update Manifest.txt'
|
30
|
+
task :update_manifest do
|
31
|
+
sh "find . -type f | sed -e 's%./%%' | egrep -v 'svn|swp|~' | egrep -v '^(doc|pkg)/' | sort > Manifest.txt"
|
32
|
+
end
|
33
|
+
|
34
|
+
desc 'Generate RDoc'
|
35
|
+
Rake::RDocTask.new :rdoc do |rd|
|
36
|
+
rd.rdoc_dir = 'doc'
|
37
|
+
rd.rdoc_files.add 'lib', 'README', 'LICENSE'
|
38
|
+
rd.rdoc_files.exclude '*/resolv.rb' # WTF doesn't this work?
|
39
|
+
rd.main = 'README'
|
40
|
+
rd.options << '-d' if `which dot` =~ /\/dot/
|
41
|
+
end
|
42
|
+
|
43
|
+
desc 'Generate RDoc for dev.robotcoop.com'
|
44
|
+
Rake::RDocTask.new :dev_rdoc do |rd|
|
45
|
+
rd.rdoc_dir = '../../../www/trunk/dev/html/Tools/logmerge'
|
46
|
+
rd.rdoc_files.add 'lib', 'README', 'LICENSE'
|
47
|
+
rd.main = 'README'
|
48
|
+
rd.options << '-d' if `which dot` =~ /\/dot/
|
49
|
+
end
|
50
|
+
|
51
|
+
desc 'Build Gem'
|
52
|
+
Rake::GemPackageTask.new spec do |pkg|
|
53
|
+
pkg.need_tar = true
|
54
|
+
end
|
55
|
+
|
56
|
+
desc 'Clean up'
|
57
|
+
task :clean => [ :clobber_rdoc, :clobber_package ]
|
58
|
+
|
59
|
+
desc 'Clean up'
|
60
|
+
task :clobber => [ :clean ]
|
61
|
+
|
62
|
+
# vim: syntax=Ruby
|
63
|
+
|
data/bin/ip2name
ADDED
data/bin/logmerge
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
$TESTING = defined? $TESTING
|
2
|
+
|
3
|
+
require 'logmerge'
|
4
|
+
|
5
|
+
##
|
6
|
+
# Merges multiple Apache log files by date.
|
7
|
+
|
8
|
+
class LogMerge::Merger
|
9
|
+
|
10
|
+
##
|
11
|
+
# Merges +files+ into +output+. If +files+ is nil, ARGV is used.
|
12
|
+
|
13
|
+
def self.merge(output = STDOUT, *files)
|
14
|
+
files = ARGV if files.empty?
|
15
|
+
merger = LogMerge::Merger.new files.map { |file| File.open file }
|
16
|
+
merger.merge output
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Creates a new Merger that will operate on an array of IO-like objects
|
21
|
+
# +streams+.
|
22
|
+
|
23
|
+
def initialize(streams)
|
24
|
+
@streams = streams
|
25
|
+
@buf = []
|
26
|
+
|
27
|
+
@streams.each_index { |slot| buf_fill slot }
|
28
|
+
|
29
|
+
@all_closed = @streams.empty?
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Are all the streams closed?
|
34
|
+
|
35
|
+
def all_closed?
|
36
|
+
@all_closed
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# Adds a line to the buffer from input strem +slot+.
|
41
|
+
|
42
|
+
def buf_fill(slot)
|
43
|
+
line = @streams[slot].gets
|
44
|
+
|
45
|
+
if line.nil? and @streams[slot].eof? then
|
46
|
+
@streams.delete_at slot
|
47
|
+
@buf.delete_at slot
|
48
|
+
elsif line.nil? then
|
49
|
+
raise "WTF? line.nil? and not eof?"
|
50
|
+
else
|
51
|
+
line =~ / \[(.+?)\] /
|
52
|
+
time = Time.parse($1.sub(':', ' ').gsub('/', '-')).to_i
|
53
|
+
@buf[slot] = [time, line]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# Merges streams into +out_stream+.
|
59
|
+
|
60
|
+
def merge(out_stream)
|
61
|
+
index, min, line = nil
|
62
|
+
|
63
|
+
until @streams.empty? do
|
64
|
+
min = @buf.min { |a,b| a.first <=> b.first}
|
65
|
+
slot = @buf.index min
|
66
|
+
buf_fill slot
|
67
|
+
out_stream.puts min.last
|
68
|
+
end
|
69
|
+
|
70
|
+
@all_closed = true
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|