fluent-plugin-elb-log 1.3.2 → 1.4.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 70cc28816877d7449177587fc80f76cb571ff1f2a73cf87725835baceacd1fa1
4
- data.tar.gz: ed8073d78f9433d8fdfbb5a499725fb55751b2f14710c48e9b02a7edfc5d2f6a
3
+ metadata.gz: 27ca22f138e46f8b033a674791600cafd324adcb87a0514d4189cf2e8cd112c2
4
+ data.tar.gz: 21beb83010ab4273a8e8eb7d1f3b923526a967c9fed8a03eae2e9bde06d1d14a
5
5
  SHA512:
6
- metadata.gz: '038e446b92d1034613eb244e4b540b2daa0668942bd662f8a807b9f01c49fe273247e22d4a321f1eac007a19f999244c86e933fb2c8c686a406b83e9b35b350d'
7
- data.tar.gz: 2355ddaec49a2b56e1fd69ae7703659ac7d9852d7e3a6ea10d44832de406dd2486690cb5fd7aa083d393c3054e0858fd9c21fbe35f1e264e1effca95ffe0a284
6
+ metadata.gz: 6e6fc7a9042cd756b9521be3bce5ea37e06f2f7d489a440d575977df03a240199ed836ddb8109db7e28817348e1848833201742330109ec1a627efed1345286d
7
+ data.tar.gz: a65c3a910d2f6ddd794e8e5555f0ef294f012b54097a5da07cf68dc0e5d47e9dc5bd3a267f22ab205bd72a70ea385c74bfc9be28fcf54da32f4b6d513a656b67
data/README.md CHANGED
@@ -58,6 +58,9 @@ SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt (If you using amazon linux)
58
58
  tag <tag name(default: elb.access)>
59
59
  delete <boolean delete processed log files from S3(default: false)>
60
60
  include_all_message <boolean (default:false)>
61
+ start_time <last timestamp to start from>
62
+ exclude_pattern_logfile_elb_name <exclude pattern for logfile_elb_name key>
63
+ use_sqs <boolean use SQS polling instead of iteratively processing the whole bucket>
61
64
 
62
65
  # following attibutes are required if you don't use IAM Role
63
66
  access_key_id <access_key>
@@ -65,6 +68,44 @@ SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt (If you using amazon linux)
65
68
  </source>
66
69
  ```
67
70
 
71
+ `use_sqs` automatically creates an SQS queue named `fluent-plugin-elb-log-<current_timestamp>`
72
+ and sets up the `all object create event` S3 event notification for the chosen S3 bucket. Stopping fluentd deletes both autmatically.
73
+ To make it work, the following IAM policy should be attached to the instance IAM role or the user:
74
+ ```
75
+ {
76
+ "Version": "2012-10-17",
77
+ "Statement": [
78
+ {
79
+ "Sid": "FluentdPermissions",
80
+ "Effect": "Allow",
81
+ "Action": [
82
+ "sqs:DeleteMessage",
83
+ "s3:GetObject",
84
+ "sqs:ReceiveMessage",
85
+ "sqs:DeleteQueue",
86
+ "sqs:GetQueueAttributes",
87
+ "s3:ListBucket",
88
+ "s3:PutBucketNotification",
89
+ "sqs:CreateQueue"
90
+ ],
91
+ "Resource": [
92
+ "arn:aws:sqs:*:123456789012:fluent-plugin-elb-log-*",
93
+ "arn:aws:s3:::alb-logs-bucket/*",
94
+ "arn:aws:s3:::alb-logs-bucket"
95
+ ]
96
+ }
97
+ ]
98
+ }
99
+ ```
100
+ When `use_sqs` is false:
101
+ - 300 seconds is a good value for the `refresh_interval`
102
+ - the plugin executes processing the whole S3 bucket (with the respect of `s3_prefix` and `start_time`/`timestamp_file`) every `refresh_interval`
103
+
104
+ When `use_sqs` is true:
105
+ - `refresh_interval` of 30-60 seconds should be fine.
106
+ - the plugin executes processing the whole S3 bucket (with the respect of `s3_prefix` and `start_time`/`timestamp_file`) only once (at start) and then
107
+ polls the SQS queue every `refresh_interval`.
108
+
68
109
  ### Example setting
69
110
  ```config
70
111
  <source>
@@ -74,16 +115,39 @@ SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt (If you using amazon linux)
74
115
  s3_prefix prodcution/web
75
116
  timestamp_file /tmp/elb_last_at.dat
76
117
  buf_file /tmp/fluentd-elblog.tmpfile
77
- refresh_interval 300
118
+ refresh_interval 30
78
119
  tag elb.access
79
120
  delete false
80
121
  include_all_message false
122
+ exclude_pattern_logfile_elb_name "^app\.(uat|qa)\."
123
+ start_time 2025-02-27T10:45:00
124
+ use_sqs true
81
125
  access_key_id XXXXXXXXXXXXXXXXXXXX
82
126
  secret_access_key xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
83
127
  </source>
84
128
 
