fluent-plugin-elb-log 1.3.2 → 1.4.0

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: b90a7ba2cb9c1a065697787d2634625df53bb3f28b2f4a3d88c940071255b848
4
+ data.tar.gz: 899bbcf97b460fbf709f4aee85a6ab418c8d58cd5fb53f7aeabaf54fcb729511
5
5
  SHA512:
6
- metadata.gz: '038e446b92d1034613eb244e4b540b2daa0668942bd662f8a807b9f01c49fe273247e22d4a321f1eac007a19f999244c86e933fb2c8c686a406b83e9b35b350d'
7
- data.tar.gz: 2355ddaec49a2b56e1fd69ae7703659ac7d9852d7e3a6ea10d44832de406dd2486690cb5fd7aa083d393c3054e0858fd9c21fbe35f1e264e1effca95ffe0a284
6
+ metadata.gz: dabbbdc5f79f83ba6003057126d62e492da600584840d72d2240eaea1bcc532cf56d9177762b0aa1cdc055e88bfb1d7840f7a11c6b95861905df3dd4e28eedbe
7
+ data.tar.gz: 48d929caa219fc1b8ef6aa2c5e971cfe2ea1c1f1f6a556ff431b3a7e338eb0c8f9a8701f284aec9ec5e71a7c1304f6cf0d0e403edccfe9d6361324bc362b76a4
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.0"
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,11 +58,62 @@ 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
+ if @use_sqs
66
+ input
67
+ @sqs_client = sqs_client
68
+ setup_sqs_timer
69
+ else
70
+ setup_input_timer
71
+ end
52
72
  end
53
73
 
54
74
  private
55
75
 
76
+ def shutdown
77
+ log.debug "shutdown"
78
+ if @running
79
+ @running = false
80
+ if @use_sqs
81
+ log.debug "pausing shutdown for 2x#{@refresh_interval}"
82
+ sleep 2*@refresh_interval
83
+ unset_sqs if @queue_url && @queue_url != ""
84
+ else
85
+ log.debug "pausing shutdown for 30 seconds"
86
+ sleep 30
87
+ end
88
+ end
89
+ end
90
+
91
+ def setup_sqs_timer
92
+ if @running
93
+ setup_sqs
94
+ timer_execute(:in_elb_log, @refresh_interval) do
95
+ if @running
96
+ process_sqs
97
+ log.debug "sleeping for #{@refresh_interval}"
98
+ else
99
+ log.debug "Unsetting SQS"
100
+ unset_sqs if @queue_url && @queue_url != ""
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ def setup_input_timer
107
+ if @running
108
+ timer_execute(:in_elb_log, @refresh_interval) do
109
+ if @running
110
+ input
111
+ log.debug "sleeping input for #{@refresh_interval}"
112
+ end
113
+ end
114
+ end
115
+ end
116
+
56
117
  def has_iam_role?
57
118
  begin
58
119
  ec2 = Aws::EC2::Client.new(region: @region)
@@ -62,6 +123,99 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
62
123
  end
63
124
  end
64
125
 
