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