fluent-plugin-slack 0.6.2 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c03f2406138aa33b38a5db1fe9df6a75b2e660e7
4
- data.tar.gz: ddb0b1cf2dc19024bca2838eeecc22a99116711c
3
+ metadata.gz: 3e77ab7baa0827ff765699dcc93878a07fb4b672
4
+ data.tar.gz: 69e2477beb5f8e394493b773f14ba92430927750
5
5
  SHA512:
6
- metadata.gz: c4dffa0ecdad7eda6d710cba98078cc1cb0fdb4c4967ed64a200bfcb57d5897a44929d9ec714f837ab443dca01a99a90ddb09ad5cef76dd5a6da85037dd6c674
7
- data.tar.gz: 6901248f0fe1b72cca79d26877f3d75e4147b66e9f52132770a537d12a8e579cba9ef45efc8f544caa4cc1f6d3f96fcdbc7f9adaf401cdd1c103d5c4a43e9fd0
6
+ metadata.gz: 2bd4b7b25d6a3c63bca594121120cf29a5679bbcb77e295d9f245ced3a80061458ed1d6028c67cbf0f159ae6cdf13ee190764f84b9ae7d7219507fc275d409f3
7
+ data.tar.gz: dd44cbe50f10718b5c5dcdc0fba0e0b9d570db7c82b636e200142be75ea8736ad3d8bbc2f885e785654328894be76c4571ac6635f7c2d9c2ed421d6cbe6d6019
@@ -1,8 +1,9 @@
1
+ sudo: false
1
2
  rvm:
2
- - 1.9.3
3
3
  - 2.0.0
4
4
  - 2.1.*
5
5
  - 2.2.*
6
+ - 2.3.0
6
7
  gemfile:
7
8
  - Gemfile
8
9
  before_install:
@@ -1,3 +1,9 @@
1
+ ## 0.6.3 (2016/05/11)
2
+
3
+ Enhancements:
4
+
5
+ * Add `verbose_fallback` option to show fallback (popup) verbosely (thanks @eisuke)
6
+
1
7
  ## 0.6.2 (2015/12/17)
2
8
 
3
9
  Fixes:
data/README.md CHANGED
@@ -10,7 +10,7 @@ $ fluent-gem install fluent-plugin-slack
10
10
 
11
11
  ```apache
12
12
  <match slack>
13
- type slack
13
+ @type slack
14
14
  webhook_url https://hooks.slack.com/services/XXX/XXX/XXX
15
15
  channel general
16
16
  username sowasowa
@@ -29,7 +29,7 @@ fluent_logger.post('slack', {
29
29
 
30
30
  ```apache
31
31
  <match slack>
32
- type slack
32
+ @type slack
33
33
  slackbot_url https://xxxx.slack.com/services/hooks/slackbot?token=XXXXXXXXX
34
34
  channel general
35
35
  flush_interval 60s
