danielsdeleo-teeth 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/LICENSE +11 -0
  2. data/README.rdoc +107 -10
  3. data/Rakefile +47 -31
  4. data/VERSION.yml +4 -0
  5. data/doc/classes/String.html +182 -0
  6. data/doc/classes/Teeth/DuplicateDefinitionError.html +113 -0
  7. data/doc/classes/Teeth/DuplicateRuleError.html +113 -0
  8. data/doc/classes/Teeth/InvalidDefaultDefinitionName.html +113 -0
  9. data/doc/classes/Teeth/InvalidExtensionDirectory.html +113 -0
  10. data/doc/classes/Teeth/RuleStatement.html +291 -0
  11. data/doc/classes/Teeth/RuleStatementGroup.html +195 -0
  12. data/doc/classes/Teeth/Scanner.html +535 -0
  13. data/doc/classes/Teeth/ScannerDefinition.html +253 -0
  14. data/doc/classes/Teeth/ScannerDefinitionArgumentError.html +113 -0
  15. data/doc/classes/Teeth/ScannerDefinitionGroup.html +269 -0
  16. data/doc/classes/Teeth/ScannerError.html +111 -0
  17. data/doc/classes/Teeth.html +129 -0
  18. data/doc/created.rid +1 -0
  19. data/doc/files/README_rdoc.html +314 -0
  20. data/doc/files/ext/scan_apache_logs/scan_apache_logs_yy_c.html +101 -0
  21. data/doc/files/ext/scan_rails_logs/scan_rails_logs_yy_c.html +101 -0
  22. data/doc/files/lib/rule_statement_rb.html +101 -0
  23. data/doc/files/lib/scanner_definition_rb.html +101 -0
  24. data/doc/files/lib/scanner_rb.html +108 -0
  25. data/doc/files/lib/teeth_rb.html +111 -0
  26. data/doc/fr_class_index.html +39 -0
  27. data/doc/fr_file_index.html +33 -0
  28. data/doc/fr_method_index.html +60 -0
  29. data/doc/index.html +24 -0
  30. data/doc/rdoc-style.css +208 -0
  31. data/ext/scan_apache_logs/Makefile +158 -0
  32. data/ext/scan_apache_logs/extconf.rb +3 -0
  33. data/ext/scan_apache_logs/scan_apache_logs.yy +267 -0
  34. data/ext/scan_apache_logs/scan_apache_logs.yy.c +8355 -0
  35. data/ext/scan_rails_logs/Makefile +158 -0
  36. data/ext/scan_rails_logs/extconf.rb +3 -0
  37. data/ext/scan_rails_logs/scan_rails_logs.yy +376 -0
  38. data/ext/scan_rails_logs/scan_rails_logs.yy.c +11127 -0
  39. data/lib/rule_statement.rb +61 -0
  40. data/lib/scanner.rb +98 -0
  41. data/lib/scanner_definition.rb +116 -0
  42. data/lib/teeth.rb +5 -1
  43. data/scanners/scan_apache_logs.rb +27 -0
  44. data/scanners/scan_rails_logs.rb +70 -0
  45. data/spec/fixtures/rails_1x.log +59 -0
  46. data/spec/fixtures/rails_22.log +12 -0
  47. data/spec/fixtures/rails_22_cached.log +10 -0
  48. data/spec/fixtures/rails_unordered.log +24 -0
  49. data/spec/playground/show_apache_processing.rb +13 -0
  50. data/spec/spec_helper.rb +6 -1
  51. data/spec/unit/rule_statement_spec.rb +60 -0
  52. data/spec/unit/{tokenize_apache_spec.rb → scan_apache_spec.rb} +16 -11
  53. data/spec/unit/scan_rails_logs_spec.rb +90 -0
  54. data/spec/unit/scaner_definition_spec.rb +65 -0
  55. data/spec/unit/scanner_spec.rb +109 -0
  56. data/teeth.gemspec +31 -0
  57. data/templates/tokenizer.yy.erb +168 -0
  58. metadata +60 -15
  59. data/ext/extconf.rb +0 -4
  60. data/ext/tokenize_apache_logs.yy +0 -215
  61. data/ext/tokenize_apache_logs.yy.c +0 -12067