126
+ def setup_sqs
127
+ begin
128
+ timestamp = Time.now.to_i
129
+ queue_name = "fluent-plugin-elb-log-#{timestamp}"
130
+
131
+ sts_client = Aws::STS::Client.new
132
+ account_id = sts_client.get_caller_identity.account
133
+
134
+ queue_policy = {
135
+ "Version": "2012-10-17",
136
+ "Id": "__default_policy_ID",
137
+ "Statement": [
138
+ {
139
+ "Sid": "S3_service_publish",
140
+ "Effect": "Allow",
141
+ "Principal": {
142
+ "Service": "s3.amazonaws.com"
143
+ },
144
+ "Action": "SQS:SendMessage",
145
+ "Resource": "arn:aws:sqs:us-east-1:#{account_id}:#{queue_name}",
146
+ "Condition": {
147
+ "StringEquals": {
148
+ "aws:SourceAccount": "#{account_id}"
149
+ },
150
+ "ArnLike": {
151
+ "aws:SourceArn": "arn:aws:s3:*:*:#{@s3_bucket}"
152
+ }
153
+ }
154
+ }
155
+ ]
156
+ }.to_json
157
+ create_queue_response = @sqs_client.create_queue(queue_name: queue_name,
158
+ attributes: {
159
+ 'Policy' => queue_policy
160
+ }
161
+ )
162
+ @queue_url = create_queue_response.queue_url
163
+ queue_attributes = @sqs_client.get_queue_attributes(
164
+ queue_url: @queue_url,
165
+ attribute_names: ['QueueArn']
166
+ )
167
+ queue_arn = queue_attributes.attributes['QueueArn']
168
+ log.debug "New SQS queue created: #{queue_arn}"
169
+
170
+ notification_configuration = {
171
+ queue_configurations: [
172
+ {
173
+ id: "fluent-plugin-elb-log",
174
+ events: ['s3:ObjectCreated:*'],
175
+ queue_arn: "#{queue_arn}",
176
+ filter: {
177
+ key: {
178
+ filter_rules: [
179
+ {
180
+ name: 'Prefix',
181
+ value: "#{@s3_prefix}"
182
+ }
183
+ ]
184
+ }
185
+ }
186
+ }
187
+ ]
188
+ }
189
+
190
+ @s3_client.put_bucket_notification_configuration(
191
+ bucket: @s3_bucketname,
192
+ notification_configuration: notification_configuration
193
+ )
194
+ log.debug "S3 notification events has been set for #{@s3_bucketname}/#{@s3_prefix}"
195
+
196
+ rescue Aws::SQS::Errors::InvalidAttributeValue => e
197
+ log.debug "SQS error: #{e.message}"
198
+
199
+ rescue Aws::S3::Errors::InvalidArgument => e
200
+ log.debug "S3 Event error: #{e.message}"
201
+ sqs_client.delete_queue(queue_url: @queue_url)
202
+ log.debug "#{queue_arn} deleted"
203
+ end
204
+ end
205
+
206
+ def unset_sqs
207
+ return if @queue_url.nil? || @queue_url == ""
208
+ @s3_client.put_bucket_notification_configuration(
209
+ bucket: @s3_bucketname,
210
+ notification_configuration: {}
211
+ )
212
+ log.debug "S3 notification events has been removed"
213
+
214
+ @sqs_client.delete_queue(queue_url: @queue_url)
215
+ log.debug "SQS queue #{@queue_url} has been removed"
216
+ @queue_url = ""
217
+ end
218
+
65
219
  def get_timestamp_file
66
220
  begin
67
221
  # get timestamp last proc
@@ -125,15 +279,34 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
125
279
  end
126
280
  end
127
281
 
282
+ def sqs_client
283
+ begin
284
+ options = {
285
+ region: @region,
286
+ }
287
+ if @access_key_id && @secret_access_key
288
+ options[:access_key_id] = @access_key_id
289
+ options[:secret_access_key] = @secret_access_key
290
+ end
291
+ if @http_proxy
292
+ options[:http_proxy] = @http_proxy
293
+ end
294
+ log.debug "SQS client connect"
295
+ Aws::SQS::Client.new(options)
296
+ rescue => e
297
+ log.warn "SQS Client error occurred: #{e.message}"
298
+ end
299
+ end
300
+
128
301
  def input
129
302
  begin
130
- log.debug "start"
303
+ log.debug "input start"
131
304
  timestamp = get_timestamp_file()
132
305
 
133
306
  object_keys = get_object_keys(timestamp)
134
307
  object_keys = sort_object_key(object_keys)
135
308
 
136
- log.info "processing #{object_keys.count} object(s)."
309
+ log.info "found #{object_keys.count} new object(s)."
137
310
 
138
311
  object_keys.each do |object_key|
139
312
  record_common = {
@@ -143,10 +316,10 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
143
316
  "logfile_elb_name" => object_key[:logfile_elb_name],
144
317
  "elb_ip_address" => object_key[:elb_ip_address],
145
318
  "logfile_hash" => object_key[:logfile_hash],
146
- "elb_timestamp" => object_key[:elb_timestamp],
319
+ "logfile_timestamp" => object_key[:logfile_timestamp],
147
320
  "key" => object_key[:key],
148
321
  "prefix" => object_key[:prefix],
149
- "elb_timestamp_unixtime" => object_key[:elb_timestamp_unixtime],
322
+ "logfile_timestamp_unixtime" => object_key[:logfile_timestamp_unixtime],
150
323
  "s3_last_modified_unixtime" => object_key[:s3_last_modified_unixtime],
151
324
  }
152
325
 
@@ -164,6 +337,89 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
164
337
  end
165
338
  end
166
339
 