85
- <match **>
86
- @type stdout
129
+ <filter elb.access>
130
+ @type record_transformer
131
+ <record>
132
+ timestamp ${record["request_creation_time"]}
133
+ logfile_name ${record["key"]}
134
+ </record>
135
+ remove_keys prefix,logfile_date,logfile_elb_name,logfile_hash,logfile_timestamp,logfile_timestamp_unixtime,key,time,s3_last_modified_unixtime
136
+ </filter>
137
+
138
+ <match elb.access>
139
+ # @type stdout
140
+ @type opensearch
141
+ hosts node-1,node-2,node-3
142
+ port 9200
143
+ scheme https
144
+ logstash_format true
145
+ logstash_prefix alb-logs
146
+ user fluentd
147
+ password secret
148
+ ssl_verify true
149
+ ca_file /etc/fluentd/root-ca.pem
150
+ flush_interval 300s
87
151
  </match>
88
152
  ```
89
153
 
@@ -96,7 +160,7 @@ SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt (If you using amazon linux)
96
160
  "logfile_elb_name":"my-elb-name",
97
161
  "elb_ip_address":"52.0.0.0",
98
162
  "logfile_hash":"12squv5w",
99
- "elb_timestamp":"20150615T0400Z",
163
+ "logfile_timestamp":"20150615T0400Z",
100
164
  "key":"TEST/AWSLogs/123456789012/elasticloadbalancing/ap-northeast-1/2015/06/15/123456789012_elasticloadbalancing_ap-northeast-1_my-elb-name_20150615T0400Z_52.68.215.138_69squv5w.log",
101
165
  "prefix":"TEST",
102
166
  "elb_timestamp_unixtime":1434340800,
@@ -104,13 +168,13 @@ SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt (If you using amazon linux)
104
168
  "elb":"my-elb-name",
105
169
  "client":"54.1.1.1",
106
170
  "client_port":"43759",
107
- "backend":"10.0.0.1",
108
- "backend_port":"80",
171
+ "target":"10.0.0.1",
172
+ "target_port":"80",
109
173
  "request_processing_time":4.0e-05,
110
- "backend_processing_time":0.105048,
174
+ "target_processing_time":0.105048,
111
175
  "response_processing_time":2.4e-05,
112
176
  "elb_status_code":"200",
113
- "backend_status_code":"200",
177
+ "target_status_code":"200",
114
178
  "received_bytes":0,
115
179
  "sent_bytes":4622,
116
180
  "request_method":"GET",
@@ -129,8 +193,10 @@ SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt (If you using amazon linux)
129
193
  "actions_executed": "forward",
130
194
  "redirect_url": "-",
131
195
  "error_reason": "-",
132
- "option1": "\"192.168.0.1:443\"",
133
- "option2": "\"301\"",
134
- "option3": null
196
+ "target_port_list": "\"192.168.0.1:443\"",
197
+ "target_status_code_list": "\"301\"",
198
+ "classification": "-",
199
+ "classification_reason": "-",
200
+ "conn_trace_id": "TID_xxxxxxxxxxxxxxxxxxxxxxx"
135
201
  }
136
202
  ```
@@ -4,12 +4,12 @@ $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 = "1.3.2"
8
- spec.authors = ["shinsaka"]
7
+ spec.version = "1.4.1"
8
+ spec.authors = ["shinsaka","jazzl0ver"]
9
9
  spec.email = ["shinx1265@gmail.com"]
10
10
  spec.summary = "Amazon ELB log input plugin"
11
11
  spec.description = "Amazon ELB log input plugin for fluentd"
12
- spec.homepage = "https://github.com/shinsaka/fluent-plugin-elb-log"
12
+ spec.homepage = "https://github.com/jazzl0ver/fluent-plugin-elb-log"
13
13
  spec.license = "MIT"
14
14
 
15
15
  spec.files = `git ls-files -z`.split("\x0")
data/fluent.conf.sample CHANGED
@@ -5,12 +5,22 @@
5
5
  s3_prefix prodcution/web
6
6
  timestamp_file /tmp/elb_last_at.dat
7
7
  buf_file /tmp/fluentd-elblog.tmpfile
8
- refresh_interval 300
8
+ refresh_interval 30
9
9
  tag elb.access
10
+ use_sqs true
10
11
  access_key_id XXXXXXXXXXXXXXXXXXXX
11
12
  secret_access_key xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
12
13
  </source>
13
14
 
15
+ <filter elb.access>
16
+ @type record_transformer
17
+ <record>
18
+ timestamp ${record["request_creation_time"]}
19
+ logfile_name ${record["key"]}
20
+ </record>
21
+ remove_keys prefix,logfile_date,logfile_elb_name,logfile_hash,logfile_timestamp,logfile_timestamp_unixtime,key,time,s3_last_modified_unixtime
22
+ </filter>
23
+
14
24
  <match elb.access>
15
- @type stdout
25
+ @type stdout
16
26
  </match>
@@ -3,6 +3,7 @@ require 'zlib'
3
3
  require 'fileutils'
4
4
  require 'aws-sdk-s3'
5
5
  require 'aws-sdk-ec2'
6
+ require 'aws-sdk-sqs'
6
7
  require 'fluent/input'
7
8
  require 'digest/sha1'
8
9
 
@@ -11,8 +12,8 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
11
12
 
12
13
  helpers :timer
13
14
 
