fluent-plugin-mqtt-io 0.4.4 → 0.5.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: e083f992d750102e55064612775e4d03b188e50fa1d6f3585837124bd681ea90
4
- data.tar.gz: 5803786735463c1c29f47b608374926fc73106310ce5d8af8594fe909744f7ff
3
+ metadata.gz: ed837b9979b990f051238be99dac2c17ba2feb7b35c0f56910f706c3c426944a
4
+ data.tar.gz: 52628c53314f60215b6b97854103a3e99c0f313fe5a5031b1e6ed87e16cfc918
5
5
  SHA512:
6
- metadata.gz: 6bdb809393dae2de2e85ad36a2f0e745ade9cc12834f136e4081aced2bd56aae14d9ed0e9dbfd307d91f34336b0ec98ae2921cbfee2a3f07599878d120c8f026
7
- data.tar.gz: fa59faf530eb786320f0bf7a6f115b6b4db12e44334aba6bfcac56fa9b2e563d0e1efa499a7302e69a297ef98fc7e1ed3a73cd355a057c9a7b16dcf367b47dd5
6
+ metadata.gz: d2b38c5196fa566997d647fe63d3b2af44b323d218b5ec2c8e613cfa6662bd64401fbc99a68935950ddeb9b1b128f7571357e885276dfae5c6fbaaab62c088e9
7
+ data.tar.gz: 2d96a742d31d3b638f989999ea5c4919c95f61c64156d46d2dc01263842b036cf584bccc596c11634a3b95f358e84c112ce7b4c64b9eafc6fe48c367f0518381
data/README.md CHANGED
@@ -5,7 +5,7 @@ Mqtt::IO Plugin is deeply inspired by Fluent::Plugin::Mqtt.
5
5
 
6
6
  https://github.com/yuuna/fluent-plugin-mqtt
7
7
 