340
+ def process_sqs
341
+ begin
342
+ if @running
343
+ number_of_messages = @sqs_client.get_queue_attributes(
344
+ queue_url: @queue_url,
345
+ attribute_names: ["ApproximateNumberOfMessages"]
346
+ ).attributes["ApproximateNumberOfMessages"].to_i
347
+
348
+ count = 0
349
+ while count < number_of_messages
350
+ messages = @sqs_client.receive_message(
351
+ queue_url: @queue_url,
352
+ max_number_of_messages: 10,
353
+ wait_time_seconds: 10
354
+ ).messages
355
+ log.debug "SQS queue has ApproximateNumberOfMessages=#{number_of_messages}" if number_of_messages > 0
356
+
357
+ break if messages.empty?
358
+
359
+ messages.each do |message|
360
+ count += 1
361
+ s3_event = JSON.parse(message.body)
362
+ unless s3_event.key?('Records')
363
+ @sqs_client.delete_message(
364
+ queue_url: @queue_url,
365
+ receipt_handle: message.receipt_handle
366
+ )
367
+ next
368
+ end
369
+ #log.debug "S3 event: #{s3_event}"
370
+ bucket = s3_event['Records'][0]['s3']['bucket']['name']
371
+ key = s3_event['Records'][0]['s3']['object']['key']
372
+ event_time = Time.parse(s3_event['Records'][0]['eventTime']).to_i
373
+ log.debug "S3 event received for #{key} at #{s3_event['Records'][0]['eventTime']}"
374
+
375
+ object_key = get_object_key(key, event_time, 0)
376
+ if object_key.nil?
377
+ @sqs_client.delete_message(
378
+ queue_url: @queue_url,
379
+ receipt_handle: message.receipt_handle
380
+ )
381
+ next
382
+ end
383
+
384
+ record_common = {
385
+ "account_id" => object_key[:account_id],
386
+ "region" => object_key[:region],
387
+ "logfile_date" => object_key[:logfile_date],
388
+ "logfile_elb_name" => object_key[:logfile_elb_name],
389
+ "elb_ip_address" => object_key[:elb_ip_address],
390
+ "logfile_hash" => object_key[:logfile_hash],
391
+ "logfile_timestamp" => object_key[:logfile_timestamp],
392
+ "key" => object_key[:key],
393
+ "prefix" => object_key[:prefix],
394
+ "logfile_timestamp_unixtime" => object_key[:logfile_timestamp_unixtime],
395
+ "s3_last_modified_unixtime" => object_key[:s3_last_modified_unixtime],
396
+ }
397
+
398
+ get_file_from_s3(object_key[:key])
399
+ emit_lines_from_buffer_file(record_common)
400
+
401
+ put_timestamp_file(object_key[:s3_last_modified_unixtime])
402
+
403
+ if @delete
404
+ delete_file_from_s3(object_key[:key])
405
+ end
406
+
407
+ @sqs_client.delete_message(
408
+ queue_url: @queue_url,
409
+ receipt_handle: message.receipt_handle
410
+ )
411
+ end
412
+ if count == 0
413
+ log.debug "No messages out of #{number_of_messages} were processed - should never happen"
414
+ break
415
+ end
416
+ end
417
+ end
418
+ rescue => e
419
+ log.warn "error occurred: #{e.message}"
420
+ end
421
+ end
422
+
167
423
  def sort_object_key(src_object_keys)
168
424
  begin
169
425
  src_object_keys.sort do |a, b|
@@ -175,52 +431,66 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
175
431
  end
176
432
 
177
433
  def get_object_list(max_num)
