fluent-plugin-elb-log 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +12 -5
- data/fluent-plugin-elb-log.gemspec +1 -1
- data/lib/fluent/plugin/in_elb_log.rb +55 -33
- data/test/plugin/in_elb_log.rb +85 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d34dc14c5627860aa7787a9c0e0dbac19edaf9d
|
4
|
+
data.tar.gz: 57c8a63726d0ad90f47653b6f3d20286d1527129
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6854587f02206b4cdcd14863516d4df01b79eda6af2765d4250c3139e21ea1bb20896b7dba86cd29287aafa5b00e7983d02456ee50bfd29da6519d6c57622012
|
7
|
+
data.tar.gz: cfb29cc94c144bf8a877a3cd287510be473c31f23fa2f6879b0421ccba0e8a992559057e27f5f2c0edc12bd6877544872c878b570511bc1eb05b58d0e173b612
|
data/README.md
CHANGED
@@ -5,8 +5,6 @@
|
|
5
5
|
|
6
6
|
## Requirements
|
7
7
|
|
8
|
-
## Requirements
|
9
|
-
|
10
8
|
| fluent-plugin-elb-log | fluentd | ruby |
|
11
9
|
|-----------------------|------------|--------|
|
12
10
|
| >= 0.3.0 | >= v0.14.0 | >= 2.1 |
|
@@ -36,6 +34,12 @@
|
|
36
34
|
- user_agent
|
37
35
|
- option1, option2, option3
|
38
36
|
|
37
|
+
## Support Application Load Balancer (ver 0.4.0 or later)
|
38
|
+
- Support Access Logs for Application Load Balancer
|
39
|
+
- https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-access-logs.html
|
40
|
+
- Existing ELB is called Classic Load Balancer
|
41
|
+
- http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/access-log-collection.html
|
42
|
+
|
39
43
|
## When SSL certification error
|
40
44
|
log:
|
41
45
|
```
|
@@ -50,7 +54,7 @@ SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt (If you using amazon linux)
|
|
50
54
|
|
51
55
|
```config
|
52
56
|
<source>
|
53
|
-
type elb_log
|
57
|
+
@type elb_log
|
54
58
|
|
55
59
|
# following attibutes are required
|
56
60
|
region <region name>
|
@@ -70,7 +74,7 @@ SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt (If you using amazon linux)
|
|
70
74
|
### Example setting
|
71
75
|
```config
|
72
76
|
<source>
|
73
|
-
type elb_log
|
77
|
+
@type elb_log
|
74
78
|
region us-east-1
|
75
79
|
s3_bucketname my-elblog-bucket
|
76
80
|
s3_prefix prodcution/web
|
@@ -83,7 +87,7 @@ SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt (If you using amazon linux)
|
|
83
87
|
</source>
|
84
88
|
|
85
89
|
<match **>
|
86
|
-
type stdout
|
90
|
+
@type stdout
|
87
91
|
</match>
|
88
92
|
```
|
89
93
|
|
@@ -119,6 +123,9 @@ SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt (If you using amazon linux)
|
|
119
123
|
"user_agent":"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)",
|
120
124
|
"ssl_cipher":"DHE-RSA-AES128-SHA",
|
121
125
|
"ssl_protocol":"TLSv1.2",
|
126
|
+
"type":"http",
|
127
|
+
"target_group_arn":"arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/lbgrp1/605122a4e4ee9f2d",
|
128
|
+
"trace_id":"\"Root=1-xxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxx\""
|
122
129
|
"option3":null
|
123
130
|
}
|
124
131
|
```
|
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "fluent-plugin-elb-log"
|
7
|
-
spec.version = "0.
|
7
|
+
spec.version = "0.4.0"
|
8
8
|
spec.authors = ["shinsaka"]
|
9
9
|
spec.email = ["shinx1265@gmail.com"]
|
10
10
|
spec.summary = "Amazon ELB log input plugin"
|
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'time'
|
2
|
+
require 'zlib'
|
3
|
+
require 'fileutils'
|
2
4
|
require 'aws-sdk'
|
3
5
|
require 'fluent/input'
|
4
6
|
|
@@ -7,8 +9,8 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
|
|
7
9
|
|
8
10
|
helpers :timer
|
9
11
|
|
10
|
-
LOGFILE_REGEXP = /^((?<prefix>.+?)\/|)AWSLogs\/(?<account_id>[0-9]{12})\/elasticloadbalancing\/(?<region>.+?)\/(?<logfile_date>[0-9]{4}\/[0-9]{2}\/[0-9]{2})\/[0-9]{12}_elasticloadbalancing_.+?_(?<logfile_elb_name>[^_]+)_(?<elb_timestamp>[0-9]{8}T[0-9]{4}Z)_(?<elb_ip_address>.+?)_(?<logfile_hash>.+)\.log
|
11
|
-
ACCESSLOG_REGEXP = /^(?<time>\d{4}-\d{2}-\d{2}T\d{2}\:\d{2}\:\d{2}\.\d{6}Z) (?<elb>.+?) (?<client>[^ ]+)\:(?<client_port>.+?) (?<backend>.+?)(\:(?<backend_port>.+?))? (?<request_processing_time>.+?) (?<backend_processing_time>.+?) (?<response_processing_time>.+?) (?<elb_status_code>.+?) (?<backend_status_code>.+?) (?<received_bytes>.+?) (?<sent_bytes>.+?) \"(?<request_method>.+?) (?<request_uri>.+?) (?<request_protocol>.+?)\"( \"(?<user_agent>.*?)\" (?<ssl_cipher>.+?) (?<ssl_protocol
|
12
|
+
LOGFILE_REGEXP = /^((?<prefix>.+?)\/|)AWSLogs\/(?<account_id>[0-9]{12})\/elasticloadbalancing\/(?<region>.+?)\/(?<logfile_date>[0-9]{4}\/[0-9]{2}\/[0-9]{2})\/[0-9]{12}_elasticloadbalancing_.+?_(?<logfile_elb_name>[^_]+)_(?<elb_timestamp>[0-9]{8}T[0-9]{4}Z)_(?<elb_ip_address>.+?)_(?<logfile_hash>.+)\.log(.gz)?$/
|
13
|
+
ACCESSLOG_REGEXP = /^((?<type>[a-z0-9]+) )?(?<time>\d{4}-\d{2}-\d{2}T\d{2}\:\d{2}\:\d{2}\.\d{6}Z) (?<elb>.+?) (?<client>[^ ]+)\:(?<client_port>.+?) (?<backend>.+?)(\:(?<backend_port>.+?))? (?<request_processing_time>.+?) (?<backend_processing_time>.+?) (?<response_processing_time>.+?) (?<elb_status_code>.+?) (?<backend_status_code>.+?) (?<received_bytes>.+?) (?<sent_bytes>.+?) \"(?<request_method>.+?) (?<request_uri>.+?) (?<request_protocol>.+?)\"( \"(?<user_agent>.*?)\" (?<ssl_cipher>.+?) (?<ssl_protocol>[^\s]+)( (?<target_group_arn>arn:.+) (?<trace_id>[^\s]+))?(| (?<option3>.*)))?/
|
12
14
|
|
13
15
|
config_param :access_key_id, :string, default: nil, secret: true
|
14
16
|
config_param :secret_access_key, :string, default: nil, secret: true
|
@@ -146,38 +148,48 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
|
|
146
148
|
end
|
147
149
|
|
148
150
|
def get_object_keys(timestamp)
|
149
|
-
# get values from object file name
|
150
151
|
begin
|
151
152
|
object_keys = []
|
153
|
+
get_object_keys_from_s3.each do |object_key|
|
154
|
+
matches = LOGFILE_REGEXP.match(object_key)
|
155
|
+
next unless matches
|
156
|
+
|
157
|
+
# snip old items
|
158
|
+
elb_timestamp_unixtime = Time.parse(matches[:elb_timestamp]).to_i
|
159
|
+
next if elb_timestamp_unixtime <= timestamp
|
160
|
+
|
161
|
+
log.debug object_key
|
162
|
+
object_keys << {
|
163
|
+
key: object_key,
|
164
|
+
prefix: matches[:prefix],
|
165
|
+
account_id: matches[:account_id],
|
166
|
+
region: matches[:region],
|
167
|
+
logfile_date: matches[:logfile_date],
|
168
|
+
logfile_elb_name: matches[:logfile_elb_name],
|
169
|
+
elb_timestamp: matches[:elb_timestamp],
|
170
|
+
elb_ip_address: matches[:elb_ip_address],
|
171
|
+
logfile_hash: matches[:logfile_hash],
|
172
|
+
elb_timestamp_unixtime: elb_timestamp_unixtime,
|
173
|
+
}
|
174
|
+
end
|
175
|
+
return object_keys
|
176
|
+
rescue => e
|
177
|
+
log.warn "error occurred: #{e.message}"
|
178
|
+
end
|
179
|
+
end
|
152
180
|
|
181
|
+
def get_object_keys_from_s3
|
182
|
+
begin
|
153
183
|
objects = s3_client.list_objects(
|
154
184
|
bucket: @s3_bucketname,
|
155
185
|
max_keys: 100,
|
156
186
|
prefix: @s3_prefix,
|
157
187
|
)
|
158
|
-
|
188
|
+
|
189
|
+
object_keys = []
|
159
190
|
objects.each do |object|
|
160
191
|
object.contents.each do |content|
|
161
|
-
|
162
|
-
next unless matches
|
163
|
-
|
164
|
-
# snip old items
|
165
|
-
elb_timestamp_unixtime = Time.parse(matches[:elb_timestamp]).to_i
|
166
|
-
next if elb_timestamp_unixtime <= timestamp
|
167
|
-
|
168
|
-
log.debug content.key
|
169
|
-
object_keys << {
|
170
|
-
key: content.key,
|
171
|
-
prefix: matches[:prefix],
|
172
|
-
account_id: matches[:account_id],
|
173
|
-
region: matches[:region],
|
174
|
-
logfile_date: matches[:logfile_date],
|
175
|
-
logfile_elb_name: matches[:logfile_elb_name],
|
176
|
-
elb_timestamp: matches[:elb_timestamp],
|
177
|
-
elb_ip_address: matches[:elb_ip_address],
|
178
|
-
logfile_hash: matches[:logfile_hash],
|
179
|
-
elb_timestamp_unixtime: elb_timestamp_unixtime,
|
180
|
-
}
|
192
|
+
object_keys << content.key
|
181
193
|
end
|
182
194
|
end
|
183
195
|
return object_keys
|
@@ -200,17 +212,24 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
|
|
200
212
|
begin
|
201
213
|
log.debug "getting object from s3 name is #{object_name}"
|
202
214
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
215
|
+
Tempfile.create('fluent-elblog') do |tfile|
|
216
|
+
s3_client.get_object(bucket: @s3_bucketname, key: object_name) do |chunk|
|
217
|
+
tfile.write(chunk)
|
218
|
+
end
|
219
|
+
tfile.close
|
220
|
+
|
221
|
+
if File.extname(object_name) != '.gz'
|
222
|
+
FileUtils.cp(tfile.path, @buf_file)
|
223
|
+
else
|
224
|
+
File.open(@buf_file, File::WRONLY|File::CREAT|File::TRUNC) do |bfile|
|
225
|
+
Zlib::GzipReader.open(tfile.path) do |gz|
|
226
|
+
bfile.write gz.read
|
227
|
+
end
|
228
|
+
end
|
210
229
|
end
|
211
230
|
end
|
212
231
|
rescue => e
|
213
|
-
log.warn "error occurred: #{e.message}"
|
232
|
+
log.warn "error occurred: #{e.message}, #{e.backtrace}"
|
214
233
|
end
|
215
234
|
end
|
216
235
|
|
@@ -224,7 +243,7 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
|
|
224
243
|
log.info "nomatch log found: #{line} in #{record_common['key']}"
|
225
244
|
next
|
226
245
|
end
|
227
|
-
|
246
|
+
|
228
247
|
record = {
|
229
248
|
"time" => line_match[:time].gsub(/Z/, "+0000"),
|
230
249
|
"elb" => line_match[:elb],
|
@@ -245,6 +264,9 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
|
|
245
264
|
"user_agent" => line_match[:user_agent],
|
246
265
|
"ssl_cipher" => line_match[:ssl_cipher],
|
247
266
|
"ssl_protocol" => line_match[:ssl_protocol],
|
267
|
+
"type" => line_match[:type],
|
268
|
+
"target_group_arn" => line_match[:target_group_arn],
|
269
|
+
"trace_id" => line_match[:trace_id],
|
248
270
|
"option3" => line_match[:option3],
|
249
271
|
}
|
250
272
|
|
data/test/plugin/in_elb_log.rb
CHANGED
@@ -113,4 +113,89 @@ class Elb_LogInputTest < Test::Unit::TestCase
|
|
113
113
|
assert_equal('secret_access_key is required', exception.message)
|
114
114
|
end
|
115
115
|
|
116
|
+
def test_logfilename_classic_lb_parse
|
117
|
+
logfile_classic = 'classic/AWSLogs/123456789012/elasticloadbalancing/ap-northeast-1/2017/05/03/123456789012_elasticloadbalancing_ap-northeast-1_elbname_20170503T1250Z_10.0.0.1_43nzjpdj.log'
|
118
|
+
|
119
|
+
m = Fluent::Plugin::Elb_LogInput::LOGFILE_REGEXP.match(logfile_classic)
|
120
|
+
assert_equal('classic', m[:prefix])
|
121
|
+
assert_equal('123456789012', m[:account_id])
|
122
|
+
assert_equal('ap-northeast-1', m[:region])
|
123
|
+
assert_equal('2017/05/03', m[:logfile_date])
|
124
|
+
assert_equal('elbname', m[:logfile_elb_name])
|
125
|
+
assert_equal('20170503T1250Z', m[:elb_timestamp])
|
126
|
+
assert_equal('10.0.0.1', m[:elb_ip_address])
|
127
|
+
assert_equal('43nzjpdj', m[:logfile_hash])
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_logfilename_appication_lb_parse
|
131
|
+
logfile_applb = 'applb/AWSLogs/123456789012/elasticloadbalancing/ap-northeast-1/2017/05/03/123456789012_elasticloadbalancing_ap-northeast-1_app.elbname.59bfa19e900030c2_20170503T1310Z_10.0.0.1_2tko12gv.log.gz'
|
132
|
+
|
133
|
+
m = Fluent::Plugin::Elb_LogInput::LOGFILE_REGEXP.match(logfile_applb)
|
134
|
+
assert_equal('applb', m[:prefix])
|
135
|
+
assert_equal('123456789012', m[:account_id])
|
136
|
+
assert_equal('ap-northeast-1', m[:region])
|
137
|
+
assert_equal('2017/05/03', m[:logfile_date])
|
138
|
+
assert_equal('app.elbname.59bfa19e900030c2', m[:logfile_elb_name])
|
139
|
+
assert_equal('20170503T1310Z', m[:elb_timestamp])
|
140
|
+
assert_equal('10.0.0.1', m[:elb_ip_address])
|
141
|
+
assert_equal('2tko12gv', m[:logfile_hash])
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_log_classic_lb_parse
|
145
|
+
log = '2017-05-05T12:53:50.128456Z elbname 10.11.12.13:37852 192.168.30.186:443 0.00004 0.085372 0.000039 301 301 0 0 "GET https://elbname-123456789.ap-northeast-1.elb.amazonaws.com:443/ HTTP/1.1" "curl/7.51.0" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2'
|
146
|
+
|
147
|
+
m = Fluent::Plugin::Elb_LogInput::ACCESSLOG_REGEXP.match(log)
|
148
|
+
assert_equal('2017-05-05T12:53:50.128456Z', m[:time])
|
149
|
+
assert_equal('elbname', m[:elb])
|
150
|
+
assert_equal('10.11.12.13', m[:client])
|
151
|
+
assert_equal('37852', m[:client_port])
|
152
|
+
assert_equal('192.168.30.186', m[:backend])
|
153
|
+
assert_equal('443', m[:backend_port])
|
154
|
+
assert_equal('0.00004', m[:request_processing_time])
|
155
|
+
assert_equal('0.085372', m[:backend_processing_time])
|
156
|
+
assert_equal('0.000039', m[:response_processing_time])
|
157
|
+
assert_equal('301', m[:elb_status_code])
|
158
|
+
assert_equal('301', m[:backend_status_code])
|
159
|
+
assert_equal('0', m[:received_bytes])
|
160
|
+
assert_equal('0', m[:sent_bytes])
|
161
|
+
assert_equal('GET', m[:request_method])
|
162
|
+
assert_equal('https://elbname-123456789.ap-northeast-1.elb.amazonaws.com:443/', m[:request_uri])
|
163
|
+
assert_equal('HTTP/1.1', m[:request_protocol])
|
164
|
+
assert_equal('curl/7.51.0', m[:user_agent])
|
165
|
+
assert_equal('ECDHE-RSA-AES128-GCM-SHA256', m[:ssl_cipher])
|
166
|
+
assert_equal('TLSv1.2', m[:ssl_protocol])
|
167
|
+
assert_equal(nil, m[:type])
|
168
|
+
assert_equal(nil, m[:target_group_arn])
|
169
|
+
assert_equal(nil, m[:trace_id])
|
170
|
+
assert_equal(nil, m[:option3])
|
171
|
+
end
|
172
|
+
|
173
|
+
def test_log_application_lb_parse
|
174
|
+
log = 'https 2017-05-05T13:07:53.468529Z app/elbname/59bfa19e900030c2 10.20.30.40:52730 192.168.30.186:443 0.006 0.000 0.086 301 301 117 507 "GET https://elbname-1121128512.ap-northeast-1.elb.amazonaws.com:443/ HTTP/1.1" "curl/7.51.0" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/lbgrp1/605122a4e4ee9f2d "Root=1-590c7929-4eb4cb393d46a01d22db8473"'
|
175
|
+
|
176
|
+
m = Fluent::Plugin::Elb_LogInput::ACCESSLOG_REGEXP.match(log)
|
177
|
+
assert_equal('2017-05-05T13:07:53.468529Z', m[:time])
|
178
|
+
assert_equal('app/elbname/59bfa19e900030c2', m[:elb])
|
179
|
+
assert_equal('10.20.30.40', m[:client])
|
180
|
+
assert_equal('52730', m[:client_port])
|
181
|
+
assert_equal('192.168.30.186', m[:backend])
|
182
|
+
assert_equal('443', m[:backend_port])
|
183
|
+
assert_equal('0.006', m[:request_processing_time])
|
184
|
+
assert_equal('0.000', m[:backend_processing_time])
|
185
|
+
assert_equal('0.086', m[:response_processing_time])
|
186
|
+
assert_equal('301', m[:elb_status_code])
|
187
|
+
assert_equal('301', m[:backend_status_code])
|
188
|
+
assert_equal('117', m[:received_bytes])
|
189
|
+
assert_equal('507', m[:sent_bytes])
|
190
|
+
assert_equal('GET', m[:request_method])
|
191
|
+
assert_equal('https://elbname-1121128512.ap-northeast-1.elb.amazonaws.com:443/', m[:request_uri])
|
192
|
+
assert_equal('HTTP/1.1', m[:request_protocol])
|
193
|
+
assert_equal('curl/7.51.0', m[:user_agent])
|
194
|
+
assert_equal('ECDHE-RSA-AES128-GCM-SHA256', m[:ssl_cipher])
|
195
|
+
assert_equal('TLSv1.2', m[:ssl_protocol])
|
196
|
+
assert_equal('https', m[:type])
|
197
|
+
assert_equal('arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/lbgrp1/605122a4e4ee9f2d', m[:target_group_arn])
|
198
|
+
assert_equal('"Root=1-590c7929-4eb4cb393d46a01d22db8473"', m[:trace_id])
|
199
|
+
assert_equal(nil, m[:option3])
|
200
|
+
end
|
116
201
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-elb-log
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- shinsaka
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-05-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fluentd
|
@@ -138,7 +138,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
138
138
|
version: '0'
|
139
139
|
requirements: []
|
140
140
|
rubyforge_project:
|
141
|
-
rubygems_version: 2.
|
141
|
+
rubygems_version: 2.6.11
|
142
142
|
signing_key:
|
143
143
|
specification_version: 4
|
144
144
|
summary: Amazon ELB log input plugin
|