logtrend 0.9.20101208165234 → 0.9.20101209201344
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|