14
- 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)?$/
15
- 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>.+?)\"(\s+\"(?<user_agent>.+?)\" (?<ssl_cipher>.+?) (?<ssl_protocol>[^\s]+)( (?<target_group_arn>arn:\S+) (?<trace_id>[^\s]+))?( \"(?<domain_name>.+?)\" \"(?<chosen_cert_arn>.+?)\" (?<matched_rule_priority>.+?) (?<request_creation_time>.+?) \"(?<actions_executed>.+?)\" \"(?<redirect_url>.+?)\" \"(?<error_reason>[^\s]+)\"( |$))?((?<option1>[^\s]+)( |$))?((?<option2>[^\s]+)( |$))?( (?<option3>.*))?)?/
15
+ 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>[^_]+)_(?<logfile_timestamp>[0-9]{8}T[0-9]{4}Z)_(?<elb_ip_address>.+?)_(?<logfile_hash>.+)\.log(.gz)?$/
16
+ ACCESSLOG_REGEXP = /^((?<type>[a-z0-9]+) )?(?<time>\d{4}-\d{2}-\d{2}T\d{2}\:\d{2}\:\d{2}\.\d{6}Z) (?<elb>\S+) (?<client>\S+)\:(?<client_port>\S+) (?<target>[^:\s]+)(?::(?<target_port>\S+))? (?<request_processing_time>\S+) (?<target_processing_time>\S+) (?<response_processing_time>\S+) (?<elb_status_code>\S+) (?<target_status_code>\S+) (?<received_bytes>\S+) (?<sent_bytes>\S+) \"(?<request_method>\S+) (?<request_uri>\S+) (?<request_protocol>\S+)\" \"(?<user_agent>.*?)\" (?<ssl_cipher>\S+) (?<ssl_protocol>\S+) (?<target_group_arn>\S+) \"(?<trace_id>\S+)\" \"(?<domain_name>\S+)\" \"(?<chosen_cert_arn>\S+)\" (?<matched_rule_priority>\S+) (?<request_creation_time>\S+) \"(?<actions_executed>\S+)\" \"(?<redirect_url>\S+)\" \"(?<error_reason>\S+)\" \"(?<target_port_list>\S+)\" \"(?<target_status_code_list>\S+)\" \"(?<classification>\S+)\" \"(?<classification_reason>\S+)\" (?<conn_trace_id>\S+)/
16
17
  config_param :access_key_id, :string, default: nil, secret: true
17
18
  config_param :secret_access_key, :string, default: nil, secret: true
18
19
  config_param :region, :string
@@ -28,6 +29,8 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
28
29
  config_param :num_nodes, :integer, default: 1
29
30
  config_param :node_no, :integer, default: 0
30
31
  config_param :include_all_message, :bool, default: false
32
+ config_param :exclude_pattern_logfile_elb_name, :string, default: nil
33
+ config_param :use_sqs, :bool, default: true
31
34
 
32
35
  def configure(conf)
33
36
  super
@@ -38,9 +41,16 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
38
41
  end
39
42
  raise Fluent::ConfigError.new("s3_bucketname is required") unless @s3_bucketname
40
43
  raise Fluent::ConfigError.new("timestamp_file is required") unless @timestamp_file
44
+
45
+ @s3_client = s3_client
41
46
  raise Fluent::ConfigError.new("s3 bucket not found #{@s3_bucketname}") unless s3bucket_is_ok?
42
47
  end
43
48
 
49
+ def initialize
50
+ super
51
+ @running = true
52
+ end
53
+
44
54
  def start
45
55
  super
46
56
 
@@ -48,20 +58,180 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
48
58
  File.open(@timestamp_file, File::RDWR|File::CREAT).close
49
59
  File.open(@buf_file, File::RDWR|File::CREAT).close
50
60
 
51
- timer_execute(:in_elb_log, @refresh_interval, &method(:input))
61
+ @exclude_pattern_logfile_elb_name_re = Regexp.new(@exclude_pattern_logfile_elb_name)
62
+
63
+ Signal.trap('INT') { shutdown }
64
+
65
+ refresh_aws_clients!
66
+
67
+ if @use_sqs
68
+ input
69
+ setup_sqs_timer
70
+ else
71
+ setup_input_timer
72
+ end
52
73
  end
53
74
 
54
75
  private
55
76
 
77
+ def refresh_aws_clients!
78
+ log.debug "Refreshing AWS credentials"
79
+ @s3_client = s3_client
80
+ @sqs_client = sqs_client if @use_sqs
81
+ end
82
+
83
+ def shutdown
84
+ log.debug "shutdown"
85
+ if @running
86
+ @running = false
87
+ if @use_sqs
88
+ log.debug "pausing shutdown for 2x#{@refresh_interval}"
89
+ sleep 2*@refresh_interval
90
+ unset_sqs if @queue_url && @queue_url != ""
91
+ else
92
+ log.debug "pausing shutdown for 30 seconds"
93
+ sleep 30
94
+ end
95
+ end
96
+ end
97
+
98
+ def setup_sqs_timer
99
+ if @running
100
+ setup_sqs
101
+ return unless @running
102
+ timer_execute(:in_elb_log, @refresh_interval) do
103
+ if @running
104
+ refresh_aws_clients!
105
+ process_sqs
106
+ log.debug "sleeping for #{@refresh_interval}"
107
+ else
108
+ if @queue_url && @queue_url != ""
109
+ log.debug "Unsetting SQS"
110
+ unset_sqs
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+
117
+ def setup_input_timer
118
+ if @running
119
+ timer_execute(:in_elb_log, @refresh_interval) do
120
+ if @running
121
+ refresh_aws_clients!
122
+ input
123
+ log.debug "sleeping input for #{@refresh_interval}"
124
+ end
125
+ end
126
+ end
127
+ end
128
+
56
129
  def has_iam_role?
