fluent-plugin-slack 0.6.2 → 0.6.3

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