alblogs 0.0.1 → 0.1.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/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/README.md +15 -0
- data/alblogs.gemspec +1 -1
- data/bin/alblogs +9 -192
- data/lib/alblogs.rb +41 -0
- data/lib/alblogs/entry.rb +21 -0
- data/lib/alblogs/request_matcher.rb +20 -0
- data/lib/alblogs/s3_bucket.rb +49 -0
- data/lib/alblogs/s3_file.rb +35 -0
- data/lib/alblogs/utils.rb +32 -0
- data/script/console +7 -0
- metadata +11 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eefbd8b8cac015fc5eee191b6e8a73ff9fde3c465f8d1410b76774e686aa9623
|
4
|
+
data.tar.gz: 3dfce14461c67824dd0ad6c5bd1ecee0081767de256191bda00cad1a99c18d1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b17f53979c6c56d8909d62e1fcacf468edcd0294fc41928cd62a706d5d206fd8495e16453c339ea5dfd236aef9158c8ad9cfcb00522cc961e18ce82e98f7a4e
|
7
|
+
data.tar.gz: d5d792b11d17f82e30a58901f18ac7a1cdf1e3cea5d07201645475a63a255a06769f64772c947653f6ab2533657c23c84bdd2db4517382d484389e506f07079f
|
data/.gitignore
CHANGED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
alblogs
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.6.3
|
data/README.md
CHANGED
@@ -2,6 +2,16 @@
|
|
2
2
|
|
3
3
|
Utility script for processing ALB access logs over a given time range
|
4
4
|
|
5
|
+
### Requirements
|
6
|
+
|
7
|
+
Need to have the AWS CLI installed. Can be found here https://aws.amazon.com/cli/
|
8
|
+
|
9
|
+
### Install
|
10
|
+
|
11
|
+
```
|
12
|
+
gem install alblogs
|
13
|
+
```
|
14
|
+
|
5
15
|
### Usage
|
6
16
|
|
7
17
|
```
|
@@ -25,3 +35,8 @@ Find all requests that took over 500ms to process in the last 12 hours.
|
|
25
35
|
alblogs -b 's3://<my-aws-alb-bucket-name>/access_logs/AWSLogs/<aws-account-id>/elasticloadbalancing/<aws-region>' -s '12 hours' -o slow-requests.log --request-times-over 0.5
|
26
36
|
```
|
27
37
|
|
38
|
+
### References
|
39
|
+
|
40
|
+
AWS Documentaion: Access Logs for Your Application Load Balancer
|
41
|
+
|
42
|
+
https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-access-logs.html
|
data/alblogs.gemspec
CHANGED
data/bin/alblogs
CHANGED
@@ -4,126 +4,7 @@ require 'optparse'
|
|
4
4
|
require 'time'
|
5
5
|
require 'shellwords'
|
6
6
|
require 'json'
|
7
|
-
|
8
|
-
def run_or_die(cmd)
|
9
|
-
res = `#{cmd}`
|
10
|
-
raise("command failed with #{$?}, #{cmd}") unless $?.success?
|
11
|
-
res
|
12
|
-
end
|
13
|
-
|
14
|
-
def parse_time_offset(str)
|
15
|
-
if str =~ /min/
|
16
|
-
str.sub(/ *min.*/, '').to_i * 60
|
17
|
-
elsif str =~ /hour/
|
18
|
-
str.sub(/ *hour.*/, '').to_i * 3600
|
19
|
-
elsif str =~ /day/
|
20
|
-
str.sub(/ *day.*/, '').to_i * 86400
|
21
|
-
else
|
22
|
-
nil
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def time_ago(now, str)
|
27
|
-
if offset = parse_time_offset(str)
|
28
|
-
time = now - offset
|
29
|
-
time - (time.to_i % 60) # round to the start of the minute
|
30
|
-
else
|
31
|
-
Time.parse(str).utc
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def get_s3_files(bucket, date_path, profile)
|
36
|
-
s3_url = "#{bucket}/#{date_path}/"
|
37
|
-
cmd = "aws"
|
38
|
-
cmd << " --profile #{Shellwords.escape(profile)}" if profile
|
39
|
-
cmd << " s3 ls #{Shellwords.escape(s3_url)}"
|
40
|
-
output = run_or_die(cmd)
|
41
|
-
output.split("\n").map do |line|
|
42
|
-
line =~ /(\d{4}\-\d{2}\-\d{2} \d{2}:\d{2}:\d{2}) +(\d+) +(.+)/
|
43
|
-
last_modified_at = Time.parse($1).utc
|
44
|
-
file_size = $2.to_i
|
45
|
-
file = $3
|
46
|
-
S3File.new("#{s3_url}#{file}", file_size, last_modified_at)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def get_s3_files_in_range(range, bucket, profile)
|
51
|
-
s3_files = {}
|
52
|
-
time = range.begin
|
53
|
-
while time < range.end
|
54
|
-
date_path = time.strftime('%Y/%m/%d')
|
55
|
-
get_s3_files(bucket, date_path, profile).each do |s3_file|
|
56
|
-
next unless s3_file.in_range?(range)
|
57
|
-
s3_files[s3_file.file] ||= s3_file
|
58
|
-
end
|
59
|
-
time += 86_400
|
60
|
-
end
|
61
|
-
s3_files
|
62
|
-
end
|
63
|
-
|
64
|
-
def download_s3_file(s3_file, dest, profile)
|
65
|
-
cmd = "aws"
|
66
|
-
cmd << " --profile #{Shellwords.escape(profile)}" if profile
|
67
|
-
cmd << " s3 cp #{Shellwords.escape(s3_file.file)} #{Shellwords.escape(dest)}.gz"
|
68
|
-
run_or_die(cmd)
|
69
|
-
cmd = "gzip -f -d #{Shellwords.escape(dest)}.gz"
|
70
|
-
run_or_die(cmd)
|
71
|
-
end
|
72
|
-
|
73
|
-
def alb_log_fields
|
74
|
-
@alb_log_fields ||=
|
75
|
-
begin
|
76
|
-
not_a_space = '([^ ]+)'
|
77
|
-
in_quotes = '"(.*?)"'
|
78
|
-
|
79
|
-
{
|
80
|
-
type: not_a_space,
|
81
|
-
timestamp: not_a_space,
|
82
|
-
elb: not_a_space,
|
83
|
-
client_port: not_a_space,
|
84
|
-
target_port: not_a_space,
|
85
|
-
request_processing_time: not_a_space,
|
86
|
-
target_processing_time: not_a_space,
|
87
|
-
response_processing_time: not_a_space,
|
88
|
-
elb_status_code: not_a_space,
|
89
|
-
target_status_code: not_a_space,
|
90
|
-
received_bytes: not_a_space,
|
91
|
-
sent_bytes: not_a_space,
|
92
|
-
request: in_quotes,
|
93
|
-
user_agent: in_quotes,
|
94
|
-
ssl_cipher: not_a_space,
|
95
|
-
ssl_protocol: not_a_space,
|
96
|
-
target_group_arn: not_a_space,
|
97
|
-
trace_id: in_quotes,
|
98
|
-
domain_name: in_quotes,
|
99
|
-
chosen_cert_arn: in_quotes,
|
100
|
-
matched_rule_priority: not_a_space,
|
101
|
-
request_creation_time: not_a_space,
|
102
|
-
actions_executed: in_quotes,
|
103
|
-
redirect_url: in_quotes,
|
104
|
-
error_reason: in_quotes
|
105
|
-
}
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
def alb_log_fields_regex
|
110
|
-
@alb_log_fields_regex ||=
|
111
|
-
begin
|
112
|
-
Regexp.new alb_log_fields.values.join(' ')
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
def get_alb_log_fields(line)
|
117
|
-
matches = alb_log_fields_regex.match(line).to_a
|
118
|
-
matches.shift
|
119
|
-
matches
|
120
|
-
end
|
121
|
-
|
122
|
-
def get_alb_log_entry(line)
|
123
|
-
entry = AlbLogEntry.new(*get_alb_log_fields(line))
|
124
|
-
entry.line = line
|
125
|
-
entry
|
126
|
-
end
|
7
|
+
require 'alblogs'
|
127
8
|
|
128
9
|
def measure
|
129
10
|
start = Time.now
|
@@ -136,75 +17,10 @@ def display_stats(stats)
|
|
136
17
|
$stderr.puts stats.inspect
|
137
18
|
end
|
138
19
|
|
139
|
-
class S3File
|
140
|
-
MINUTES_5 = 5 * 60
|
141
|
-
|
142
|
-
attr_reader :file,
|
143
|
-
:file_size,
|
144
|
-
:last_modified_at
|
145
|
-
|
146
|
-
def initialize(file, file_size, last_modified_at)
|
147
|
-
@file = file
|
148
|
-
@file_size = file_size
|
149
|
-
@last_modified_at = last_modified_at
|
150
|
-
end
|
151
|
-
|
152
|
-
def end_time
|
153
|
-
@end_time ||=
|
154
|
-
begin
|
155
|
-
unless @file =~ /_(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})Z_/
|
156
|
-
raise("unable to find time stamp in #{@file}")
|
157
|
-
end
|
158
|
-
Time.new($1, $2, $3, $4, $5, 0, 0)
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
def start_time
|
163
|
-
@start_time ||= (end_time - MINUTES_5)
|
164
|
-
end
|
165
|
-
|
166
|
-
def in_range?(range)
|
167
|
-
return false if end_time < range.begin
|
168
|
-
return false if start_time > range.end
|
169
|
-
true
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
class AlbLogEntry < Struct.new(*alb_log_fields.keys)
|
174
|
-
attr_accessor :line
|
175
|
-
|
176
|
-
def timestamp
|
177
|
-
@timestamp ||= Time.iso8601(self[:timestamp])
|
178
|
-
end
|
179
|
-
|
180
|
-
def target_processing_time
|
181
|
-
@target_processing_time ||= self[:target_processing_time].to_f
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
class RequestMatcher
|
186
|
-
attr_reader :range
|
187
|
-
|
188
|
-
def initialize(options)
|
189
|
-
@range = options[:start_time]..options[:end_time]
|
190
|
-
@exclude_filter = options[:exclude_filter]
|
191
|
-
@include_filter = options[:include_filter]
|
192
|
-
@request_times_over = options[:request_times_over]
|
193
|
-
end
|
194
|
-
|
195
|
-
def match?(entry)
|
196
|
-
return false unless @range.cover?(entry.timestamp)
|
197
|
-
return false if @include_filter && ! @include_filter.match?(entry.line)
|
198
|
-
return false if @exclude_filter && @exclude_filter.match?(entry.line)
|
199
|
-
return false if @request_times_over && @request_times_over > entry.target_processing_time
|
200
|
-
true
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
20
|
started_at = Time.now.utc
|
205
21
|
|
206
22
|
options = {
|
207
|
-
start_time: time_ago(started_at, '30 min'),
|
23
|
+
start_time: Alblogs::Utils.time_ago(started_at, '30 min'),
|
208
24
|
end_time: started_at,
|
209
25
|
include_filter: nil,
|
210
26
|
exclude_filter: nil,
|
@@ -218,11 +34,11 @@ OptionParser.new do |opts|
|
|
218
34
|
opts.banner = "Usage: alblogs [options]"
|
219
35
|
|
220
36
|
opts.on("-s", "--start=TIME_EXP", "Start time") do |v|
|
221
|
-
options[:start_time] = time_ago(started_at, v)
|
37
|
+
options[:start_time] = Alblogs::Utils.time_ago(started_at, v)
|
222
38
|
end
|
223
39
|
|
224
40
|
opts.on("-e", "--end=TIME_EXP", "End time") do |v|
|
225
|
-
options[:end_time] = time_ago(started_at, v)
|
41
|
+
options[:end_time] = Alblogs::Utils.time_ago(started_at, v)
|
226
42
|
end
|
227
43
|
|
228
44
|
opts.on("--include=REGEX", "Include filter") do |v|
|
@@ -264,7 +80,7 @@ if options[:end_time] && options[:end_time] < options[:start_time]
|
|
264
80
|
options[:start_time], options[:end_time] = options[:end_time], options[:start_time]
|
265
81
|
end
|
266
82
|
|
267
|
-
request_matcher = RequestMatcher.new options
|
83
|
+
request_matcher = Alblogs::RequestMatcher.new options
|
268
84
|
|
269
85
|
stats = Hash.new(0)
|
270
86
|
stats[:started_at] = started_at
|
@@ -282,11 +98,12 @@ File.unlink("#{tmp_file}.gz") if File.exists?("#{tmp_file}.gz")
|
|
282
98
|
$stop = false
|
283
99
|
trap("INT") { $stop = true }
|
284
100
|
|
285
|
-
|
101
|
+
s3_bucket = Alblogs::S3Bucket.new(options[:alb_s3_bucket], options[:aws_profile])
|
102
|
+
s3_bucket.get_s3_files_in_range(request_matcher.range).values.each do |s3_file|
|
286
103
|
stats[:files] += 1
|
287
104
|
|
288
105
|
stats[:total_download_time] += measure do
|
289
|
-
download_s3_file(s3_file, tmp_file
|
106
|
+
s3_bucket.download_s3_file(s3_file, tmp_file)
|
290
107
|
end
|
291
108
|
|
292
109
|
stats[:total_file_processing_time] += measure do
|
@@ -294,7 +111,7 @@ get_s3_files_in_range(request_matcher.range, options[:alb_s3_bucket], options[:a
|
|
294
111
|
while(! f.eof? && ! $stop)
|
295
112
|
stats[:lines] += 1
|
296
113
|
line = f.readline
|
297
|
-
entry =
|
114
|
+
entry = Alblogs::Entry.from_line(line)
|
298
115
|
stats[:min_log_time] = ! stats[:min_log_time] || stats[:min_log_time] > entry.timestamp ? entry.timestamp : stats[:min_log_time]
|
299
116
|
stats[:max_log_time] = ! stats[:max_log_time] || stats[:max_log_time] < entry.timestamp ? entry.timestamp : stats[:max_log_time]
|
300
117
|
next unless request_matcher.match?(entry)
|
data/lib/alblogs.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
module Alblogs
|
2
|
+
autoload :Entry, 'alblogs/entry'
|
3
|
+
autoload :RequestMatcher, 'alblogs/request_matcher'
|
4
|
+
autoload :S3Bucket, 'alblogs/s3_bucket'
|
5
|
+
autoload :S3File, 'alblogs/s3_file'
|
6
|
+
autoload :Utils, 'alblogs/utils'
|
7
|
+
|
8
|
+
FIELDS =
|
9
|
+
begin
|
10
|
+
not_a_space = '([^ ]+)'
|
11
|
+
in_quotes = '"(.*?)"'
|
12
|
+
|
13
|
+
{
|
14
|
+
type: not_a_space,
|
15
|
+
timestamp: not_a_space,
|
16
|
+
elb: not_a_space,
|
17
|
+
client_port: not_a_space,
|
18
|
+
target_port: not_a_space,
|
19
|
+
request_processing_time: not_a_space,
|
20
|
+
target_processing_time: not_a_space,
|
21
|
+
response_processing_time: not_a_space,
|
22
|
+
elb_status_code: not_a_space,
|
23
|
+
target_status_code: not_a_space,
|
24
|
+
received_bytes: not_a_space,
|
25
|
+
sent_bytes: not_a_space,
|
26
|
+
request: in_quotes,
|
27
|
+
user_agent: in_quotes,
|
28
|
+
ssl_cipher: not_a_space,
|
29
|
+
ssl_protocol: not_a_space,
|
30
|
+
target_group_arn: not_a_space,
|
31
|
+
trace_id: in_quotes,
|
32
|
+
domain_name: in_quotes,
|
33
|
+
chosen_cert_arn: in_quotes,
|
34
|
+
matched_rule_priority: not_a_space,
|
35
|
+
request_creation_time: not_a_space,
|
36
|
+
actions_executed: in_quotes,
|
37
|
+
redirect_url: in_quotes,
|
38
|
+
error_reason: in_quotes
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Alblogs
|
2
|
+
class Entry < Struct.new(:line, *::Alblogs::FIELDS.keys)
|
3
|
+
REGEXP = Regexp.new(::Alblogs::FIELDS.values.join(' '))
|
4
|
+
|
5
|
+
def timestamp
|
6
|
+
@timestamp ||= Time.iso8601(self[:timestamp])
|
7
|
+
end
|
8
|
+
|
9
|
+
def target_processing_time
|
10
|
+
self[:target_processing_time].to_f
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.from_line(line)
|
14
|
+
new(*get_fields(line))
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.get_fields(line)
|
18
|
+
REGEXP.match(line).to_a
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Alblogs
|
2
|
+
class RequestMatcher
|
3
|
+
attr_reader :range
|
4
|
+
|
5
|
+
def initialize(options)
|
6
|
+
@range = options[:start_time]..options[:end_time]
|
7
|
+
@exclude_filter = options[:exclude_filter]
|
8
|
+
@include_filter = options[:include_filter]
|
9
|
+
@request_times_over = options[:request_times_over]
|
10
|
+
end
|
11
|
+
|
12
|
+
def match?(entry)
|
13
|
+
return false unless @range.cover?(entry.timestamp)
|
14
|
+
return false if @include_filter && ! @include_filter.match?(entry.line)
|
15
|
+
return false if @exclude_filter && @exclude_filter.match?(entry.line)
|
16
|
+
return false if @request_times_over && @request_times_over > entry.target_processing_time
|
17
|
+
true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Alblogs
|
2
|
+
class S3Bucket
|
3
|
+
attr_reader :bucket,
|
4
|
+
:aws_profile
|
5
|
+
|
6
|
+
def initialize(bucket, aws_profile=nil)
|
7
|
+
@bucket = bucket
|
8
|
+
@aws_profile = aws_profile
|
9
|
+
end
|
10
|
+
|
11
|
+
def get_s3_files(date_path)
|
12
|
+
s3_url = "#{bucket}/#{date_path}/"
|
13
|
+
cmd = "aws"
|
14
|
+
cmd << " --profile #{Shellwords.escape(aws_profile)}" if aws_profile
|
15
|
+
cmd << " s3 ls #{Shellwords.escape(s3_url)}"
|
16
|
+
output = ::Alblogs::Utils.run_or_die(cmd)
|
17
|
+
output.split("\n").map do |line|
|
18
|
+
line =~ /(\d{4}\-\d{2}\-\d{2} \d{2}:\d{2}:\d{2}) +(\d+) +(.+)/
|
19
|
+
last_modified_at = Time.parse($1).utc
|
20
|
+
file_size = $2.to_i
|
21
|
+
file = $3
|
22
|
+
::Alblogs::S3File.new("#{s3_url}#{file}", file_size, last_modified_at)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_s3_files_in_range(range)
|
27
|
+
s3_files = {}
|
28
|
+
time = range.begin
|
29
|
+
while time < range.end
|
30
|
+
date_path = time.strftime('%Y/%m/%d')
|
31
|
+
get_s3_files(date_path).each do |s3_file|
|
32
|
+
next unless s3_file.in_range?(range)
|
33
|
+
s3_files[s3_file.file] ||= s3_file
|
34
|
+
end
|
35
|
+
time += 86_400
|
36
|
+
end
|
37
|
+
s3_files
|
38
|
+
end
|
39
|
+
|
40
|
+
def download_s3_file(s3_file, dest)
|
41
|
+
cmd = "aws"
|
42
|
+
cmd << " --profile #{Shellwords.escape(aws_profile)}" if aws_profile
|
43
|
+
cmd << " s3 cp #{Shellwords.escape(s3_file.file)} #{Shellwords.escape(dest)}.gz"
|
44
|
+
::Alblogs::Utils.run_or_die(cmd)
|
45
|
+
cmd = "gzip -f -d #{Shellwords.escape(dest)}.gz"
|
46
|
+
::Alblogs::Utils.run_or_die(cmd)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Alblogs
|
2
|
+
class S3File
|
3
|
+
MINUTES_5 = 5 * 60
|
4
|
+
|
5
|
+
attr_reader :file,
|
6
|
+
:file_size,
|
7
|
+
:last_modified_at
|
8
|
+
|
9
|
+
def initialize(file, file_size, last_modified_at)
|
10
|
+
@file = file
|
11
|
+
@file_size = file_size
|
12
|
+
@last_modified_at = last_modified_at
|
13
|
+
end
|
14
|
+
|
15
|
+
def end_time
|
16
|
+
@end_time ||=
|
17
|
+
begin
|
18
|
+
unless @file =~ /_(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})Z_/
|
19
|
+
raise("unable to find time stamp in #{@file}")
|
20
|
+
end
|
21
|
+
Time.new($1, $2, $3, $4, $5, 0, 0)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def start_time
|
26
|
+
@start_time ||= (end_time - MINUTES_5)
|
27
|
+
end
|
28
|
+
|
29
|
+
def in_range?(range)
|
30
|
+
return false if end_time < range.begin
|
31
|
+
return false if start_time > range.end
|
32
|
+
true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Alblogs
|
2
|
+
module Utils
|
3
|
+
module_function
|
4
|
+
|
5
|
+
def parse_time_offset(str)
|
6
|
+
if str =~ /min/
|
7
|
+
str.sub(/ *min.*/, '').to_i * 60
|
8
|
+
elsif str =~ /hour/
|
9
|
+
str.sub(/ *hour.*/, '').to_i * 3600
|
10
|
+
elsif str =~ /day/
|
11
|
+
str.sub(/ *day.*/, '').to_i * 86400
|
12
|
+
else
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def time_ago(now, str)
|
18
|
+
if offset = parse_time_offset(str)
|
19
|
+
time = now - offset
|
20
|
+
time - (time.to_i % 60) # round to the start of the minute
|
21
|
+
else
|
22
|
+
Time.parse(str).utc
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def run_or_die(cmd)
|
27
|
+
res = `#{cmd}`
|
28
|
+
raise("command failed with #{$?}, #{cmd}") unless $?.success?
|
29
|
+
res
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/script/console
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alblogs
|
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
|
- Doug Youch
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-10-08 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Utility script for processing ALB access logs over a given time range
|
14
14
|
email: dougyouch@gmail.com
|
@@ -18,9 +18,18 @@ extensions: []
|
|
18
18
|
extra_rdoc_files: []
|
19
19
|
files:
|
20
20
|
- ".gitignore"
|
21
|
+
- ".ruby-gemset"
|
22
|
+
- ".ruby-version"
|
21
23
|
- README.md
|
22
24
|
- alblogs.gemspec
|
23
25
|
- bin/alblogs
|
26
|
+
- lib/alblogs.rb
|
27
|
+
- lib/alblogs/entry.rb
|
28
|
+
- lib/alblogs/request_matcher.rb
|
29
|
+
- lib/alblogs/s3_bucket.rb
|
30
|
+
- lib/alblogs/s3_file.rb
|
31
|
+
- lib/alblogs/utils.rb
|
32
|
+
- script/console
|
24
33
|
homepage: https://github.com/dougyouch/alblogs
|
25
34
|
licenses: []
|
26
35
|
metadata: {}
|