fluent-plugin-mqtt-io 0.0.6 → 0.1.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
  SHA1:
3
- metadata.gz: 9a44345e5a1d555cccb9052cb5026a1d1c74ba99
4
- data.tar.gz: 38f42494ed8fedaf6f183eb0ec424a19b1e5490f
3
+ metadata.gz: d296aa7e9f2bf32ab247b8f99ad7bdaf972cf763
4
+ data.tar.gz: 669477119ff620c36cb45bf2ed63ae2ed238b1d2
5
5
  SHA512:
6
- metadata.gz: 69ae3c6e96f603776b577e139f4375acee20273bb885526def569e50e57977339ba0af0f145fd3dbdd2a9bbfea192dc673f80884468e71cc394041050fb32424
7
- data.tar.gz: 2029b0f4d5cd40210d598ab5131367367c5478fe6a77537fb27357728ec0735b16f89353b7b077766211a615ef98c3608ce4b0ba7017795504d5a68cbfc2818d
6
+ metadata.gz: a105c66f6dd6e4e11a6e7f118c34295590da1c10ec0bd31e6393aafc21cceef2274dc3f2468c1d6a5c6105a4a44e6c53eb79e48d27fde883e866bbebd6e89d7e
7
+ data.tar.gz: 04fd6db671975fb44c8ba536fc10e31c43503d1d20eb0d76bda5a41bfc6a5657dedea25f9489d44495f22f76b5ec4b2158ca9b563c583c9f5b05391691f56fb7
data/README.md CHANGED
@@ -26,6 +26,8 @@ Or install it yourself as:
26
26
 
27
27
  fluent-plugin-mqtt-io provides Input and Output Plugins for MQTT.
28
28
 
29
+ ### Input Plugin (Fluet::MqttInput)
30
+
29
31
  Input Plugin can be used via source directive in the configuration.
30
32
 
31
33
  ```
@@ -44,9 +46,11 @@ The default MQTT topic is "#". Configurable options are the following:
44
46
  - bind: IP address of MQTT broker
45
47
  - port: Port number of MQTT broker
46
48
  - format (mandatory): Input parser can be chosen, e.g. json, xml
47
- - in order to use xml format, you need to install [fluent-plugin-xml-parser](https://github.com/toyokazu/fluent-plugin-xml-parser).
48
- - default time_key field for json format is 'time'
49
+ - In order to use xml format, you need to install [fluent-plugin-xml-parser](https://github.com/toyokazu/fluent-plugin-xml-parser).
50
+ - Default time_key field for json format is 'time'
49
51
  - topic: Topic name to be subscribed
52
+ - bulk_trans: Enable bulk transfer to support buffered output (mqtt_buf, Fluent::MqttBufferedOutput, defaut: true)
53
+ - bulk_trans_sep: A message separator for bulk transfer. The default separator is "\t".
50
54
  - username: User name for authentication
51
55
  - password: Password for authentication
52
56
  - ssl: set true if you want to use SSL/TLS. If set to true, the following parameter must be provided
@@ -56,6 +60,8 @@ The default MQTT topic is "#". Configurable options are the following:
56
60
 
57
61
  Input Plugin supports @label directive.
58
62
 
63
+ ### Output Plugin (Fluent::MqttOutput, Fluent::MqttBufferedOutput)
64
+
59
65
  Output Plugin can be used via match directive.
60
66
 
61
67
  ```
@@ -68,7 +74,7 @@ Output Plugin can be used via match directive.
68
74
 
69
75
  ```
70
76
 
71
- The options are basically the same as Input Plugin. The difference is the following.
77
+ The options are basically the same as Input Plugin except for "format" and "bulk_trans". Additional options for Output Plugin are the following.
72
78
 
73
79
  - time_key: An attribute name used for timestamp field genarated from fluentd time field. Default is nil (omitted).
74
80
  If this option is omitted, timestamp field is not appended to the output record.
@@ -93,7 +99,7 @@ The topic name or tag name, e.g. "topic", received from an event can not be publ
93
99
 
94
100
  ```