178
- s3_client.list_objects(
434
+ @s3_client.list_objects(
179
435
  bucket: @s3_bucketname,
180
436
  max_keys: max_num,
181
437
  prefix: @s3_prefix
182
438
  )
183
439
  end
184
440
 
441
+ def get_object_key(key, last_modified, timestamp)
442
+ node_no = Digest::SHA1.hexdigest(key).to_i(16) % @num_nodes
443
+ return nil unless node_no == @node_no
444
+
445
+ matches = LOGFILE_REGEXP.match(key)
446
+
447
+ s3_last_modified_unixtime = last_modified
448
+ if s3_last_modified_unixtime > timestamp and matches
449
+ exclude_pattern_matches = @exclude_pattern_logfile_elb_name_re.match(matches[:logfile_elb_name])
450
+ if exclude_pattern_matches
451
+ log.debug "Skipping object #{key} b/c it matches exclude_pattern_logfile_elb_name"
452
+ return nil
453
+ end
454
+
455
+ object_key = {
456
+ key: key,
457
+ prefix: matches[:prefix],
458
+ account_id: matches[:account_id],
459
+ region: matches[:region],
460
+ logfile_date: matches[:logfile_date],
461
+ logfile_elb_name: matches[:logfile_elb_name],
462
+ logfile_timestamp: matches[:logfile_timestamp],
463
+ elb_ip_address: matches[:elb_ip_address],
464
+ logfile_hash: matches[:logfile_hash],
465
+ logfile_timestamp_unixtime: Time.parse(matches[:logfile_timestamp]).to_i,
466
+ s3_last_modified_unixtime: s3_last_modified_unixtime,
467
+ }
468
+ end
469
+
470
+ return object_key
471
+ end
472
+
185
473
  def get_object_keys(timestamp)
186
474
  object_keys = []
187
475
 
188
- resp = s3_client.list_objects_v2(
476
+ resp = @s3_client.list_objects_v2(
189
477
  bucket: @s3_bucketname,
190
478
  prefix: @s3_prefix
191
479
  )
192
480
 
193
- loop do
481
+ while @running do
194
482
  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
483
+ log.debug "Getting #{content.key}"
484
+ object_key = get_object_key(content.key, content.last_modified.to_i, timestamp)
485
+ next if object_key.nil?
486
+ object_keys << object_key
217
487
  end
218
488
 
219
489
  if !resp.is_truncated
220
490
  return object_keys
221
491
  end
222
492
 
223
- resp = s3_client.list_objects_v2(
493
+ resp = @s3_client.list_objects_v2(
224
494
  bucket: @s3_bucketname,
225
495
  prefix: @s3_prefix,
226
496
  continuation_token: resp.next_continuation_token
@@ -248,10 +518,10 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
248
518
 
249
519
  def get_file_from_s3(object_name)
250
520
  begin
251
- log.debug "getting object from s3 name is #{object_name}"
521
+ log.debug "retrieving #{object_name}"
252
522
 
253
523
  Tempfile.create('fluent-elblog') do |tfile|
254
- s3_client.get_object(bucket: @s3_bucketname, key: object_name, response_target: tfile.path)
524
+ @s3_client.get_object(bucket: @s3_bucketname, key: object_name, response_target: tfile.path)
255
525
 
256
526
  if File.extname(object_name) != '.gz'
257
527
  FileUtils.cp(tfile.path, @buf_file)
@@ -268,7 +538,7 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
268
538
  begin
269
539
  log.debug "deleting object from s3 name is #{object_name}"
270
540
 
271
- s3_client.delete_object(bucket: @s3_bucketname, key: object_name)
541
+ @s3_client.delete_object(bucket: @s3_bucketname, key: object_name)
272
542
  rescue => e
273
543
  log.warn "error occurred: #{e.message}, #{e.backtrace}"
274
544
  end
@@ -308,13 +578,13 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
308
578
  "elb" => item[:elb],
309
579
  "client" => item[:client],
310
580
  "client_port" => item[:client_port],
311
- "backend" => item[:backend],
312
- "backend_port" => item[:backend_port],
581
+ "target" => item[:target],
582
+ "target_port" => item[:target_port],
313
583
  "request_processing_time" => item[:request_processing_time].to_f,
314
- "backend_processing_time" => item[:backend_processing_time].to_f,
584
+ "target_processing_time" => item[:target_processing_time].to_f,
315
585
  "response_processing_time" => item[:response_processing_time].to_f,
316
586
  "elb_status_code" => item[:elb_status_code],
317
- "backend_status_code" => item[:backend_status_code],
587
+ "target_status_code" => item[:target_status_code],
318
588
  "received_bytes" => item[:received_bytes].to_i,
319
589
  "sent_bytes" => item[:sent_bytes].to_i,
320
590
  "request_method" => item[:request_method],
@@ -333,9 +603,11 @@ class Fluent::Plugin::Elb_LogInput < Fluent::Plugin::Input
333
603
  "actions_executed" => item[:actions_executed],
334
604
  "redirect_url" => item[:redirect_url],
335
605
  "error_reason" => item[:error_reason],
336
- "option1" => item[:option1],
337
- "option2" => item[:option2],
338
- "option3" => item[:option3]
606
+ "target_port_list" => item[:target_port_list],
607
+ "target_status_code_list" => item[:target_status_code_list],
608
+ "classification" => item[:classification],
609
+ "classification_reason" => item[:classification_reason],
610
+ "conn_trace_id" => item[:conn_trace_id]
339
611
  }
340
612
  end
341
613
  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.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - shinsaka
8
+ - jazzl0ver
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2019-11-10 00:00:00.000000000 Z
12
+ date: 2025-03-01 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: fluentd
@@ -146,7 +147,7 @@ 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: {}
@@ -165,7 +166,7 @@ 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
+ rubygems_version: 3.3.5
169
170
  signing_key:
170
171
  specification_version: 4
171
172
  summary: Amazon ELB log input plugin