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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9e2cdd52d7bb6925077930b4af585a251b7adefc
4
- data.tar.gz: 64429389036f8c97f4a502dad80cfebce71aaa83
3
+ metadata.gz: 6d34dc14c5627860aa7787a9c0e0dbac19edaf9d
4
+ data.tar.gz: 57c8a63726d0ad90f47653b6f3d20286d1527129
5
5
  SHA512:
6
- metadata.gz: 05735444de0f2eceaaa76a417cd146971bc90ac614626dbaab1d4881b85651c06ab24aabad039fa9c90047f96e53e9dc406ba12c47743522d8f6947e34dce660
7
- data.tar.gz: 8592521b71b5bb4df3311ea87f833627e129e7582ccb5cb8360a5bab67140e4efc284a35d273b767ec088db432aebea1505ba2b76efa2e1871027e989181e2a9
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.3.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>.+)(| (?<option3>.*)))?/
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
- matches = LOGFILE_REGEXP.match(content.key)
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
- # read an object from S3 to a file and write buffer file
204
- File.open(@buf_file, File::WRONLY|File::CREAT|File::TRUNC) do |file|
205
- s3_client.get_object(
206
- bucket: @s3_bucketname,
207
- key: object_name
208
- ) do |chunk|
209
- file.write(chunk)
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
 
@@ -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.3.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-03-29 00:00:00.000000000 Z
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.4.5.1
141
+ rubygems_version: 2.6.11
142
142
  signing_key:
143
143
  specification_version: 4
144
144
  summary: Amazon ELB log input plugin