@@ -0,0 +1,61 @@
1
+ module Teeth
2
+
3
+ class DuplicateRuleError < ScannerError
4
+ end
5
+
6
+ class RuleStatement
7
+ attr_reader :name, :regex, :strip_ends, :skip_line, :begin
8
+
9
+ def initialize(name, regex, options={})
10
+ @name, @regex = name, regex
11
+ @strip_ends, @skip_line, @begin = options[:strip_ends], options[:skip_line], options[:begin]
12
+ @ignore = options[:ignore]
13
+ end
14
+
15
+ def ==(other)
16
+ other.kind_of?(RuleStatement) && other.name == name && other.regex == regex
17
+ end
18
+
19
+ def scanner_code
20
+ if @ignore
21
+ regex
22
+ else
23
+ "#{regex} {\n" + function_body + "}"
24
+ end
25
+ end
26
+
27
+ def function_body
28
+ code = ""
29
+ code += " BEGIN(#{@begin});\n" if @begin
30
+ if skip_line
31
+ code += " return EOF_KVPAIR;\n"
32
+ else
33
+ code += " KVPAIR #{name.to_s} = {\"#{name.to_s}\", #{yytext_statement}};\n" +
34
+ " return #{name.to_s};\n"
35
+ end
36
+ code
37
+ end
38
+
39
+ def yytext_statement
40
+ strip_ends ? "strip_ends(yytext)" : "yytext"
41
+ end
42
+
43
+ end
44
+
45
+ class RuleStatementGroup < Array
46
+
47
+ def add(name, regex, options={})
48
+ push RuleStatement.new(name, regex, options)
49
+ end
50
+
51
+ def rule_names
52
+ map { |rule_statement| rule_statement.name.to_s }
53
+ end
54
+
55
+ def method_missing(called_method_name, *args, &block)
56
+ args[1] ||={}
57
+ add(called_method_name, args[0], args[1])
58
+ end
59
+
60
+ end
61
+ end
data/lib/scanner.rb ADDED
@@ -0,0 +1,98 @@
1
+ require "erb"
2
+ module Teeth
3
+ class ScannerError < StandardError
4
+ end
5
+
6
+ class InvalidExtensionDirectory < ScannerError
7
+ end
8
+
9
+ class Scanner
10
+ TEMPLATE = File.dirname(__FILE__) + "/../templates/tokenizer.yy.erb"
11
+ attr_reader :scanner_defns, :scanner_rules, :rdoc
12
+
13
+ def initialize(name, ext_dir=nil)
14
+ @scanner_base_name, @ext_dir = name, ext_dir
15
+ @scanner_defns, @scanner_rules = ScannerDefinitionGroup.new, RuleStatementGroup.new
16
+ ensure_ext_dir_exists if ext_dir
17
+ end
18
+
19
+ def scanner_name
20
+ "scan_" + @scanner_base_name.to_s
21
+ end
22
+
23
+ def main_function_name
24
+ "t_" + scanner_name
25
+ end
26
+
27
+ def init_function_name
28
+ "Init_" + scanner_name
29
+ end
30
+
31
+ def function_prefix
32
+ @scanner_base_name.to_s + "_yy"
33
+ end
34
+
35
+ def entry_point
36
+ "scan_" + @scanner_base_name.to_s
37
+ end
38
+
39
+ def extconf
40
+ 'require "mkmf"' + "\n" + '$CFLAGS += " -Wall"' + "\n" + "create_makefile " +
41
+ %Q|"teeth/#{scanner_name}", "./"\n|
42
+ end
43
+
44
+ def rdoc=(rdoc_text)
45
+ lines_of_rdoc_text = rdoc_text.split("\n").map { |line| " * " + line.strip}
46
+ lines_of_rdoc_text.first[0] = "/"
47
+ lines_of_rdoc_text[-1] = lines_of_rdoc_text.last + " */"
48
+ @rdoc = lines_of_rdoc_text.join("\n")
49
+ end
50
+
51
+ def define(*args)
52
+ @scanner_defns.add(*args)
53
+ end
54
+
55
+ def definitions
56
+ yield @scanner_defns
57
+ end
58
+
59
+ def load_default_definitions_for(*defn_types)
60
+ @scanner_defns.defaults_for(*defn_types)
61
+ end
62
+
63
+ def rule(*args)
64
+ scanner_rules.add(*args)
65
+ end
66
+
67
+ def rules
68
+ yield scanner_rules
69
+ end
70
+
71
+ def generate
72
+ template = ERB.new(IO.read(TEMPLATE))
73
+ scanner = self
74
+ b = binding
75
+ template.result(b)
76
+ end
77
+
78
+ def write!
79
+ raise InvalidExtensionDirectory, "no extension directory specified" unless @ext_dir
80
+ File.open(@ext_dir + "/extconf.rb", "w") do |extconf_rb|
81
+ extconf_rb.write extconf
82
+ end
83
+ File.open(@ext_dir + "/" + scanner_name + ".yy", "w") do |scanner|
84
+ scanner.write generate
85
+ end
86
+ end
87
+
88
+ private
89
+
90
+ def ensure_ext_dir_exists
91
+ unless File.exist?(@ext_dir)
92
+ Dir.mkdir @ext_dir
93
+ end
94
+ end
95
+
96
+ end
97
+
98
+ end
@@ -0,0 +1,116 @@
1
+ module Teeth
2
+ class DuplicateDefinitionError < ScannerError
3
+ end
4
+
5
+ class InvalidDefaultDefinitionName < ScannerError
6
+ end
7
+
8
+ class ScannerDefinitionArgumentError < ScannerError
9
+ end
10
+
11
+ class ScannerDefinition
12
+ attr_reader :name, :regex
13
+
14
+ def initialize(name, regex, opts={})
15
+ if regex.kind_of?(Hash)
16
+ regex, opts = nil, regex
17
+ end
18
+ @name, @regex, @start_condition = name, regex, opts[:start_condition]
19
+ assert_valid_argument_combination
20
+ end
21
+
22
+ def scanner_code
23
+ start_condition_string + @name.to_s + regex_to_s
24
+ end
25
+
26
+ def regex_to_s
27
+ unless @regex.to_s == ""
28
+ " " + @regex.to_s
29
+ else
30
+ ""
31
+ end
32
+ end
33
+
34
+ def start_condition_string
35
+ case @start_condition.to_s
36
+ when /^inc/
37
+ "%s "
38
+ when /^exc/
39
+ "%x "
40
+ else
41
+ ""
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def assert_valid_argument_combination
48
+ if @start_condition
49
+ if @regex.to_s != "" # (nil or "").to_s == ""
50
+ raise ScannerDefinitionArgumentError, "a scanner definition cannot define both a regex and start condition"
51
+ end
52
+ end
53
+ end
54
+
55
+ end
56
+
57
+ class ScannerDefinitionGroup < Array
58
+
59
+ DEFAULT_DEFINITIONS = {}
60
+ DEFAULT_DEFINITIONS[:whitespace] = [["WS", '[[:space:]]'],
61
+ ["NON_WS", "([a-z]|[0-9]|[:punct:])"]]
62
+ DEFAULT_DEFINITIONS[:ip] = [ ["IP4_OCT", "[0-9]|[0-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]"],
63
+ ["HOST", '[a-z0-9][a-z0-9\-]*\.[a-z0-9][a-z0-9\-]*.[a-z0-9][a-z0-9\-\.]*[a-z]+(\:[0-9]+)?']]
64
+ DEFAULT_DEFINITIONS[:time] = [ ["WDAY", "mon|tue|wed|thu|fri|sat|sun"],
65
+ ["MON", "jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec"],
66
+ ["MONTH_NUM", "0[1-9]|1[0-2]"],
67
+ ["MDAY", "3[0-1]|[1-2][0-9]|0[1-9]"],
68
+ ["HOUR", "2[0-3]|[0-1][0-9]"],
69
+ ["MINSEC", "[0-5][0-9]|60"],
70
+ ["YEAR", "[0-9][0-9][0-9][0-9]"],
71
+ ["PLUSMINUS", '(\+|\-)']]
72
+ DEFAULT_DEFINITIONS[:web] = [ ["REL_URL", %q{(\/|\\\\|\.)[a-z0-9\._\~\-\/\?&;#=\%\:\+\[\]\\\\]*}],
73
+ ["PROTO", "(http:|https:)"],
74
+ ["ERR_LVL", "(emerg|alert|crit|err|error|warn|warning|notice|info|debug)"],
75
+ ["HTTP_VERS", 'HTTP\/(1.0|1.1)'],
76
+ ["HTTP_VERB", "(get|head|put|post|delete|trace|connect)"],
77
+ ["HTTPCODE", "(100|101|20[0-6]|30[0-5]|307|40[0-9]|41[0-7]|50[0-5])"],
78
+ ["BROWSER_STR", '\"(moz|msie|lynx).+\"']]
79
+
80
+ def add(name, regex, options={})
81
+ assert_defn_has_unique_name(name)
82
+ push ScannerDefinition.new(name, regex, options)
83
+ end
84
+
85
+ def assert_defn_has_unique_name(name)
86
+ if defn_names.include?(name.to_s)
87
+ raise DuplicateDefinitionError, "a definition for #{name.to_s} has already been defined"
88
+ end
89
+ end
90
+
91
+ def defn_names
92
+ map { |defn_statement| defn_statement.name.to_s }
93
+ end
94
+
95
+ def method_missing(called_method_name, *args, &block)
96
+ args[1] ||={}
97
+ add(called_method_name, args[0], args[1])
98
+ end
99
+
100
+ def defaults_for(*default_types)
101
+ default_types.each do |default_type|
102
+ unless default_definitions = DEFAULT_DEFINITIONS[default_type]
103
+ raise InvalidDefaultDefinitionName, "no default definitions found for #{default_type.to_s}"
104
+ end
105
+ default_definitions.each do |defn|
106
+ begin
107
+ add(defn.first, defn.last)
108
+ rescue DuplicateDefinitionError
109
+ end
110
+ end
111
+ end
112
+ end
113
+
114
+
115
+ end
116
+ end
data/lib/teeth.rb CHANGED
@@ -1 +1,5 @@
1
- require "teeth/tokenize_apache_logs"
1
+ require "teeth/scan_apache_logs"
2
+ $:.unshift File.dirname(__FILE__) + "/"
3
+ require "scanner"
4
+ require "scanner_definition"
5
+ require "rule_statement"
@@ -0,0 +1,27 @@
1
+ require File.dirname(__FILE__) + "/../lib/teeth"
2
+ scanner = Teeth::Scanner.new(:apache_logs, File.dirname(__FILE__) + '/../ext/scan_apache_logs/')
3
+ scanner.load_default_definitions_for(:whitespace, :ip, :time, :web)
4
+ scanner.rdoc = <<-RDOC
5
+ Scans self, which is expected to be a single line from an Apache error or
6
+ access log, and returns a Hash of the components of the log message. The
7
+ following parts of the log message are returned if they are present:
8
+ IPv4 address, datetime, HTTP Version used, the browser string given by the
9
+ client, any absolute or relative URLs, the error level, HTTP response code,
10
+ HTTP Method (verb), and any other uncategorized strings present.
11
+ RDOC
12
+ scanner.rules do |r|
13
+ r.ipv4_addr '{IP4_OCT}"."{IP4_OCT}"."{IP4_OCT}"."{IP4_OCT}'
14
+ r.apache_err_datetime '{WDAY}{WS}{MON}{WS}{MDAY}{WS}{HOUR}":"{MINSEC}":"{MINSEC}{WS}{YEAR}'
15
+ r.apache_access_datetime '{MDAY}\/{MON}\/{YEAR}":"{HOUR}":"{MINSEC}":"{MINSEC}{WS}{PLUSMINUS}{YEAR}'
16
+ r.http_version '{HTTP_VERS}'
17
+ r.browser_string '{BROWSER_STR}', :strip_ends => true
18
+ r.absolute_url '{PROTO}"\/\/"({HOST}|{IP4_OCT}"."{IP4_OCT}"."{IP4_OCT}"."{IP4_OCT})({REL_URL}|"\/")?'
19
+ r.host '{HOST}'
20
+ r.relative_url '{REL_URL}'
21
+ r.error_level '{ERR_LVL}'
22
+ r.http_response '{HTTPCODE}'
23
+ r.http_method '{HTTP_VERB}'
24
+ r.strings '{NON_WS}{NON_WS}*'
25
+ end
26
+
27
+ scanner.write!
@@ -0,0 +1,70 @@
1
+ require File.dirname(__FILE__) + "/../lib/teeth"
2
+ scanner = Teeth::Scanner.new(:rails_logs, File.dirname(__FILE__) + '/../ext/scan_rails_logs/')
3
+ scanner.load_default_definitions_for(:whitespace, :ip, :time, :web)
4
+ scanner.rdoc = <<-RDOC
5
+ Scans self, which is expected to be a line from a Rails production or dev log,
6
+ and returns a Hash of the significant features in the log message, including
7
+ the IP address of the client, the Controller and Action, any partials rendered,
8
+ and the time spent rendering them, the duration of the DB request(s), the HTTP
9
+ verb, etc.
10
+ RDOC
11
+ scanner.definitions do |define|
12
+ define.RAILS_TEASER '(processing|filter\ chain\ halted|rendered)'
13
+ define.CONTROLLER_ACTION '[a-z0-9]+#[a-z0-9]+'
14
+ define.RAILS_SKIP_LINES '(session\ id)'
15
+ define.CACHE_HIT 'actioncontroller"::"caching"::"actions"::"actioncachefilter":"0x[0-9a-f]+'
16
+ define.PARTIAL_SESSION_ID '^([a-z0-9]+"="*"-"+[a-z0-9]+)'
17
+ define.RAILS_ERROR_CLASS '([a-z]+\:\:)*[a-z]+error'
18
+ define.REQUEST_COMPLETED :start_condition => :exclusive
19
+ define.COMPLETED_REQ_VIEW_STATS :start_condition => :exclusive
20
+ define.COMPLETED_REQ_DB_STATS :start_condition => :exclusive
21
+ end
22
+ scanner.rules do |r|
23
+ # Processing DashboardController#index (for 1.1.1.1 at 2008-08-14 21:16:25) [GET]
24
+ r.teaser '{RAILS_TEASER}'
25
+ r.controller_action '{CONTROLLER_ACTION}'
26
+ r.ipv4_addr '{IP4_OCT}"."{IP4_OCT}"."{IP4_OCT}"."{IP4_OCT}'
27
+ r.datetime '{YEAR}"-"{MONTH_NUM}"-"{MDAY}{WS}{HOUR}":"{MINSEC}":"{MINSEC}'
28
+ r.http_method '{HTTP_VERB}'
29
+ # Session ID: BAh7CToMcmVmZXJlciIbL3ByaXNjaWxsYS9wZW9wbGUvMjM1MCIKZmxhc2hJ
30
+ # QzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVz ...
31
+ r.skip_lines '{RAILS_SKIP_LINES}', :skip_line => true
32
+ r.end_session_id '{PARTIAL_SESSION_ID}'
33
+ # RuntimeError (Cannot destroy employee): /app/models/employee.rb:198:in `before_destroy'
34
+ # ActionController::RoutingError (no route found to match "/favicon.ico" with {:method=>:get}):
35
+ # ActionView::TemplateError (No rhtml, rxml, rjs or delegate template found for /shared/_ids_modal_selection_panel in script/../config/../app/views) on line #2 of app/views/events/index.rhtml:
36
+ # ActionView::TemplateError (You have a nil object when you didn't expect it!
37
+ # NoMethodError (undefined method `find' for ActionController::Filters::Filter:Class):
38
+ r.error '{RAILS_ERROR_CLASS}'
39
+ r.error_message '\(({WS}|{NON_WS})+\)', :strip_ends => true
40
+ r.line_number '"#"[0-9]+{WS}', :strip_ends => true
41
+ r.file_and_line '{WS}{REL_URL}":"', :strip_ends => true
42
+ # Filter chain halted as [#<ActionController::Caching::Actions::ActionCacheFilter:0x2a999ad620 @check=nil, @options={:store_options=>{}, :layout=>nil, :cache_path=>#<Proc:0x0000002a999b8890@/app/controllers/cached_controller.rb:8>}>] rendered_or_redirected.
43
+ r.cache_hit '{CACHE_HIT}'
44
+ # Rendered shared/_analytics (0.2ms)
45
+ # Rendered layouts/_doc_type (0.00001)
46
+ r.partial '[a-z0-9]+{REL_URL}/\ \('
47
+ r.render_duration_ms '[0-9\.]+/ms\)'
48
+ r.render_duration_s '\([0-9\.]+\)', :strip_ends => true
49
+ # Completed in 0.21665 (4 reqs/sec) | Rendering: 0.00926 (4%) | DB: 0.00000 (0%) | 200 OK [http://demo.nu/employees]
50
+ # Completed in 614ms (View: 120, DB: 31) | 200 OK [http://floorplanner.local/demo]
51
+ r.teaser 'completed\ in', :begin => "REQUEST_COMPLETED"
52
+ r.duration_s '<REQUEST_COMPLETED>[0-9]+\.[0-9]+'
53
+ r.duration_ms '<REQUEST_COMPLETED>[0-9]+/ms'
54
+ r.start_view_stats '<REQUEST_COMPLETED>(View":"|Rendering":")', :begin => "COMPLETED_REQ_VIEW_STATS"
55
+ r.view_s '<COMPLETED_REQ_VIEW_STATS>([0-9]+\.[0-9]+)', :begin => "REQUEST_COMPLETED"
56
+ r.view_ms '<COMPLETED_REQ_VIEW_STATS>[0-9]+', :begin => "REQUEST_COMPLETED"
57
+ r.view_throwaway_tokens '<COMPLETED_REQ_VIEW_STATS>{CATCHALL}', :ignore => true
58
+ r.start_db_stats '<REQUEST_COMPLETED>DB":"', :begin => "COMPLETED_REQ_DB_STATS"
59
+ r.db_s '<COMPLETED_REQ_DB_STATS>[0-9]+\.[0-9]+', :begin => "REQUEST_COMPLETED"
60
+ r.db_ms '<COMPLETED_REQ_DB_STATS>[0-9]+', :begin => "REQUEST_COMPLETED"
61
+ r.db_throwaway_tokens '<COMPLETED_REQ_DB_STATS>{CATCHALL}', :ignore => true
62
+ r.url '<REQUEST_COMPLETED>\[{PROTO}"\/\/"({HOST}|{IP4_OCT}"."{IP4_OCT}"."{IP4_OCT}"."{IP4_OCT})({REL_URL}|"\/")?\]', :strip_ends => true
63
+ r.http_response '<REQUEST_COMPLETED>{HTTPCODE}'
64
+ r.strings '<REQUEST_COMPLETED>{NON_WS}{NON_WS}*'
65
+ r.ignore_others '<REQUEST_COMPLETED>{CATCHALL}', :ignore => true
66
+ # fallback to collecting strings
67
+ r.strings '{NON_WS}{NON_WS}*'
68
+ end
69
+
70
+ scanner.write!
@@ -0,0 +1,59 @@
1
+ Processing DashboardController#index (for 1.1.1.1 at 2008-08-14 21:16:25) [GET]
2
+ Session ID: BAh7CToMcmVmZXJlciIbL3ByaXNjaWxsYS9wZW9wbGUvMjM1MCIKZmxhc2hJ
3
+ QzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVz
4
+ ZWR7ADoNbGFuZ3VhZ2VvOhNMb2NhbGU6Ok9iamVjdBI6CUB3aW4wOg1AY291
5
+ bnRyeSIHTkw6CkBoYXNoaf3L2Js6DkBvcmlnX3N0ciIKbmwtTkw6DUBpc28z
6
+ MDY2MDoNQGNoYXJzZXQiClVURi04Og5AbGFuZ3VhZ2UiB25sOg5AbW9kaWZp
7
+ ZXIwOgtAcG9zaXgiCm5sX05MOg1AZ2VuZXJhbCIKbmxfTkw6DUB2YXJpYW50
8
+ MDoOQGZhbGxiYWNrMDoMQHNjcmlwdDA6DnBlcnNvbl9pZGkCMgc=--7918aed37151c13360cd370c37b541f136146fbd
9
+ Parameters: {"action"=>"index", "controller"=>"dashboard"}
10
+ Set language to: nl_NL
11
+ Rendering template within layouts/priscilla
12
+ Rendering dashboard/index
13
+ Completed in 0.22699 (4 reqs/sec) | Rendering: 0.02667 (11%) | DB: 0.03057 (13%) | 200 OK [https://www.example.com/]
14
+
15
+
16
+ Processing PeopleController#index (for 1.1.1.1 at 2008-08-14 21:16:30) [GET]
17
+ Session ID: BAh7CSIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNo
18
+ SGFzaHsABjoKQHVzZWR7ADoMcmVmZXJlciIQL3ByaXNjaWxsYS86DnBlcnNv
19
+ bl9pZGkCMgc6DWxhbmd1YWdlbzoTTG9jYWxlOjpPYmplY3QSOg1AY291bnRy
20
+ eSIHTkw6CUB3aW4wOg5Ab3JpZ19zdHIiCm5sLU5MOgpAaGFzaGn9y9ibOg5A
21
+ bGFuZ3VhZ2UiB25sOg1AY2hhcnNldCIKVVRGLTg6DUBpc28zMDY2MDoOQG1v
22
+ ZGlmaWVyMDoLQHBvc2l4IgpubF9OTDoNQHZhcmlhbnQwOg1AZ2VuZXJhbCIK
23
+ bmxfTkw6DEBzY3JpcHQwOg5AZmFsbGJhY2sw--48cbe3788ef27f6005f8e999610a42af6e90ffb3
24
+ Parameters: {"commit"=>"Zoek", "action"=>"index", "q"=>"gaby", "controller"=>"people"}
25
+ Set language to: nl_NL
26
+ Redirected to https://www.example.com/people/2545
27
+ Completed in 0.04759 (21 reqs/sec) | DB: 0.03719 (78%) | 302 Found [https://www.example.com/people?q=gaby&commit=Zoek]
28
+
29
+
30
+ Processing PeopleController#show (for 1.1.1.1 at 2008-08-14 21:16:30) [GET]
31
+ Session ID: BAh7CToMcmVmZXJlciIpL3ByaXNjaWxsYS9wZW9wbGU/cT1nYWJ5JmNvbW1p
32
+ dD1ab2VrIgpmbGFzaElDOidBY3Rpb25Db250cm9sbGVyOjpGbGFzaDo6Rmxh
33
+ c2hIYXNoewAGOgpAdXNlZHsAOg1sYW5ndWFnZW86E0xvY2FsZTo6T2JqZWN0
34
+ EjoJQHdpbjA6DUBjb3VudHJ5IgdOTDoKQGhhc2hp/cvYmzoOQG9yaWdfc3Ry
35
+ IgpubC1OTDoNQGlzbzMwNjYwOg1AY2hhcnNldCIKVVRGLTg6DkBsYW5ndWFn
36
+ ZSIHbmw6DkBtb2RpZmllcjA6C0Bwb3NpeCIKbmxfTkw6DUBnZW5lcmFsIgpu
37
+ bF9OTDoNQHZhcmlhbnQwOg5AZmFsbGJhY2swOgxAc2NyaXB0MDoOcGVyc29u
38
+ X2lkaQIyBw==--3ad1948559448522a49d289a2a89dc7ccbe8847a
39
+ Parameters: {"action"=>"show", "id"=>"2545", "controller"=>"people"}
40
+ Set language to: nl_NL
41
+ Rendering template within layouts/priscilla
42
+ Rendering people/show
43
+ person: John Doe, study_year: 2008/2009
44
+ Completed in 0.29077 (3 reqs/sec) | Rendering: 0.24187 (83%) | DB: 0.04030 (13%) | 200 OK [https://www.example.com/people/2545]
45
+
46
+
47
+ Processing PeopleController#picture (for 1.1.1.1 at 2008-08-14 21:16:35) [GET]
48
+ Session ID: BAh7CSIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNo
49
+ SGFzaHsABjoKQHVzZWR7ADoMcmVmZXJlciIbL3ByaXNjaWxsYS9wZW9wbGUv
50
+ MjU0NToOcGVyc29uX2lkaQIyBzoNbGFuZ3VhZ2VvOhNMb2NhbGU6Ok9iamVj
51
+ dBI6DUBjb3VudHJ5IgdOTDoJQHdpbjA6DkBvcmlnX3N0ciIKbmwtTkw6CkBo
52
+ YXNoaf3L2Js6DkBsYW5ndWFnZSIHbmw6DUBjaGFyc2V0IgpVVEYtODoNQGlz
53
+ bzMwNjYwOg5AbW9kaWZpZXIwOgtAcG9zaXgiCm5sX05MOg1AdmFyaWFudDA6
54
+ DUBnZW5lcmFsIgpubF9OTDoMQHNjcmlwdDA6DkBmYWxsYmFjazA=--797a33f280a482647111397d138d0918f2658167
55
+ Parameters: {"action"=>"picture", "id"=>"2545", "controller"=>"people"}
56
+ Set language to: nl_NL
57
+ Rendering template within layouts/priscilla
58
+ Rendering people/picture
59
+ Completed in 0.05383 (18 reqs/sec) | Rendering: 0.04622 (85%) | DB: 0.00206 (3%) | 200 OK [https://www.example.com/people/2545/picture]
@@ -0,0 +1,12 @@
1
+ Processing PageController#demo (for 127.0.0.1 at 2008-12-10 16:28:09) [GET]
2
+ Parameters: {"action"=>"demo", "controller"=>"page"}
3
+ Logging in from session data...
4
+ Logged in as test@example.com
5
+ Using locale: en-US, http-accept: ["en-US"], session: , det browser: en-US, det domain:
6
+ Rendering template within layouts/demo
7
+ Rendering page/demo
8
+ Rendered shared/_analytics (0.2ms)
9
+ Rendered layouts/_actions (0.6ms)
10
+ Rendered layouts/_menu (2.2ms)
11
+ Rendered layouts/_tabbar (0.5ms)
12
+ Completed in 614ms (View: 120, DB: 31) | 200 OK [http://www.example.coml/demo]
@@ -0,0 +1,10 @@
1
+ Processing CachedController#cached (for 1.1.1.1 at 2008-12-24 07:36:53) [GET]
2
+ Parameters: {"action"=>"cached", "controller"=>"cached"}
3
+ Logging in from session data...
4
+ Logging in using cookie...
5
+ Using locale: zh-Hans, http-accept: ["zh-CN", "zh-HK", "zh-TW", "en-US"], session: , det browser: zh-Hans, det domain: , user pref locale:
6
+ Referer: http://www.example.com/referer
7
+ Cached fragment hit: views/zh-Hans-www-cached-cached-all-CN--- (0.0ms)
8
+ Filter chain halted as [#<ActionController::Caching::Actions::ActionCacheFilter:0x2a999ad620 @check=nil, @options={:store_options=>{}, :layout=>nil, :cache_path=>#<Proc:0x0000002a999b8890@/app/controllers/cached_controller.rb:8>}>] rendered_or_redirected.
9
+ Filter chain halted as [#<ActionController::Filters::AroundFilter:0x2a999ad120 @identifier=nil, @kind=:filter, @options={:only=>#<Set: {"cached"}>, :if=>:not_logged_in?, :unless=>nil}, @method=#<ActionController::Caching::Actions::ActionCacheFilter:0x2a999ad620 @check=nil, @options={:store_options=>{}, :layout=>nil, :cache_path=>#<Proc:0x0000002a999b8890@/app/controllers/cached_controller.rb:8>}>>] did_not_yield.
10
+ Completed in 3ms (View: 0, DB: 0) | 200 OK [http://www.example.com/cached/cached/]
@@ -0,0 +1,24 @@
1
+ Processing AccountController#dashboard (for 1.1.1.1 at 2008-12-24 07:36:49) [GET]
2
+ Parameters: {"action"=>"dashboard", "controller"=>"account", "first_use"=>"true"}
3
+ Logging in from session data...
4
+
5
+
6
+ Processing ProjectsController#new (for 1.1.1.1 at 2008-12-24 07:36:49) [GET]
7
+ Parameters: {"action"=>"new", "controller"=>"projects"}
8
+ Rendering template within layouts/default
9
+ Rendering account/dashboard
10
+ Logging in from session data...
11
+ Logging in using cookie...
12
+ Using locale: en-US, http-accept: [], session: , det browser: , det domain: , user pref locale:
13
+ Rendered shared/_maintenance (0.6ms)
14
+ Rendering template within layouts/templates/general_default/index.html.erb
15
+ Rendered projects/_recent_designs (4.3ms)
16
+ Rendered projects/_project (13.6ms)
17
+ Rendered projects/_projects (18.7ms)
18
+ Rendered layouts/_menu (1.4ms)
19
+ Completed in 36ms (View: 30, DB: 3) | 200 OK [http://www.example.com/projects/new]
20
+ Rendered layouts/_actions (0.3ms)
21
+ Rendered layouts/_menu (1.6ms)
22
+ Rendered layouts/_tabbar (1.9ms)
23
+ Rendered layouts/_footer (3.2ms)
24
+ Completed in 50ms (View: 41, DB: 4) | 200 OK [http://www.example.com/dashboard?first_use=true]
@@ -0,0 +1,13 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper" # loads libs
2
+
3
+ error_line = %q{[Sun Nov 30 14:23:45 2008] [error] [client 10.0.1.197] Invalid URI in request GET .\\.\\.\\.\\.\\.\\.\\.\\.\\.\\/winnt/win.ini HTTP/1.1}
4
+ access_line = %q{127.81.248.53 - - [14/Jan/2009:11:49:43 -0500] "GET /reports/REPORT7_1ART02.pdf HTTP/1.1" 206 255404}
5
+
6
+ mangled_error_line = error_line + "more words"
7
+
8
+ puts "Processed Error Message:"
9
+ puts error_line.tokenize_apache_logs.inspect
10
+ puts "Error Message with extras:"
11
+ puts mangled_error_line.tokenize_apache_logs.inspect
12
+ puts "Processed Access Message"
13
+ puts access_line.tokenize_apache_logs.inspect
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,7 @@
1
- require 'teeth/tokenize_apache_logs'
1
+ require 'teeth/scan_apache_logs'
2
+ #require 'teeth/scan_rails_logs'
3
+
4
+ require File.dirname(__FILE__) + "/../lib/teeth"
2
5
 
3
6
  def be_greater_than(expected)
4
7
  simple_matcher("be greater than #{expected.to_s}") do |given, matcher|
@@ -8,3 +11,5 @@ def be_greater_than(expected)
8
11
  end
9
12
 
10
13
  end
14
+
15
+ include Teeth
@@ -0,0 +1,60 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe RuleStatement do
4
+
5
+ it "should generate a rule to short circuit scanner processing when given option :skip_line => true" do
6
+ rs = RuleStatement.new :rails_session_id_start, '{WS}*Session ID":"', :skip_line => true
7
+ expected =
8
+ %q|{WS}*Session ID":" {
9
+ return EOF_KVPAIR;
10
+ }|
11
+ rs.scanner_code.should == expected
12
+ end
13
+
14
+ it "should use strip_ends(yytext) in the rule when given option :strip_ends => true" do
15
+ rs = RuleStatement.new :browser_string, '{BROWSER_STR}', :strip_ends => true
16
+ expected =
17
+ %q|{BROWSER_STR} {
18
+ KVPAIR browser_string = {"browser_string", strip_ends(yytext)};
19
+ return browser_string;
20
+ }|
21
+ rs.scanner_code.should == expected
22
+ end
23
+
24
+ it "should include a call to the BEGIN() macro if given the :begin option" do
25
+ rs = RuleStatement.new :start_special_state, '{SPECIAL_STATE_REGEX}', :begin => "SPECIAL_STATE"
26
+ expected =
27
+ %q|{SPECIAL_STATE_REGEX} {
28
+ BEGIN(SPECIAL_STATE);
29
+ KVPAIR start_special_state = {"start_special_state", yytext};
30
+ return start_special_state;
31
+ }|
32
+ rs.scanner_code.should == expected
33
+ end
34
+
35
+ it "should not include any C code if given :ignore => true" do
36
+ rs = RuleStatement.new :catchall_rule_for_special_state, '<SPECIAL_STATE>{CATCHALL}', :ignore => true
37
+ expected = %q|<SPECIAL_STATE>{CATCHALL}|
38
+ rs.scanner_code.should == expected
39
+ end
40
+
41
+ end
42
+
43
+ describe RuleStatementGroup do
44
+
45
+ before(:each) do
46
+ @statement_group = RuleStatementGroup.new
47
+ end
48
+
49
+ it "should not reject duplicate rule definitions" do
50
+ @statement_group.add :explode_on_2nd_try, '{WS}'
51
+ lambda {@statement_group.add :explode_on_2nd_try, '{WS}'}.should_not raise_error DuplicateRuleError
52
+ end
53
+
54
+ it "should use method missing magic to define rules with sugary syntax" do
55
+ @statement_group.http_version "{HTTP_VERSION}"
56
+ @statement_group.first.should == RuleStatement.new(:http_version, "{HTTP_VERSION}")
57
+ end
58
+
59
+
60
+ end
@@ -1,15 +1,16 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper'
2
+ require "teeth/scan_apache_logs"
2
3
  $INCLUDE_SLOW_TESTS = true
3
4
 
4
5
  describe "Apache Lexer Extension", "when lexing apache errors" do
5
6
 
6
7
  before(:each) do
7
8
  str = "[Sun Nov 30 14:23:45 2008] [error] [client 10.0.1.197] Invalid URI in request GET .\\.\\.\\.\\.\\.\\.\\.\\.\\.\\/winnt/win.ini HTTP/1.1"
8
- @tokens = str.tokenize_apache_logs
9
+ @tokens = str.scan_apache_logs
9
10
  end
10
11
 
11
12
  it "should return an uuid and empty message for an empty string" do
12
- tokens = "".tokenize_apache_logs
13
+ tokens = "".scan_apache_logs
13
14
  tokens[:message].should == ""
14
15
  tokens[:id].should match(/[0-9A-F]{32}/)
15
16
  end
@@ -30,9 +31,13 @@ describe "Apache Lexer Extension", "when lexing apache errors" do
30
31
  @tokens[:relative_url].first.should == ".\\.\\.\\.\\.\\.\\.\\.\\.\\.\\/winnt/win.ini"
31
32
  end
32
33
 
34
+ it "should group unknown tokens into strings" do
35
+ @tokens[:strings].should == ["client", "Invalid URI in request"]
36
+ end
37
+
33
38
  it "should error out if the string is longer than 1M chars" do
34
39
  str = ((("abcDE" * 2) * 1000) * 100) + "X"
35
- lambda {str.tokenize_apache_logs[:word]}.should raise_error(ArgumentError, "string too long for tokenize_apache_logs! max length is 1,000,000 chars")
40
+ lambda {str.scan_apache_logs}.should raise_error(ArgumentError, "string too long for scan_apache_logs! max length is 1,000,000 chars")
36
41
  end
37
42
 
38
43
  end
@@ -40,19 +45,19 @@ end
40
45
  describe "Apache Lexer Extension", "when lexing apache access logs" do
41
46
  before(:each) do
42
47
  str = %q{couchdb.localdomain:80 172.16.115.1 - - [13/Dec/2008:19:26:11 -0500] "GET /favicon.ico HTTP/1.1" 404 241 "http://172.16.115.130/" "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_4_11; en) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/3.2.1 Safari/525.27.1"}
43
- @tokens = str.tokenize_apache_logs
48
+ @tokens = str.scan_apache_logs
44
49
  str2 = %q{127.162.219.29 - - [14/Jan/2009:15:32:32 -0500] "GET /reports//ee_commerce/paypalcart.php?toroot=http://www.shenlishi.com//skin/fxid1.txt?? HTTP/1.1" 404 5636}
45
- @tokens2 = str2.tokenize_apache_logs
50
+ @tokens2 = str2.scan_apache_logs
46
51
  str3 = %q{127.81.248.53 - - [14/Jan/2009:11:49:43 -0500] "GET /reports/REPORT7_1ART02.pdf HTTP/1.1" 206 255404}
47
- @tokens3 = str3.tokenize_apache_logs
52
+ @tokens3 = str3.scan_apache_logs
48
53
  str4 = %q{127.140.136.56 - - [23/Jan/2009:12:59:24 -0500] "GET /scripts/..%255c%255c../winnt/system32/cmd.exe?/c+dir" 404 5607}
49
- @tokens4 = str4.tokenize_apache_logs
54
+ @tokens4 = str4.scan_apache_logs
50
55
  str5 = %q{127.254.43.205 - - [26/Jan/2009:08:32:08 -0500] "GET /reports/REPORT9_3.pdf//admin/includes/footer.php?admin_template_default=../../../../../../../../../../../../../etc/passwd%00 HTTP/1.1" 404 5673}
51
- @tokens5 = str5.tokenize_apache_logs
56
+ @tokens5 = str5.scan_apache_logs
52
57
  str6 = %q{127.218.234.82 - - [26/Jan/2009:08:32:19 -0500] "GET /reports/REPORT9_3.pdf//admin/includes/header.php?bypass_installed=1&bypass_restrict=1&row_secure[account_theme]=../../../../../../../../../../../../../etc/passwd%00 HTTP/1.1" 404 5721}
53
- @tokens6 = str6.tokenize_apache_logs
58
+ @tokens6 = str6.scan_apache_logs
54
59
  str_naked_url = %q{127.218.234.82 - - [26/Jan/2009:08:32:19 -0500] "GET / HTTP/1.1" 404 5721}
55
- @tokens_naked_url = str_naked_url.tokenize_apache_logs
60
+ @tokens_naked_url = str_naked_url.scan_apache_logs
56
61
  end
57
62
 
58
63
  it "provides hints for testing" do
@@ -74,7 +79,7 @@ describe "Apache Lexer Extension", "when lexing apache access logs" do
74
79
  (300 .. 305).map { |n| n.to_s } + ['307'] + (400 .. 417).map { |n| n.to_s } +
75
80
  (500 .. 505).map { |n| n.to_s }
76
81
  codes.each do |code|
77
- code.tokenize_apache_logs[:http_response].first.should == code
82
+ code.scan_apache_logs[:http_response].first.should == code
78
83
  end
79
84
  end
80
85