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.
- data/LICENSE +11 -0
- data/README.rdoc +107 -10
- data/Rakefile +47 -31
- data/VERSION.yml +4 -0
- data/doc/classes/String.html +182 -0
- data/doc/classes/Teeth/DuplicateDefinitionError.html +113 -0
- data/doc/classes/Teeth/DuplicateRuleError.html +113 -0
- data/doc/classes/Teeth/InvalidDefaultDefinitionName.html +113 -0
- data/doc/classes/Teeth/InvalidExtensionDirectory.html +113 -0
- data/doc/classes/Teeth/RuleStatement.html +291 -0
- data/doc/classes/Teeth/RuleStatementGroup.html +195 -0
- data/doc/classes/Teeth/Scanner.html +535 -0
- data/doc/classes/Teeth/ScannerDefinition.html +253 -0
- data/doc/classes/Teeth/ScannerDefinitionArgumentError.html +113 -0
- data/doc/classes/Teeth/ScannerDefinitionGroup.html +269 -0
- data/doc/classes/Teeth/ScannerError.html +111 -0
- data/doc/classes/Teeth.html +129 -0
- data/doc/created.rid +1 -0
- data/doc/files/README_rdoc.html +314 -0
- data/doc/files/ext/scan_apache_logs/scan_apache_logs_yy_c.html +101 -0
- data/doc/files/ext/scan_rails_logs/scan_rails_logs_yy_c.html +101 -0
- data/doc/files/lib/rule_statement_rb.html +101 -0
- data/doc/files/lib/scanner_definition_rb.html +101 -0
- data/doc/files/lib/scanner_rb.html +108 -0
- data/doc/files/lib/teeth_rb.html +111 -0
- data/doc/fr_class_index.html +39 -0
- data/doc/fr_file_index.html +33 -0
- data/doc/fr_method_index.html +60 -0
- data/doc/index.html +24 -0
- data/doc/rdoc-style.css +208 -0
- data/ext/scan_apache_logs/Makefile +158 -0
- data/ext/scan_apache_logs/extconf.rb +3 -0
- data/ext/scan_apache_logs/scan_apache_logs.yy +267 -0
- data/ext/scan_apache_logs/scan_apache_logs.yy.c +8355 -0
- data/ext/scan_rails_logs/Makefile +158 -0
- data/ext/scan_rails_logs/extconf.rb +3 -0
- data/ext/scan_rails_logs/scan_rails_logs.yy +376 -0
- data/ext/scan_rails_logs/scan_rails_logs.yy.c +11127 -0
- data/lib/rule_statement.rb +61 -0
- data/lib/scanner.rb +98 -0
- data/lib/scanner_definition.rb +116 -0
- data/lib/teeth.rb +5 -1
- data/scanners/scan_apache_logs.rb +27 -0
- data/scanners/scan_rails_logs.rb +70 -0
- data/spec/fixtures/rails_1x.log +59 -0
- data/spec/fixtures/rails_22.log +12 -0
- data/spec/fixtures/rails_22_cached.log +10 -0
- data/spec/fixtures/rails_unordered.log +24 -0
- data/spec/playground/show_apache_processing.rb +13 -0
- data/spec/spec_helper.rb +6 -1
- data/spec/unit/rule_statement_spec.rb +60 -0
- data/spec/unit/{tokenize_apache_spec.rb → scan_apache_spec.rb} +16 -11
- data/spec/unit/scan_rails_logs_spec.rb +90 -0
- data/spec/unit/scaner_definition_spec.rb +65 -0
- data/spec/unit/scanner_spec.rb +109 -0
- data/teeth.gemspec +31 -0
- data/templates/tokenizer.yy.erb +168 -0
- metadata +60 -15
- data/ext/extconf.rb +0 -4
- data/ext/tokenize_apache_logs.yy +0 -215
- data/ext/tokenize_apache_logs.yy.c +0 -12067
@@ -0,0 +1,90 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
require "teeth/scan_rails_logs"
|
3
|
+
# special shout out to Willem van Bergen, author of request-log-analyzer:
|
4
|
+
# http://github.com/wvanbergen/request-log-analyzer/
|
5
|
+
# Thanks for the log samples!
|
6
|
+
|
7
|
+
describe "Rails Request Log Lexer", "when lexing Rails 1.x logs" do
|
8
|
+
|
9
|
+
it "should extract the Controller, action, IP, timestamp and HTTP verb from a ``Processing'' line" do
|
10
|
+
line = %q{Processing PageController#demo (for 127.0.0.1 at 2008-12-10 16:28:09) [GET]}
|
11
|
+
result = line.scan_rails_logs
|
12
|
+
result[:teaser].first.should == "Processing"
|
13
|
+
result[:controller_action].first.should == "PageController#demo"
|
14
|
+
result[:ipv4_addr].first.should == "127.0.0.1"
|
15
|
+
result[:http_method].first.should == "GET"
|
16
|
+
result[:datetime].first.should == "2008-12-10 16:28:09"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should give a hash with :cache_hit => not falsy value for a cache hit" do
|
20
|
+
cache_hit = %q{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.}
|
21
|
+
cache_hit.scan_rails_logs[:cache_hit].should be_true
|
22
|
+
cache_hit.scan_rails_logs[:teaser].first.should == "Filter chain halted"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should extract an error, error_message, line of code, source code file, and stack_trace from a ``RuntimeError'' line" do
|
26
|
+
line = %q{RuntimeError (Cannot destroy employee): /app/models/employee.rb:198:in `before_destroy' }
|
27
|
+
result = line.scan_rails_logs
|
28
|
+
puts "###\n" + result.inspect
|
29
|
+
result[:error].first.should == "RuntimeError"
|
30
|
+
result[:error_message].first.should == "Cannot destroy employee"
|
31
|
+
result[:file_and_line].first.should == "/app/models/employee.rb:198"
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should extract the duration, view duration, db duration, HTTP status code, and url from a ``Completed'' line for Rails 1.x" do
|
35
|
+
rails_1x = %q{Completed in 0.21665 (4 reqs/sec) | Rendering: 0.00926 (4%) | DB: 0.00000 (0%) | 200 OK [http://demo.nu/employees]}
|
36
|
+
result = rails_1x.scan_rails_logs
|
37
|
+
puts "\n==completed (1.x): " + result.inspect
|
38
|
+
result[:teaser].first.should == "Completed in"
|
39
|
+
result[:duration_s].first.should == "0.21665"
|
40
|
+
result[:view_s].first.should == "0.00926"
|
41
|
+
result[:db_s].first.should == "0.00000"
|
42
|
+
result[:http_response].first.should == "200"
|
43
|
+
result[:url].first.should == "http://demo.nu/employees"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should extract the relevant components from a ``Completed'' line for Rails 2.x" do
|
47
|
+
rails_2x = %q{Completed in 614ms (View: 120, DB: 31) | 200 OK [http://floorplanner.local/demo]}
|
48
|
+
result = rails_2x.scan_rails_logs
|
49
|
+
puts "\n==completed (2.x): " + result.inspect
|
50
|
+
result[:teaser].first.should == "Completed in"
|
51
|
+
result[:duration_ms].first.should == "614"
|
52
|
+
result[:view_ms].first.should == "120"
|
53
|
+
result[:db_ms].first.should == "31"
|
54
|
+
result[:http_response].first.should == "200"
|
55
|
+
result[:url].first.should == "http://floorplanner.local/demo"
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should extract the duration and partial from a ``Rendered'' line for rails 2.x" do
|
59
|
+
rendered_2x = "Rendered shared/_analytics (0.2ms)"
|
60
|
+
#puts "(rendered 2.x): " + rendered_2x.scan_rails_logs.inspect
|
61
|
+
rendered_2x.scan_rails_logs[:partial].first.should == "shared/_analytics"
|
62
|
+
rendered_2x.scan_rails_logs[:render_duration_ms].first.should == "0.2"
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should extract the duration and partial from a ``Rendered'' line for rails 1.x" do
|
66
|
+
rendered_1x = "Rendered layouts/_doc_type (0.00001)"
|
67
|
+
#puts "(rendered 1.x): " + rendered_1x.scan_rails_logs.inspect
|
68
|
+
rendered_1x.scan_rails_logs[:partial].first.should == "layouts/_doc_type"
|
69
|
+
rendered_1x.scan_rails_logs[:render_duration_s].first.should == "0.00001"
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should skip session id lines" do
|
73
|
+
session_id = %q{Session ID: BAh7CToMcmVmZXJlciIbL3ByaXNjaWxsYS9wZW9wbGUvMjM1MCIKZmxhc2hJ}
|
74
|
+
session_id.scan_rails_logs.keys.map { |k| k.to_s}.sort.should == ["id", "message"]
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should not return a teaser for session id continuation lines" do
|
78
|
+
session_id_contd = "ZWR7ADoNbGFuZ3VhZ2VvOhNMb2NhbGU6Ok9iamVjdBI6CUB3aW4wOg1AY291"
|
79
|
+
session_id_contd.scan_rails_logs[:teaser].should be_nil
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should give a non falsy value for :end_session_id at for the last line of a session id" do
|
83
|
+
session_id_end_1 = "bmxfTkw6DEBzY3JpcHQwOg5AZmFsbGJhY2sw--48cbe3788ef27f6005f8e999610a42af6e90ffb3"
|
84
|
+
session_id_end_1.scan_rails_logs[:end_session_id].should_not be_nil
|
85
|
+
session_id_end_2 = "X2lkaQIyBw==--3ad1948559448522a49d289a2a89dc7ccbe8847a"
|
86
|
+
session_id_end_2.scan_rails_logs[:end_session_id].should_not be_nil
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
4
|
+
|
5
|
+
describe ScannerDefinition do
|
6
|
+
|
7
|
+
it "should generate text for flex definitions" do
|
8
|
+
defn = ScannerDefinition.new "IP4_OCTET", "[0-9]|[0-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]"
|
9
|
+
defn.scanner_code.should == "IP4_OCTET [0-9]|[0-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]"
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should complain if given a :start_condition option and a regex" do
|
13
|
+
fail = lambda {ScannerDefinition.new "FAIL", "FAIL", :start_condition => :inclusive}
|
14
|
+
fail.should raise_error ScannerDefinitionArgumentError
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should add %s to the beginning of the definition for option :start_condition => :inclusive" do
|
18
|
+
defn = ScannerDefinition.new "SPECIAL_STATE", :start_condition => :inclusive
|
19
|
+
defn.scanner_code.should == "%s SPECIAL_STATE"
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
describe ScannerDefinitionGroup do
|
25
|
+
before(:each) do
|
26
|
+
@defn_group = ScannerDefinitionGroup.new
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should hold multiple definitions" do
|
30
|
+
@defn_group.add "IP4_OCTET", "[0-9]|[0-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]"
|
31
|
+
@defn_group.add "WDAY", "mon|tue|wed|thu|fri|sat|sun"
|
32
|
+
@defn_group.should have(2).definitions
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should use method missing magic for sugary definitions" do
|
36
|
+
@defn_group.IP4_OCTET "[0-9]|[0-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]"
|
37
|
+
@defn_group.scanner_defns.first.scanner_code.should == "IP4_OCTET [0-9]|[0-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]"
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should reject duplicate definitions" do
|
41
|
+
@defn_group.add("WS", '[\000-\s]')
|
42
|
+
lambda { @defn_group.add("WS", '[\000-\s]') }.should raise_error DuplicateDefinitionError
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should add a default set of definitions" do
|
46
|
+
@defn_group.defaults_for(:whitespace, :ip)
|
47
|
+
@defn_group.defn_names.should == ["WS", "NON_WS", "IP4_OCT", "HOST"]
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should explode if requested to add default definitions that don't exist" do
|
51
|
+
lambda { @defn_group.defaults_for(:foobarbaz) }.should raise_error InvalidDefaultDefinitionName
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should not error if conflicting user definitions exist when loading defaults" do
|
55
|
+
@defn_group.add "WS", '[\000-\s]'
|
56
|
+
lambda {@defn_group.load_default_definitions_for(:whitespace)}.should_not raise_error
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should not override user definitions when loading defaults" do
|
60
|
+
@defn_group.add "WS", "a-telltale-sign"
|
61
|
+
@defn_group.load_default_definitions_for(:whitespace)
|
62
|
+
@defn_group.reject { |defn| defn.name != "WS" }.first.regex.should == "a-telltale-sign"
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
require "fileutils"
|
3
|
+
include FileUtils
|
4
|
+
describe Scanner do
|
5
|
+
TEST_EXT_DIR = File.dirname(__FILE__) + "/test_ext_dir"
|
6
|
+
|
7
|
+
IPV4_ACTION_TEXT =
|
8
|
+
%q|{IP4_OCT}"."{IP4_OCT}"."{IP4_OCT}"."{IP4_OCT} {
|
9
|
+
KVPAIR ipv4_addr = {"ipv4_addr", yytext};
|
10
|
+
return ipv4_addr;
|
11
|
+
}|
|
12
|
+
|
13
|
+
def clean_test_scanner_dir
|
14
|
+
rm_rf TEST_EXT_DIR
|
15
|
+
end
|
16
|
+
|
17
|
+
before(:all) do
|
18
|
+
clean_test_scanner_dir
|
19
|
+
end
|
20
|
+
|
21
|
+
before(:each) do
|
22
|
+
@scanner = Scanner.new(:rspec_awesome)
|
23
|
+
end
|
24
|
+
|
25
|
+
after(:all) do
|
26
|
+
clean_test_scanner_dir
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should generate the code for an extconf file" do
|
30
|
+
expected = 'require "mkmf"' + "\n" + '$CFLAGS += " -Wall"' + "\n" +
|
31
|
+
'create_makefile "teeth/scan_rspec_awesome", "./"' + "\n"
|
32
|
+
@scanner.extconf.should == expected
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should create a new directory for the extension" do
|
36
|
+
scanner = Scanner.new(:rspec_awesomeness, TEST_EXT_DIR)
|
37
|
+
File.exist?(TEST_EXT_DIR).should be_true
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should initialize with a name for for the tokenizer function and method" do
|
41
|
+
scanner = Scanner.new(:rails_dev_logs)
|
42
|
+
scanner.scanner_name.should == "scan_rails_dev_logs"
|
43
|
+
scanner.main_function_name.should == "t_scan_rails_dev_logs"
|
44
|
+
scanner.init_function_name.should == "Init_scan_rails_dev_logs"
|
45
|
+
scanner.function_prefix.should == "rails_dev_logs_yy"
|
46
|
+
scanner.entry_point.should == "scan_rails_dev_logs"
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should format rdoc for the C function which corresponds to the ruby method" do
|
50
|
+
@scanner.rdoc = <<-RDOC
|
51
|
+
Premature optimization
|
52
|
+
is the root of
|
53
|
+
all evil.
|
54
|
+
RDOC
|
55
|
+
@scanner.rdoc.should == "/* Premature optimization\n * is the root of\n * all evil. */"
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should accept a ``global'' option to include UUID generation or not"
|
59
|
+
|
60
|
+
it "should store scanner definitions" do
|
61
|
+
@scanner.define "IP4_OCTET", "[0-9]|[0-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]"
|
62
|
+
@scanner.scanner_defns.should have(1).definition
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should accept definitions in a block" do
|
66
|
+
@scanner.definitions do |d|
|
67
|
+
d.add "IP4_OCTET", "[0-9]|[0-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]"
|
68
|
+
d.add "WDAY", "mon|tue|wed|thu|fri|sat|sun"
|
69
|
+
end
|
70
|
+
@scanner.scanner_defns.should have(2).definitions
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should generate scanner rule statements, defaulting to returning a KVPAIR of rule name, yytext" do
|
74
|
+
@scanner.rule :ipv4_addr, '{IP4_OCT}"."{IP4_OCT}"."{IP4_OCT}"."{IP4_OCT}'
|
75
|
+
@scanner.scanner_rules.first.scanner_code.should == IPV4_ACTION_TEXT
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should accept rule statments in a block" do
|
79
|
+
@scanner.rules do |rules|
|
80
|
+
rules.add :ipv4_addr, '{IP4_OCT}"."{IP4_OCT}"."{IP4_OCT}"."{IP4_OCT}'
|
81
|
+
end
|
82
|
+
#@scanner.scanner_rules.first.scanner_code.should == IPV4_ACTION_TEXT
|
83
|
+
@scanner.scanner_rules.should have(1).scanner_rule
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should render a scanner scanner from the template" do
|
87
|
+
@scanner.load_default_definitions_for(:whitespace, :ip, :web)
|
88
|
+
@scanner.rules do |rule|
|
89
|
+
rule.ipv4_addr '{IP4_OCT}"."{IP4_OCT}"."{IP4_OCT}"."{IP4_OCT}'
|
90
|
+
rule.relative_url '{REL_URL}'
|
91
|
+
end
|
92
|
+
result = @scanner.generate
|
93
|
+
# real test is if scanner compiles and passes its own tests
|
94
|
+
result.should_not match(Regexp.new(Regexp.quote '<%='))
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should write the scanner and extconf files in the ext directory" do
|
98
|
+
scanner = Scanner.new(:rspec_awesomeness, TEST_EXT_DIR)
|
99
|
+
scanner.load_default_definitions_for(:whitespace, :ip, :web)
|
100
|
+
scanner.rules do |rule|
|
101
|
+
rule.ipv4_addr '{IP4_OCT}"."{IP4_OCT}"."{IP4_OCT}"."{IP4_OCT}'
|
102
|
+
rule.relative_url '{REL_URL}'
|
103
|
+
end
|
104
|
+
scanner.write!
|
105
|
+
File.exist?(TEST_EXT_DIR + "/extconf.rb").should be_true
|
106
|
+
File.exist?(TEST_EXT_DIR + "/scan_rspec_awesomeness.yy").should be_true
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
data/teeth.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{teeth}
|
5
|
+
s.version = "0.1.0"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Daniel DeLeo"]
|
9
|
+
s.date = %q{2009-03-29}
|
10
|
+
s.description = %q{Fast log file parsing in Ruby}
|
11
|
+
s.email = %q{ddeleo@basecommander.net}
|
12
|
+
s.extensions = ["ext/scan_apache_logs/extconf.rb", "ext/scan_rails_logs/extconf.rb"]
|
13
|
+
s.extra_rdoc_files = ["README.rdoc"]
|
14
|
+
s.files = ["LICENSE", "README.rdoc", "Rakefile", "VERSION.yml", "doc/classes/String.html", "doc/classes/Teeth.html", "doc/classes/Teeth/DuplicateDefinitionError.html", "doc/classes/Teeth/DuplicateRuleError.html", "doc/classes/Teeth/InvalidDefaultDefinitionName.html", "doc/classes/Teeth/InvalidExtensionDirectory.html", "doc/classes/Teeth/RuleStatement.html", "doc/classes/Teeth/RuleStatementGroup.html", "doc/classes/Teeth/Scanner.html", "doc/classes/Teeth/ScannerDefinition.html", "doc/classes/Teeth/ScannerDefinitionArgumentError.html", "doc/classes/Teeth/ScannerDefinitionGroup.html", "doc/classes/Teeth/ScannerError.html", "doc/created.rid", "doc/files/README_rdoc.html", "doc/files/ext/scan_apache_logs/scan_apache_logs_yy_c.html", "doc/files/ext/scan_rails_logs/scan_rails_logs_yy_c.html", "doc/files/lib/rule_statement_rb.html", "doc/files/lib/scanner_definition_rb.html", "doc/files/lib/scanner_rb.html", "doc/files/lib/teeth_rb.html", "doc/fr_class_index.html", "doc/fr_file_index.html", "doc/fr_method_index.html", "doc/index.html", "doc/rdoc-style.css", "ext/scan_apache_logs/Makefile", "ext/scan_apache_logs/extconf.rb", "ext/scan_apache_logs/scan_apache_logs.yy", "ext/scan_apache_logs/scan_apache_logs.yy.c", "ext/scan_rails_logs/Makefile", "ext/scan_rails_logs/extconf.rb", "ext/scan_rails_logs/scan_rails_logs.yy", "ext/scan_rails_logs/scan_rails_logs.yy.c", "lib/rule_statement.rb", "lib/scanner.rb", "lib/scanner_definition.rb", "lib/teeth.rb", "scanners/scan_apache_logs.rb", "scanners/scan_rails_logs.rb", "spec/fixtures/rails_1x.log", "spec/fixtures/rails_22.log", "spec/fixtures/rails_22_cached.log", "spec/fixtures/rails_unordered.log", "spec/playground/show_apache_processing.rb", "spec/spec.opts", "spec/spec_helper.rb", "spec/unit/rule_statement_spec.rb", "spec/unit/scan_apache_spec.rb", "spec/unit/scan_rails_logs_spec.rb", "spec/unit/scaner_definition_spec.rb", "spec/unit/scanner_spec.rb", "teeth.gemspec", "templates/tokenizer.yy.erb"]
|
15
|
+
s.has_rdoc = true
|
16
|
+
s.homepage = %q{http://github.com/danielsdeleo/teeth}
|
17
|
+
s.rdoc_options = ["--inline-source", "--charset=UTF-8"]
|
18
|
+
s.require_paths = [["lib"]]
|
19
|
+
s.rubygems_version = %q{1.3.1}
|
20
|
+
s.summary = %q{Fast log file parsing in Ruby}
|
21
|
+
|
22
|
+
if s.respond_to? :specification_version then
|
23
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
24
|
+
s.specification_version = 2
|
25
|
+
|
26
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
27
|
+
else
|
28
|
+
end
|
29
|
+
else
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
%option prefix="<%= scanner.function_prefix %>"
|
2
|
+
%option full
|
3
|
+
%option never-interactive
|
4
|
+
%option read
|
5
|
+
%option nounput
|
6
|
+
%option noyywrap noreject noyymore nodefault
|
7
|
+
%{
|
8
|
+
#include <ruby.h>
|
9
|
+
#include <uuid/uuid.h>
|
10
|
+
/* Data types */
|
11
|
+
typedef struct {
|
12
|
+
char *key;
|
13
|
+
char *value;
|
14
|
+
} KVPAIR;
|
15
|
+
const KVPAIR EOF_KVPAIR = {"EOF", "EOF"};
|
16
|
+
/* prototypes */
|
17
|
+
char *strip_ends(char *);
|
18
|
+
VALUE <%= scanner.main_function_name %>(VALUE);
|
19
|
+
void new_uuid(char *str_ptr);
|
20
|
+
void raise_error_for_string_too_long(VALUE string);
|
21
|
+
void include_message_in_token_hash(VALUE message, VALUE token_hash);
|
22
|
+
void add_uuid_to_token_hash(VALUE token_hash);
|
23
|
+
void push_kv_pair_to_hash(KVPAIR key_value, VALUE token_hash);
|
24
|
+
void concat_word_to_string(KVPAIR key_value, VALUE token_hash);
|
25
|
+
/* Set the scanner name, and return type */
|
26
|
+
#define YY_DECL KVPAIR <%= scanner.entry_point %>(void)
|
27
|
+
#define yyterminate() return EOF_KVPAIR
|
28
|
+
/* Ruby 1.8 and 1.9 compatibility */
|
29
|
+
#if !defined(RSTRING_LEN)
|
30
|
+
# define RSTRING_LEN(x) (RSTRING(x)->len)
|
31
|
+
# define RSTRING_PTR(x) (RSTRING(x)->ptr)
|
32
|
+
#endif
|
33
|
+
|
34
|
+
%}
|
35
|
+
|
36
|
+
/* Definitions */
|
37
|
+
|
38
|
+
CATCHALL (.|"\n")
|
39
|
+
|
40
|
+
<% scanner.scanner_defns.each do |scanner_defn| %>
|
41
|
+
<%= scanner_defn.scanner_code %>
|
42
|
+
<% end %>
|
43
|
+
|
44
|
+
%%
|
45
|
+
/*
|
46
|
+
Actions
|
47
|
+
*/
|
48
|
+
|
49
|
+
<% scanner.scanner_rules.each do |scanner_rule| %>
|
50
|
+
<%= scanner_rule.scanner_code %>
|
51
|
+
<% end %>
|
52
|
+
{CATCHALL} /* ignore */
|
53
|
+
%%
|
54
|
+
|
55
|
+
char *strip_ends(char *string) {
|
56
|
+
string[yyleng-1] = '\0';
|
57
|
+
++string;
|
58
|
+
return string;
|
59
|
+
}
|
60
|
+
|
61
|
+
void uuid_unparse_upper_sans_dash(const uuid_t uu, char *out)
|
62
|
+
{
|
63
|
+
sprintf(out,
|
64
|
+
"%02X%02X%02X%02X"
|
65
|
+
"%02X%02X"
|
66
|
+
"%02X%02X"
|
67
|
+
"%02X%02X"
|
68
|
+
"%02X%02X%02X%02X%02X%02X",
|
69
|
+
uu[0], uu[1], uu[2], uu[3],
|
70
|
+
uu[4], uu[5],
|
71
|
+
uu[6], uu[7],
|
72
|
+
uu[8], uu[9],
|
73
|
+
uu[10], uu[11], uu[12], uu[13], uu[14], uu[15]);
|
74
|
+
}
|
75
|
+
|
76
|
+
void new_uuid(char *str_ptr){
|
77
|
+
uuid_t new_uuid;
|
78
|
+
uuid_generate_time(new_uuid);
|
79
|
+
uuid_unparse_upper_sans_dash(new_uuid, str_ptr);
|
80
|
+
}
|
81
|
+
|
82
|
+
void raise_error_for_string_too_long(VALUE string){
|
83
|
+
if( RSTRING_LEN(string) > 1000000){
|
84
|
+
rb_raise(rb_eArgError, "string too long for <%=scanner.scanner_name %>! max length is 1,000,000 chars");
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
<%= scanner.rdoc %>
|
89
|
+
VALUE <%= scanner.main_function_name %>(VALUE self) {
|
90
|
+
KVPAIR kv_result;
|
91
|
+
int scan_complete = 0;
|
92
|
+
int building_words_to_string = 0;
|
93
|
+
VALUE token_hash = rb_hash_new();
|
94
|
+
|
95
|
+
BEGIN(INITIAL);
|
96
|
+
|
97
|
+
/* error out on absurdly large strings */
|
98
|
+
raise_error_for_string_too_long(self);
|
99
|
+
/* {:message => self()} */
|
100
|
+
include_message_in_token_hash(self, token_hash);
|
101
|
+
/* {:id => UUID} */
|
102
|
+
add_uuid_to_token_hash(token_hash);
|
103
|
+
yy_scan_string(RSTRING_PTR(self));
|
104
|
+
while (scan_complete == 0) {
|
105
|
+
kv_result = <%= scanner.entry_point %>();
|
106
|
+
if (kv_result.key == "EOF"){
|
107
|
+
scan_complete = 1;
|
108
|
+
}
|
109
|
+
else if (kv_result.key == "strings"){
|
110
|
+
/* build a string until we get a non-word */
|
111
|
+
if (building_words_to_string == 0){
|
112
|
+
building_words_to_string = 1;
|
113
|
+
push_kv_pair_to_hash(kv_result, token_hash);
|
114
|
+
}
|
115
|
+
else{
|
116
|
+
concat_word_to_string(kv_result, token_hash);
|
117
|
+
}
|
118
|
+
}
|
119
|
+
else {
|
120
|
+
building_words_to_string = 0;
|
121
|
+
push_kv_pair_to_hash(kv_result, token_hash);
|
122
|
+
}
|
123
|
+
}
|
124
|
+
yy_delete_buffer(YY_CURRENT_BUFFER);
|
125
|
+
return rb_obj_dup(token_hash);
|
126
|
+
}
|
127
|
+
|
128
|
+
void add_uuid_to_token_hash(VALUE token_hash) {
|
129
|
+
char new_uuid_str[33];
|
130
|
+
new_uuid(new_uuid_str);
|
131
|
+
VALUE hsh_key_id = ID2SYM(rb_intern("id"));
|
132
|
+
VALUE hsh_val_id = rb_tainted_str_new2(new_uuid_str);
|
133
|
+
rb_hash_aset(token_hash, hsh_key_id, hsh_val_id);
|
134
|
+
}
|
135
|
+
|
136
|
+
void include_message_in_token_hash(VALUE message, VALUE token_hash) {
|
137
|
+
/* {:message => self()} */
|
138
|
+
VALUE hsh_key_msg = ID2SYM(rb_intern("message"));
|
139
|
+
rb_hash_aset(token_hash, hsh_key_msg, message);
|
140
|
+
}
|
141
|
+
|
142
|
+
void concat_word_to_string(KVPAIR key_value, VALUE token_hash) {
|
143
|
+
char * space = " ";
|
144
|
+
VALUE hsh_key = ID2SYM(rb_intern(key_value.key));
|
145
|
+
VALUE hsh_value = rb_hash_aref(token_hash, hsh_key);
|
146
|
+
VALUE string = rb_ary_entry(hsh_value, -1);
|
147
|
+
rb_str_cat(string, space, 1);
|
148
|
+
rb_str_cat(string, key_value.value, yyleng);
|
149
|
+
}
|
150
|
+
|
151
|
+
void push_kv_pair_to_hash(KVPAIR key_value, VALUE token_hash) {
|
152
|
+
VALUE hsh_key = ID2SYM(rb_intern(key_value.key));
|
153
|
+
VALUE hsh_value = rb_hash_aref(token_hash, hsh_key);
|
154
|
+
VALUE ary_for_token_type = rb_ary_new();
|
155
|
+
switch (TYPE(hsh_value)) {
|
156
|
+
case T_NIL:
|
157
|
+
rb_ary_push(ary_for_token_type, rb_tainted_str_new2(key_value.value));
|
158
|
+
rb_hash_aset(token_hash, hsh_key, ary_for_token_type);
|
159
|
+
break;
|
160
|
+
case T_ARRAY:
|
161
|
+
rb_ary_push(hsh_value, rb_tainted_str_new2(key_value.value));
|
162
|
+
break;
|
163
|
+
}
|
164
|
+
}
|
165
|
+
|
166
|
+
void <%=scanner.init_function_name %>() {
|
167
|
+
rb_define_method(rb_cString, "<%= scanner.scanner_name %>", <%= scanner.main_function_name %>, 0);
|
168
|
+
}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: danielsdeleo-teeth
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel DeLeo
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-03-
|
12
|
+
date: 2009-03-29 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -18,24 +18,69 @@ email: ddeleo@basecommander.net
|
|
18
18
|
executables: []
|
19
19
|
|
20
20
|
extensions:
|
21
|
-
- ext/extconf.rb
|
21
|
+
- ext/scan_apache_logs/extconf.rb
|
22
|
+
- ext/scan_rails_logs/extconf.rb
|
22
23
|
extra_rdoc_files:
|
23
24
|
- README.rdoc
|
24
25
|
files:
|
26
|
+
- LICENSE
|
25
27
|
- README.rdoc
|
26
28
|
- Rakefile
|
27
|
-
-
|
28
|
-
-
|
29
|
-
-
|
29
|
+
- VERSION.yml
|
30
|
+
- doc/classes/String.html
|
31
|
+
- doc/classes/Teeth.html
|
32
|
+
- doc/classes/Teeth/DuplicateDefinitionError.html
|
33
|
+
- doc/classes/Teeth/DuplicateRuleError.html
|
34
|
+
- doc/classes/Teeth/InvalidDefaultDefinitionName.html
|
35
|
+
- doc/classes/Teeth/InvalidExtensionDirectory.html
|
36
|
+
- doc/classes/Teeth/RuleStatement.html
|
37
|
+
- doc/classes/Teeth/RuleStatementGroup.html
|
38
|
+
- doc/classes/Teeth/Scanner.html
|
39
|
+
- doc/classes/Teeth/ScannerDefinition.html
|
40
|
+
- doc/classes/Teeth/ScannerDefinitionArgumentError.html
|
41
|
+
- doc/classes/Teeth/ScannerDefinitionGroup.html
|
42
|
+
- doc/classes/Teeth/ScannerError.html
|
43
|
+
- doc/created.rid
|
44
|
+
- doc/files/README_rdoc.html
|
45
|
+
- doc/files/ext/scan_apache_logs/scan_apache_logs_yy_c.html
|
46
|
+
- doc/files/ext/scan_rails_logs/scan_rails_logs_yy_c.html
|
47
|
+
- doc/files/lib/rule_statement_rb.html
|
48
|
+
- doc/files/lib/scanner_definition_rb.html
|
49
|
+
- doc/files/lib/scanner_rb.html
|
50
|
+
- doc/files/lib/teeth_rb.html
|
51
|
+
- doc/fr_class_index.html
|
52
|
+
- doc/fr_file_index.html
|
53
|
+
- doc/fr_method_index.html
|
54
|
+
- doc/index.html
|
55
|
+
- doc/rdoc-style.css
|
56
|
+
- ext/scan_apache_logs/Makefile
|
57
|
+
- ext/scan_apache_logs/extconf.rb
|
58
|
+
- ext/scan_apache_logs/scan_apache_logs.yy
|
59
|
+
- ext/scan_apache_logs/scan_apache_logs.yy.c
|
60
|
+
- ext/scan_rails_logs/Makefile
|
61
|
+
- ext/scan_rails_logs/extconf.rb
|
62
|
+
- ext/scan_rails_logs/scan_rails_logs.yy
|
63
|
+
- ext/scan_rails_logs/scan_rails_logs.yy.c
|
64
|
+
- lib/rule_statement.rb
|
65
|
+
- lib/scanner.rb
|
66
|
+
- lib/scanner_definition.rb
|
30
67
|
- lib/teeth.rb
|
31
|
-
-
|
32
|
-
-
|
33
|
-
- spec/fixtures/
|
34
|
-
- spec/fixtures/
|
35
|
-
- spec/fixtures/
|
68
|
+
- scanners/scan_apache_logs.rb
|
69
|
+
- scanners/scan_rails_logs.rb
|
70
|
+
- spec/fixtures/rails_1x.log
|
71
|
+
- spec/fixtures/rails_22.log
|
72
|
+
- spec/fixtures/rails_22_cached.log
|
73
|
+
- spec/fixtures/rails_unordered.log
|
74
|
+
- spec/playground/show_apache_processing.rb
|
36
75
|
- spec/spec.opts
|
37
76
|
- spec/spec_helper.rb
|
38
|
-
- spec/unit/
|
77
|
+
- spec/unit/rule_statement_spec.rb
|
78
|
+
- spec/unit/scan_apache_spec.rb
|
79
|
+
- spec/unit/scan_rails_logs_spec.rb
|
80
|
+
- spec/unit/scaner_definition_spec.rb
|
81
|
+
- spec/unit/scanner_spec.rb
|
82
|
+
- teeth.gemspec
|
83
|
+
- templates/tokenizer.yy.erb
|
39
84
|
has_rdoc: true
|
40
85
|
homepage: http://github.com/danielsdeleo/teeth
|
41
86
|
post_install_message:
|
@@ -46,9 +91,9 @@ require_paths:
|
|
46
91
|
- - lib
|
47
92
|
required_ruby_version: !ruby/object:Gem::Requirement
|
48
93
|
requirements:
|
49
|
-
- -
|
94
|
+
- - ">="
|
50
95
|
- !ruby/object:Gem::Version
|
51
|
-
version:
|
96
|
+
version: "0"
|
52
97
|
version:
|
53
98
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
99
|
requirements:
|
@@ -58,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
58
103
|
version:
|
59
104
|
requirements: []
|
60
105
|
|
61
|
-
rubyforge_project:
|
106
|
+
rubyforge_project:
|
62
107
|
rubygems_version: 1.2.0
|
63
108
|
signing_key:
|
64
109
|
specification_version: 2
|
data/ext/extconf.rb
DELETED