danielsdeleo-teeth 0.0.2 → 0.1.0

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.
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