95
101
 
96
- You can also use mqtt_buf type which is implemented as BufferedOutput.
102
+ You can also use mqtt_buf type which is implemented as Fluent::MqttBufferedOutput.
97
103
 
98
104
  ```
99
105
 
@@ -110,10 +116,13 @@ You can also use mqtt_buf type which is implemented as BufferedOutput.
110
116
 
111
117
  ```
112
118
 
119
+ When a plugin implemented as Fluent::BufferedOutput, fluentd stores the received messages into buffers (Fluent::MemoryBuffer is used as default) separated by tag names. Writer Threads emit those stored messages periodically in the specified interval. In MqttBufferedOutput, the stored messages are concatenated with 'bulk_trans_sep' (default: "\t"). This function reduces the number of messages sent via MQTT if data producing interval of sensors are smaller than publish interval (flush_interval). The concatinated messages can be properly handled by Fluent::MqttInput plugin by specifying 'bulk_trans' option.
113
120
 
114
121
  ## Use case examples
115
122
 
116
- ### Libelium sensor data collection
123
+ ### Sensor data collection (not for Libelium now)
124
+
125
+ *additional description (2015-12-25)*: Thanks to the updates by Libelium, Meshlium farmware now supports flexible output format configuration including JSON. As a result, data conversion by XmlParser is not required for this use case. The following description is kept just for sharing know-how of data conversion in fluentd.
117
126
 
118
127
  There are many kinds of commercial sensor products on the market, e.g. [Libelium](http://www.libelium.com/). Major sensor products support MQTT to upload sensor data. The following example shows how to store uploaded Libelium sensor data into ElasticSearch.
119
128
 
@@ -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.0.6"
7
+ spec.version = "0.1.0"
8
8
  spec.authors = ["Toyokazu Akiyama"]
9
9
  spec.email = ["toyokazu@gmail.com"]
10
10
 
@@ -6,6 +6,8 @@ module Fluent
6
6
  config_param :bind, :string, :default => '127.0.0.1'
7
7
  config_param :topic, :string, :default => '#'
8
8
  config_param :format, :string, :default => 'json'
9
+ config_param :bulk_trans, :bool, :default => true
10
+ config_param :bulk_trans_sep, :string, :default => "\t"
9
11
  config_param :username, :string, :default => nil
10
12
  config_param :password, :string, :default => nil
11
13
  config_param :ssl, :bool, :default => nil
@@ -24,6 +26,8 @@ module Fluent
24
26
  super
25
27
  @bind ||= conf['bind']
26
28
  @topic ||= conf['topic']
29
+ @bulk_trans ||= conf['bulk_trans']
30
+ @bulk_trans_sep ||= conf['bulk_trans_sep']
27
31
  @port ||= conf['port']
28
32
  @username ||= conf['username']
29
33
  @password ||= conf['password']
@@ -47,27 +51,56 @@ module Fluent
47
51
  opts[:ca_file] = @ca_file if @ca_file
48
52
  opts[:cert_file] = @cert_file if @cert_file
49
53
  opts[:key_file] = @key_file if @key_file
50
- @connect = MQTT::Client.connect(opts)
51
- @connect.subscribe(@topic)
52
54
 
53
- @thread = Thread.new do
54
- @connect.get do |topic,message|
55
- emit topic, message
55
+ # In order to handle Exception raised from reading Thread
56
+ # in MQTT::Client caused by network disconnection (during read_byte),
57
+ # @connect_thread generates connection.
58
+ @client = MQTT::Client.new(opts)
59
+ @connect_thread = Thread.new do
60
+ while (true)
61
+ begin
62
+ @client.disconnect if @client.connected?
63
+ @client.connect
64
+ @client.subscribe(@topic)
65
+ @get_thread.kill if !@get_thread.nil? && @get_thread.alive?
66
+ @get_thread = Thread.new do
67
+ @client.get do |topic, message|
68
+ emit(topic, message)
69
+ end
70
+ end
71
+ sleep
72
+ rescue MQTT::ProtocolException => pe
73
+ $log.debug "Handling #{pe.class}: #{pe.message}"
74
+ next
75
+ rescue Timeout::Error => te
76
+ $log.debug "Handling #{te.class}: #{te.message}"
77
+ next
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ def parse(message)
84
+ @parser.parse(message) do |time, record|
85
+ if time.nil?
86
+ $log.debug "Since time_key field is nil, Fluent::Engine.now is used."
87
+ time = Fluent::Engine.now
56
88
  end
89
+ $log.debug "#{topic}, #{time}, #{record}"
90
+ return [time, record]
57
91
  end
58
92
  end
59
93
 
60
- def emit topic, message
94
+ def emit(topic, message)
61
95
  begin
62
96
  topic.gsub!("/","\.")
63
- @parser.parse(message) {|time, record|
64
- if time.nil?
65
- $log.debug "Since time_key field is nil, Fluent::Engine.now is used."
66
- time = Fluent::Engine.now
97
+ if @bulk_trans
98
+ message.split(@bulk_trans_sep).each do |m|
99
+ router.emit(topic, *parse(m))
67
100
  end
68
- $log.debug "#{topic}, #{time}, #{record}"
69
- router.emit(topic, time, record)
70
- }
101
+ else
102
+ router.emit(topic, *parse(message))
103
+ end
71
104
  rescue Exception => e
72
105
  $log.error :error => e.to_s
73
106
  $log.debug_backtrace(e.backtrace)
@@ -75,8 +108,9 @@ module Fluent
75
108
  end
76
109
 
77
110
  def shutdown
78
- @thread.kill
79
- @connect.disconnect
111
+ @get_thread.kill
112
+ @connect_thread.kill
113
+ @client.disconnect
80
114
  end
81
115
  end
82
116
  end
@@ -12,10 +12,11 @@ module Fluent
12
12
  base.config_param :ca_file, :string, :default => nil
13
13
  base.config_param :key_file, :string, :default => nil
14
14
  base.config_param :cert_file, :string, :default => nil
15
- base.config_param :time_key, :string, :default => nil
15
+ base.config_param :time_key, :string, :default => 'time'
16
16
  base.config_param :time_format, :string, :default => nil
17
17
  base.config_param :topic_rewrite_pattern, :string, :default => nil
18
18
  base.config_param :topic_rewrite_replacement, :string, :default => nil
19
+ base.config_param :bulk_trans_sep, :string, :default => "\t"
19
20
  end
20
21
 
21
22
  require 'mqtt'
@@ -35,6 +36,7 @@ module Fluent
35
36
  @time_format ||= conf['time_format']
36
37
  @topic_rewrite_pattern ||= conf['topic_rewrite_pattern']
37
38
  @topic_rewrite_replacement ||= conf['topic_rewrite_replacement']
39
+ @bulk_trans_sep ||= conf['bulk_trans_sep']
38
40
  end
39
41
 
40
42
  # This method is called when starting.
@@ -53,7 +55,25 @@ module Fluent
53
55
  opts[:ca_file] = @ca_file if @ca_file
54
56
  opts[:cert_file] = @cert_file if @cert_file
55
57
  opts[:key_file] = @key_file if @key_file
56
- @connect = MQTT::Client.connect(opts)
58
+ # In order to handle Exception raised from reading Thread
59
+ # in MQTT::Client caused by network disconnection (during read_byte),
60
+ # @connect_thread generates connection.
61
+ @client = MQTT::Client.new(opts)
62
+ @connect_thread = Thread.new do
63
+ while (true)
64
+ begin
65
+ @client.disconnect if @client.connected?
66
+ @client.connect
67
+ sleep
68
+ rescue MQTT::ProtocolException => pe
69
+ $log.debug "Handling #{pe.class}: #{pe.message}"
70
+ next
71
+ rescue Timeout::Error => te
72
+ $log.debug "Handling #{te.class}: #{te.message}"
73
+ next
74
+ end
75
+ end
76
+ end
57
77
  end
58
78
 
59
79
  # This method is called when shutting down.
@@ -61,13 +81,19 @@ module Fluent
61
81
  def shutdown
62
82
  super
63
83
 
64
- @connect.disconnect
84
+ @client.disconnect
65
85
  end
66
86
 
67
87
  def format_time(time)
68
- if @time_format.nil?
88
+ case @time_format
89
+ when nil then
90
+ # default format is integer value
91
+ time
92
+ when "iso8601" then
93
+ # iso8601 format
69
94
  Time.at(time).iso8601
70
95
  else
96
+ # specified strftime format
71
97
  Time.at(time).strftime(@time_format)
72
98
  end
73
99
  end
@@ -10,7 +10,7 @@ module Fluent
10
10
  def emit(tag, es, chain)
11
11
  es.each {|time,record|
12
12
  $log.debug "#{tag}, #{format_time(time)}, #{record}"
13
- @connect.publish(rewrite_tag(tag), record.merge(timestamp_hash(time)).to_json)
13
+ @client.publish(rewrite_tag(tag), record.merge(timestamp_hash(time)).to_json)
14
14
  }
15
15
  $log.flush
16
16
 
@@ -1,5 +1,5 @@
1
1
  module Fluent
2
- class MqttOutput < BufferedOutput
2
+ class MqttBufferedOutput < BufferedOutput
3
3
  require 'fluent/plugin/mqtt_output_mixin'
4
4
  include Fluent::MqttOutputMixin
5
5
 
@@ -10,7 +10,8 @@ module Fluent
10
10
  # This method is called when an event reaches to Fluentd.
11
11
  # Convert the event to a raw string.
12
12
  def format(tag, time, record)
13
- [tag, time, record].to_json + "\n"
13
+ [tag, time, record].to_msgpack
14
+ #[tag, time, record].to_json + "\n"
14
15
  end
15
16
 
16
17
  # This method is called every flush interval. Write the buffer chunk
@@ -21,10 +22,21 @@ module Fluent
21
22
  #
22
23
  # NOTE! This method is called by internal thread, not Fluentd's main thread. So IO wait doesn't affect other plugins.
23
24
  def write(chunk)
24
- json = json_parse(chunk.read)
25
- $log.debug "#{json[0]}, #{format_time(json[1])}, #{json[2]}"
26
- @connect.publish(rewrite_tag(json[0]), (json[2].merge(timestamp_hash(json[1]))).to_json)
25
+ messages = {}
26
+ chunk.msgpack_each do |tag, time, record|
27
+ #$log.debug "Thread ID: #{Thread.current.object_id}, tag: #{tag}, time: #{format_time(time)}, record: #{record}"
28
+ messages[tag] = [] if messages[tag].nil?
29
+ messages[tag] << record.merge(timestamp_hash(time))
30
+ end
31
+ messages.keys.each do |tag|
32
+ $log.debug "Thread ID: #{Thread.current.object_id}, topic: #{rewrite_tag(tag)}, message: #{messages[tag]}"
33
+ @client.publish(rewrite_tag(tag), messages[tag].map {|m| m.to_json}.join(@bulk_trans_sep))
34
+ end
27
35
  $log.flush
36
+ #json = json_parse(chunk.open {|io| io.readline})
37
+ #$log.debug "#{json[0]}, #{format_time(json[1])}, #{json[2]}"
38
+ #@client.publish(rewrite_tag(json[0]), (json[2].merge(timestamp_hash(json[1]))).to_json)
39
+ #$log.flush
28
40
  end
29
41
  end
30
42
  end
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.0.6
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Toyokazu Akiyama
8
8
  autorequire:
9
9
  bindir: []
10
10
  cert_chain: []
11
- date: 2015-12-24 00:00:00.000000000 Z
11
+ date: 2015-12-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd