fluent-plugin-rds-pgsql-slow-query-log 0.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7cc2b1177e5a9d4ca640b8ec2f33d59b347f851e
4
+ data.tar.gz: 5da348ea4a145532272ac12388aacb5fe18a50d6
5
+ SHA512:
6
+ metadata.gz: a53d77095c1db650e85de115dd0fd27f91d0509b397c9d69153850bd181e48eae69758d9129a90a59cdf58b1bbc0f6eba0a36f28213654bdc086e5dadb82386c
7
+ data.tar.gz: 442401d78145a7d29928981895486fddc0436326aee8bf45906d71f8f1a0ba26c1da81ca615da96c46a1f19c8b84cdc867708fe6dd8853811c35589f04aa18fe
@@ -0,0 +1,3 @@
1
+ *.gem
2
+ fluent.conf
3
+
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 hSATAC
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,74 @@
1
+ # Amazon RDS for PostgreSQL log input plugin for fluentd
2
+
3
+ ## Overview
4
+ - Amazon Web Services RDS log input plugin for fluentd
5
+ - Forked from [fluentd-plugin-rds-pgsql-log](https://github.com/shinsaka/fluent-plugin-rds-pgsql-log)
6
+ - Add slow query duration parsing.
7
+
8
+ ## Installation
9
+
10
+ $ fluentd-gem install fluent-plugin-rds-pgsql-log
11
+
12
+ ## AWS ELB Settings
13
+ - settings see: [PostgreSQL Database Log Files](http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_LogAccess.Concepts.PostgreSQL.html)
14
+
15
+ ## When SSL certification error
16
+ log:
17
+ ```
18
+ SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
19
+ ```
20
+ Do env setting follows:
21
+ ```
22
+ SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt (If you using amazon linux)
23
+ ```
24
+
25
+ ## Configuration
26
+
27
+ ```config
28
+ <source>
29
+ type rds_pgsql_log
30
+ # required
31
+ region <region name>
32
+ db_instance_identifier <instance identifier>
33
+ # optional if you can IAM credentials
34
+ access_key_id <access_key>
35
+ secret_access_key <secret_access_key>
36
+ # optional
37
+ refresh_interval <interval number by second(default: 30)>
38
+ tag <tag name(default: rds-pgsql.log>
39
+ pos_file <log getting position file(default: rds-pgsql.log)>
40
+ </source>
41
+ ```
42
+
43
+ ### Example setting
44
+ ```config
45
+ <source>
46
+ type rds_pgsql_log
47
+ region ap-northeast-1
48
+ db_instance_identifier test-postgres
49
+ access_key_id XXXXXXXXXXXXXXXXXXXX
50
+ secret_access_key xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
51
+ refresh_interval 30
52
+ tag pgsql.log
53
+ pos_file /tmp/pgsql-log-pos.dat
54
+ </source>
55
+
56
+ <match pgsql.log>
57
+ type stdout
58
+ </match>
59
+ ```
60
+
61
+ ### json output example
62
+ ```
63
+
64
+ {"time":"2015-05-30 02:19:22 UTC",
65
+ "host":"192.168.30.175(53092)",
66
+ "user":"testuser",
67
+ "database":"db1",
68
+ "pid":"9769",
69
+ "message_level":"LOG",
70
+ "message":" statement: select 1;",
71
+ "log_file_name":"error/postgresql.log.2015-05-30-02"
72
+ }
73
+ ```
74
+
@@ -0,0 +1,23 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "fluent-plugin-rds-pgsql-slow-query-log"
6
+ spec.version = "0.1.1"
7
+ spec.authors = ["hSATAC"]
8
+ spec.email = ["hSATAC@gmail.com"]
9
+ spec.summary = "Amazon RDS for PostgreSQL log input plugin with slow query support"
10
+ spec.description = "fluentd plugin for Amazon RDS for PostgreSQL log input with slow query support"
11
+ spec.homepage = "https://github.com/hSATAC/fluent-plugin-rds-pgsql-log"
12
+ spec.license = "MIT"
13
+
14
+ spec.files = `git ls-files -z`.split("\x0")
15
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_dependency "fluentd", "~> 0"
20
+ spec.add_dependency "aws-sdk", "~> 2"
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.7"
23
+ end
@@ -0,0 +1,14 @@
1
+ <source>
2
+ type rds_pgsql_log
3
+ access_key_id XXXXXXXXXXXXXXXXXXXX
4
+ secret_access_key xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
5
+ region ap-northeast-1
6
+ db_instance_identifier test-postgres
7
+ refresh_interval 30
8
+ tag pgsql.log
9
+ pos_file /tmp/pgsql-log-pos.dat
10
+ </source>
11
+
12
+ <match pgsql.log>
13
+ type stdout
14
+ </match>
@@ -0,0 +1,237 @@
1
+ class Fluent::RdsPgsqlLogInput < Fluent::Input
2
+ Fluent::Plugin.register_input('rds_pgsql_slow_query_log', self)
3
+
4
+ LOG_REGEXP = /^(?<time>\d{4}-\d{2}-\d{2} \d{2}\:\d{2}\:\d{2} .+?):(?<host>.*?):(?<user>.*?)@(?<database>.*?):\[(?<pid>.*?)\]:(?<message_level>.*?):(?<message>.*)$/
5
+
6
+ config_param :access_key_id, :string, :default => nil
7
+ config_param :secret_access_key, :string, :default => nil
8
+ config_param :region, :string, :default => nil
9
+ config_param :db_instance_identifier, :string, :default => nil
10
+ config_param :pos_file, :string, :default => "fluent-plugin-rds-pgsql-log-pos.dat"
11
+ config_param :refresh_interval, :integer, :default => 30
12
+ config_param :tag, :string, :default => "rds-pgsql.log"
13
+
14
+ def configure(conf)
15
+ super
16
+ require 'aws-sdk'
17
+
18
+ raise Fluent::ConfigError.new("region is required") unless @region
19
+ if !has_iam_role?
20
+ raise Fluent::ConfigError.new("access_key_id is required") if @access_key_id.nil?
21
+ raise Fluent::ConfigError.new("secret_access_key is required") if @secret_access_key.nil?
22
+ end
23
+ raise Fluent::ConfigError.new("db_instance_identifier is required") unless @db_instance_identifier
24
+ raise Fluent::ConfigError.new("pos_file is required") unless @pos_file
25
+ raise Fluent::ConfigError.new("refresh_interval is required") unless @refresh_interval
26
+ raise Fluent::ConfigError.new("tag is required") unless @tag
27
+ end
28
+
29
+ def start
30
+ super
31
+
32
+ # pos file touch
33
+ File.open(@pos_file, File::RDWR|File::CREAT).close
34
+
35
+ begin
36
+ options = {
37
+ :region => @region,
38
+ }
39
+ if @access_key_id && @secret_access_key
40
+ options[:access_key_id] = @access_key_id
41
+ options[:secret_access_key] = @secret_access_key
42
+ end
43
+ @rds = Aws::RDS::Client.new(options)
44
+ rescue => e
45
+ $log.warn "RDS Client error occurred: #{e.message}"
46
+ end
47
+
48
+ @loop = Coolio::Loop.new
49
+ timer_trigger = TimerWatcher.new(@refresh_interval, true, &method(:input))
50
+ timer_trigger.attach(@loop)
51
+ @thread = Thread.new(&method(:run))
52
+ end
53
+
54
+ def shutdown
55
+ super
56
+ @loop.stop
57
+ @thread.join
58
+ end
59
+
60
+ private
61
+
62
+ def run
63
+ @loop.run
64
+ end
65
+
66
+ def input
67
+ get_and_parse_posfile
68
+ log_files = get_logfile_list
69
+ get_logfile(log_files)
70
+ put_posfile
71
+ end
72
+
73
+ def has_iam_role?
74
+ begin
75
+ ec2 = Aws::EC2::Client.new(region: @region)
76
+ !ec2.config.credentials.nil?
77
+ rescue => e
78
+ $log.warn "EC2 Client error occurred: #{e.message}"
79
+ end
80
+ end
81
+
82
+ def get_and_parse_posfile
83
+ begin
84
+ # get & parse pos file
85
+ $log.debug "pos file get start"
86
+
87
+ pos_last_written_timestamp = 0
88
+ pos_info = {}
89
+ File.open(@pos_file, File::RDONLY) do |file|
90
+ file.each_line do |line|
91
+
92
+ pos_match = /^(\d+)$/.match(line)
93
+ if pos_match
94
+ pos_last_written_timestamp = pos_match[1].to_i
95
+ $log.debug "pos_last_written_timestamp: #{pos_last_written_timestamp}"
96
+ end
97
+
98
+ pos_match = /^(.+)\t(.+)$/.match(line)
99
+ if pos_match
100
+ pos_info[pos_match[1]] = pos_match[2]
101
+ $log.debug "log_file: #{pos_match[1]}, marker: #{pos_match[2]}"
102
+ end
103
+ end
104
+ @pos_last_written_timestamp = pos_last_written_timestamp
105
+ @pos_info = pos_info
106
+ end
107
+ rescue => e
108
+ $log.warn "pos file get and parse error occurred: #{e.message}"
109
+ end
110
+ end
111
+
112
+ def put_posfile
113
+ # pos file write
114
+ begin
115
+ $log.debug "pos file write"
116
+ File.open(@pos_file, File::WRONLY|File::TRUNC) do |file|
117
+ file.puts @pos_last_written_timestamp.to_s
118
+
119
+ @pos_info.each do |log_file_name, marker|
120
+ file.puts "#{log_file_name}\t#{marker}"
121
+ end
122
+ end
123
+ rescue => e
124
+ $log.warn "pos file write error occurred: #{e.message}"
125
+ end
126
+ end
127
+
128
+ def get_logfile_list
129
+ begin
130
+ $log.debug "get logfile-list from rds: db_instance_identifier=#{@db_instance_identifier}, pos_last_written_timestamp=#{@pos_last_written_timestamp}"
131
+ @rds.describe_db_log_files(
132
+ db_instance_identifier: @db_instance_identifier,
133
+ file_last_written: @pos_last_written_timestamp,
134
+ max_records: 10,
135
+ )
136
+ rescue => e
137
+ $log.warn "RDS Client describe_db_log_files error occurred: #{e.message}"
138
+ end
139
+ end
140
+
141
+ def get_logfile(log_files)
142
+ begin
143
+ log_files.each do |log_file|
144
+ log_file.describe_db_log_files.each do |item|
145
+ # save maximum written timestamp value
146
+ @pos_last_written_timestamp = item[:last_written] if @pos_last_written_timestamp < item[:last_written]
147
+
148
+ # log file download
149
+ log_file_name = item[:log_file_name]
150
+ marker = @pos_info.has_key?(log_file_name) ? @pos_info[log_file_name] : "0"
151
+
152
+ $log.debug "download log from rds: log_file_name=#{log_file_name}, marker=#{marker}"
153
+ logs = @rds.download_db_log_file_portion(
154
+ db_instance_identifier: @db_instance_identifier,
155
+ log_file_name: log_file_name,
156
+ marker: marker,
157
+ )
158
+ raw_records = get_logdata(logs)
159
+
160
+ #emit
161
+ parse_and_emit(raw_records, log_file_name) unless raw_records.nil?
162
+ end
163
+ end
164
+ rescue => e
165
+ $log.warn e.message
166
+ end
167
+ end
168
+
169
+ def get_logdata(logs)
170
+ log_file_name = logs.context.params[:log_file_name]
171
+ raw_records = []
172
+ begin
173
+ logs.each do |log|
174
+ # save got line's marker
175
+ @pos_info[log_file_name] = log.marker
176
+
177
+ raw_records += log.log_file_data.split("\n")
178
+ end
179
+ rescue => e
180
+ $log.warn e.message
181
+ end
182
+ return raw_records
183
+ end
184
+
185
+ def parse_and_emit(raw_records, log_file_name)
186
+ begin
187
+ $log.debug "raw_records.count: #{raw_records.count}"
188
+ record = nil
189
+ raw_records.each do |raw_record|
190
+ $log.debug "raw_record=#{raw_record}"
191
+ line_match = LOG_REGEXP.match(raw_record)
192
+
193
+ unless line_match
194
+ # combine chain of log
195
+ record["message"] << "\n" + raw_record unless record.nil?
196
+ else
197
+ # emit before record
198
+ Fluent::Engine.emit(@tag, Fluent::Engine.now, record) unless record.nil?
199
+
200
+ # set a record
201
+ record = {
202
+ "time" => line_match[:time],
203
+ "host" => line_match[:host],
204
+ "user" => line_match[:user],
205
+ "database" => line_match[:database],
206
+ "pid" => line_match[:pid],
207
+ "message_level" => line_match[:message_level],
208
+ "message" => line_match[:message],
209
+ "log_file_name" => log_file_name,
210
+ }
211
+
212
+ # Parse duration for slow query
213
+ duration = line_match[:message].match(/duration: ([0-9\.]+) ms/)
214
+ if duration
215
+ record["duration"] = duration[1].to_f
216
+ end
217
+ end
218
+ end
219
+ # emit last record
220
+ Fluent::Engine.emit(@tag, Fluent::Engine.now, record) unless record.nil?
221
+ rescue => e
222
+ $log.warn e.message
223
+ end
224
+ end
225
+
226
+ class TimerWatcher < Coolio::TimerWatcher
227
+ def initialize(interval, repeat, &callback)
228
+ @callback = callback
229
+ on_timer # first call
230
+ super(interval, repeat)
231
+ end
232
+
233
+ def on_timer
234
+ @callback.call
235
+ end
236
+ end
237
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-rds-pgsql-slow-query-log
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - hSATAC
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-10-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fluentd
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: aws-sdk
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.7'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.7'
55
+ description: fluentd plugin for Amazon RDS for PostgreSQL log input with slow query
56
+ support
57
+ email:
58
+ - hSATAC@gmail.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - .gitignore
64
+ - Gemfile
65
+ - LICENSE.txt
66
+ - README.md
67
+ - fluent-plugin-rds-pgsql-slow-query-log.gemspec
68
+ - fluent.conf.sample
69
+ - lib/fluent/plugin/in_rds_pgsql_slow_query_log.rb
70
+ homepage: https://github.com/hSATAC/fluent-plugin-rds-pgsql-log
71
+ licenses:
72
+ - MIT
73
+ metadata: {}
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project:
90
+ rubygems_version: 2.2.2
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: Amazon RDS for PostgreSQL log input plugin with slow query support
94
+ test_files: []