fluent-plugin-irc 0.0.5 → 0.0.6

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 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: