fluent-plugin-irc 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: af5ed88db24d18583875f6882b7b9d4ef794a944
4
+ data.tar.gz: 0384195c283d6d18d4a62534b3ea9909134351f5
5
+ SHA512:
6
+ metadata.gz: ec009deb6f1f6b60c253a200803442a109d0f59f8b415528471e984676681250c4d529b70ff91f868211347f24181e5de7c1a463a46331eec8c454160919fac6
7
+ data.tar.gz: 4150d2d06239c7aa689c438d78b89f3e0f0430d3e77f8e25d9b9a50c43dba0649386adb1c038094493bd079e3ab4871cc0f26a48de783e48a981d12bfb54f1a1
data/.travis.yml ADDED
@@ -0,0 +1,16 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 2.2
5
+
6
+ os:
7
+ - linux
8
+
9
+ branches:
10
+ only:
11
+ - master
12
+
13
+ gemfile:
14
+ - Gemfile
15
+
16
+ script: bundle exec rake
data/README.md CHANGED
@@ -1,4 +1,6 @@
1
- # Fluent::Plugin::Irc
1
+ # Fluent::Plugin::Irc, a plugin for [Fluentd](http://fluentd.org)
2
+
3
+ [![Build Status](https://travis-ci.org/choplin/fluent-plugin-irc.svg)](https://travis-ci.org/choplin/fluent-plugin-irc)
2
4
 
3
5
  Fluent plugin to send messages to IRC server
4
6
 
@@ -42,10 +44,12 @@ Fluent plugin to send messages to IRC server
42
44
  |time_key|key name for time|time|
43
45
  |time_format|time format. This will be formatted with Time#strftime.|%Y/%m/%d %H:%M:%S|
44
46
  |tag_key|key name for tag|tag|
47
+ |command|irc command. `priv_msg` or `notice`|priv_msg|
48
+ |channel_keys|keys used to format channel. %s will be replaced with value specified by channel_keys if this option is used|nil|
45
49
 
46
50
  ## Copyright
47
51
 
48
52
  <table>
49
- <tr><td>Copyright</td><td>Copyright (c) 2013 OKUNO Akihiro</td></tr>
53
+ <tr><td>Copyright</td><td>Copyright (c) 2015 OKUNO Akihiro</td></tr>
50
54
  <tr><td>License</td><td>Apache License, Version 2.0</td></tr>
51
55
  </table>
data/example.conf CHANGED
@@ -16,4 +16,5 @@
16
16
  time_key time
17
17
  time_format %Y/%m/%d %H:%M:%S
18
18
  tag_key tag
19
+ command priv_msg
19
20
  </match>
@@ -3,12 +3,13 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "fluent-plugin-irc"
6
- s.version = "0.0.5"
6
+ s.version = "0.0.6"
7
7
  s.authors = ["OKUNO Akihiro"]
8
8
  s.email = ["choplin.choplin@gmail.com"]
9
9
  s.homepage = "https://github.com/choplin/fluent-plugin-irc"
10
10
  s.summary = %q{Output plugin for IRC}
11
11
  s.description = %q{Output plugin for IRC}
12
+ s.license = "Apache-2.0"
12
13
 
13
14
  s.rubyforge_project = "fluent-plugin-irc"
14
15
 
@@ -19,4 +20,7 @@ Gem::Specification.new do |s|
19
20
 
20
21
  s.add_runtime_dependency "fluentd"
21
22
  s.add_runtime_dependency "irc_parser"
23
+
24
+ s.add_development_dependency "test-unit"
25
+ s.add_development_dependency "rake"
22
26
  end
@@ -11,6 +11,9 @@ module Fluent
11
11
  config_param :host , :string , :default => 'localhost'
12
12
  config_param :port , :integer , :default => 6667
13
13
  config_param :channel , :string
14
+ config_param :channel_keys, :default => nil do |val|
15
+ val.split(',')
16
+ end
14
17
  config_param :nick , :string , :default => 'fluentd'
15
18
  config_param :user , :string , :default => 'fluentd'
16
19
  config_param :real , :string , :default => 'fluentd'
@@ -22,7 +25,16 @@ module Fluent
22
25
  config_param :time_key , :string , :default => 'time'
23
26
  config_param :time_format , :string , :default => '%Y/%m/%d %H:%M:%S'
24
27
  config_param :tag_key , :string , :default => 'tag'
28
+ config_param :command , :string , :default => 'priv_msg'
29
+
30
+ config_param :blocking_timeout, :time, :default => 0.5
25
31
 
32
+ COMMAND_LIST = %w[priv_msg notice]
33
+
34
+ # To support log_level option implemented by Fluentd v0.10.43
35
+ unless method_defined?(:log)
36
+ define_method("log") { $log }
37
+ end
26
38
 
27
39
  def initialize
28
40
  super
@@ -31,40 +43,67 @@ module Fluent
31
43
 
32
44
  def configure(conf)
33
45
  super
46
+
34
47
  begin
35
48
  @message % (['1'] * @out_keys.length)
36
49
  rescue ArgumentError
37
50
  raise Fluent::ConfigError, "string specifier '%s' and out_keys specification mismatch"
38
51
  end
52
+
53
+ if @channel_keys
54
+ begin
55
+ @channel % (['1'] * @channel_keys.length)
56
+ rescue ArgumentError
57
+ raise Fluent::ConfigError, "string specifier '%s' and channel_keys specification mismatch"
58
+ end
59
+ end
60
+ @channel = '#'+@channel
61
+
62
+ unless COMMAND_LIST.include?(@command)
63
+ raise Fluent::ConfigError, "command must be one of #{COMMAND_LIST.join(', ')}"
64
+ end
65
+
39
66
  end
40
67
 
41
68
  def start
42
69
  super
43
70
 
44
71
  begin
45
- @loop = Coolio::Loop.default
72
+ @loop = Coolio::Loop.new
46
73
  @conn = create_connection
47
- rescue
48
- raise Fluent::ConfigError, "failto connect IRC server #{@host}:#{@port}"
74
+ @thread = Thread.new(&method(:run))
75
+ rescue => e
76
+ puts e
77
+ raise Fluent::ConfigError, "failed to connect IRC server #{@host}:#{@port}"
49
78
  end
50
79
  end
51
80
 
52
81
  def shutdown
53
82
  super
54
- @conn.close unless @conn.closed?
83
+ @loop.watchers.each { |w| w.detach }
84
+ @loop.stop
85
+ @conn.close
86
+ @thread.join
87
+ end
88
+
89
+ def run
90
+ @loop.run(@blocking_timeout)
91
+ rescue => e
92
+ log.error "unexpected error", :error => e, :error_class => e.class
93
+ log.error_backtrace
55
94
  end
56
95
 
57
96
  def emit(tag, es, chain)
58
97
  chain.next
59
98
 
60
99
  if @conn.closed?
61
- $log.warn "out_irc: connection is closed. try to reconnect"
100
+ log.warn "out_irc: connection is closed. try to reconnect"
62
101
  @conn = create_connection
63
102
  end
64
103
 
65
104
  es.each do |time,record|
66
105
  filter_record(tag, time, record)
67
- @conn.send_message(build_message(record))
106
+ @conn.send_message(build_message(record), build_channel(record))
68
107
  end
69
108
  end
70
109
 
@@ -72,6 +111,7 @@ module Fluent
72
111
 
73
112
  def create_connection
74
113
  conn = IRCConnection.connect(@host, @port)
114
+ conn.command = @command
75
115
  conn.channel = '#'+@channel
76
116
  conn.nick = @nick
77
117
  conn.user = @user
@@ -86,7 +126,7 @@ module Fluent
86
126
  begin
87
127
  record.fetch(key).to_s
88
128
  rescue KeyError
89
- $log.warn "out_irc: the specified key '#{key}' not found in record. [#{record}]"
129
+ log.warn "out_irc: the specified key '#{key}' not found in record. [#{record}]"
90
130
  ''
91
131
  end
92
132
  end
@@ -94,8 +134,28 @@ module Fluent
94
134
  @message % values
95
135
  end
96
136
 
137
+ def build_channel(record)
138
+ return @channel unless @channel_keys
139
+
140
+ values = @channel_keys.map do |key|
141
+ begin
142
+ record.fetch(key).to_s
143
+ rescue KeyError
144
+ $log.warn "out_irc: the specified key '#{key}' not found in record. [#{record}]"
145
+ ''
146
+ end
147
+ end
148
+
149
+ @channel % values
150
+ end
151
+
97
152
  class IRCConnection < Cool.io::TCPSocket
98
- attr_accessor :channel, :nick, :user, :real, :password
153
+ attr_accessor :command, :channel, :nick, :user, :real, :password
154
+
155
+ def initialize(*args)
156
+ super
157
+ @joined = {}
158
+ end
99
159
 
100
160
  def on_connect
101
161
  if @password
@@ -120,11 +180,6 @@ module Fluent
120
180
  begin
121
181
  msg = IRCParser.parse(line)
122
182
  case msg.class.to_sym
123
- when :rpl_welcome
124
- IRCParser.message(:join) do |m|
125
- m.channels = @channel
126
- write m
127
- end
128
183
  when :ping
129
184
  IRCParser.message(:pong) do |m|
130
185
  m.target = msg.target
@@ -132,7 +187,7 @@ module Fluent
132
187
  write m
133
188
  end
134
189
  when :error
135
- $log.warn "out_irc: an error occured. \"#{msg.error_message}\""
190
+ log.warn "out_irc: an error occured. \"#{msg.error_message}\""
136
191
  end
137
192
  rescue
138
193
  #TODO
@@ -140,9 +195,22 @@ module Fluent
140
195
  end
141
196
  end
142
197
 
143
- def send_message(msg)
144
- IRCParser.message(:priv_msg) do |m|
145
- m.target = @channel
198
+ def joined?(channel)
199
+ @joined[channel]
200
+ end
201
+
202
+ def join(channel)
203
+ IRCParser.message(:join) do |m|
204
+ m.channels = channel
205
+ write m
206
+ end
207
+ @joined[channel] = true
208
+ end
209
+
210
+ def send_message(msg, channel)
211
+ join(channel) unless joined?(channel)
212
+ IRCParser.message(@command) do |m|
213
+ m.target = channel
146
214
  m.body = msg
147
215
  write m
148
216
  end
@@ -1,46 +1,164 @@
1
1
  require 'helper'
2
+ require 'socket'
2
3
 
3
4
  class IRCOutputTest < Test::Unit::TestCase
5
+ TAG = "test"
6
+ PORT = 6667
7
+ CHANNEL = "fluentd"
8
+ NICK = "fluentd"
9
+ USER = "fluentd"
10
+ REAL = "fluentd"
11
+ COMMAND = :notice
12
+ MESSAGE = "notice: %s [%s] %s"
13
+ TIME_FORMAT = "%Y/%m/%d %H:%M:%S"
14
+
4
15
  def setup
5
16
  Fluent::Test.setup
17
+ Fluent::Engine.now = Time.now
18
+ end
19
+
20
+ def config(
21
+ port: PORT,
22
+ channel: CHANNEL,
23
+ channel_keys: ""
24
+ )
25
+ %[
26
+ type irc
27
+ host localhost
28
+ port #{port}
29
+ channel #{channel}
30
+ channel_keys #{channel_keys}
31
+ nick #{NICK}
32
+ user #{USER}
33
+ real #{REAL}
34
+ command #{COMMAND.to_s}
35
+ message #{MESSAGE}
36
+ out_keys tag,time,msg
37
+ time_key time
38
+ time_format #{TIME_FORMAT}
39
+ tag_key tag
40
+ ]
6
41
  end
7
42
 
8
- CONFIG = %[
9
- type irc
10
- host localhost
11
- port 6667
12
- channel fluentd
13
- nick fluentd
14
- user fluentd
15
- real fluentd
16
- message notice: %s [%s] %s
17
- out_keys tag,time,msg
18
- time_key time
19
- time_format %Y/%m/%d %H:%M:%S
20
- tag_key tag
21
- ]
22
43
 
23
- def create_driver(conf = CONFIG)
24
- Fluent::Test::OutputTestDriver.new(Fluent::IRCOutput).configure(conf)
44
+ def create_driver(conf = config)
45
+ Fluent::Test::OutputTestDriver.new(Fluent::IRCOutput, TAG).configure(conf)
25
46
  end
26
47
 
27
48
  def test_configure
28
49
  d = create_driver
29
50
 
30
51
  assert_equal "localhost", d.instance.host
31
- assert_equal 6667, d.instance.port
32
- assert_equal "fluentd", d.instance.channel
33
- assert_equal "fluentd", d.instance.nick
34
- assert_equal "fluentd", d.instance.user
35
- assert_equal "fluentd", d.instance.real
36
- assert_equal "notice: %s [%s] %s", d.instance.message
52
+ assert_equal PORT, d.instance.port
53
+ assert_equal "##{CHANNEL}", d.instance.channel
54
+ assert_equal NICK, d.instance.nick
55
+ assert_equal USER, d.instance.user
56
+ assert_equal REAL, d.instance.real
57
+ assert_equal COMMAND.to_s, d.instance.command
58
+ assert_equal MESSAGE, d.instance.message
37
59
  assert_equal ["tag","time","msg"], d.instance.out_keys
38
60
  assert_equal "time", d.instance.time_key
39
- assert_equal "%Y/%m/%d %H:%M:%S", d.instance.time_format
61
+ assert_equal TIME_FORMAT, d.instance.time_format
40
62
  assert_equal "tag", d.instance.tag_key
41
63
  end
42
64
 
43
- #def test_emit
44
- #TODO
45
- #end
65
+ def test_configure_channel_keys
66
+ d = create_driver(config(channel:"%s", channel_keys:"channel"))
67
+ assert_equal "#%s", d.instance.channel
68
+ assert_equal ["channel"], d.instance.channel_keys
69
+ end
70
+
71
+ def test_emit
72
+ msg = "test"
73
+ msgs = [{"msg" => msg}]
74
+ body = MESSAGE % [TAG, Time.at(Fluent::Engine.now).utc.strftime(TIME_FORMAT), msg]
75
+
76
+ emit_test(msgs) do |socket|
77
+ m = IRCParser.parse(socket.gets)
78
+ assert_equal m.class.to_sym, :nick
79
+ assert_equal m.nick, NICK
80
+
81
+ m = IRCParser.parse(socket.gets)
82
+ assert_equal m.class.to_sym, :user
83
+ assert_equal m.user, USER
84
+ assert_equal m.postfix, REAL
85
+
86
+ m = IRCParser.parse(socket.gets)
87
+ assert_equal m.class.to_sym, :join
88
+ assert_equal m.channels, ["##{CHANNEL}"]
89
+
90
+ m = IRCParser.parse(socket.gets)
91
+ assert_equal m.class.to_sym, COMMAND
92
+ assert_equal m.target, "##{CHANNEL}"
93
+ assert_equal m.body, body
94
+
95
+ assert_nil socket.gets # expects EOF
96
+ end
97
+ end
98
+
99
+ def test_dynamic_channel
100
+ msgs = [
101
+ {"msg" => "test", "channel" => "chan1"},
102
+ {"msg" => "test", "channel" => "chan2"},
103
+ {"msg" => "test", "channel" => "chan1"},
104
+ ]
105
+
106
+ extra_config = {
107
+ channel: "%s",
108
+ channel_keys: "channel",
109
+ }
110
+
111
+ emit_test(msgs, extra_config: extra_config) do |socket|
112
+ socket.gets # ignore NICK
113
+ socket.gets # ignore USER
114
+
115
+ m = IRCParser.parse(socket.gets)
116
+ assert_equal m.class.to_sym, :join
117
+ assert_equal m.channels, ["#chan1"]
118
+
119
+ m = IRCParser.parse(socket.gets)
120
+ assert_equal m.class.to_sym, COMMAND
121
+ assert_equal m.target, "#chan1"
122
+
123
+ m = IRCParser.parse(socket.gets)
124
+ assert_equal m.class.to_sym, :join
125
+ assert_equal m.channels, ["#chan2"]
126
+
127
+ m = IRCParser.parse(socket.gets)
128
+ assert_equal m.class.to_sym, COMMAND
129
+ assert_equal m.target, "#chan2"
130
+
131
+ m = IRCParser.parse(socket.gets)
132
+ assert_equal m.class.to_sym, COMMAND
133
+ assert_equal m.target, "#chan1"
134
+
135
+ assert_nil socket.gets # expects EOF
136
+ end
137
+ end
138
+
139
+ private
140
+
141
+ def emit_test(msgs, extra_config: {}, &block)
142
+ TCPServer.open(0) do |serv|
143
+ port = serv.addr[1]
144
+ d = create_driver(config({port: port}.merge(extra_config)))
145
+
146
+ thread = Thread.new do
147
+ s = serv.accept
148
+ block.call(s)
149
+ s.close
150
+ end
151
+
152
+ d.run do
153
+ msgs.each do |m|
154
+ d.emit(m, Fluent::Engine.now)
155
+ end
156
+ # How to remove sleep?
157
+ # It is necessary to ensure that no data remains in Cool.io write buffer before detach.
158
+ sleep 1
159
+ end
160
+
161
+ thread.join
162
+ end
163
+ end
46
164
  end
metadata CHANGED
@@ -1,46 +1,69 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-irc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
5
- prerelease:
4
+ version: 0.0.6
6
5
  platform: ruby
7
6
  authors:
8
7
  - OKUNO Akihiro
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-08-22 00:00:00.000000000 Z
11
+ date: 2015-03-18 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: fluentd
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - ">="
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: irc_parser
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - ">="
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: test-unit
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
44
67
  - !ruby/object:Gem::Version
45
68
  version: '0'
46
69
  description: Output plugin for IRC
@@ -50,7 +73,8 @@ executables: []
50
73
  extensions: []
51
74
  extra_rdoc_files: []
52
75
  files:
53
- - .gitignore
76
+ - ".gitignore"
77
+ - ".travis.yml"
54
78
  - Gemfile
55
79
  - LICENSE
56
80
  - README.md
@@ -61,30 +85,29 @@ files:
61
85
  - test/helper.rb
62
86
  - test/plugin/test_out_irc.rb
63
87
  homepage: https://github.com/choplin/fluent-plugin-irc
64
- licenses: []
88
+ licenses:
89
+ - Apache-2.0
90
+ metadata: {}
65
91
  post_install_message:
66
92
  rdoc_options: []
67
93
  require_paths:
68
94
  - lib
69
95
  required_ruby_version: !ruby/object:Gem::Requirement
70
- none: false
71
96
  requirements:
72
- - - ! '>='
97
+ - - ">="
73
98
  - !ruby/object:Gem::Version
74
99
  version: '0'
75
100
  required_rubygems_version: !ruby/object:Gem::Requirement
76
- none: false
77
101
  requirements:
78
- - - ! '>='
102
+ - - ">="
79
103
  - !ruby/object:Gem::Version
80
104
  version: '0'
81
105
  requirements: []
82
106
  rubyforge_project: fluent-plugin-irc
83
- rubygems_version: 1.8.23
107
+ rubygems_version: 2.4.5
84
108
  signing_key:
85
- specification_version: 3
109
+ specification_version: 4
86
110
  summary: Output plugin for IRC
87
111
  test_files:
88
112
  - test/helper.rb
89
113
  - test/plugin/test_out_irc.rb
90
- has_rdoc: