fluent-plugin-websocket 0.1.2

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.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fluent-plugin-websocket.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2013 IZAWA Tetsu (@moccos)
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,79 @@
1
+ # Fluent::Plugin::Websocket
2
+
3
+ Fluentd websocket output plugin.
4
+
5
+ ## Installation
6
+
7
+ Copy __out_websocket.rb__ into your fluentd plugin directory.
8
+
9
+ Default plugin directory is _/etc/fluent/plugin_. You can specify additional location by _-p_ option. (Please see _fluentd -h_)
10
+
11
+ This plugin depends on [__em-websocket__](https://github.com/igrigorik/em-websocket) module. You can install it by _gem install em-websocket_.
12
+
13
+
14
+ ## Configuration
15
+ <match foo.**>
16
+ type websocket
17
+ host 192.168.1.1 # default: 0.0.0.0 (ANY)
18
+ port 8080 # default: 8080
19
+ use_msgpack false # default: false
20
+ add_time false # default: false
21
+ add_tag true # default: true
22
+ </match>
23
+
24
+ - __host__: WebSocket server IP address.
25
+ - __port__: WebSocket server port.
26
+ - __use\_msgpack__: Send [MessagePack](http://msgpack.org/) format binary. Otherwise, you send JSON format text.
27
+ - __add\_time__: Add timestamp to the data.
28
+ - __add\_tag__: Add fluentd tag to the data.
29
+
30
+ If there are no websocket connections, this plugin silently discards data. You may use _out\_copy_ plugin like this:
31
+
32
+ <match foo.**>
33
+ type copy
34
+ <store>
35
+ type file
36
+ path /var/log/foo/bar.log
37
+ </store>
38
+ <store>
39
+ type websocket
40
+ port 8080
41
+ </store>
42
+ </match>
43
+
44
+ ## Data format
45
+ [tag, timestamp, data_object]
46
+
47
+ - tag is appended when _add\_tag_ option is true.
48
+ - timespamp is appended when _add\_time_ option is true.
49
+
50
+ ### Example
51
+ curl -X POST -d 'json={"action":"login","user":6}' http://localhost:8888/foo/bar
52
+
53
+ ["foo.bar",1364699026,{"action":"login","user":6}]
54
+
55
+ ## Client sample
56
+ ### JSON format (use_msgpack: false)
57
+ function onMessage(evt) {
58
+ data = JSON.parse(evt.data);
59
+ ...
60
+ }
61
+
62
+ ### Msgpack format binary (use_msgpack: true)
63
+ Extract data by [msgpack.js](https://github.com/msgpack/msgpack-javascript).
64
+
65
+ websocket.binaryType = "arraybuffer"
66
+ ...
67
+ function onMessage(evt) {
68
+ data = msgpack.unpack(new Uint8Array(evt.data))
69
+ ...
70
+ }
71
+
72
+ ## Contributing
73
+
74
+ 1. Fork it
75
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
76
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
77
+ 4. Push to the branch (`git push origin my-new-feature`)
78
+ 5. Create new Pull Request
79
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ #env rake
2
+ require 'bundler/gem_tasks'
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << "test"
7
+ t.test_files = FileList['test/plugin/test*.rb']
8
+ t.verbose = true
9
+ end
10
+ task :default => :test
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.name = "fluent-plugin-websocket"
6
+ gem.version = "0.1.2"
7
+ gem.authors = ["IZAWA Tetsu (@moccos)"]
8
+ gem.email = ["tt.izawa@gmail.com"]
9
+ gem.homepage = "https://github.com/moccos/fluent-plugin-websocket"
10
+ gem.summary = %q{Fluentd websocket output plugin}
11
+ gem.description = %q{Fluentd websocket output plugin}
12
+ gem.required_ruby_version = ">= 1.9.2"
13
+
14
+ gem.files = `git ls-files`.split($/)
15
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
16
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
17
+ gem.require_paths = ["lib"]
18
+
19
+ gem.add_development_dependency "rake"
20
+ gem.add_development_dependency "fluentd"
21
+ gem.add_development_dependency "websocket-ocket-eventmachine-client"
22
+ gem.add_development_dependency "msgpack"
23
+ gem.add_runtime_dependency "fluentd"
24
+ gem.add_runtime_dependency "em-websocket"
25
+ end
@@ -0,0 +1,82 @@
1
+ # Copyright (C) 2013 IZAWA Tetsu (@moccos)
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'em-websocket'
16
+ require 'thread'
17
+
18
+ module Fluent
19
+ $lock = Mutex::new
20
+ $channel = EM::Channel.new
21
+
22
+ class WebSocketOutput < Fluent::Output
23
+ Fluent::Plugin.register_output('websocket', self)
24
+ config_param :use_msgpack, :bool, :default => false
25
+ config_param :host, :string, :default => "0.0.0.0"
26
+ config_param :port, :integer, :default => 8080
27
+ config_param :add_time, :bool, :default => false
28
+ config_param :add_tag, :bool, :default => true
29
+
30
+ def configure(conf)
31
+ super
32
+ $thread = Thread.new do
33
+ $log.trace "Started em-websocket thread."
34
+ $log.info "WebSocket server #{@host}:#{@port} [msgpack: #{@use_msgpack}]"
35
+ EM.run {
36
+ EM::WebSocket.run(:host => @host, :port => @port) do |ws|
37
+ ws.onopen { |handshake|
38
+ callback = @use_msgpack ? proc{|msg| ws.send_binary(msg)} : proc{|msg| ws.send(msg)}
39
+ $lock.synchronize do
40
+ sid = $channel.subscribe callback
41
+ $log.trace "WebSocket connection: ID " + sid.to_s
42
+ ws.onclose {
43
+ $log.trace "Connection closed: ID " + sid.to_s
44
+ $lock.synchronize do
45
+ $channel.unsubscribe(sid)
46
+ end
47
+ }
48
+ end
49
+
50
+ #ws.onmessage { |msg|
51
+ #}
52
+ }
53
+ end
54
+ }
55
+ end
56
+ end
57
+
58
+ def start
59
+ super
60
+ end
61
+
62
+ def shutdown
63
+ super
64
+ EM.stop
65
+ Thread::kill($thread)
66
+ $log.trace "Killed em-websocket thread."
67
+ end
68
+
69
+ def emit(tag, es, chain)
70
+ chain.next
71
+ es.each {|time,record|
72
+ data = [record]
73
+ if (@add_time) then data.unshift(time) end
74
+ if (@add_tag) then data.unshift(tag) end
75
+ output = @use_msgpack ? data.to_msgpack : data.to_json
76
+ $lock.synchronize do
77
+ $channel.push output
78
+ end
79
+ }
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,76 @@
1
+ require 'json'
2
+ require 'msgpack'
3
+ require 'fluent/test'
4
+ require 'fluent/plugin/out_websocket'
5
+ require 'websocket-eventmachine-client'
6
+
7
+ class WebSocketForTest
8
+ def initialize(key, n)
9
+ @n_received = 0
10
+ @v_received = []
11
+
12
+ @ws = WebSocket::EventMachine::Client.connect(:uri => 'ws://localhost:8080')
13
+ @ws.onmessage do |msg, type|
14
+ #puts "Received message: #{msg.to_s} / #{type.to_s}"
15
+ data = type == :text ? JSON.parse(msg): MessagePack.unpack(msg)
16
+ @v_received.push(data[0][key])
17
+ @n_received += 1
18
+ if (n == @n_received)
19
+ @ws.close()
20
+ end
21
+ end
22
+ end
23
+
24
+ attr_reader :n_received, :v_received
25
+ end
26
+
27
+ class WebSocketOutputTest < Test::Unit::TestCase
28
+ def setup
29
+ Fluent::Test.setup
30
+ v_str = "sekaiichi kawaiiyo"
31
+ v_int = -1234567
32
+ v_double = -123.4567
33
+ @key = "key"
34
+ @values = [v_str, v_int, v_double]
35
+ end
36
+
37
+ CONFIG = %[
38
+ ]
39
+
40
+ def create_driver(conf = CONFIG)
41
+ Fluent::Test::OutputTestDriver.new(Fluent::WebSocketOutput).configure(conf)
42
+ end
43
+
44
+ def impl_test(d)
45
+ sleep(0.2)
46
+ ws = WebSocketForTest.new(@key, @values.length)
47
+ sleep(0.2)
48
+ for v in @values
49
+ d.emit({@key => v}, 0)
50
+ end
51
+ sleep(0.5)
52
+ assert_equal(@values.length, ws.n_received)
53
+ result = ws.v_received
54
+ for i in 0 .. @values.length
55
+ assert_equal(@values[i], result[i])
56
+ end
57
+ end
58
+
59
+ # TODO: How to test another configuration?
60
+ #def test_json_out
61
+ #d = create_driver %[
62
+ #use_msgpack false
63
+ #add_tag false
64
+ #]
65
+ #impl_test(d)
66
+ #end
67
+
68
+ def test_msgpack_out
69
+ d = create_driver %[
70
+ use_msgpack true
71
+ add_tag false
72
+ ]
73
+ impl_test(d)
74
+ end
75
+
76
+ end
metadata ADDED
@@ -0,0 +1,150 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-websocket
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - IZAWA Tetsu (@moccos)
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-04-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: fluentd
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: websocket-ocket-eventmachine-client
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: msgpack
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: fluentd
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: em-websocket
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description: Fluentd websocket output plugin
111
+ email:
112
+ - tt.izawa@gmail.com
113
+ executables: []
114
+ extensions: []
115
+ extra_rdoc_files: []
116
+ files:
117
+ - .gitignore
118
+ - Gemfile
119
+ - LICENSE.txt
120
+ - README.md
121
+ - Rakefile
122
+ - fluent-plugin-websocket.gemspec
123
+ - lib/fluent/plugin/out_websocket.rb
124
+ - test/plugin/test_out_websocket.rb
125
+ homepage: https://github.com/moccos/fluent-plugin-websocket
126
+ licenses: []
127
+ post_install_message:
128
+ rdoc_options: []
129
+ require_paths:
130
+ - lib
131
+ required_ruby_version: !ruby/object:Gem::Requirement
132
+ none: false
133
+ requirements:
134
+ - - ! '>='
135
+ - !ruby/object:Gem::Version
136
+ version: 1.9.2
137
+ required_rubygems_version: !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ! '>='
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ requirements: []
144
+ rubyforge_project:
145
+ rubygems_version: 1.8.25
146
+ signing_key:
147
+ specification_version: 3
148
+ summary: Fluentd websocket output plugin
149
+ test_files:
150
+ - test/plugin/test_out_websocket.rb