57
130
  begin
58
131
  ec2 = Aws::EC2::Client.new(region: @region)
59
132
  !ec2.config.credentials.nil?
60
133
  rescue => e
61
134
  log.warn "EC2 Client error occurred: #{e.message}"
135
+ @running = false
136
+ end
137
+ end
138
+
139
+ def setup_sqs
140
+ begin
141
+ timestamp = Time.now.to_i
142
+ queue_name = "fluent-plugin-elb-log-#{timestamp}"
143
+
144
+ sts_client = Aws::STS::Client.new(region: @region)
145
+ account_id = sts_client.get_caller_identity.account
146
+
147
+ queue_policy = {
148
+ "Version": "2012-10-17",
149
+ "Id": "__default_policy_ID",
150
+ "Statement": [
151
+ {
152
+ "Sid": "S3_service_publish",
153
+ "Effect": "Allow",
154
+ "Principal": {
155
+ "Service": "s3.amazonaws.com"
156
+ },
157
+ "Action": "SQS:SendMessage",
158
+ "Resource": "arn:aws:sqs:#{@region}:#{account_id}:#{queue_name}",
159
+ "Condition": {
160
+ "StringEquals": {
161
+ "aws:SourceAccount": "#{account_id}"
162
+ },
163
+ "ArnLike": {
164
+ "aws:SourceArn": "arn:aws:s3:*:*:#{@s3_bucketname}"
165
+ }
166
+ }
167
+ }
168
+ ]
169
+ }.to_json
170
+ create_queue_response = @sqs_client.create_queue(queue_name: queue_name,
171
+ attributes: {
172
+ 'Policy' => queue_policy
173
+ }
174
+ )
175
+ @queue_url = create_queue_response.queue_url
176
+ queue_attributes = @sqs_client.get_queue_attributes(
177
+ queue_url: @queue_url,
178
+ attribute_names: ['QueueArn']
179
+ )
180
+ queue_arn = queue_attributes.attributes['QueueArn']
181
+ log.debug "New SQS queue created: #{queue_arn}"
182
+
183
+ notification_configuration = {
184
+ queue_configurations: [
185
+ {
186
+ id: "fluent-plugin-elb-log",
187
+ events: ['s3:ObjectCreated:*'],
188
+ queue_arn: "#{queue_arn}",
189
+ filter: {
190
+ key: {
191
+ filter_rules: [
192
+ {
193
+ name: 'Prefix',
194
+ value: "#{@s3_prefix}"
195
+ }
196
+ ]
197
+ }
198
+ }
199
+ }
200
+ ]
201
+ }
202
+
203
+ @s3_client.put_bucket_notification_configuration(
204
+ bucket: @s3_bucketname,
205
+ notification_configuration: notification_configuration
206
+ )
207
+ log.debug "S3 notification events has been set for #{@s3_bucketname}/#{@s3_prefix}"
208
+
209
+ rescue Aws::SQS::Errors::InvalidAttributeValue => e
210
+ log.debug "SQS error: #{e.message}"
211
+ @running = false
212
+
213
+ rescue Aws::S3::Errors::InvalidArgument => e
214
+ log.debug "S3 Event error: #{e.message}"
215
+ sqs_client.delete_queue(queue_url: @queue_url)
216
+ @queue_url = ""
217
+ log.debug "#{queue_arn} deleted"
218
+ @running = false
62
219
  end
63
220
  end
64
221
 
222
+ def unset_sqs
223
+ return if @queue_url.nil? || @queue_url == ""
224
+ @s3_client.put_bucket_notification_configuration(
225
+ bucket: @s3_bucketname,
226
+ notification_configuration: {}
227
+ )
228
+ log.debug "S3 notification events has been removed"
229
+
230
+ @sqs_client.delete_queue(queue_url: @queue_url)
231
+ log.debug "SQS queue #{@queue_url} has been removed"
232
+ @queue_url = ""
233
+ end
234
+
65
235
  def get_timestamp_file
66
236
  begin
67
237
  # get timestamp last proc
@@ -80,6 +250,7 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
80
250
  return timestamp
81
251
  rescue => e
82
252
  log.warn "timestamp file get and parse error occurred: #{e.message}"
253
+ @running = false
83
254
  end
84
255
  end
85
256
 
@@ -91,6 +262,7 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
91
262
  end
92
263
  rescue => e
93
264
  log.warn "timestamp file get and parse error occurred: #{e.message}"
265
+ @running = false
94
266
  end
95
267
  end
96
268
 
@@ -110,6 +282,7 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
110
282
  Aws::S3::Client.new(options)
111
283
  rescue => e
112
284
  log.warn "S3 Client error occurred: #{e.message}"
285
+ @running = false
113
286
  end
114
287
  end
115
288
 
@@ -121,19 +294,40 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
121
294
  !(get_object_list(1).nil?)
122
295
  rescue => e
123
296
  log.warn "error occurred: #{e.message}"
297
+ @running = false
124
298
  false
125
299
  end
126
300
  end
127
301
 