8
- Mqtt::IO plugin focus on federating components, e.g. sensors, messaging platform and databases. Encryption/Decryption is not supported in this plugin but [fluent-plugin-jwt-filter](https://github.com/toyokazu/fluent-plugin-jwt-filter) can be used to encrypt/decrypt messages using JSON Web Token technology.
8
+ Mqtt::IO plugin focus on federating components, e.g. sensors, messaging platform and databases. Connection encryption/decryption (TLS) is supported by ruby-mqtt but end-to-end encryption/decryption is not supported in this plugin. [fluent-plugin-jwt-filter](https://github.com/toyokazu/fluent-plugin-jwt-filter) can be used to encrypt/decrypt messages using JSON Web Token technology.
9
9
 
10
10
  ## Installation
11
11
 
@@ -83,6 +83,7 @@ The default MQTT topic is "#". Configurable options are the following:
83
83
  - **initial_interval**: An initial value of retry interval (s) (default 1)
84
84
  - **retry_inc_ratio**: An increase ratio of retry interval per connection failure (default 2 (double)). It may be better to set the value to 1 in a mobile environment for eager reconnection.
85
85
  - **max_retry_interval**: Maximum value of retry interval (default 300)
86
+ - **max_retry_freq**: Threshold of retry frequency described by a number of retries per minutes. This option is provided for detecting failure via proxy services, e.g. ssh port forwarding. When the thresold is exceeded, MqttProxy::ExceedRetryFrequencyThresholdException is raised and the fluentd will be restarted. So, it is enough to be specified once for a MQTT server at a source/match directive in your configuration (default 10)
86
87
 
87
88
  Input Plugin supports @label directive.
88
89
 
@@ -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-mqtt-io"
7
- spec.version = "0.4.4"
7
+ spec.version = "0.5.0"
8
8
  spec.authors = ["Toyokazu Akiyama"]
9
9
  spec.email = ["toyokazu@gmail.com"]
10
10
 
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
24
24
  spec.add_dependency 'fluentd', [">= 0.14.0", "< 2"]
25
25
  spec.add_dependency "mqtt", "~> 0.5"
26
26
 
27
- spec.add_development_dependency "bundler", "~> 1.14"
28
- spec.add_development_dependency "rake", "~> 12.0"
27
+ spec.add_development_dependency "bundler", [">= 1.14", "< 2.3"]
28
+ spec.add_development_dependency "rake", "~> 13.0"
29
29
  spec.add_development_dependency "test-unit"
30
30
  end
@@ -20,11 +20,6 @@ module Fluent::Plugin
20
20
  config_param :@type, :string, default: 'none'
21
21
  end
22
22
 
23
- # bulk_trans is deprecated
24
- # multiple entries must be inputted as an Array
25
- #config_param :bulk_trans, :bool, default: true
26
- #config_param :bulk_trans_sep, :string, default: "\t"
27
-
28
23
  config_section :monitor, required: false, multi: false do
29
24
  desc 'Record received time into message or not.'
30
25
  config_param :recv_time, :bool, default: false
@@ -66,20 +61,28 @@ module Fluent::Plugin
66
61
  :in_mqtt
67
62
  end
68
63
 
69
- def kill_thread
70
- @get_thread.kill if !@get_thread.nil?
64
+ def exit_thread
65
+ @get_thread.exit if !@get_thread.nil?
66
+ end
67
+
68
+ def disconnect
69
+ begin
70
+ @client.disconnect if @client.connected?
71
+ rescue => e
72
+ log.error "Error in in_mqtt#disconnect,#{e.class},#{e.message}"
73
+ end
74
+ exit_thread
71
75
  end
72
76
 
73
- def after_disconnection
74
- kill_thread
77
+ def terminate
78
+ exit_thread
75
79
  super
76
80
  end
77
81
 
78
82
  def after_connection
79
83
  if @client.connected?
80
84
  @client.subscribe(@topic)
81
- #@get_thread = thread_create(:in_mqtt_get) do
82
- @get_thread = Thread.new do
85
+ @get_thread = thread_create(:in_mqtt_get) do
83
86
  @client.get do |topic, message|
84
87
  emit(topic, message)
85
88
  end
@@ -20,8 +20,10 @@ module Fluent::Plugin
20
20
  base.config_param :initial_interval, :integer, default: 1
21
21
  base.desc 'Specify increasing ratio of connection retry interval.'
22
22
  base.config_param :retry_inc_ratio, :integer, default: 2
23
- base.desc 'Specify maximum connection retry interval.'
23
+ base.desc 'Specify the maximum connection retry interval.'
24
24
  base.config_param :max_retry_interval, :integer, default: 300
25
+ base.desc 'Specify threshold of retry frequency as number of retries per minutes. Frequency is monitored per retry.'
26
+ base.config_param :max_retry_freq, :integer, default: 10
25
27
 
26
28
  base.config_section :security, required: false, multi: false do
27
29
  ### User based authentication
@@ -44,11 +46,20 @@ module Fluent::Plugin
44
46
 
45
47
  class MqttError < StandardError; end
46
48
 
49
+ class ExceedRetryFrequencyThresholdException < StandardError; end
50
+
47
51
  def current_plugin_name
48
52
  # should be implemented
49
53
  end
50
54
 
51
55
  def start_proxy
56
+ # Start a thread from main thread for handling a thread generated
57
+ # by MQTT::Client#get (in_mqtt). Dummy thread is used for out_mqtt
58
+ # to keep the same implementation style.
59
+ @proxy_thread = thread_create("#{current_plugin_name}_proxy".to_sym, &method(:proxy))
60
+ end
61
+
62
+ def proxy
52
63
  log.debug "start mqtt proxy for #{current_plugin_name}"
53
64
  log.debug "start to connect mqtt broker #{@host}:#{@port}"
54
65
  opts = {
@@ -68,12 +79,13 @@ module Fluent::Plugin
68
79
  end
69
80
 
70
81
  init_retry_interval
82
+ @retry_sequence = []
71
83
  @client = MQTT::Client.new(opts)
72
84
  connect
73
85
  end
74
86
 
75
87
  def shutdown_proxy
76
- @client.disconnect
88
+ disconnect
77
89
  end
78
90
 
79
91
  def init_retry_interval
@@ -81,29 +93,43 @@ module Fluent::Plugin
81
93
  end
82
94
 
83
95
  def increment_retry_interval
84
- return @retry_interval if @retry_interval >= @max_retry_interval
96
+ return @max_retry_interval if @retry_interval >= @max_retry_interval
85
97
  @retry_interval = @retry_interval * @retry_inc_ratio
86
98
  end
87
99
 
88
- def retry_connect(e, message)
89
- if !@_retrying
90
- log.error "#{message},#{e.class},#{e.message}"
91
- log.error "Retry in #{@retry_interval} sec"
92
- timer_execute("#{current_plugin_name}_connect".to_sym, @retry_interval, repeat: false, &method(:connect))
93
- @_retrying = true
94
- increment_retry_interval
95
- after_disconnection
96
- @client.disconnect if @client.connected?
100
+ def update_retry_sequence(e)
101
+ @retry_sequence << {time: Time.now, error: "#{e.class}: #{e.message}"}
102
+ # delete old retry records
103
+ while @retry_sequence[0][:time] < Time.now - 60
104
+ @retry_sequence.shift
105
+ end
106
+ end
107
+
108
+ def check_retry_frequency
109
+ return if @retry_sequence.size <= 1
110
+ if @retry_sequence.size > @max_retry_freq
111
+ log.error "Retry frequency threshold is exceeded: #{@retry_sequence}"
112
+ raise ExceedRetryFrequencyThresholdException
97
113
  end
98
114
  end
99
115
 
100
- def kill_connect_thread
101
- @connect_thread.kill if !@connect_thread.nil?
116
+ def retry_connect(e, message)
117
+ log.error "#{message},#{e.class},#{e.message}"
118
+ log.error "Retry in #{@retry_interval} sec"
119
+ update_retry_sequence(e)
120
+ check_retry_frequency
121
+ disconnect
122
+ sleep @retry_interval
123
+ increment_retry_interval
124
+ connect
125
+ # never reach here
102
126
  end
103
127
 
104
- def after_disconnection
128
+ def disconnect
105
129
  # should be implemented
106
- kill_connect_thread
130
+ end
131
+
132
+ def terminate
107
133
  end
108
134
 
109
135
  def rescue_disconnection
@@ -114,22 +140,13 @@ module Fluent::Plugin
114
140
  begin
115
141
  yield
116
142
  rescue MQTT::ProtocolException => e
117
- # TODO:
118
- # Thread created via fluentd thread API, e.g. thread_create,
119
- # cannot catch MQTT::ProtocolException raised from @read_thread
120
- # in ruby-mqtt. So, the current version uses plugin local thread
121
- # @connect_thread to catch it.
122
143
  retry_connect(e, "Protocol error occurs in #{current_plugin_name}.")
123
- raise MqttError, "Protocol error occurs."
124
144
  rescue Timeout::Error => e
125
145
  retry_connect(e, "Timeout error occurs in #{current_plugin_name}.")
126
- raise Timeout::Error, "Timeout error occurs."
127
146
  rescue SystemCallError => e
128
147
  retry_connect(e, "System call error occurs in #{current_plugin_name}.")
129
- raise SystemCallError, "System call error occurs."
130
148
  rescue StandardError=> e
131
149
  retry_connect(e, "The other error occurs in #{current_plugin_name}.")
132
- raise StandardError, "The other error occurs."
133
150
  rescue MQTT::NotConnectedException=> e
134
151
  # Since MQTT::NotConnectedException is raised only on publish,
135
152
  # connection error should be catched before this error.
@@ -137,7 +154,7 @@ module Fluent::Plugin
137
154
  # to prevent waistful increment of retry interval.
138
155
  #log.error "MQTT not connected exception occurs.,#{e.class},#{e.message}"
139
156
  #retry_connect(e, "MQTT not connected exception occurs.")
140
- raise MqttError, "MQTT not connected exception occurs in #{current_plugin_name}."
157
+ #raise MqttError, "MQTT not connected exception occurs in #{current_plugin_name}."
141
158
  end
142
159
  end
143
160
 
@@ -148,16 +165,12 @@ module Fluent::Plugin
148
165
  end
149
166
 
150
167
  def connect
151
- #@connect_thread = thread_create("#{current_plugin_name}_monitor".to_sym) do
152
- @_retrying = false
153
- @connect_thread = Thread.new do
154
- rescue_disconnection do
155
- @client.connect
156
- log.debug "connected to mqtt broker #{@host}:#{@port} for #{current_plugin_name}"
157
- init_retry_interval
158
- thread = after_connection
159
- thread.join
160
- end
168
+ rescue_disconnection do
169
+ @client.connect
170
+ log.debug "connected to mqtt broker #{@host}:#{@port} for #{current_plugin_name}"
171
+ init_retry_interval
172
+ thread = after_connection
173
+ thread.join
161
174
  end
162
175
  end
163
176
  end
@@ -89,27 +89,35 @@ module Fluent::Plugin
89
89
  # Shutdown the thread and close sockets or files here.
90
90
  def shutdown
91
91
  shutdown_proxy
92
- kill_thread
92
+ exit_thread
93
93
  super
94
94
  end
95
95
 
96
- def kill_thread
97
- @dummy_thread.kill if !@dummy_thread.nil?
96
+ def exit_thread
97
+ @dummy_thread.exit if !@dummy_thread.nil?
98
98
  end
99
99
 
100
- def after_connection
101
- #@dummy_thread = thread_create(:out_mqtt_dummy) do
102
- @dummy_thread = Thread.new do
103
- Thread.stop
100
+ def disconnect
101
+ begin
102
+ @client.disconnect if @client.connected?
103
+ rescue => e
104
+ log.error "Error in out_mqtt#disconnect,#{e.class},#{e.message}"
104
105
  end
105
- @dummy_thread
106
+ exit_thread
106
107
  end
107
108
 
108
- def after_disconnection
109
- kill_thread
109
+ def terminate
110
+ exit_thread
110
111
  super
111
112
  end
112
113
 
114
+ def after_connection
115
+ @dummy_thread = thread_create(:out_mqtt_dummy) do
116
+ Thread.stop
117
+ end
118
+ @dummy_thread
119
+ end
120
+
113
121
  def current_plugin_name
114
122
  :out_mqtt
115
123
  end
@@ -148,7 +156,7 @@ module Fluent::Plugin
148
156
  end
149
157
 
150
158
  def publish(tag, time, record)
151
- log.debug "MqttOutput::#{caller_locations(1,1)[0].label}: #{rewrite_tag(rewrite_tag(tag))}, #{time}, #{add_send_time(record)}"
159
+ log.debug "MqttOutput::#{caller_locations(1,1)[0].label}: #{rewrite_tag(tag)}, #{time}, #{add_send_time(record)}"
152
160
  @client.publish(
153
161
  rewrite_tag(tag),
154
162
  @formatter.format(tag, time, add_send_time(record)),
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-mqtt-io
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.4
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Toyokazu Akiyama
8
8
  autorequire:
9
9
  bindir: []
10
10
  cert_chain: []
11
- date: 2019-12-19 00:00:00.000000000 Z
11
+ date: 2020-12-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd
@@ -48,30 +48,36 @@ dependencies:
48
48
  name: bundler
49
49
  requirement: !ruby/object:Gem::Requirement
50
50
  requirements:
51
- - - "~>"
51
+ - - ">="
52
52
  - !ruby/object:Gem::Version
53
53
  version: '1.14'
54
+ - - "<"
55
+ - !ruby/object:Gem::Version
56
+ version: '2.3'
54
57
  type: :development
55
58
  prerelease: false
56
59
  version_requirements: !ruby/object:Gem::Requirement
57
60
  requirements:
58
- - - "~>"
61
+ - - ">="
59
62
  - !ruby/object:Gem::Version
60
63
  version: '1.14'
64
+ - - "<"
65
+ - !ruby/object:Gem::Version
66
+ version: '2.3'
61
67
  - !ruby/object:Gem::Dependency
62
68
  name: rake
63
69
  requirement: !ruby/object:Gem::Requirement
64
70
  requirements:
65
71
  - - "~>"
66
72
  - !ruby/object:Gem::Version
67
- version: '12.0'
73
+ version: '13.0'
68
74
  type: :development
69
75
  prerelease: false
70
76
  version_requirements: !ruby/object:Gem::Requirement
71
77
  requirements:
72
78
  - - "~>"
73
79
  - !ruby/object:Gem::Version
74
- version: '12.0'
80
+ version: '13.0'
75
81
  - !ruby/object:Gem::Dependency
76
82
  name: test-unit
77
83
  requirement: !ruby/object:Gem::Requirement
@@ -127,7 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
127
133
  - !ruby/object:Gem::Version
128
134
  version: '0'
129
135
  requirements: []
130
- rubygems_version: 3.0.3
136
+ rubygems_version: 3.1.4
131
137
  signing_key:
132
138
  specification_version: 4
133
139
  summary: fluentd input/output plugin for mqtt broker