logtrend 0.9.20101208165234 → 0.9.20101209201344
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/logtrend.rb +89 -46
- metadata +4 -4
data/lib/logtrend.rb
CHANGED
@@ -5,67 +5,85 @@ require 'rrd'
|
|
5
5
|
require 'logger'
|
6
6
|
require 'erb'
|
7
7
|
|
8
|
+
# A Ruby module that uses RRD (http://www.mrtg.org/rrdtool/) to generate graphs for trending data from log files.
|
9
|
+
#
|
10
|
+
# logtrend tails a log file and matches lines one by one, sending matched counters to RRD as appropriate.
|
8
11
|
module LogTrend
|
9
12
|
class Base
|
10
13
|
# This sets the directory where graphs should be stored.
|
11
14
|
attr_accessor :graphs_dir
|
15
|
+
|
12
16
|
# This sets the directory where your RRD files will rest.
|
13
17
|
attr_accessor :rrd_dir
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
18
|
+
|
19
|
+
# This sets the logger to use. Must be something that behaves like a Logger object.
|
20
|
+
attr_accessor :logger
|
21
|
+
|
22
|
+
# This sets the HTML file template for the generated index.html file.
|
23
|
+
# The String here will pass through ERB, with self being set as the binding.
|
24
|
+
#
|
25
|
+
# The default generates a simple HTML file that loads one IMG tag per graph.
|
26
|
+
attr_accessor :template
|
27
|
+
|
28
|
+
# Defines the amount of time between each updates, given in seconds. Default value is 60 seconds.
|
29
|
+
#
|
30
|
+
# From the rrdcreate(2) manual page:
|
31
|
+
#
|
32
|
+
# Specifies the base interval in seconds with which data will be fed into the RRD.
|
33
|
+
#
|
34
|
+
#
|
35
|
+
# @see http://www.mrtg.org/rrdtool/doc/rrdcreate.en.html
|
36
|
+
attr_accessor :step
|
37
|
+
|
38
|
+
# Defines the amount of time between updates that will mark a value unknown.
|
39
|
+
#
|
40
|
+
# From the rrdcreate(2) manual page:
|
41
|
+
#
|
42
|
+
# heartbeat defines the maximum number of seconds that may pass between two updates of this data source before the value of the data source is assumed to be *UNKNOWN*.
|
43
|
+
#
|
44
|
+
# @see http://www.mrtg.org/rrdtool/doc/rrdcreate.en.html
|
45
|
+
attr_accessor :heartbeat
|
46
|
+
|
47
|
+
def initialize(options={})
|
48
|
+
set_defaults
|
49
|
+
|
50
|
+
options.each do |key, val|
|
51
|
+
send("#{key}=", val)
|
52
|
+
end
|
35
53
|
end
|
36
54
|
|
37
55
|
def add_trend(name, &block)
|
38
|
-
|
56
|
+
raise ArgumentError, "D'oh! No block." unless block_given?
|
39
57
|
@trends[name] = block
|
40
58
|
end
|
41
|
-
|
59
|
+
|
42
60
|
def add_graph(name, &block)
|
43
|
-
|
61
|
+
raise ArgumentError, "D'oh! No block." unless block_given?
|
44
62
|
graph = Graph.new(name)
|
45
63
|
yield graph
|
46
64
|
@graphs << graph
|
47
65
|
end
|
48
|
-
|
66
|
+
#
|
49
67
|
# This is the preferred entry point.
|
50
|
-
def self.run(logfile, &block)
|
68
|
+
def self.run(logfile, options={}, &block)
|
51
69
|
throw "D'oh! No block." unless block_given?
|
52
|
-
l = Base.new
|
70
|
+
l = Base.new(options)
|
53
71
|
yield l
|
54
72
|
l.run logfile
|
55
73
|
end
|
56
74
|
|
57
75
|
def run(logfile)
|
58
76
|
counters = reset_counters
|
59
|
-
|
60
|
-
EventMachine.run do
|
61
|
-
EventMachine::add_periodic_timer(
|
77
|
+
|
78
|
+
EventMachine.run do
|
79
|
+
EventMachine::add_periodic_timer(step) do
|
62
80
|
@logger.debug "#{Time.now} #{counters.inspect}"
|
63
|
-
counters.each {|name, value| update_rrd(name, value)}
|
81
|
+
counters.each {|name, value| update_rrd(name, value)}
|
64
82
|
@graphs.each {|graph| build_graph(graph)}
|
65
83
|
build_page
|
66
84
|
counters = reset_counters
|
67
85
|
end
|
68
|
-
|
86
|
+
|
69
87
|
EventMachine::file_tail(logfile) do |filetail, line|
|
70
88
|
@trends.each do |name, block|
|
71
89
|
counters[name] += 1 if block.call(line)
|
@@ -76,7 +94,7 @@ module LogTrend
|
|
76
94
|
end
|
77
95
|
|
78
96
|
private
|
79
|
-
|
97
|
+
|
80
98
|
def reset_counters
|
81
99
|
counters = {}
|
82
100
|
@trends.keys.each do |k|
|
@@ -84,19 +102,19 @@ module LogTrend
|
|
84
102
|
end
|
85
103
|
counters
|
86
104
|
end
|
87
|
-
|
105
|
+
|
88
106
|
def update_rrd(name, value)
|
89
107
|
file_name = File.join(@rrd_dir,"#{name}.rrd")
|
90
108
|
rrd = RRD::Base.new(file_name)
|
91
|
-
if !File.
|
92
|
-
rrd.create :start => Time.now - 10.seconds, :step =>
|
93
|
-
datasource "#{name}_count", :type => :gauge, :heartbeat =>
|
109
|
+
if !File.file?(file_name)
|
110
|
+
rrd.create :start => Time.now - 10.seconds, :step => step do
|
111
|
+
datasource "#{name}_count", :type => :gauge, :heartbeat => heartbeat, :min => 0, :max => :unlimited
|
94
112
|
archive :average, :every => 5.minutes, :during => 1.year
|
95
113
|
end
|
96
114
|
end
|
97
115
|
rrd.update Time.now, value
|
98
116
|
end
|
99
|
-
|
117
|
+
|
100
118
|
def build_graph(graph)
|
101
119
|
rrd_dir = @rrd_dir
|
102
120
|
RRD.graph File.join(@graphs_dir,"#{graph.name}.png"), :title => graph.name, :width => 800, :height => 250, :color => ["FONT#000000", "BACK#FFFFFF"] do
|
@@ -104,35 +122,60 @@ module LogTrend
|
|
104
122
|
if point.style == :line
|
105
123
|
line File.join(rrd_dir,"#{point.name}.rrd"), "#{point.name}_count" => :average, :color => point.color, :label => point.name.to_s
|
106
124
|
elsif point.style == :area
|
107
|
-
area File.join(rrd_dir,"#{point.name}.rrd"), "#{point.name}_count" => :average, :color => point.color, :label => point.name.to_s
|
125
|
+
area File.join(rrd_dir,"#{point.name}.rrd"), "#{point.name}_count" => :average, :color => point.color, :label => point.name.to_s
|
108
126
|
end
|
109
127
|
end
|
110
128
|
end
|
111
129
|
end
|
112
|
-
|
130
|
+
|
113
131
|
def build_page
|
114
132
|
file_name = File.join(@graphs_dir,'index.html')
|
115
133
|
File.open(file_name, "w") do |f|
|
116
134
|
f << @template.result(binding)
|
117
135
|
end
|
118
136
|
end
|
119
|
-
|
137
|
+
|
138
|
+
def set_defaults
|
139
|
+
@graphs_dir = '.'
|
140
|
+
@rrd_dir = '.'
|
141
|
+
@trends = {}
|
142
|
+
@graphs = []
|
143
|
+
@logger = Logger.new(STDERR)
|
144
|
+
@logger.level = ($DEBUG and Logger::DEBUG or Logger::WARN)
|
145
|
+
|
146
|
+
@step = 1.minute
|
147
|
+
@heartbeat = 5.minutes
|
148
|
+
|
149
|
+
@template = ERB.new <<-EOF
|
150
|
+
<html>
|
151
|
+
<head>
|
152
|
+
<title>logtrend</title>
|
153
|
+
</head>
|
154
|
+
<body>
|
155
|
+
<% @graphs.each do |graph| %>
|
156
|
+
<img src='<%=graph.name%>.png' />
|
157
|
+
<% end %>
|
158
|
+
</body>
|
159
|
+
</html>
|
160
|
+
EOF
|
161
|
+
end
|
162
|
+
private :set_defaults
|
120
163
|
end
|
121
164
|
|
122
165
|
class Graph
|
123
|
-
|
166
|
+
|
124
167
|
attr_reader :points
|
125
168
|
attr_reader :name
|
126
|
-
|
169
|
+
|
127
170
|
def initialize(name)
|
128
171
|
@name = name
|
129
172
|
@points = []
|
130
173
|
end
|
131
|
-
|
174
|
+
|
132
175
|
def add_point(style,name,color)
|
133
|
-
@points << GraphPoint.new(style, name, color)
|
176
|
+
@points << GraphPoint.new(style, name, color)
|
134
177
|
end
|
135
178
|
end
|
136
179
|
|
137
180
|
GraphPoint = Struct.new(:style, :name, :color)
|
138
|
-
end
|
181
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logtrend
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 40202418402747
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 9
|
9
|
-
-
|
10
|
-
version: 0.9.
|
9
|
+
- 20101209201344
|
10
|
+
version: 0.9.20101209201344
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Michael Gorsuch
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-12-
|
18
|
+
date: 2010-12-09 00:00:00 -05:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|