302
+ def sqs_client
303
+ begin
304
+ options = {
305
+ region: @region,
306
+ }
307
+ if @access_key_id && @secret_access_key
308
+ options[:access_key_id] = @access_key_id
309
+ options[:secret_access_key] = @secret_access_key
310
+ end
311
+ if @http_proxy
312
+ options[:http_proxy] = @http_proxy
313
+ end
314
+ log.debug "SQS client connect"
315
+ Aws::SQS::Client.new(options)
316
+ rescue => e
317
+ log.warn "SQS Client error occurred: #{e.message}"
318
+ @running = false
319
+ end
320
+ end
321
+
128
322
  def input
129
323
  begin
130
- log.debug "start"
324
+ log.debug "input start"
131
325
  timestamp = get_timestamp_file()
132
326
 
133
327
  object_keys = get_object_keys(timestamp)
134
328
  object_keys = sort_object_key(object_keys)
135
329
 
136
- log.info "processing #{object_keys.count} object(s)."
330
+ log.info "found #{object_keys.count} new object(s)."
137
331
 
138
332
  object_keys.each do |object_key|
139
333
  record_common = {
@@ -143,10 +337,10 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
143
337
  "logfile_elb_name" => object_key[:logfile_elb_name],
144
338
  "elb_ip_address" => object_key[:elb_ip_address],
145
339
  "logfile_hash" => object_key[:logfile_hash],
146
- "elb_timestamp" => object_key[:elb_timestamp],
340
+ "logfile_timestamp" => object_key[:logfile_timestamp],
147
341
  "key" => object_key[:key],
148
342
  "prefix" => object_key[:prefix],
149
- "elb_timestamp_unixtime" => object_key[:elb_timestamp_unixtime],
343
+ "logfile_timestamp_unixtime" => object_key[:logfile_timestamp_unixtime],
150
344
  "s3_last_modified_unixtime" => object_key[:s3_last_modified_unixtime],
151
345
  }
152
346
 
@@ -161,6 +355,91 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
161
355
  end
162
356
  rescue => e
163
357
  log.warn "error occurred: #{e.message}"
358
+ @running = false
359
+ end
360
+ end
361
+
362
+ def process_sqs
363
+ begin
364
+ if @running
365
+ number_of_messages = @sqs_client.get_queue_attributes(
366
+ queue_url: @queue_url,
367
+ attribute_names: ["ApproximateNumberOfMessages"]
368
+ ).attributes["ApproximateNumberOfMessages"].to_i
369
+
370
+ count = 0
371
+ while count < number_of_messages
372
+ messages = @sqs_client.receive_message(
373
+ queue_url: @queue_url,
374
+ max_number_of_messages: 10,
375
+ wait_time_seconds: 10
376
+ ).messages
377
+ log.debug "SQS queue has ApproximateNumberOfMessages=#{number_of_messages}" if number_of_messages > 0
378
+
379
+ break if messages.empty?
380
+
381
+ messages.each do |message|
382
+ count += 1
383
+ s3_event = JSON.parse(message.body)
384
+ unless s3_event.key?('Records')
385
+ @sqs_client.delete_message(
386
+ queue_url: @queue_url,
387
+ receipt_handle: message.receipt_handle
388
+ )
389
+ next
390
+ end
391
+ #log.debug "S3 event: #{s3_event}"
392
+ bucket = s3_event['Records'][0]['s3']['bucket']['name']
393
+ key = s3_event['Records'][0]['s3']['object']['key']
394
+ event_time = Time.parse(s3_event['Records'][0]['eventTime']).to_i
395
+ log.debug "S3 event received for #{key} at #{s3_event['Records'][0]['eventTime']}"
396
+
397
+ object_key = get_object_key(key, event_time, 0)
398
+ if object_key.nil?
399
+ @sqs_client.delete_message(
400
+ queue_url: @queue_url,
401
+ receipt_handle: message.receipt_handle
402
+ )
403
+ next
404
+ end
405
+
406
+ record_common = {
407
+ "account_id" => object_key[:account_id],
408
+ "region" => object_key[:region],
409
+ "logfile_date" => object_key[:logfile_date],
410
+ "logfile_elb_name" => object_key[:logfile_elb_name],
411
+ "elb_ip_address" => object_key[:elb_ip_address],
412
+ "logfile_hash" => object_key[:logfile_hash],
413
+ "logfile_timestamp" => object_key[:logfile_timestamp],
414
+ "key" => object_key[:key],
415
+ "prefix" => object_key[:prefix],
416
+ "logfile_timestamp_unixtime" => object_key[:logfile_timestamp_unixtime],
417
+ "s3_last_modified_unixtime" => object_key[:s3_last_modified_unixtime],
418
+ }
419
+
420
+ get_file_from_s3(object_key[:key])
421
+ emit_lines_from_buffer_file(record_common)
422
+
423
+ put_timestamp_file(object_key[:s3_last_modified_unixtime])
424
+
425
+ if @delete
426
+ delete_file_from_s3(object_key[:key])
427
+ end
428
+
429
+ @sqs_client.delete_message(
430
+ queue_url: @queue_url,
431
+ receipt_handle: message.receipt_handle
432
+ )
433
+ end
434
+ if count == 0
435
+ log.debug "No messages out of #{number_of_messages} were processed - should never happen"
436
+ break
437
+ end
438
+ end
439
+ end
440
+ rescue => e
441
+ log.warn "error occurred: #{e.message}"
442
+ @running = false
164
443
  end
165
444
  end
166
445
 
@@ -171,56 +450,71 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
171
450
  end
172
451
  rescue => e