@@ -46,7 +46,7 @@ fluent_logger.post('slack', {
46
46
 
47
47
  ```apache
48
48
  <match slack>
49
- type slack
49
+ @type slack
50
50
  token xoxb-XXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXX
51
51
  channel general
52
52
  username sowasowa
@@ -83,6 +83,7 @@ fluent_logger.post('slack', {
83
83
  |message_keys|keys used to format messages|message|
84
84
  |auto_channels_create|Create channels if not exist. Not available for Incoming Webhook mode (since Incoming Webhook is specific to a channel). A web api `token` for Normal User is required (Bot User can not create channels. See https://api.slack.com/bot-users)|false|
85
85
  |https_proxy|https proxy url such as `https://proxy.foo.bar:443`|nil|
86
+ |verbose_fallback|Originally, only `title` is used for the fallback which is the message shown on popup if `title` is given. If this option is set to be `true`, messages are also included to the fallback attribute|false|
86
87
 
87
88
  `fluent-plugin-slack` uses `SetTimeKeyMixin` and `SetTagKeyMixin`, so you can also use:
88
89
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.2
1
+ 0.6.3
@@ -0,0 +1 @@
1
+ out_slack.rb
@@ -5,38 +5,113 @@ module Fluent
5
5
  Fluent::Plugin.register_output('buffered_slack', self) # old version compatiblity
6
6
  Fluent::Plugin.register_output('slack', self)
7
7
 
8
+ # For fluentd v0.12.16 or earlier
9
+ class << self
10
+ unless method_defined?(:desc)
11
+ def desc(description)
12
+ end
13
+ end
14
+ end
15
+
8
16
  include SetTimeKeyMixin
9
17
  include SetTagKeyMixin
10
18
 
11
19
  config_set_default :include_time_key, true
12
20
  config_set_default :include_tag_key, true
13
-
14
- config_param :webhook_url, :string, default: nil # incoming webhook
15
- config_param :slackbot_url, :string, default: nil # slackbot
16
- config_param :token, :string, default: nil # api token
21
+
22
+ desc <<-DESC
23
+ Incoming Webhook URI (Required for Incoming Webhook mode).
24
+ See: https://api.slack.com/incoming-webhooks
25
+ DESC
26
+ config_param :webhook_url, :string, default: nil
27
+ desc <<-DESC
28
+ Slackbot URI (Required for Slackbot mode).
29
+ See https://api.slack.com/slackbot.
30
+ NOTE: most of optional parameters such as `username`, `color`, `icon_emoji`,
31
+ `icon_url`, and `title` are not available for this mode, but Desktop Notification
32
+ via Highlight Words works with only this mode.
33
+ DESC
34
+ config_param :slackbot_url, :string, default: nil
35
+ desc <<-DESC
36
+ Token for Web API (Required for Web API mode). See: https://api.slack.com/web.
37
+ DESC
38
+ config_param :token, :string, default: nil
39
+ desc "Name of bot."
17
40
  config_param :username, :string, default: nil
41
+ desc <<-DESC
42
+ Color to use such as `good` or `bad`.
43
+ See Color section of https://api.slack.com/docs/attachments.
44
+ NOTE: This parameter must not be specified to receive Desktop Notification
45
+ via Mentions in cases of Incoming Webhook and Slack Web API.
46
+ DESC
18
47
  config_param :color, :string, default: nil
48
+ desc <<-DESC
49
+ Emoji to use as the icon.
50
+ Either of `icon_emoji` or `icon_url` can be specified.
51
+ DESC
19
52
  config_param :icon_emoji, :string, default: nil
53
+ desc <<-DESC
54
+ Url to an image to use as the icon.
55
+ Either of `icon_emoji` or `icon_url` can be specified.
56
+ DESC
20
57
  config_param :icon_url, :string, default: nil
58
+ desc "Enable formatting. See: https://api.slack.com/docs/formatting."
21
59
  config_param :mrkdwn, :bool, default: true
60
+ desc <<-DESC
61
+ Find and link channel names and usernames.
62
+ NOTE: This parameter must be `true` to receive Desktop Notification
63
+ via Mentions in cases of Incoming Webhook and Slack Web API.
64
+ DESC
22
65
  config_param :link_names, :bool, default: true
66
+ desc <<-DESC
67
+ Change how messages are treated. `none` or `full` can be specified.
68
+ See Parsing mode section of https://api.slack.com/docs/formatting.
69
+ DESC
23
70
  config_param :parse, :string, default: nil
71
+ desc <<-DESC
72
+ Create channels if not exist. Not available for Incoming Webhook mode
73
+ (since Incoming Webhook is specific to a channel).
74
+ A web api token for Normal User is required.
75
+ (Bot User can not create channels. See https://api.slack.com/bot-users)
76
+ DESC
24
77
  config_param :auto_channels_create, :bool, default: false
78
+ desc "https proxy url such as https://proxy.foo.bar:443"
25
79
  config_param :https_proxy, :string, default: nil
26
80
 
81
+ desc "channel to send messages (without first '#')."
27
82
  config_param :channel, :string
83
+ desc <<-DESC
84
+ Keys used to format channel.
85
+ %s will be replaced with value specified by channel_keys if this option is used.
86
+ DESC
28
87
  config_param :channel_keys, default: nil do |val|
29
88
  val.split(',')
30
89
  end
90
+ desc <<-DESC
91
+ Title format.
92
+ %s will be replaced with value specified by title_keys.
93
+ Title is created from the first appeared record on each tag.
94
+ NOTE: This parameter must **not** be specified to receive Desktop Notification
95
+ via Mentions in cases of Incoming Webhook and Slack Web API.
96
+ DESC
31
97
  config_param :title, :string, default: nil
98
+ desc "Keys used to format the title."
32
99
  config_param :title_keys, default: nil do |val|
33
100
  val.split(',')
34
101
  end
102
+ desc <<-DESC
103
+ Message format.
104
+ %s will be replaced with value specified by message_keys.
105
+ DESC
35
106
  config_param :message, :string, default: nil
107
+ desc "Keys used to format messages."
36
108
  config_param :message_keys, default: nil do |val|
37
109
  val.split(',')
38
110
  end
39
111
 
112
+ desc "Include messages to the fallback attributes"
113
+ config_param :verbose_fallback, :bool, default: false
114
+
40
115
  # for test
41
116
  attr_reader :slack, :time_format, :localtime, :timef, :mrkdwn_in, :post_message_opts
42
117
 
@@ -189,10 +264,16 @@ module Fluent
189
264
  ch_fields[channel][per].value << "#{build_message(record)}\n"
190
265
  end
191
266
  ch_fields.map do |channel, fields|
267
+ fallback_text = if @verbose_fallback
268
+ fields.values.map { |f| "#{f.title} #{f.value}" }.join(' ')
269
+ else
270
+ fields.values.map(&:title).join(' ')
271
+ end
272
+
192
273
  {
193
274
  channel: channel,
194
275
  attachments: [{
195
- :fallback => fields.values.map(&:title).join(' '), # fallback is the message shown on popup
276
+ :fallback => fallback_text, # fallback is the message shown on popup
196
277
  :fields => fields.values.map(&:to_h)
197
278
  }.merge(common_attachment)],
198
279
  }.merge(common_payload)
@@ -342,6 +342,30 @@ class SlackOutputTest < Test::Unit::TestCase
342
342
  end
343
343
  end
344
344
 
345
+ def test_title_payload_with_verbose_fallback_option
346
+ title = "mytitle"
347
+ d = create_driver(CONFIG + %[title #{title}\nverbose_fallback true])
348
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
349
+ d.tag = 'test'
350
+ # attachments field should be changed to show the title
351
+ mock(d.instance.slack).post_message(default_payload.merge({
352
+ attachments: [default_attachment.merge({
353
+ fallback: "#{title} sowawa1\nsowawa2\n",
354
+ fields: [
355
+ {
356
+ title: title,
357
+ value: "sowawa1\nsowawa2\n",
358
+ }
359
+ ],
360
+ })]
361
+ }), {})
362
+ with_timezone('Asia/Tokyo') do
363
+ d.emit({message: 'sowawa1'}, time)
364
+ d.emit({message: 'sowawa2'}, time)
365
+ d.run
366
+ end
367
+ end
368
+
345
369
  def test_color_payload
346
370
  color = 'good'
347
371
  d = create_driver(CONFIG + %[color #{color}])
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-slack
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.6.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keisuke SOGAWA
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-12-17 00:00:00.000000000 Z
12
+ date: 2016-05-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: fluentd
@@ -168,7 +168,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
168
168
  version: '0'
169
169
  requirements: []
170
170
  rubyforge_project:
171
- rubygems_version: 2.4.5
171
+ rubygems_version: 2.5.1
172
172
  signing_key:
173
173
  specification_version: 4
174
174
  summary: fluent Slack plugin
@@ -1,265 +0,0 @@
1
- require_relative 'slack_client'
2
-
3
- module Fluent
4
- class SlackOutput < Fluent::BufferedOutput
5
- Fluent::Plugin.register_output('buffered_slack', self) # old version compatiblity
6
- Fluent::Plugin.register_output('slack', self)
7
-
8
- include SetTimeKeyMixin
9
- include SetTagKeyMixin
10
-
11
- config_set_default :include_time_key, true
12
- config_set_default :include_tag_key, true
13
-
14
- config_param :webhook_url, :string, default: nil # incoming webhook
15
- config_param :slackbot_url, :string, default: nil # slackbot
16
- config_param :token, :string, default: nil # api token
17
- config_param :username, :string, default: nil
18
- config_param :color, :string, default: nil
19
- config_param :icon_emoji, :string, default: nil
20
- config_param :icon_url, :string, default: nil
21
- config_param :mrkdwn, :bool, default: true
22
- config_param :link_names, :bool, default: true
23
- config_param :parse, :string, default: nil
24
- config_param :auto_channels_create, :bool, default: false
25
- config_param :https_proxy, :string, default: nil
26
-
27
- config_param :channel, :string
28
- config_param :channel_keys, default: nil do |val|
29
- val.split(',')
30
- end
31
- config_param :title, :string, default: nil
32
- config_param :title_keys, default: nil do |val|
33
- val.split(',')
34
- end
35
- config_param :message, :string, default: nil
36
- config_param :message_keys, default: nil do |val|
37
- val.split(',')
38
- end
39
-
40
- # for test
41
- attr_reader :slack, :time_format, :localtime, :timef, :mrkdwn_in, :post_message_opts
42
-
43
- def initialize
44
- super
45
- require 'uri'
46
- end
47
-
48
- def configure(conf)
49
- conf['time_format'] ||= '%H:%M:%S' # old version compatiblity
50
- conf['localtime'] ||= true unless conf['utc']
51
-
52
- super
53
-
54
- @channel = URI.unescape(@channel) # old version compatibility
55
- @channel = '#' + @channel unless @channel.start_with?('#')
56
-
57
- if @webhook_url
58
- if @webhook_url.empty?
59
- raise Fluent::ConfigError.new("`webhook_url` is an empty string")
60
- end
61
- @slack = Fluent::SlackClient::IncomingWebhook.new(@webhook_url)
62
- elsif @slackbot_url
63
- if @slackbot_url.empty?
64
- raise Fluent::ConfigError.new("`slackbot_url` is an empty string")
65
- end
66
- if @username or @color or @icon_emoji or @icon_url
67
- log.warn "out_slack: `username`, `color`, `icon_emoji`, `icon_url` parameters are not available for Slackbot Remote Control"
68
- end
69
- @slack = Fluent::SlackClient::Slackbot.new(@slackbot_url)
70
- elsif @token
71
- if @token.empty?
72
- raise Fluent::ConfigError.new("`token` is an empty string")
73
- end
74
- @slack = Fluent::SlackClient::WebApi.new
75
- else
76
- raise Fluent::ConfigError.new("One of `webhook_url` or `slackbot_url`, or `token` is required")
77
- end
78
- @slack.log = log
79
- @slack.debug_dev = log.out if log.level <= Fluent::Log::LEVEL_TRACE
80
-
81
- if @https_proxy
82
- @slack.https_proxy = @https_proxy
83
- end
84
-
85
- @message ||= '%s'
86
- @message_keys ||= %w[message]
87
- begin
88
- @message % (['1'] * @message_keys.length)
89
- rescue ArgumentError
90
- raise Fluent::ConfigError, "string specifier '%s' for `message` and `message_keys` specification mismatch"
91
- end
92
- if @title and @title_keys
93
- begin
94
- @title % (['1'] * @title_keys.length)
95
- rescue ArgumentError
96
- raise Fluent::ConfigError, "string specifier '%s' for `title` and `title_keys` specification mismatch"
97
- end
98
- end
99
- if @channel_keys
100
- begin
101
- @channel % (['1'] * @channel_keys.length)
102
- rescue ArgumentError
103
- raise Fluent::ConfigError, "string specifier '%s' for `channel` and `channel_keys` specification mismatch"
104
- end
105
- end
106
-
107
- if @icon_emoji and @icon_url
108
- raise Fluent::ConfigError, "either of `icon_emoji` or `icon_url` can be specified"
109
- end
110
-
111
- if @mrkdwn
112
- # Enable markdown for attachments. See https://api.slack.com/docs/formatting
113
- @mrkdwn_in = %w[text fields]
114
- end
115
-
116
- if @parse and !%w[none full].include?(@parse)
117
- raise Fluent::ConfigError, "`parse` must be either of `none` or `full`"
118
- end
119
-
120
- @post_message_opts = {}
121
- if @auto_channels_create
122
- raise Fluent::ConfigError, "`token` parameter is required to use `auto_channels_create`" unless @token
123
- @post_message_opts = {auto_channels_create: true}
124
- end
125
- end
126
-
127
- def format(tag, time, record)
128
- [tag, time, record].to_msgpack
129
- end
130
-
131
- def write(chunk)
132
- begin
133
- payloads = build_payloads(chunk)
134
- payloads.each {|payload| @slack.post_message(payload, @post_message_opts) }
135
- rescue Timeout::Error => e
136
- log.warn "out_slack:", :error => e.to_s, :error_class => e.class.to_s
137
- raise e # let Fluentd retry
138
- rescue => e
139
- log.error "out_slack:", :error => e.to_s, :error_class => e.class.to_s
140
- log.warn_backtrace e.backtrace
141
- # discard. @todo: add more retriable errors
142
- end
143
- end
144
-
145
- private
146
-
147
- def build_payloads(chunk)
148
- if @title
149
- build_title_payloads(chunk)
150
- elsif @color
151
- build_color_payloads(chunk)
152
- else
153
- build_plain_payloads(chunk)
154
- end
155
- end
156
-
157
- def common_payload
158
- return @common_payload if @common_payload
159
- @common_payload = {}
160
- @common_payload[:username] = @username if @username
161
- @common_payload[:icon_emoji] = @icon_emoji if @icon_emoji
162
- @common_payload[:icon_url] = @icon_url if @icon_url
163
- @common_payload[:mrkdwn] = @mrkdwn if @mrkdwn
164
- @common_payload[:link_names] = @link_names if @link_names
165
- @common_payload[:parse] = @parse if @parse
166
- @common_payload[:token] = @token if @token
167
- @common_payload
168
- end
169
-
170
- def common_attachment
171
- return @common_attachment if @common_attachment
172
- @common_attachment = {}
173
- @common_attachment[:color] = @color if @color
174
- @common_attachment[:mrkdwn_in] = @mrkdwn_in if @mrkdwn_in
175
- @common_attachment
176
- end
177
-
178
- Field = Struct.new("Field", :title, :value)
179
- # ruby 1.9.x does not provide #to_h
180
- Field.send(:define_method, :to_h) { {title: title, value: value} }
181
-
182
- def build_title_payloads(chunk)
183
- ch_fields = {}
184
- chunk.msgpack_each do |tag, time, record|
185
- channel = build_channel(record)
186
- per = tag # title per tag
187
- ch_fields[channel] ||= {}
188
- ch_fields[channel][per] ||= Field.new(build_title(record), '')
189
- ch_fields[channel][per].value << "#{build_message(record)}\n"
190
- end
191
- ch_fields.map do |channel, fields|
192
- {
193
- channel: channel,
194
- attachments: [{
195
- :fallback => fields.values.map(&:title).join(' '), # fallback is the message shown on popup
196
- :fields => fields.values.map(&:to_h)
197
- }.merge(common_attachment)],
198
- }.merge(common_payload)
199
- end
200
- end
201
-
202
- def build_color_payloads(chunk)
203
- messages = {}
204
- chunk.msgpack_each do |tag, time, record|
205
- channel = build_channel(record)
206
- messages[channel] ||= ''
207
- messages[channel] << "#{build_message(record)}\n"
208
- end
209
- messages.map do |channel, text|
210
- {
211
- channel: channel,
212
- attachments: [{
213
- :fallback => text,
214
- :text => text,
215
- }.merge(common_attachment)],
216
- }.merge(common_payload)
217
- end
218
- end
219
-
220
- def build_plain_payloads(chunk)
221
- messages = {}
222
- chunk.msgpack_each do |tag, time, record|
223
- channel = build_channel(record)
224
- messages[channel] ||= ''
225
- messages[channel] << "#{build_message(record)}\n"
226
- end
227
- messages.map do |channel, text|
228
- {
229
- channel: channel,
230
- text: text,
231
- }.merge(common_payload)
232
- end
233
- end
234
-
235
- def build_message(record)
236
- values = fetch_keys(record, @message_keys)
237
- @message % values
238
- end
239
-
240
- def build_title(record)
241
- return @title unless @title_keys
242
-
243
- values = fetch_keys(record, @title_keys)
244
- @title % values
245
- end
246
-
247
- def build_channel(record)
248
- return @channel unless @channel_keys
249
-
250
- values = fetch_keys(record, @channel_keys)
251
- @channel % values
252
- end
253
-
254
- def fetch_keys(record, keys)
255
- Array(keys).map do |key|
256
- begin
257
- record.fetch(key).to_s
258
- rescue KeyError
259
- log.warn "out_slack: the specified key '#{key}' not found in record. [#{record}]"
260
- ''
261
- end
262
- end
263
- end
264
- end
265
- end