forked from wvanbergen/request-log-analyzer
-
Notifications
You must be signed in to change notification settings - Fork 1
/
summarizer.rb
175 lines (149 loc) · 5.95 KB
/
summarizer.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
module RequestLogAnalyzer::Aggregator
class Summarizer < Base
class Definer
attr_reader :trackers
# Initialize tracker array
def initialize
@trackers = []
end
# Initialize tracker summarizer by duping the trackers of another summarizer
# <tt>other</tt> The other Summarizer
def initialize_copy(other)
@trackers = other.trackers.dup
end
# Drop all trackers
def reset!
@trackers = []
end
# Include missing trackers through method missing.
def method_missing(tracker_method, *args)
track(tracker_method, *args)
end
# Track the frequency of a specific category
# <tt>category_field</tt> Field to track
# <tt>options</tt> options are passed to new frequency tracker
def frequency(category_field, options = {})
if category_field.kind_of?(Symbol)
track(:frequency, options.merge(:category => category_field))
elsif category_field.kind_of?(Hash)
track(:frequency, category_field.merge(options))
end
end
# Track the duration of a specific category
# <tt>duration_field</tt> Field to track
# <tt>options</tt> options are passed to new frequency tracker
def duration(duration_field, options = {})
if duration_field.kind_of?(Symbol)
track(:duration, options.merge(:duration => duration_field))
elsif duration_field.kind_of?(Hash)
track(:duration, duration_field.merge(options))
end
end
# Helper function to initialize a tracker and add it to the tracker array.
# <tt>tracker_class</tt> The class to include
# <tt>optiont</tt> The options to pass to the trackers.
def track(tracker_klass, options = {})
tracker_klass = RequestLogAnalyzer::Tracker.const_get(RequestLogAnalyzer::to_camelcase(tracker_klass)) if tracker_klass.kind_of?(Symbol)
@trackers << tracker_klass.new(options)
end
end
attr_reader :trackers
attr_reader :warnings_encountered
# Initialize summarizer.
# Generate trackers from speciefied source.file_format.report_trackers and set them up
def initialize(source, options = {})
super(source, options)
@warnings_encountered = {}
@trackers = source.file_format.report_trackers
setup
end
def setup
end
# Call prepare on all trackers.
def prepare
raise "No trackers set up in Summarizer!" if @trackers.nil? || @trackers.empty?
@trackers.each { |tracker| tracker.prepare }
end
# Pass all requests to trackers and let them update if necessary.
# <tt>request</tt> The request to pass.
def aggregate(request)
@trackers.each do |tracker|
tracker.update(request) if tracker.should_update?(request)
end
end
# Call finalize on all trackers. Saves a YAML dump if this is set in the options.
def finalize
@trackers.each { |tracker| tracker.finalize }
save_results_dump(options[:dump]) if options[:dump]
end
# Saves the results of all the trackers in YAML format to a file.
# <tt>filename</tt> The file to store the YAML dump in.
def save_results_dump(filename)
File.open(filename, 'w') { |file| file.write(to_yaml) }
end
# Exports all the tracker results to YAML. It will call the to_yaml_object method
# for every tracker and combines these into a single YAML export.
def to_yaml
require 'yaml'
trackers_export = @trackers.inject({}) do |export, tracker|
export[tracker.title] = tracker.to_yaml_object; export
end
YAML::dump(trackers_export)
end
# Call report on all trackers.
# <tt>output</tt> RequestLogAnalyzer::Output object to output to
def report(output)
report_header(output)
if source.parsed_requests > 0
@trackers.each { |tracker| tracker.report(output) }
else
output.puts
output.puts('There were no requests analyzed.')
end
report_footer(output)
end
# Generate report header.
# <tt>output</tt> RequestLogAnalyzer::Output object to output to
def report_header(output)
output.title("Request summary")
output.with_style(:cell_separator => false) do
output.table({:width => 20}, {:font => :bold}) do |rows|
rows << ['Parsed lines:', source.parsed_lines]
rows << ['Skipped lines:', source.skipped_lines]
rows << ['Parsed requests:', source.parsed_requests]
rows << ['Skipped requests:', source.skipped_requests]
rows << ["Warnings:", @warnings_encountered.map { |(key, value)| "#{key}: #{value}" }.join(', ')] if has_warnings?
end
end
output << "\n"
end
# Generate report footer.
# <tt>output</tt> RequestLogAnalyzer::Output object to output to
def report_footer(output)
if has_log_ordering_warnings?
output.title("Parse warnings")
output.puts "Parseable lines were ancountered without a header line before it. It"
output.puts "could be that logging is not setup correctly for your application."
output.puts "Visit this website for logging configuration tips:"
output.puts output.link("http://github.com/wvanbergen/request-log-analyzer/wikis/configure-logging")
output.puts
end
end
# Returns true if there were any warnings generated by the trackers
def has_warnings?
@warnings_encountered.inject(0) { |result, (key, value)| result += value } > 0
end
# Returns true if there were any log ordering warnings
def has_log_ordering_warnings?
@warnings_encountered[:no_current_request] && @warnings_encountered[:no_current_request] > 0
end
# Store an encountered warning
# <tt>type</tt> Type of warning
# <tt>message</tt> Warning message
# <tt>lineno</tt> The line on which the error was encountered
def warning(type, message, lineno)
@warnings_encountered[type] ||= 0
@warnings_encountered[type] += 1
end
end
end