173
452
  log.warn "error occurred: #{e.message}"
453
+ @running = false
174
454
  end
175
455
  end
176
456
 
177
457
  def get_object_list(max_num)
178
- s3_client.list_objects(
458
+ @s3_client.list_objects(
179
459
  bucket: @s3_bucketname,
180
460
  max_keys: max_num,
181
461
  prefix: @s3_prefix
182
462
  )
183
463
  end
184
464
 
465
+ def get_object_key(key, last_modified, timestamp)
466
+ node_no = Digest::SHA1.hexdigest(key).to_i(16) % @num_nodes
467
+ return nil unless node_no == @node_no
468
+
469
+ matches = LOGFILE_REGEXP.match(key)
470
+
471
+ s3_last_modified_unixtime = last_modified
472
+ if s3_last_modified_unixtime > timestamp and matches
473
+ exclude_pattern_matches = @exclude_pattern_logfile_elb_name_re.match(matches[:logfile_elb_name])
474
+ if exclude_pattern_matches
475
+ log.debug "Skipping object #{key} b/c it matches exclude_pattern_logfile_elb_name"
476
+ return nil
477
+ end
478
+
479
+ object_key = {
480
+ key: key,
481
+ prefix: matches[:prefix],
482
+ account_id: matches[:account_id],
483
+ region: matches[:region],
484
+ logfile_date: matches[:logfile_date],
485
+ logfile_elb_name: matches[:logfile_elb_name],
486
+ logfile_timestamp: matches[:logfile_timestamp],
487
+ elb_ip_address: matches[:elb_ip_address],
488
+ logfile_hash: matches[:logfile_hash],
489
+ logfile_timestamp_unixtime: Time.parse(matches[:logfile_timestamp]).to_i,
490
+ s3_last_modified_unixtime: s3_last_modified_unixtime,
491
+ }
492
+ end
493
+
494
+ return object_key
495
+ end
496
+
185
497
  def get_object_keys(timestamp)
186
498
  object_keys = []
187
499
 
188
- resp = s3_client.list_objects_v2(
500
+ resp = @s3_client.list_objects_v2(
189
501
  bucket: @s3_bucketname,
190
502
  prefix: @s3_prefix
191
503
  )
192
504
 
193
- loop do
505
+ while @running do
194
506
  resp.contents.each do |content|
195
- s3_last_modified_unixtime = content.last_modified.to_i
196
-
197
- object_key = content.key
198
- node_no = Digest::SHA1.hexdigest(object_key).to_i(16) % @num_nodes
199
- next unless node_no == @node_no
200
-
201
- matches = LOGFILE_REGEXP.match(object_key)
202
- if s3_last_modified_unixtime > timestamp and matches
203
- object_keys << {
204
- key: object_key,
205
- prefix: matches[:prefix],
206
- account_id: matches[:account_id],
207
- region: matches[:region],
208
- logfile_date: matches[:logfile_date],
209
- logfile_elb_name: matches[:logfile_elb_name],
210
- elb_timestamp: matches[:elb_timestamp],
211
- elb_ip_address: matches[:elb_ip_address],
212
- logfile_hash: matches[:logfile_hash],
213
- elb_timestamp_unixtime: Time.parse(matches[:elb_timestamp]).to_i,
214
- s3_last_modified_unixtime: s3_last_modified_unixtime,
215
- }
216
- end
507
+ log.debug "Getting #{content.key}"
508
+ object_key = get_object_key(content.key, content.last_modified.to_i, timestamp)
509
+ next if object_key.nil?
510
+ object_keys << object_key
217
511
  end
218
512
 
219
513
  if !resp.is_truncated
220
514
  return object_keys
221
515
  end
222
516
 
223
- resp = s3_client.list_objects_v2(
517
+ resp = @s3_client.list_objects_v2(
224
518
  bucket: @s3_bucketname,
225
519
  prefix: @s3_prefix,
226
520
  continuation_token: resp.next_continuation_token
@@ -248,10 +542,10 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
248
542
 
249
543
  def get_file_from_s3(object_name)
250
544
  begin
251
- log.debug "getting object from s3 name is #{object_name}"
545
+ log.debug "retrieving #{object_name}"
252
546
 
253
547
  Tempfile.create('fluent-elblog') do |tfile|
254
- s3_client.get_object(bucket: @s3_bucketname, key: object_name, response_target: tfile.path)
548
+ @s3_client.get_object(bucket: @s3_bucketname, key: object_name, response_target: tfile.path)
255
549
 
256
550
  if File.extname(object_name) != '.gz'
257
551
  FileUtils.cp(tfile.path, @buf_file)
@@ -261,6 +555,7 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
261
555
  end
262
556
  rescue => e
263
557
  log.warn "error occurred: #{e.message}, #{e.backtrace}"
558
+ @running = false
264
559
  end
265
560
  end
266
561
 
@@ -268,7 +563,7 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
268
563
  begin
269
564
  log.debug "deleting object from s3 name is #{object_name}"
270
565
 
271
- s3_client.delete_object(bucket: @s3_bucketname, key: object_name)
566
+ @s3_client.delete_object(bucket: @s3_bucketname, key: object_name)
272
567
  rescue => e
273
568
  log.warn "error occurred: #{e.message}, #{e.backtrace}"
274
569
  end
@@ -300,6 +595,7 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
300
595
  end
301
596
  rescue => e
302
597
  log.warn "error occurred: #{e.message}"
598
+ @running = false
303
599
  end
304
600
  end
305
601
 
@@ -308,13 +604,13 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
308
604
  "elb" => item[:elb],
309
605
  "client" => item[:client],
310
606
  "client_port" => item[:client_port],
311
- "backend" => item[:backend],
312
- "backend_port" => item[:backend_port],
607
+ "target" => item[:target],
608
+ "target_port" => item[:target_port],
313
609
  "request_processing_time" => item[:request_processing_time].to_f,
314
- "backend_processing_time" => item[:backend_processing_time].to_f,
610
+ "target_processing_time" => item[:target_processing_time].to_f,
315
611
  "response_processing_time" => item[:response_processing_time].to_f,
316
612
  "elb_status_code" => item[:elb_status_code],
317
- "backend_status_code" => item[:backend_status_code],
613
+ "target_status_code" => item[:target_status_code],
318
614
  "received_bytes" => item[:received_bytes].to_i,
319
615
  "sent_bytes" => item[:sent_bytes].to_i,
320
616
  "request_method" => item[:request_method],
@@ -333,9 +629,11 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
333
629
  "actions_executed" => item[:actions_executed],
334
630
  "redirect_url" => item[:redirect_url],
335
631
  "error_reason" => item[:error_reason],
336
- "option1" => item[:option1],
337
- "option2" => item[:option2],
338
- "option3" => item[:option3]
632
+ "target_port_list" => item[:target_port_list],
633
+ "target_status_code_list" => item[:target_status_code_list],
634
+ "classification" => item[:classification],
635
+ "classification_reason" => item[:classification_reason],
636
+ "conn_trace_id" => item[:conn_trace_id]
339
637
  }
340
638
  end
341
639
  end
@@ -164,7 +164,7 @@ class Elb_LogInputTest < Test::Unit::TestCase
164
164
  assert_equal('ap-northeast-1', m[:region])
165
165
  assert_equal('2017/05/03', m[:logfile_date])
166
166
  assert_equal('app.elbname.59bfa19e900030c2', m[:logfile_elb_name])
167
- assert_equal('20170503T1310Z', m[:elb_timestamp])
167
+ assert_equal('20170503T1310Z', m[:logfile_timestamp])
168
168
  assert_equal('10.0.0.1', m[:elb_ip_address])
169
169
  assert_equal('2tko12gv', m[:logfile_hash])
170
170
  end
@@ -177,13 +177,13 @@ class Elb_LogInputTest < Test::Unit::TestCase
177
177
  assert_equal('elbname', m[:elb])
178
178
  assert_equal('10.11.12.13', m[:client])
179
179
  assert_equal('37852', m[:client_port])
180
- assert_equal('192.168.30.186', m[:backend])
181
- assert_equal('443', m[:backend_port])
180
+ assert_equal('192.168.30.186', m[:target])
181
+ assert_equal('443', m[:target_port])
182
182
  assert_equal('0.00004', m[:request_processing_time])
183
- assert_equal('0.085372', m[:backend_processing_time])
183
+ assert_equal('0.085372', m[:target_processing_time])
184
184
  assert_equal('0.000039', m[:response_processing_time])
185
185
  assert_equal('301', m[:elb_status_code])
186
- assert_equal('301', m[:backend_status_code])
186
+ assert_equal('301', m[:target_status_code])
187
187
  assert_equal('0', m[:received_bytes])
188
188
  assert_equal('0', m[:sent_bytes])
189
189
  assert_equal('GET', m[:request_method])
@@ -195,7 +195,7 @@ class Elb_LogInputTest < Test::Unit::TestCase
195
195
  assert_equal(nil, m[:type])
196
196
  assert_equal(nil, m[:target_group_arn])
197
197
  assert_equal(nil, m[:trace_id])
198
- assert_equal(nil, m[:option3])
198
+ assert_equal(nil, m[:conn_trace_id])
199
199
  end
200
200
 
201
201
  def test_log_application_lb_parse
@@ -206,13 +206,13 @@ class Elb_LogInputTest < Test::Unit::TestCase
206
206
  assert_equal('app/elbname/59bfa19e900030c2', m[:elb])
207
207
  assert_equal('10.20.30.40', m[:client])
208
208
  assert_equal('52730', m[:client_port])
209
- assert_equal('192.168.30.186', m[:backend])
210
- assert_equal('443', m[:backend_port])
209
+ assert_equal('192.168.30.186', m[:target])
210
+ assert_equal('443', m[:target_port])
211
211
  assert_equal('0.006', m[:request_processing_time])
212
- assert_equal('0.000', m[:backend_processing_time])
212
+ assert_equal('0.000', m[:target_processing_time])
213
213
  assert_equal('0.086', m[:response_processing_time])
214
214
  assert_equal('301', m[:elb_status_code])
215
- assert_equal('301', m[:backend_status_code])
215
+ assert_equal('301', m[:target_status_code])
216
216
  assert_equal('117', m[:received_bytes])
217
217
  assert_equal('507', m[:sent_bytes])
218
218
  assert_equal('GET', m[:request_method])
@@ -224,7 +224,7 @@ class Elb_LogInputTest < Test::Unit::TestCase
224
224
  assert_equal('https', m[:type])
225
225
  assert_equal('arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/lbgrp1/605122a4e4ee9f2d', m[:target_group_arn])
226
226
  assert_equal('"Root=1-590c7929-4eb4cb393d46a01d22db8473"', m[:trace_id])
227
- assert_equal(nil, m[:option3])
227
+ assert_equal(nil, m[:conn_trace_id])
228
228
  end
229
229
 
230
230
  def test_grp_and_trace_fileld
@@ -235,13 +235,13 @@ class Elb_LogInputTest < Test::Unit::TestCase
235
235
  assert_equal('app/elbname/aabbccdd9988', m[:elb])
236
236
  assert_equal('10.248.9.92', m[:client])
237
237
  assert_equal('54000', m[:client_port])
238
- assert_equal('10.248.9.77', m[:backend])
239
- assert_equal('80', m[:backend_port])
238
+ assert_equal('10.248.9.77', m[:target])
239
+ assert_equal('80', m[:target_port])
240
240
  assert_equal('0.001', m[:request_processing_time])
241
- assert_equal('0.002', m[:backend_processing_time])
241
+ assert_equal('0.002', m[:target_processing_time])
242
242
  assert_equal('0.003', m[:response_processing_time])
243
243
  assert_equal('200', m[:elb_status_code])
244
- assert_equal('200', m[:backend_status_code])
244
+ assert_equal('200', m[:target_status_code])
245
245
  assert_equal('686', m[:received_bytes])
246
246
  assert_equal('6476', m[:sent_bytes])
247
247
  assert_equal('GET', m[:request_method])
@@ -252,7 +252,9 @@ class Elb_LogInputTest < Test::Unit::TestCase
252
252
  assert_equal('-', m[:ssl_protocol])
253
253
  assert_equal('arn:aws:elasticloadbalancing:us-east-1:123456789123:targetgroup/example-service/1234abcd1234abcd', m[:target_group_arn])
254
254
  assert_equal('"Root=1-xxxxxxxx-yyyyyyyyyyyyyyyyyyyzzzzz"', m[:trace_id])
255
- assert_equal('"-" "-" 3', m[:option3])
255
+ assert_equal('domain_name', m[:domain_name])
256
+ assert_equal('chosen_cert_arn', m[:chosen_cert_arn])
257
+ assert_equal('matched_rule_priority', m[:matched_rule_priority])
256
258
  end
257
259
 
258
260
  def test_alb_all_field
@@ -264,14 +266,14 @@ class Elb_LogInputTest < Test::Unit::TestCase
264
266
  assert_equal('app/my-alb/520e61ffffffffff', m[:elb])
265
267
  assert_equal('60.11.22.33', m[:client])
266
268
  assert_equal('51306', m[:client_port])
267
- assert_equal('192.168.30.111', m[:backend])
268
- assert_equal('443', m[:backend_port])
269
+ assert_equal('192.168.30.111', m[:target])
270
+ assert_equal('443', m[:target_port])
269
271
 
270
272
  assert_equal('0.010', m[:request_processing_time])
271
- assert_equal('0.097', m[:backend_processing_time])
273
+ assert_equal('0.097', m[:target_processing_time])
272
274
  assert_equal('0.001', m[:response_processing_time])
273
275
  assert_equal('301', m[:elb_status_code])
274
- assert_equal('301', m[:backend_status_code])
276
+ assert_equal('301', m[:target_status_code])
275
277
  assert_equal('414', m[:received_bytes])
276
278
  assert_equal('507', m[:sent_bytes])
277
279
  assert_equal('GET', m[:request_method])
@@ -289,8 +291,8 @@ class Elb_LogInputTest < Test::Unit::TestCase
289
291
  assert_equal('forward', m[:actions_executed])
290
292
  assert_equal('redirect://url-something.com/', m[:redirect_url])
291
293
  assert_equal('error_reason', m[:error_reason])
292
- assert_equal('"192.168.30.186:443"', m[:option1])
293
- assert_equal('"301"', m[:option2])
294
- assert_equal(nil, m[:option3])
294
+ assert_equal('"192.168.30.186:443"', m[:target_port_list])
295
+ assert_equal('"301"', m[:target_status_code_list])
296
+ assert_equal(nil, m[:classification])
295
297
  end
296
298
  end
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-elb-log
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.2
4
+ version: 1.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - shinsaka
8
- autorequire:
8
+ - jazzl0ver
9
+ autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2019-11-10 00:00:00.000000000 Z
12
+ date: 2026-06-11 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: fluentd
@@ -146,11 +147,11 @@ files:
146
147
  - lib/fluent/plugin/in_elb_log.rb
147
148
  - test/helper.rb
148
149
  - test/plugin/in_elb_log.rb
149
- homepage: https://github.com/shinsaka/fluent-plugin-elb-log
150
+ homepage: https://github.com/jazzl0ver/fluent-plugin-elb-log
150
151
  licenses:
151
152
  - MIT
152
153
  metadata: {}
153
- post_install_message:
154
+ post_install_message:
154
155
  rdoc_options: []
155
156
  require_paths:
156
157
  - lib
@@ -165,8 +166,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
165
166
  - !ruby/object:Gem::Version
166
167
  version: '0'
167
168
  requirements: []
168
- rubygems_version: 3.0.3
169
- signing_key:
169
+ rubygems_version: 3.5.22
170
+ signing_key:
170
171
  specification_version: 4
171
172
  summary: Amazon ELB log input plugin
172
173
  test_files: