logeater 0.2.4 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +7 -20
- data/db/migrate/20150110151439_create_requests.rb +3 -3
- data/db/migrate/20160218230227_add_indexes.rb +7 -0
- data/db/migrate/20160502131002_drop_http_response.rb +9 -0
- data/db/schema.rb +15 -13
- data/lib/logeater/cli.rb +2 -4
- data/lib/logeater/params_parser.rb +16 -16
- data/lib/logeater/parser.rb +30 -30
- data/lib/logeater/parser_errors.rb +5 -5
- data/lib/logeater/reader.rb +34 -30
- data/lib/logeater/version.rb +1 -1
- data/logeater.gemspec +2 -2
- data/test/integration/logeater_test.rb +16 -17
- data/test/test_helper.rb +3 -3
- data/test/unit/params_parser_test.rb +28 -28
- data/test/unit/parser_test.rb +68 -68
- metadata +9 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 678d8cc0af848644fd37cf1762d97a9d7779bd5a
|
4
|
+
data.tar.gz: 0ac115076cd9daedc7b74d4f01dd04e2d63e56a6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e3d70df2e56453afba0d382252555801e17e8d7c2ec7d83da83dc147e91bc61f6fd8dc4127bfaadf9c2d71bcdce561cd8c09403a5cc83a129443031ed3ff1545
|
7
|
+
data.tar.gz: 0085e7c733283ecb91ec507a5de05bb53bd2a2d1b4a63a23431cfb750505cd489e2425a63772da3f4f9cb92a274743551ac0a7c112cc0570d7f3c5813cc3272c
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Logeater
|
2
2
|
|
3
|
-
Parses log files and imports them into a database
|
3
|
+
Parses log files and imports them into a database or converts them to json
|
4
4
|
|
5
5
|
### Features
|
6
6
|
|
@@ -12,30 +12,17 @@ Parses log files and imports them into a database
|
|
12
12
|
|
13
13
|
### Usage
|
14
14
|
|
15
|
-
Clone the gem
|
16
15
|
|
17
|
-
|
18
|
-
bundle
|
16
|
+
###### Importing log files
|
19
17
|
|
20
|
-
|
18
|
+
gem install logeater
|
19
|
+
DATABASE_URL=<production database url> logeater import <app name> <path to logs>/*.gz
|
21
20
|
|
22
|
-
|
21
|
+
###### Converting log files to JSON
|
23
22
|
|
24
|
-
|
23
|
+
gem install logeater
|
24
|
+
logeater parse <app name> <path to logs>/*.gz > parsed-logs.json
|
25
25
|
|
26
|
-
bundle exec rake install
|
27
|
-
|
28
|
-
Import log files
|
29
|
-
|
30
|
-
logeater my_app ~/Desktop/logs/*.gz
|
31
|
-
|
32
|
-
|
33
|
-
### To Do
|
34
|
-
|
35
|
-
- Set up databases without cloning the gem?
|
36
|
-
- Import to a [Heroku Postgres database](https://dashboard.heroku.com/apps/logs-production)?
|
37
|
-
- Parse other kinds of logs?
|
38
|
-
- Collect other data from Rails logs?
|
39
26
|
|
40
27
|
|
41
28
|
### Contributing
|
@@ -3,7 +3,7 @@ class CreateRequests < ActiveRecord::Migration
|
|
3
3
|
create_table :requests do |t|
|
4
4
|
t.string :app, null: false
|
5
5
|
t.string :logfile, null: false
|
6
|
-
|
6
|
+
|
7
7
|
t.string :uuid, null: false
|
8
8
|
t.string :subdomain
|
9
9
|
t.timestamp :started_at
|
@@ -18,10 +18,10 @@ class CreateRequests < ActiveRecord::Migration
|
|
18
18
|
t.string :format
|
19
19
|
t.integer :http_status
|
20
20
|
t.string :http_response
|
21
|
-
|
21
|
+
|
22
22
|
t.timestamps
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
add_index :requests, :app
|
26
26
|
add_index :requests, :logfile
|
27
27
|
add_index :requests, :uuid, unique: true
|
data/db/schema.rb
CHANGED
@@ -11,38 +11,40 @@
|
|
11
11
|
#
|
12
12
|
# It's strongly recommended that you check this file into your version control system.
|
13
13
|
|
14
|
-
ActiveRecord::Schema.define(version:
|
14
|
+
ActiveRecord::Schema.define(version: 20160502131002) do
|
15
15
|
|
16
16
|
# These are extensions that must be enabled in order to support this database
|
17
17
|
enable_extension "plpgsql"
|
18
18
|
|
19
19
|
create_table "requests", force: :cascade do |t|
|
20
|
-
t.string "app",
|
21
|
-
t.string "logfile",
|
22
|
-
t.string "uuid",
|
23
|
-
t.string "subdomain"
|
20
|
+
t.string "app", null: false
|
21
|
+
t.string "logfile", null: false
|
22
|
+
t.string "uuid", null: false
|
23
|
+
t.string "subdomain"
|
24
24
|
t.datetime "started_at"
|
25
25
|
t.datetime "completed_at"
|
26
26
|
t.integer "duration"
|
27
|
-
t.string "http_method"
|
27
|
+
t.string "http_method"
|
28
28
|
t.text "path"
|
29
29
|
t.jsonb "params"
|
30
|
-
t.string "controller"
|
31
|
-
t.string "action"
|
32
|
-
t.string "remote_ip"
|
33
|
-
t.string "format"
|
30
|
+
t.string "controller"
|
31
|
+
t.string "action"
|
32
|
+
t.string "remote_ip"
|
33
|
+
t.string "format"
|
34
34
|
t.integer "http_status"
|
35
|
-
t.
|
36
|
-
t.datetime "
|
37
|
-
t.datetime "updated_at", null: false
|
35
|
+
t.datetime "created_at"
|
36
|
+
t.datetime "updated_at"
|
38
37
|
t.integer "user_id"
|
39
38
|
t.boolean "tester_bar"
|
40
39
|
end
|
41
40
|
|
42
41
|
add_index "requests", ["app"], name: "index_requests_on_app", using: :btree
|
42
|
+
add_index "requests", ["completed_at"], name: "index_requests_on_completed_at", using: :btree
|
43
43
|
add_index "requests", ["controller", "action"], name: "index_requests_on_controller_and_action", using: :btree
|
44
44
|
add_index "requests", ["http_status"], name: "index_requests_on_http_status", using: :btree
|
45
45
|
add_index "requests", ["logfile"], name: "index_requests_on_logfile", using: :btree
|
46
|
+
add_index "requests", ["params"], name: "index_requests_on_params", using: :gin
|
47
|
+
add_index "requests", ["subdomain"], name: "index_requests_on_subdomain", using: :btree
|
46
48
|
add_index "requests", ["uuid"], name: "index_requests_on_uuid", unique: true, using: :btree
|
47
49
|
|
48
50
|
end
|
data/lib/logeater/cli.rb
CHANGED
@@ -57,14 +57,12 @@ module Logeater
|
|
57
57
|
reader = Logeater::Reader.new(app, file, options.slice(:progress, :verbose))
|
58
58
|
reader.remove_existing_entries!
|
59
59
|
|
60
|
-
started_count = Logeater::Request.count
|
61
60
|
started_at = Time.now
|
62
|
-
reader.import
|
61
|
+
count = reader.import
|
63
62
|
finished_at = Time.now
|
64
|
-
finished_count = Logeater::Request.count
|
65
63
|
|
66
64
|
$stderr.puts " > \e[34mImported \e[1m%d\e[0;34m requests in \e[1m%.2f\e[0;34m seconds (%d of %d)\e[0m\n\n" % [
|
67
|
-
|
65
|
+
count,
|
68
66
|
finished_at - started_at,
|
69
67
|
i + 1,
|
70
68
|
files.length ]
|
@@ -3,15 +3,15 @@ require "ripper"
|
|
3
3
|
module Logeater
|
4
4
|
class ParamsParser
|
5
5
|
attr_reader :params
|
6
|
-
|
6
|
+
|
7
7
|
def initialize(params)
|
8
8
|
@params = params
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
def parse!
|
12
12
|
identify tokenize_hash(clean(params))
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
def clean(params)
|
16
16
|
loop do
|
17
17
|
result = params.gsub(/\#<((?:[\w]|::)+):[^<>]+>/) { "\"#{$1}\"" }
|
@@ -20,46 +20,46 @@ module Logeater
|
|
20
20
|
end
|
21
21
|
params
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
private
|
25
|
-
|
25
|
+
|
26
26
|
def tokenize_hash(ruby)
|
27
27
|
sexp = Ripper.sexp(ruby)
|
28
28
|
raise Parser::MalformedParameters.new(ruby) unless sexp
|
29
|
-
|
29
|
+
|
30
30
|
# [:program, [[:hash, ... ]]]
|
31
31
|
sexp[1][0]
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
def identify(sexp)
|
35
35
|
case sexp[0]
|
36
|
-
|
36
|
+
|
37
37
|
# [:string_literal, [:string_content, [:@tstring_content, "utf8", [1, 2]]]]
|
38
38
|
# [:string_literal, [:string_content]]
|
39
39
|
when :string_literal then sexp[1][1] ? sexp[1][1][1] : ""
|
40
|
-
|
40
|
+
|
41
41
|
# [:@int, "10", [1, 14]]
|
42
42
|
when :@int then sexp[1].to_i
|
43
|
-
|
43
|
+
|
44
44
|
# [:@float, "10.56", [1, 14]]
|
45
45
|
when :@float then sexp[1].to_f
|
46
|
-
|
46
|
+
|
47
47
|
# [:unary, :-@, [:@float, \\\"173.41\\\", [1, 17285]]]
|
48
48
|
when :unary then
|
49
49
|
return -identify(sexp[2]) if sexp[1] == :-@
|
50
50
|
raise Parser::ParserNotImplemented, "Unknown unary operator: #{sexp[1].inspect}"
|
51
|
-
|
51
|
+
|
52
52
|
# [:var_ref, [:@kw, "true", [1, 12]]]
|
53
53
|
when :var_ref then
|
54
54
|
return true if sexp[1][1] == "true"
|
55
55
|
return false if sexp[1][1] == "false"
|
56
56
|
return nil if sexp[1][1] == "nil"
|
57
57
|
raise Parser::ParserNotImplemented, "Unknown variable: #{sexp[1].inspect}"
|
58
|
-
|
58
|
+
|
59
59
|
# [:array, [[:@int, "1", [1, 9]], [:@int, "4", [1, 12]]]]
|
60
60
|
# [:array, nil]
|
61
61
|
when :array then sexp[1] ? sexp[1].map { |sexp| identify(sexp) } : []
|
62
|
-
|
62
|
+
|
63
63
|
# [:hash,
|
64
64
|
# [:assoclist_from_args,
|
65
65
|
# [[:assoc_new,
|
@@ -67,7 +67,7 @@ module Logeater
|
|
67
67
|
# [:string_literal, [:string_content, [:@tstring_content, "✓", [1, 12]]]]]]]]]
|
68
68
|
# [:hash, nil]
|
69
69
|
when :hash then sexp[1] ? sexp[1][1].each_with_object({}) { |(_, key, value), hash| hash[identify(key)] = identify(value) } : {}
|
70
|
-
|
70
|
+
|
71
71
|
else
|
72
72
|
raise Parser::ParserNotImplemented, "I don't know how to identify #{sexp.inspect}"
|
73
73
|
nil
|
@@ -76,6 +76,6 @@ module Logeater
|
|
76
76
|
raise Parser::ParserNotImplemented, "An exception occurred when parsing #{sexp.inspect}\n#{$!.class.name}: #{$!.message}"
|
77
77
|
nil
|
78
78
|
end
|
79
|
-
|
79
|
+
|
80
80
|
end
|
81
81
|
end
|
data/lib/logeater/parser.rb
CHANGED
@@ -5,52 +5,52 @@ require "logeater/parser_errors"
|
|
5
5
|
|
6
6
|
module Logeater
|
7
7
|
class Parser
|
8
|
-
|
9
|
-
|
8
|
+
|
9
|
+
|
10
10
|
LINE_MATCHER = /^
|
11
11
|
[A-Z],\s
|
12
12
|
\[(?<timestamp>[^\s\]]+)(?:\s[^\]]*)?\]\s+
|
13
13
|
(?<log_level>[A-Z]+)\s+\-\-\s:\s+
|
14
14
|
(?<message>.*)
|
15
15
|
$/x.freeze
|
16
|
-
|
16
|
+
|
17
17
|
REQUEST_LINE_MATCHER = /^
|
18
18
|
\[(?<subdomain>[^\]]+)\]\s
|
19
19
|
\[(?<uuid>[\w\-]{36})\]\s+
|
20
20
|
(?:\[(?:guest|user\.(?<user_id>\d+)(?<tester_bar>:cph)?)\]\s+)?
|
21
21
|
(?<message>.*)
|
22
22
|
$/x.freeze
|
23
|
-
|
23
|
+
|
24
24
|
REQUEST_STARTED_MATCHER = /^
|
25
25
|
Started\s
|
26
26
|
(?<http_method>[A-Z]+)\s
|
27
27
|
"(?<path>[^"]+)"\sfor\s
|
28
28
|
(?<remote_ip>[\d\.]+)
|
29
29
|
/x.freeze
|
30
|
-
|
30
|
+
|
31
31
|
REQUEST_CONTROLLER_MATCHER = /^
|
32
32
|
Processing\sby\s
|
33
33
|
(?<controller>[A-Za-z0-9:]+)\#
|
34
34
|
(?<action>[a-z_0-9]+)\sas\s
|
35
35
|
(?<format>.*)
|
36
36
|
/x.freeze
|
37
|
-
|
37
|
+
|
38
38
|
REQUEST_PARAMETERS_MATCHER = /^
|
39
39
|
Parameters:\s
|
40
40
|
(?<params>\{.*\})
|
41
41
|
$/x.freeze
|
42
|
-
|
42
|
+
|
43
43
|
REQUEST_COMPLETED_MATCHER = /^
|
44
44
|
Completed\s
|
45
45
|
(?<http_status>\d\d\d)\s
|
46
46
|
(?:(?<http_response>.*)\s)?in\s
|
47
47
|
(?<duration>[\d\.]+)(?<units>ms)\b
|
48
48
|
/x.freeze # optional: (Views: 0.1ms | ActiveRecord: 50.0ms)
|
49
|
-
|
49
|
+
|
50
50
|
def parse!(line)
|
51
51
|
match = line.match LINE_MATCHER
|
52
52
|
raise UnmatchedLine.new(line) unless match
|
53
|
-
|
53
|
+
|
54
54
|
result = {
|
55
55
|
type: :generic,
|
56
56
|
timestamp: match["timestamp"],
|
@@ -59,13 +59,13 @@ module Logeater
|
|
59
59
|
}.merge(
|
60
60
|
parse_message(match["message"]))
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
63
|
def parse_message(message)
|
64
64
|
match = message.match REQUEST_LINE_MATCHER
|
65
65
|
return {} unless match
|
66
|
-
|
66
|
+
|
67
67
|
message = match["message"]
|
68
|
-
|
68
|
+
|
69
69
|
{ subdomain: match["subdomain"],
|
70
70
|
uuid: match["uuid"],
|
71
71
|
type: :request_line,
|
@@ -75,37 +75,37 @@ module Logeater
|
|
75
75
|
}.merge(
|
76
76
|
parse_message_extra(message))
|
77
77
|
end
|
78
|
-
|
78
|
+
|
79
79
|
def parse_message_extra(message)
|
80
80
|
match = message.match(REQUEST_STARTED_MATCHER)
|
81
81
|
return parse_request_started_message(match) if match
|
82
|
-
|
82
|
+
|
83
83
|
match = message.match(REQUEST_CONTROLLER_MATCHER)
|
84
84
|
return parse_request_controller_message(match) if match
|
85
|
-
|
85
|
+
|
86
86
|
match = message.match(REQUEST_PARAMETERS_MATCHER)
|
87
87
|
return parse_request_params_message(match) if match
|
88
|
-
|
88
|
+
|
89
89
|
match = message.match(REQUEST_COMPLETED_MATCHER)
|
90
90
|
return parse_request_completed_message(match) if match
|
91
|
-
|
91
|
+
|
92
92
|
{}
|
93
93
|
end
|
94
|
-
|
94
|
+
|
95
95
|
def parse_request_started_message(match)
|
96
96
|
{ type: :request_started,
|
97
97
|
http_method: match["http_method"],
|
98
98
|
path: parsed_uri[match["path"]],
|
99
99
|
remote_ip: match["remote_ip"] }
|
100
100
|
end
|
101
|
-
|
101
|
+
|
102
102
|
def parse_request_controller_message(match)
|
103
103
|
{ type: :request_controller,
|
104
104
|
controller: normalized_controller_name[match["controller"]],
|
105
105
|
action: match["action"],
|
106
106
|
format: match["format"] }
|
107
107
|
end
|
108
|
-
|
108
|
+
|
109
109
|
def parse_request_params_message(match)
|
110
110
|
{ type: :request_params,
|
111
111
|
params: ParamsParser.new(match["params"]).parse! }
|
@@ -113,35 +113,35 @@ module Logeater
|
|
113
113
|
log "Unable to parse parameters: #{match["params"].inspect}"
|
114
114
|
{ params: match["params"] }
|
115
115
|
end
|
116
|
-
|
116
|
+
|
117
117
|
def parse_request_completed_message(match)
|
118
118
|
{ type: :request_completed,
|
119
119
|
http_status: match["http_status"].to_i,
|
120
120
|
http_response: match["http_response"],
|
121
121
|
duration: match["duration"].to_i }
|
122
122
|
end
|
123
|
-
|
124
|
-
|
125
|
-
|
123
|
+
|
124
|
+
|
125
|
+
|
126
126
|
def log(statement)
|
127
127
|
$stderr.puts "\e[33m#{statement}\e[0m"
|
128
128
|
end
|
129
|
-
|
130
|
-
|
131
|
-
|
129
|
+
|
130
|
+
|
131
|
+
|
132
132
|
def initialize
|
133
133
|
@normalized_controller_name = Hash.new do |hash, controller_name|
|
134
134
|
hash[controller_name] = controller_name.underscore.gsub(/_controller$/, "")
|
135
135
|
end
|
136
|
-
|
136
|
+
|
137
137
|
@parsed_uri = Hash.new do |hash, uri|
|
138
138
|
hash[uri] = Addressable::URI.parse(uri).path
|
139
139
|
end
|
140
140
|
end
|
141
|
-
|
141
|
+
|
142
142
|
private
|
143
143
|
attr_reader :normalized_controller_name,
|
144
144
|
:parsed_uri
|
145
|
-
|
145
|
+
|
146
146
|
end
|
147
147
|
end
|
@@ -1,30 +1,30 @@
|
|
1
1
|
module Logeater
|
2
2
|
class Parser
|
3
|
-
|
3
|
+
|
4
4
|
class Error < ::ArgumentError
|
5
5
|
def initialize(message, input)
|
6
6
|
super "#{message}: #{input.inspect}"
|
7
7
|
end
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
class UnmatchedLine < Error
|
11
11
|
def initialize(input)
|
12
12
|
super "Unmatched line", input
|
13
13
|
end
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
class MalformedTimestamp < Error
|
17
17
|
def initialize(input)
|
18
18
|
super "Malformed timestamp", input
|
19
19
|
end
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
class MalformedParameters < Error
|
23
23
|
def initialize(input)
|
24
24
|
super "Malformed parameters", input
|
25
25
|
end
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
class ParserNotImplemented < Error
|
29
29
|
def initialize(input)
|
30
30
|
super "Unable to parse", input
|
data/lib/logeater/reader.rb
CHANGED
@@ -6,7 +6,7 @@ require "oj"
|
|
6
6
|
module Logeater
|
7
7
|
class Reader
|
8
8
|
attr_reader :app, :path, :filename, :batch_size
|
9
|
-
|
9
|
+
|
10
10
|
def initialize(app, path, options={})
|
11
11
|
@app = app
|
12
12
|
@path = path
|
@@ -15,25 +15,28 @@ module Logeater
|
|
15
15
|
@show_progress = options.fetch :progress, false
|
16
16
|
@batch_size = options.fetch :batch_size, 500
|
17
17
|
@verbose = options.fetch :verbose, false
|
18
|
+
@count = 0
|
18
19
|
@requests = {}
|
19
20
|
@completed_requests = []
|
20
21
|
end
|
21
|
-
|
22
|
-
|
23
|
-
|
22
|
+
|
23
|
+
|
24
|
+
|
24
25
|
def reimport
|
25
26
|
remove_existing_entries!
|
26
27
|
import
|
27
28
|
end
|
28
|
-
|
29
|
+
|
29
30
|
def import
|
31
|
+
@count = 0
|
30
32
|
each_request do |attributes|
|
31
33
|
completed_requests.push Logeater::Request.new(attributes)
|
32
34
|
save! if completed_requests.length >= batch_size
|
33
35
|
end
|
34
36
|
save!
|
37
|
+
@count
|
35
38
|
end
|
36
|
-
|
39
|
+
|
37
40
|
def parse(to: $stdout)
|
38
41
|
to << "["
|
39
42
|
first = true
|
@@ -49,19 +52,19 @@ module Logeater
|
|
49
52
|
ensure
|
50
53
|
to << "]"
|
51
54
|
end
|
52
|
-
|
55
|
+
|
53
56
|
def remove_existing_entries!
|
54
57
|
Logeater::Request.where(app: app, logfile: filename).delete_all
|
55
58
|
end
|
56
|
-
|
59
|
+
|
57
60
|
def show_progress?
|
58
61
|
@show_progress
|
59
62
|
end
|
60
|
-
|
63
|
+
|
61
64
|
def verbose?
|
62
65
|
@verbose
|
63
66
|
end
|
64
|
-
|
67
|
+
|
65
68
|
def each_line
|
66
69
|
File.open(path) do |file|
|
67
70
|
io = File.extname(path) == ".gz" ? Zlib::GzipReader.new(file) : file
|
@@ -74,7 +77,7 @@ module Logeater
|
|
74
77
|
end
|
75
78
|
end
|
76
79
|
alias :scan :each_line
|
77
|
-
|
80
|
+
|
78
81
|
def each_request
|
79
82
|
count = 0
|
80
83
|
each_line do |line|
|
@@ -85,63 +88,64 @@ module Logeater
|
|
85
88
|
end
|
86
89
|
count
|
87
90
|
end
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
+
|
92
|
+
|
93
|
+
|
91
94
|
private
|
92
95
|
attr_reader :parser, :requests, :completed_requests
|
93
|
-
|
96
|
+
|
94
97
|
def process_line!(line, &block)
|
95
98
|
attributes = parser.parse!(line)
|
96
|
-
|
99
|
+
|
97
100
|
return if [:generic, :request_line].member? attributes[:type]
|
98
|
-
|
101
|
+
|
99
102
|
if attributes[:type] == :request_started
|
100
103
|
requests[attributes[:uuid]] = attributes
|
101
104
|
.slice(:uuid, :subdomain, :http_method, :path, :remote_ip, :user_id, :tester_bar)
|
102
105
|
.merge(started_at: attributes[:timestamp], logfile: filename, app: app)
|
103
106
|
return
|
104
107
|
end
|
105
|
-
|
108
|
+
|
106
109
|
request_attributes = requests[attributes[:uuid]]
|
107
110
|
unless request_attributes
|
108
111
|
log "Attempting to record #{attributes[:type].inspect}; but there is no request started with UUID #{attributes[:uuid].inspect}" if verbose?
|
109
112
|
return
|
110
113
|
end
|
111
|
-
|
114
|
+
|
112
115
|
case attributes[:type]
|
113
116
|
when :request_controller
|
114
117
|
request_attributes.merge! attributes.slice(:controller, :action, :format)
|
115
|
-
|
118
|
+
|
116
119
|
when :request_params
|
117
120
|
request_attributes.merge! attributes.slice(:params)
|
118
|
-
|
121
|
+
|
119
122
|
when :request_completed
|
120
123
|
request_attributes.merge! attributes
|
121
|
-
.slice(:http_status, :
|
124
|
+
.slice(:http_status, :duration)
|
122
125
|
.merge(completed_at: attributes[:timestamp])
|
123
|
-
|
126
|
+
|
124
127
|
yield request_attributes
|
125
128
|
requests.delete attributes[:uuid]
|
126
129
|
end
|
127
|
-
|
130
|
+
|
128
131
|
rescue Logeater::Parser::UnmatchedLine
|
129
132
|
$stderr.puts "\e[90m#{$!.message}\e[0m" if verbose?
|
130
133
|
rescue Logeater::Parser::Error
|
131
134
|
log $!.message
|
132
135
|
end
|
133
|
-
|
136
|
+
|
134
137
|
def save!
|
135
138
|
return if completed_requests.empty?
|
136
|
-
Logeater::Request.import(completed_requests)
|
139
|
+
result = Logeater::Request.import(completed_requests)
|
140
|
+
@count += result.num_inserts
|
137
141
|
completed_requests.clear
|
138
142
|
end
|
139
|
-
|
140
|
-
|
141
|
-
|
143
|
+
|
144
|
+
|
145
|
+
|
142
146
|
def log(statement)
|
143
147
|
$stderr.puts "\e[33m#{statement}\e[0m"
|
144
148
|
end
|
145
|
-
|
149
|
+
|
146
150
|
end
|
147
151
|
end
|
data/lib/logeater/version.rb
CHANGED
data/logeater.gemspec
CHANGED
@@ -24,9 +24,9 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.add_dependency "standalone_migrations", "~> 4.0.0"
|
25
25
|
spec.add_dependency "addressable"
|
26
26
|
spec.add_dependency "ruby-progressbar"
|
27
|
-
spec.add_dependency "activerecord-import", "~> 0.10
|
27
|
+
spec.add_dependency "activerecord-import", "~> 0.10"
|
28
28
|
spec.add_dependency "thor", "~> 0.19.1"
|
29
|
-
spec.add_dependency "oj", "~> 2.
|
29
|
+
spec.add_dependency "oj", "~> 2.15"
|
30
30
|
|
31
31
|
spec.add_development_dependency "bundler", "~> 1.7"
|
32
32
|
spec.add_development_dependency "rake", "~> 10.0"
|
@@ -2,27 +2,27 @@ require "test_helper"
|
|
2
2
|
|
3
3
|
class LogeaterTest < ActiveSupport::TestCase
|
4
4
|
attr_reader :logfile
|
5
|
-
|
6
|
-
|
5
|
+
|
6
|
+
|
7
7
|
context "Given the log of a single request, it" do
|
8
8
|
setup do
|
9
9
|
@logfile = File.expand_path("../../data/single_request.log", __FILE__)
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
should "identify the name of the logfile" do
|
13
13
|
assert_equal "single_request.log", reader.filename
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
should "create an entry in the database" do
|
17
17
|
assert_difference "Logeater::Request.count", +1 do
|
18
18
|
reader.import
|
19
19
|
end
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
should "set all the attributes" do
|
23
23
|
reader.import
|
24
24
|
request = Logeater::Request.first
|
25
|
-
|
25
|
+
|
26
26
|
params = {"refresh_page" => "true", "id" => "1035826228"}
|
27
27
|
assert_equal "test", request.app
|
28
28
|
assert_equal "single_request.log", request.logfile
|
@@ -39,42 +39,41 @@ class LogeaterTest < ActiveSupport::TestCase
|
|
39
39
|
assert_equal "71.218.222.249", request.remote_ip
|
40
40
|
assert_equal "JS", request.format
|
41
41
|
assert_equal 200, request.http_status
|
42
|
-
assert_equal "OK", request.http_response
|
43
42
|
end
|
44
|
-
|
43
|
+
|
45
44
|
should "erase any entries that had already been imported with that app and filename" do
|
46
45
|
Logeater::Request.create!(app: app, logfile: "single_request.log", uuid: "1")
|
47
46
|
Logeater::Request.create!(app: app, logfile: "single_request.log", uuid: "2")
|
48
47
|
Logeater::Request.create!(app: app, logfile: "single_request.log", uuid: "3")
|
49
|
-
|
48
|
+
|
50
49
|
assert_difference "Logeater::Request.count", -2 do
|
51
50
|
reader.reimport
|
52
51
|
end
|
53
52
|
end
|
54
53
|
end
|
55
|
-
|
56
|
-
|
54
|
+
|
55
|
+
|
57
56
|
context "Given a gzipped logfile, it" do
|
58
57
|
setup do
|
59
58
|
@logfile = File.expand_path("../../data/single_request.gz", __FILE__)
|
60
59
|
end
|
61
|
-
|
60
|
+
|
62
61
|
should "create an entry in the database" do
|
63
62
|
assert_difference "Logeater::Request.count", +1 do
|
64
63
|
reader.import
|
65
64
|
end
|
66
65
|
end
|
67
66
|
end
|
68
|
-
|
69
|
-
|
67
|
+
|
68
|
+
|
70
69
|
private
|
71
|
-
|
70
|
+
|
72
71
|
def app
|
73
72
|
"test"
|
74
73
|
end
|
75
|
-
|
74
|
+
|
76
75
|
def reader
|
77
76
|
Logeater::Reader.new(app, logfile)
|
78
77
|
end
|
79
|
-
|
78
|
+
|
80
79
|
end
|
data/test/test_helper.rb
CHANGED
@@ -1,83 +1,83 @@
|
|
1
1
|
require "test_helper"
|
2
2
|
|
3
3
|
class ParamsParserTest < ActiveSupport::TestCase
|
4
|
-
|
5
|
-
|
4
|
+
|
5
|
+
|
6
6
|
context "Given a simple hash, it" do
|
7
7
|
should "parse it" do
|
8
8
|
assert_parses '{"utf8"=>"✓"}' => {"utf8"=>"✓"}
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
should "handle integers" do
|
12
12
|
assert_parses '{"person_id"=>10}' => {"person_id"=>10}
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
should "handle floats" do
|
16
16
|
assert_parses '{"person_id"=>10.56}' => {"person_id"=>10.56}
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
should "handle negatives" do
|
20
20
|
assert_parses '{"person_id"=>-10}' => {"person_id"=>-10}
|
21
21
|
assert_parses '{"person_id"=>-10.56}' => {"person_id"=>-10.56}
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
should "handle booleans" do
|
25
25
|
assert_parses '{"visible"=>true}' => {"visible"=>true}
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
should "handle nil" do
|
29
29
|
assert_parses '{"visible"=>nil}' => {"visible"=>nil}
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
should "handle arrays" do
|
33
33
|
assert_parses '{"ids"=>[1, 4]}' => {"ids"=>[1,4]}
|
34
34
|
end
|
35
|
-
|
36
|
-
|
37
|
-
|
35
|
+
|
36
|
+
|
37
|
+
|
38
38
|
should "handle empty strings" do
|
39
39
|
assert_parses '{"visible"=>""}' => {"visible"=>""}
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
should "handle empty arrays" do
|
43
43
|
assert_parses '{"array"=>[]}' => {"array"=>[]}
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
should "handle empty hashes" do
|
47
47
|
assert_parses '{"hash"=>{}}' => {"hash"=>{}}
|
48
48
|
end
|
49
49
|
end
|
50
|
-
|
51
|
-
|
50
|
+
|
51
|
+
|
52
52
|
context "Given a hash with more than one key, it" do
|
53
53
|
should "parse it" do
|
54
54
|
assert_parses '{"utf8"=>"✓", "authenticity_token"=>"kDM07..."}' => {"utf8"=>"✓", "authenticity_token"=>"kDM07..."}
|
55
55
|
end
|
56
56
|
end
|
57
|
-
|
58
|
-
|
57
|
+
|
58
|
+
|
59
59
|
context "Given a hash with a nested hash, it" do
|
60
60
|
should "handle nested hashes" do
|
61
61
|
assert_parses '{"person"=>{"name"=>"Tim"}}' => {"person"=>{"name"=>"Tim"}}
|
62
62
|
end
|
63
|
-
|
63
|
+
|
64
64
|
should "handle arrays of nested hashes" do
|
65
65
|
assert_parses '{"people"=>[{"id"=>1},{"id"=>2}]}' => {"people"=>[{"id"=>1},{"id"=>2}]}
|
66
66
|
end
|
67
67
|
end
|
68
|
-
|
69
|
-
|
68
|
+
|
69
|
+
|
70
70
|
context "Given a hash with a serialized Ruby object, it" do
|
71
71
|
should "parse it" do
|
72
72
|
assert_parses '{"tempfile"=>#<Tempfile:/tmp/RackMultipart20141213-1847-1c8fpzw>}' => {"tempfile"=>"Tempfile"}
|
73
73
|
end
|
74
|
-
|
74
|
+
|
75
75
|
should "ignore the object's ivars" do
|
76
76
|
assert_parses '{"photo"=>#<ActionDispatch::Http::UploadedFile:0x007f7c685318a8 @tempfile=#<Tempfile:/tmp/RackMultipart20141213-1847-1c8fpzw>, @original_filename="Martin-008.JPG", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"person[photo]\"; filename=\"Martin-008.JPG\"\\r\\nContent-Type: image/jpeg\\r\\n\">}' => {"photo"=>"ActionDispatch::Http::UploadedFile"}
|
77
77
|
end
|
78
78
|
end
|
79
|
-
|
80
|
-
|
79
|
+
|
80
|
+
|
81
81
|
context "Given an invalid input, it" do
|
82
82
|
should "raise MalformedParameters" do
|
83
83
|
assert_raises Logeater::Parser::MalformedParameters do
|
@@ -85,17 +85,17 @@ class ParamsParserTest < ActiveSupport::TestCase
|
|
85
85
|
end
|
86
86
|
end
|
87
87
|
end
|
88
|
-
|
89
|
-
|
88
|
+
|
89
|
+
|
90
90
|
private
|
91
|
-
|
91
|
+
|
92
92
|
def assert_parses(params)
|
93
93
|
value, result = params.to_a[0]
|
94
94
|
assert_equal result, parse!(value)
|
95
95
|
end
|
96
|
-
|
96
|
+
|
97
97
|
def parse!(value)
|
98
98
|
Logeater::ParamsParser.new(value).parse!
|
99
99
|
end
|
100
|
-
|
100
|
+
|
101
101
|
end
|
data/test/unit/parser_test.rb
CHANGED
@@ -2,247 +2,247 @@ require "test_helper"
|
|
2
2
|
|
3
3
|
class ParserTest < ActiveSupport::TestCase
|
4
4
|
attr_reader :line
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
|
6
|
+
|
7
|
+
|
8
8
|
context "given a line that doesn't start with the generic log prefix, it" do
|
9
9
|
setup do
|
10
10
|
@line = "\n"
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
should "raise UnmatchedLine" do
|
14
14
|
assert_raises Logeater::Parser::UnmatchedLine do
|
15
15
|
parse!
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
|
20
|
+
|
21
|
+
|
22
22
|
context "given any generic log line, it" do
|
23
23
|
setup do
|
24
24
|
@line = "I, [2015-01-10T15:18:05.850839 #18070] INFO -- : the message\n"
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
should "identify the line as :generic" do
|
28
28
|
assert_parses type: :generic
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
should "identify the log level" do
|
32
32
|
assert_parses log_level: "INFO"
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
should "identify the time, including milliseconds" do
|
36
36
|
assert_parses timestamp: "2015-01-10T15:18:05.850839"
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
should "identify the remainder of the log message" do
|
40
40
|
assert_parses message: "the message"
|
41
41
|
end
|
42
42
|
end
|
43
|
-
|
44
|
-
|
45
|
-
|
43
|
+
|
44
|
+
|
45
|
+
|
46
46
|
context "given a log line for a Rails request, it" do
|
47
47
|
setup do
|
48
48
|
@line = "I, [2015-01-10T15:18:05.850839 #18070] INFO -- : [livingsaviorco] [2d89d962-57c4-47c9-a9e9-6a16a5f22a12] [gzip] Compress reponse by 42.2 KB (83.3%) (1.4ms)"
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
should "identify the line as :generic" do
|
52
52
|
assert_parses type: :request_line
|
53
53
|
end
|
54
|
-
|
54
|
+
|
55
55
|
should "identify the subdomain" do
|
56
56
|
assert_parses subdomain: "livingsaviorco"
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
should "identify the request's ID" do
|
60
60
|
assert_parses uuid: "2d89d962-57c4-47c9-a9e9-6a16a5f22a12"
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
63
|
should "identify the remainder of the log message" do
|
64
64
|
assert_parses message: "[gzip] Compress reponse by 42.2 KB (83.3%) (1.4ms)"
|
65
65
|
end
|
66
66
|
end
|
67
|
-
|
68
|
-
|
69
|
-
|
67
|
+
|
68
|
+
|
69
|
+
|
70
70
|
context "given a log line for a Rails request" do
|
71
71
|
context "that indicates the current user (who was logged in with the tester bar), it" do
|
72
72
|
setup do
|
73
73
|
@line = "I, [2015-01-10T15:18:05.850839 #18070] INFO -- : [livingsaviorco] [2d89d962-57c4-47c9-a9e9-6a16a5f22a12] [user.902544074:cph] [gzip] Compress reponse by 42.2 KB (83.3%) (1.4ms)"
|
74
74
|
end
|
75
|
-
|
75
|
+
|
76
76
|
should "identify the user's id" do
|
77
77
|
assert_parses user_id: 902544074
|
78
78
|
end
|
79
|
-
|
79
|
+
|
80
80
|
should "notice that the user was logged-in with the tester bar" do
|
81
81
|
assert_parses tester_bar: true
|
82
82
|
end
|
83
|
-
|
83
|
+
|
84
84
|
should "identify the remainder of the log message" do
|
85
85
|
assert_parses message: "[gzip] Compress reponse by 42.2 KB (83.3%) (1.4ms)"
|
86
86
|
end
|
87
87
|
end
|
88
|
-
|
88
|
+
|
89
89
|
context "that indicates the current user (who was not logged in with the tester bar), it" do
|
90
90
|
setup do
|
91
91
|
@line = "I, [2015-01-10T15:18:05.850839 #18070] INFO -- : [livingsaviorco] [2d89d962-57c4-47c9-a9e9-6a16a5f22a12] [user.902544074] [gzip] Compress reponse by 42.2 KB (83.3%) (1.4ms)"
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
94
|
should "identify the user's id" do
|
95
95
|
assert_parses user_id: 902544074
|
96
96
|
end
|
97
|
-
|
97
|
+
|
98
98
|
should "notice that the user was not logged-in with the tester bar" do
|
99
99
|
assert_parses tester_bar: false
|
100
100
|
end
|
101
|
-
|
101
|
+
|
102
102
|
should "identify the remainder of the log message" do
|
103
103
|
assert_parses message: "[gzip] Compress reponse by 42.2 KB (83.3%) (1.4ms)"
|
104
104
|
end
|
105
105
|
end
|
106
|
-
|
106
|
+
|
107
107
|
context "that indicates that the user is logged out, it" do
|
108
108
|
setup do
|
109
109
|
@line = "I, [2015-01-10T15:18:05.850839 #18070] INFO -- : [livingsaviorco] [2d89d962-57c4-47c9-a9e9-6a16a5f22a12] [guest] [gzip] Compress reponse by 42.2 KB (83.3%) (1.4ms)"
|
110
110
|
end
|
111
|
-
|
111
|
+
|
112
112
|
should "identify the remainder of the log message" do
|
113
113
|
assert_parses message: "[gzip] Compress reponse by 42.2 KB (83.3%) (1.4ms)"
|
114
114
|
end
|
115
115
|
end
|
116
116
|
end
|
117
|
-
|
118
|
-
|
119
|
-
|
117
|
+
|
118
|
+
|
119
|
+
|
120
120
|
context "given the \"Started\" line, it" do
|
121
121
|
setup do
|
122
122
|
@line = "I, [2015-01-10T15:18:12.064392 #2354] INFO -- : [livingsaviorco] [0fc5154a-c288-4bad-9c7a-de3d7e7d2496] Started GET \"/people/1035826228?refresh_page=true\" for 71.218.222.249 at 2015-01-10 15:18:12 +0000"
|
123
123
|
end
|
124
|
-
|
124
|
+
|
125
125
|
should "identify the line as :request_started" do
|
126
126
|
assert_parses type: :request_started
|
127
127
|
end
|
128
|
-
|
128
|
+
|
129
129
|
should "identify the HTTP method" do
|
130
130
|
assert_parses http_method: "GET"
|
131
131
|
end
|
132
|
-
|
132
|
+
|
133
133
|
should "identify the path (without params)" do
|
134
134
|
assert_parses path: "/people/1035826228"
|
135
135
|
end
|
136
|
-
|
136
|
+
|
137
137
|
should "identify the remote client's IP address" do
|
138
138
|
assert_parses remote_ip: "71.218.222.249"
|
139
139
|
end
|
140
140
|
end
|
141
|
-
|
142
|
-
|
143
|
-
|
141
|
+
|
142
|
+
|
143
|
+
|
144
144
|
context "given the \"Processing by\" line, it" do
|
145
145
|
setup do
|
146
146
|
@line = "I, [2015-01-10T15:18:12.067034 #2354] INFO -- : [livingsaviorco] [0fc5154a-c288-4bad-9c7a-de3d7e7d2496] Processing by Api::V1::PeopleController#show as JS"
|
147
147
|
end
|
148
|
-
|
148
|
+
|
149
149
|
should "identify the line as :request_controller" do
|
150
150
|
assert_parses type: :request_controller
|
151
151
|
end
|
152
|
-
|
152
|
+
|
153
153
|
should "identify the controller and action" do
|
154
154
|
assert_parses controller: "api/v1/people", action: "show"
|
155
155
|
end
|
156
|
-
|
156
|
+
|
157
157
|
should "identify the format requested" do
|
158
158
|
assert_parses format: "JS"
|
159
159
|
end
|
160
160
|
end
|
161
|
-
|
162
|
-
|
163
|
-
|
161
|
+
|
162
|
+
|
163
|
+
|
164
164
|
context "given the \"Parameters\" line, it" do
|
165
165
|
setup do
|
166
166
|
@line = "I, [2015-01-10T15:18:12.067134 #2354] INFO -- : [livingsaviorco] [0fc5154a-c288-4bad-9c7a-de3d7e7d2496] Parameters: {\"refresh_page\"=>\"true\", \"id\"=>\"1035826228\"}"
|
167
167
|
end
|
168
|
-
|
168
|
+
|
169
169
|
should "identify the line as :request_params" do
|
170
170
|
assert_parses type: :request_params
|
171
171
|
end
|
172
|
-
|
172
|
+
|
173
173
|
should "identify the params" do
|
174
174
|
assert_parses params: {"refresh_page" => "true", "id" => "1035826228"}
|
175
175
|
end
|
176
176
|
end
|
177
|
-
|
177
|
+
|
178
178
|
context "when the \"Parameters\" line contains invalid syntax, it" do
|
179
179
|
setup do
|
180
180
|
@line = "I, [2015-01-10T15:18:12.067134 #2354] INFO -- : [livingsaviorco] [0fc5154a-c288-4bad-9c7a-de3d7e7d2496] Parameters: {\"refresh_page\"=>}"
|
181
181
|
end
|
182
|
-
|
182
|
+
|
183
183
|
should "return the params unparsed" do
|
184
184
|
assert_parses params: "{\"refresh_page\"=>}"
|
185
185
|
end
|
186
186
|
end
|
187
|
-
|
188
|
-
|
189
|
-
|
187
|
+
|
188
|
+
|
189
|
+
|
190
190
|
context "given the \"Completed\" line, it" do
|
191
191
|
setup do
|
192
192
|
@line = "I, [2015-01-10T15:18:12.262903 #2354] INFO -- : [livingsaviorco] [0fc5154a-c288-4bad-9c7a-de3d7e7d2496] Completed 401 Unauthorized in 2ms"
|
193
193
|
end
|
194
|
-
|
194
|
+
|
195
195
|
should "identify the line as :request_completed" do
|
196
196
|
assert_parses type: :request_completed
|
197
197
|
end
|
198
|
-
|
198
|
+
|
199
199
|
should "identify the HTTP response" do
|
200
200
|
assert_parses http_status: 401, http_response: "Unauthorized"
|
201
201
|
end
|
202
|
-
|
202
|
+
|
203
203
|
should "identify the duration of the request" do
|
204
204
|
assert_parses duration: 2
|
205
205
|
end
|
206
206
|
end
|
207
|
-
|
207
|
+
|
208
208
|
context "when the \"Completed\" line doesn't have a textual description of the status, it" do
|
209
209
|
setup do
|
210
210
|
@line = "I, [2015-01-10T15:18:12.262903 #2354] INFO -- : [livingsaviorco] [0fc5154a-c288-4bad-9c7a-de3d7e7d2496] Completed 307 in 0.8ms"
|
211
211
|
end
|
212
|
-
|
212
|
+
|
213
213
|
should "be cool with that" do
|
214
214
|
assert_parses http_status: 307, http_response: nil
|
215
215
|
end
|
216
216
|
end
|
217
|
-
|
217
|
+
|
218
218
|
context "when the \"Completed\" line contains a breakdown of times, it" do
|
219
219
|
setup do
|
220
220
|
@line = "I, [2015-01-10T15:18:12.262903 #2354] INFO -- : [livingsaviorco] [0fc5154a-c288-4bad-9c7a-de3d7e7d2496] Completed 200 OK in 196ms (Views: 0.1ms | ActiveRecord: 50.0ms)"
|
221
221
|
end
|
222
|
-
|
222
|
+
|
223
223
|
should "identify the duration of the request" do
|
224
224
|
assert_parses duration: 196
|
225
225
|
end
|
226
226
|
end
|
227
|
-
|
228
|
-
|
229
|
-
|
227
|
+
|
228
|
+
|
229
|
+
|
230
230
|
private
|
231
|
-
|
231
|
+
|
232
232
|
def assert_parses(expectations)
|
233
233
|
results = parse!
|
234
|
-
|
234
|
+
|
235
235
|
expectations.each do |key, value|
|
236
236
|
assert_equal value, results[key]
|
237
237
|
end
|
238
238
|
end
|
239
|
-
|
239
|
+
|
240
240
|
def parse!
|
241
241
|
parser.parse!(line)
|
242
242
|
end
|
243
|
-
|
243
|
+
|
244
244
|
def parser
|
245
245
|
Logeater::Parser.new
|
246
246
|
end
|
247
|
-
|
247
|
+
|
248
248
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logeater
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bob Lail
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-05-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -100,14 +100,14 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 0.10
|
103
|
+
version: '0.10'
|
104
104
|
type: :runtime
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: 0.10
|
110
|
+
version: '0.10'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: thor
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -128,14 +128,14 @@ dependencies:
|
|
128
128
|
requirements:
|
129
129
|
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: 2.
|
131
|
+
version: '2.15'
|
132
132
|
type: :runtime
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: 2.
|
138
|
+
version: '2.15'
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: bundler
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -241,6 +241,8 @@ files:
|
|
241
241
|
- db/migrate/20150207183757_change_requests_params_to_jsonb.rb
|
242
242
|
- db/migrate/20150224021844_change_requests_path_to_text.rb
|
243
243
|
- db/migrate/20150602022241_add_user_id_and_tester_bar_to_requests.rb
|
244
|
+
- db/migrate/20160218230227_add_indexes.rb
|
245
|
+
- db/migrate/20160502131002_drop_http_response.rb
|
244
246
|
- db/schema.rb
|
245
247
|
- lib/logeater.rb
|
246
248
|
- lib/logeater/cli.rb
|
@@ -277,7 +279,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
277
279
|
version: '0'
|
278
280
|
requirements: []
|
279
281
|
rubyforge_project:
|
280
|
-
rubygems_version: 2.
|
282
|
+
rubygems_version: 2.5.1
|
281
283
|
signing_key:
|
282
284
|
specification_version: 4
|
283
285
|
summary: Parses log files and imports them into a database
|