fluent-plugin-slack-stakater 0.6.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 96ca178e4ae8555e05a0fdd6466c04c637a42c6d
4
+ data.tar.gz: 7288a88ed3aa6501568d18ca3af72e34bb9bfae7
5
+ SHA512:
6
+ metadata.gz: 02ae31e51c9d21408f1278a96dc109be007a122e34a8322bb91cac8ea180558258a5b54f975b9f6135cf1a7748439617cf976e9568650705aa398bc85ea68d0f
7
+ data.tar.gz: 14174efe5615240505d66269a5343a0602d1e1625c8ac24521608cbc8be7523dd01a9b02deac6bf377796f0a1dc75c0e279fb7998edf0f2c8397e907c5704bdf
@@ -0,0 +1,8 @@
1
+ /fluent/
2
+ /pkg/
3
+ /coverage/
4
+ /vendor/
5
+ Gemfile.lock
6
+ tmp/
7
+ .ruby-version
8
+ .env
@@ -0,0 +1,11 @@
1
+ sudo: false
2
+ rvm:
3
+ - 2.1.*
4
+ - 2.2.*
5
+ - 2.3.*
6
+ - 2.4.*
7
+ gemfile:
8
+ - Gemfile
9
+ - Gemfile.fluentd.0.12
10
+ before_install:
11
+ - gem update bundler
@@ -0,0 +1,95 @@
1
+ ## 0.6.7 (2017/05/23)
2
+
3
+ Enhancements:
4
+
5
+ * Allow channel @username (DM)
6
+
7
+ ## 0.6.6 (2017/05/23)
8
+
9
+ Enhancements:
10
+
11
+ * Make channel config optional on webhook because webhook has its defaul channel setting (thanks to @hirakiuc)
12
+
13
+ ## 0.6.5 (2017/05/20)
14
+
15
+ Enhancements:
16
+
17
+ * Avoid Encoding::UndefinedConversionError from ASCII-8BIT to UTF-8 on to_json by doing String#scrub! (thanks @yoheimuta)
18
+
19
+ ## 0.6.4 (2016/07/07)
20
+
21
+ Enhancements:
22
+
23
+ * Add `as_user` option (thanks @yacchin1205)
24
+
25
+ ## 0.6.3 (2016/05/11)
26
+
27
+ Enhancements:
28
+
29
+ * Add `verbose_fallback` option to show fallback (popup) verbosely (thanks @eisuke)
30
+
31
+ ## 0.6.2 (2015/12/17)
32
+
33
+ Fixes:
34
+
35
+ * escape special characters in message (thanks @fujiwara)
36
+
37
+ ## 0.6.1 (2015/05/17)
38
+
39
+ Fixes:
40
+
41
+ * Support ruby 1.9.3
42
+
43
+ ## 0.6.0 (2015/04/02)
44
+
45
+ This version has impcompatibility with previous versions in default option values
46
+
47
+ Enhancements:
48
+
49
+ * Support `link_names` and `parse` option. `link_names` option is `true` as default
50
+
51
+ Changes:
52
+
53
+ * the default payload of Incoming Webhook was changed
54
+ * `color` is `nil` as default
55
+ * `icon_emoji` is `nil` as default
56
+ * `username` is `nil` as default
57
+ * `mrkdwn` is `true` as default
58
+
59
+ ## 0.5.5 (2015/04/01)
60
+
61
+ Enhancements:
62
+
63
+ * Support Slackbot Remote Control API
64
+
65
+ ## 0.5.4 (2015/03/31)
66
+
67
+ Enhancements:
68
+
69
+ * Support `mrkdwn` option
70
+
71
+ ## 0.5.3 (2015/03/29)
72
+
73
+ Enhancements:
74
+
75
+ * Support `https_proxy` option
76
+
77
+ ## 0.5.2 (2015/03/29)
78
+
79
+ Enhancements:
80
+
81
+ * Support `icon_url` option (thanks to @jwyjoy)
82
+
83
+ ## 0.5.1 (2015/03/27)
84
+
85
+ Enhancements:
86
+
87
+ * Support `auto_channels_create` option to automatically create channels.
88
+
89
+ ## 0.5.0 (2015/03/22)
90
+
91
+ Enhancements:
92
+
93
+ * Support `message` and `message_keys` options
94
+ * Support `title` and `title_keys` options
95
+ * Support `channel_keys` options to dynamically change channels
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+ gem 'fluentd', '~> 0.12.0'
@@ -0,0 +1,126 @@
1
+ # fluent-plugin-slack [![Build Status](https://travis-ci.org/sowawa/fluent-plugin-slack.svg)](https://travis-ci.org/sowawa/fluent-plugin-slack)
2
+
3
+ # Installation
4
+
5
+ ```
6
+ $ fluent-gem install fluent-plugin-slack
7
+ ```
8
+
9
+ # Usage (Incoming Webhook)
10
+
11
+ ```apache
12
+ <match slack>
13
+ @type slack
14
+ webhook_url https://hooks.slack.com/services/XXX/XXX/XXX
15
+ channel general
16
+ username sowasowa
17
+ icon_emoji :ghost:
18
+ flush_interval 60s
19
+ </match>
20
+ ```
21
+
22
+ ```ruby
23
+ fluent_logger.post('slack', {
24
+ :message => 'Hello<br>World!'
25
+ })
26
+ ```
27
+
28
+ # Usage (Slackbot)
29
+
30
+ ```apache
31
+ <match slack>
32
+ @type slack
33
+ slackbot_url https://xxxx.slack.com/services/hooks/slackbot?token=XXXXXXXXX
34
+ channel general
35
+ flush_interval 60s
36
+ </match>
37
+ ```
38
+
39
+ ```ruby
40
+ fluent_logger.post('slack', {
41
+ :message => 'Hello<br>World!'
42
+ })
43
+ ```
44
+
45
+ # Usage (Web API a.k.a. Bots)
46
+
47
+ ```apache
48
+ <match slack>
49
+ @type slack
50
+ token xoxb-XXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXX
51
+ channel C061EG9SL
52
+ username sowasowa
53
+ icon_emoji :ghost:
54
+ flush_interval 60s
55
+ </match>
56
+ ```
57
+
58
+ ```ruby
59
+ fluent_logger.post('slack', {
60
+ :message => 'Hello<br>World!'
61
+ })
62
+ ```
63
+
64
+ ### Parameter
65
+
66
+ |parameter|description|default|
67
+ |---|---|---|
68
+ |webhook_url|Incoming Webhook URI (Required for Incoming Webhook mode). See https://api.slack.com/incoming-webhooks||
69
+ |slackbot_url|Slackbot URI (Required for Slackbot mode). See https://api.slack.com/slackbot. NOTE: most of optional parameters such as `username`, `color`, `icon_emoji`, `icon_url`, and `title` are not available for this mode, but Desktop Notification via Highlight Words works with only this mode||
70
+ |token|Token for Web API (Required for Web API mode). See https://api.slack.com/web||
71
+ |as_user|post messages as a bot user. See https://api.slack.com/bot-users#post_messages_and_react_to_users. NOTE: This parameter is only enabled if you use the Web API with your bot token. You cannot use both of `username` and `icon_emoji`(`icon_url`) when you set this parameter to `true`.|nil|
72
+ |username|name of bot|nil|
73
+ |color|color to use such as `good` or `bad`. See `Color` section of https://api.slack.com/docs/attachments. NOTE: This parameter must **not** be specified to receive Desktop Notification via Mentions in cases of Incoming Webhook and Slack Web API|nil|
74
+ |icon_emoji|emoji to use as the icon. either of `icon_emoji` or `icon_url` can be specified|nil|
75
+ |icon_url|url to an image to use as the icon. either of `icon_emoji` or `icon_url` can be specified|nil|
76
+ |mrkdwn|enable formatting. see https://api.slack.com/docs/formatting|true|
77
+ |link_names|find and link channel names and usernames. NOTE: This parameter must be `true` to receive Desktop Notification via Mentions in cases of Incoming Webhook and Slack Web API|true|
78
+ |parse|change how messages are treated. `none` or `full` can be specified. See `Parsing mode` section of https://api.slack.com/docs/formatting|nil|
79
+ |channel|Channel name or id to send messages (without first '#'). Channel ID is recommended because it is unchanged even if a channel is renamed||
80
+ |channel_keys|keys used to format channel. %s will be replaced with value specified by channel_keys if this option is used|nil|
81
+ |title|title format. %s will be replaced with value specified by title_keys. title is created from the first appeared record on each tag. NOTE: This parameter must **not** be specified to receive Desktop Notification via Mentions in cases of Incoming Webhook and Slack Web API|nil|
82
+ |title_keys|keys used to format the title|nil|
83
+ |message|message format. %s will be replaced with value specified by message_keys|%s|
84
+ |message_keys|keys used to format messages|message|
85
+ |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|
86
+ |https_proxy|https proxy url such as `https://proxy.foo.bar:443`|nil|
87
+ |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|
88
+
89
+ `fluent-plugin-slack` uses `SetTimeKeyMixin` and `SetTagKeyMixin`, so you can also use:
90
+
91
+ |parameter|description|default|
92
+ |---|---|---|
93
+ |timezone|timezone such as `Asia/Tokyo`||
94
+ |localtime|use localtime as timezone|true|
95
+ |utc|use utc as timezone||
96
+ |time_key|key name for time used in xxx_keys|time|
97
+ |time_format|time format. This will be formatted with Time#strftime.|%H:%M:%S|
98
+ |tag_key|key name for tag used in xxx_keys|tag|
99
+
100
+ `fluent-plugin-slack` is a kind of BufferedOutput plugin, so you can also use [Buffer Parameters](http://docs.fluentd.org/articles/out_exec#buffer-parameters).
101
+
102
+ ## FAQ
103
+
104
+ ### Desktop Notification seems not working?
105
+
106
+ Currently, slack.com has following limitations:
107
+
108
+ 1. Desktop Notification via both Highlight Words and Mentions works only with Slackbot Remote Control
109
+ 2. Desktop Notification via Mentions works for the `text` field if `link_names` parameter is specified in cases of Incoming Webhook and Slack Web API, that is,
110
+ * Desktop Notification does not work for the `attachments` filed (used in `color` and `title`)
111
+ * Desktop Notification via Highlight Words does not work for Incoming Webhook and Slack Web API anyway
112
+
113
+ ## ChangeLog
114
+
115
+ See [CHANGELOG.md](CHANGELOG.md) for details.
116
+
117
+ # Contributors
118
+
119
+ - [@sonots](https://github.com/sonots)
120
+ - [@kenjiskywalker](https://github.com/kenjiskywalker)
121
+
122
+ # Copyright
123
+
124
+ * Copyright:: Copyright (c) 2014- Keisuke SOGAWA
125
+ * License:: Apache License, Version 2.0
126
+
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'rake/testtask'
5
+ Rake::TestTask.new(:test) do |test|
6
+ test.libs << 'lib' << 'test'
7
+ test.pattern = 'test/**/test_*.rb'
8
+ test.verbose = true
9
+ end
10
+ task :default => :test
11
+
12
+ desc 'Open an irb session preloaded with the gem library'
13
+ task :console do
14
+ sh 'irb -rubygems -I lib'
15
+ end
16
+ task :c => :console
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.6.8
@@ -0,0 +1,18 @@
1
+ <source>
2
+ @type forward
3
+ </source>
4
+
5
+ <match tag>
6
+ @type slack
7
+ token "#{ENV['TOKEN']}"
8
+ username fluentd
9
+ color good
10
+ icon_emoji :ghost: # if you want to use icon_url, delete this param.
11
+ #icon_url http://www.google.com/s2/favicons?domain=www.google.de
12
+ channel general
13
+ message %s %s
14
+ message_keys tag,message
15
+ title %s %s
16
+ title_keys tag,message
17
+ flush_interval 1s # slack API has limit as a post / sec
18
+ </match>
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.name = "fluent-plugin-slack-stakater"
6
+ gem.description = "fluent Slack plugin"
7
+ gem.homepage = "https://github.com/stakater/fluent-plugin-slack"
8
+ gem.license = "Apache-2.0"
9
+ gem.summary = gem.description
10
+ gem.version = File.read("VERSION").strip
11
+ gem.authors = ["Keisuke SOGAWA", "Naotoshi Seo", "stakater"]
12
+ gem.email = ["hello@stakater.com"]
13
+ gem.has_rdoc = false
14
+ gem.files = `git ls-files`.split("\n")
15
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ gem.require_paths = ['lib']
18
+
19
+ gem.add_dependency "fluentd", ">= 0.12.0"
20
+
21
+ gem.add_development_dependency "rake", ">= 10.1.1"
22
+ gem.add_development_dependency "rr", ">= 1.0.0"
23
+ gem.add_development_dependency "pry"
24
+ gem.add_development_dependency "pry-nav"
25
+ gem.add_development_dependency "test-unit", "~> 3.0.2"
26
+ gem.add_development_dependency "test-unit-rr", "~> 1.0.3"
27
+ gem.add_development_dependency "dotenv"
28
+ end
@@ -0,0 +1 @@
1
+ out_slack.rb
@@ -0,0 +1,382 @@
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
+ helpers :record_accessor
9
+
10
+ # For fluentd v0.12.16 or earlier
11
+ class << self
12
+ unless method_defined?(:desc)
13
+ def desc(description)
14
+ end
15
+ end
16
+ end
17
+
18
+ include SetTimeKeyMixin
19
+ include SetTagKeyMixin
20
+
21
+ config_set_default :include_time_key, true
22
+ config_set_default :include_tag_key, true
23
+
24
+ desc <<-DESC
25
+ Incoming Webhook URI (Required for Incoming Webhook mode).
26
+ See: https://api.slack.com/incoming-webhooks
27
+ DESC
28
+ config_param :webhook_url, :string, default: nil
29
+ desc <<-DESC
30
+ Slackbot URI (Required for Slackbot mode).
31
+ See https://api.slack.com/slackbot.
32
+ NOTE: most of optional parameters such as `username`, `color`, `icon_emoji`,
33
+ `icon_url`, and `title` are not available for this mode, but Desktop Notification
34
+ via Highlight Words works with only this mode.
35
+ DESC
36
+ config_param :slackbot_url, :string, default: nil
37
+ desc <<-DESC
38
+ Token for Web API (Required for Web API mode). See: https://api.slack.com/web.
39
+ DESC
40
+ config_param :token, :string, default: nil
41
+ desc "Name of bot."
42
+ config_param :username, :string, default: nil
43
+ desc <<-DESC
44
+ Color to use such as `good` or `bad`.
45
+ See Color section of https://api.slack.com/docs/attachments.
46
+ NOTE: This parameter must not be specified to receive Desktop Notification
47
+ via Mentions in cases of Incoming Webhook and Slack Web API.
48
+ DESC
49
+ config_param :color, :string, default: nil
50
+ desc <<-DESC
51
+ Emoji to use as the icon.
52
+ Either of `icon_emoji` or `icon_url` can be specified.
53
+ DESC
54
+ config_param :as_user, :bool, default: nil
55
+ desc <<-DESC
56
+ Post message as the authenticated user.
57
+ NOTE: This parameter is only enabled if you use the Web API with your bot token.
58
+ You cannot use both of `username` and `icon_emoji`(`icon_url`) when
59
+ you set this parameter to `true`.
60
+ DESC
61
+ config_param :icon_emoji, :string, default: nil
62
+ desc <<-DESC
63
+ Url to an image to use as the icon.
64
+ Either of `icon_emoji` or `icon_url` can be specified.
65
+ DESC
66
+ config_param :icon_url, :string, default: nil
67
+ desc "Enable formatting. See: https://api.slack.com/docs/formatting."
68
+ config_param :mrkdwn, :bool, default: true
69
+ desc <<-DESC
70
+ Find and link channel names and usernames.
71
+ NOTE: This parameter must be `true` to receive Desktop Notification
72
+ via Mentions in cases of Incoming Webhook and Slack Web API.
73
+ DESC
74
+ config_param :link_names, :bool, default: true
75
+ desc <<-DESC
76
+ Change how messages are treated. `none` or `full` can be specified.
77
+ See Parsing mode section of https://api.slack.com/docs/formatting.
78
+ DESC
79
+ config_param :parse, :string, default: nil
80
+ desc <<-DESC
81
+ Create channels if not exist. Not available for Incoming Webhook mode
82
+ (since Incoming Webhook is specific to a channel).
83
+ A web api token for Normal User is required.
84
+ (Bot User can not create channels. See https://api.slack.com/bot-users)
85
+ DESC
86
+ config_param :auto_channels_create, :bool, default: false
87
+ desc "https proxy url such as https://proxy.foo.bar:443"
88
+ config_param :https_proxy, :string, default: nil
89
+
90
+ desc "channel to send messages (without first '#')."
91
+ config_param :channel, :string, default: nil
92
+ desc <<-DESC
93
+ Keys used to format channel.
94
+ %s will be replaced with value specified by channel_keys if this option is used.
95
+ DESC
96
+ config_param :channel_keys, default: nil do |val|
97
+ val.split(',')
98
+ end
99
+ desc <<-DESC
100
+ Title format.
101
+ %s will be replaced with value specified by title_keys.
102
+ Title is created from the first appeared record on each tag.
103
+ NOTE: This parameter must **not** be specified to receive Desktop Notification
104
+ via Mentions in cases of Incoming Webhook and Slack Web API.
105
+ DESC
106
+ config_param :title, :string, default: nil
107
+ desc "Keys used to format the title."
108
+ config_param :title_keys, default: nil do |val|
109
+ val.split(',')
110
+ end
111
+ desc <<-DESC
112
+ Message format.
113
+ %s will be replaced with value specified by message_keys.
114
+ DESC
115
+ config_param :message, :string, default: nil
116
+ desc "Keys used to format messages."
117
+ config_param :message_keys, default: nil do |val|
118
+ val.split(',')
119
+ end
120
+
121
+ desc "Include messages to the fallback attributes"
122
+ config_param :verbose_fallback, :bool, default: false
123
+
124
+ # for test
125
+ attr_reader :slack, :time_format, :localtime, :timef, :mrkdwn_in, :post_message_opts
126
+
127
+ def initialize
128
+ super
129
+ require 'uri'
130
+ end
131
+
132
+ def configure(conf)
133
+ conf['time_format'] ||= '%H:%M:%S' # old version compatiblity
134
+ conf['localtime'] ||= true unless conf['utc']
135
+
136
+ super
137
+
138
+ if @channel
139
+ @channel = URI.unescape(@channel) # old version compatibility
140
+ if !@channel.start_with?('#') and !@channel.start_with?('@')
141
+ @channel = '#' + @channel # Add # since `#` is handled as a comment in fluentd conf
142
+ end
143
+ end
144
+
145
+ if @webhook_url
146
+ if @webhook_url.empty?
147
+ raise Fluent::ConfigError.new("`webhook_url` is an empty string")
148
+ end
149
+ unless @as_user.nil?
150
+ log.warn "out_slack: `as_user` parameter are not available for Incoming Webhook"
151
+ end
152
+ @slack = Fluent::SlackClient::IncomingWebhook.new(@webhook_url)
153
+ elsif @slackbot_url
154
+ if @slackbot_url.empty?
155
+ raise Fluent::ConfigError.new("`slackbot_url` is an empty string")
156
+ end
157
+ if @channel.nil?
158
+ raise Fluent::ConfigError.new("`channel` parameter required for Slackbot Remote Control")
159
+ end
160
+
161
+ if @username or @color or @icon_emoji or @icon_url
162
+ log.warn "out_slack: `username`, `color`, `icon_emoji`, `icon_url` parameters are not available for Slackbot Remote Control"
163
+ end
164
+ unless @as_user.nil?
165
+ log.warn "out_slack: `as_user` parameter are not available for Slackbot Remote Control"
166
+ end
167
+ @slack = Fluent::SlackClient::Slackbot.new(@slackbot_url)
168
+ elsif @token
169
+ if @token.empty?
170
+ raise Fluent::ConfigError.new("`token` is an empty string")
171
+ end
172
+ if @channel.nil?
173
+ raise Fluent::ConfigError.new("`channel` parameter required for Slack WebApi")
174
+ end
175
+
176
+ @slack = Fluent::SlackClient::WebApi.new
177
+ else
178
+ raise Fluent::ConfigError.new("One of `webhook_url` or `slackbot_url`, or `token` is required")
179
+ end
180
+ @slack.log = log
181
+ @slack.debug_dev = log.out if log.level <= Fluent::Log::LEVEL_TRACE
182
+
183
+ if @https_proxy
184
+ @slack.https_proxy = @https_proxy
185
+ end
186
+
187
+ @message ||= '%s'
188
+ @message_keys ||= %w[message]
189
+ begin
190
+ @message % (['1'] * @message_keys.length)
191
+ rescue ArgumentError
192
+ raise Fluent::ConfigError, "string specifier '%s' for `message` and `message_keys` specification mismatch"
193
+ end
194
+ if @title and @title_keys
195
+ begin
196
+ @title % (['1'] * @title_keys.length)
197
+ rescue ArgumentError
198
+ raise Fluent::ConfigError, "string specifier '%s' for `title` and `title_keys` specification mismatch"
199
+ end
200
+ end
201
+ if @channel && @channel_keys
202
+ begin
203
+ @channel % (['1'] * @channel_keys.length)
204
+ rescue ArgumentError
205
+ raise Fluent::ConfigError, "string specifier '%s' for `channel` and `channel_keys` specification mismatch"
206
+ end
207
+ end
208
+
209
+ if @icon_emoji and @icon_url
210
+ raise Fluent::ConfigError, "either of `icon_emoji` or `icon_url` can be specified"
211
+ end
212
+
213
+ if @as_user and (@icon_emoji or @icon_url or @username)
214
+ raise Fluent::ConfigError, "`username`, `icon_emoji` and `icon_url` cannot be specified when `as_user` is set to true"
215
+ end
216
+
217
+ if @mrkdwn
218
+ # Enable markdown for attachments. See https://api.slack.com/docs/formatting
219
+ @mrkdwn_in = %w[text fields]
220
+ end
221
+
222
+ if @parse and !%w[none full].include?(@parse)
223
+ raise Fluent::ConfigError, "`parse` must be either of `none` or `full`"
224
+ end
225
+
226
+ @post_message_opts = {}
227
+ if @auto_channels_create
228
+ raise Fluent::ConfigError, "`token` parameter is required to use `auto_channels_create`" unless @token
229
+ @post_message_opts = {auto_channels_create: true}
230
+ end
231
+ end
232
+
233
+ def format(tag, time, record)
234
+ [tag, time, record].to_msgpack
235
+ end
236
+
237
+ def write(chunk)
238
+ begin
239
+ payloads = build_payloads(chunk)
240
+ payloads.each {|payload| @slack.post_message(payload, @post_message_opts) }
241
+ rescue Timeout::Error => e
242
+ log.warn "out_slack:", :error => e.to_s, :error_class => e.class.to_s
243
+ raise e # let Fluentd retry
244
+ rescue => e
245
+ log.error "out_slack:", :error => e.to_s, :error_class => e.class.to_s
246
+ log.warn_backtrace e.backtrace
247
+ # discard. @todo: add more retriable errors
248
+ end
249
+ end
250
+
251
+ private
252
+
253
+ def build_payloads(chunk)
254
+ if @title
255
+ build_title_payloads(chunk)
256
+ elsif @color
257
+ build_color_payloads(chunk)
258
+ else
259
+ build_plain_payloads(chunk)
260
+ end
261
+ end
262
+
263
+ def common_payload
264
+ return @common_payload if @common_payload
265
+ @common_payload = {}
266
+ @common_payload[:as_user] = @as_user unless @as_user.nil?
267
+ @common_payload[:username] = @username if @username
268
+ @common_payload[:icon_emoji] = @icon_emoji if @icon_emoji
269
+ @common_payload[:icon_url] = @icon_url if @icon_url
270
+ @common_payload[:mrkdwn] = @mrkdwn if @mrkdwn
271
+ @common_payload[:link_names] = @link_names if @link_names
272
+ @common_payload[:parse] = @parse if @parse
273
+ @common_payload[:token] = @token if @token
274
+ @common_payload
275
+ end
276
+
277
+ def common_attachment
278
+ return @common_attachment if @common_attachment
279
+ @common_attachment = {}
280
+ @common_attachment[:color] = @color if @color
281
+ @common_attachment[:mrkdwn_in] = @mrkdwn_in if @mrkdwn_in
282
+ @common_attachment
283
+ end
284
+
285
+ Field = Struct.new("Field", :title, :value)
286
+ # ruby 1.9.x does not provide #to_h
287
+ Field.send(:define_method, :to_h) { {title: title, value: value} }
288
+
289
+ def build_title_payloads(chunk)
290
+ ch_fields = {}
291
+ chunk.msgpack_each do |tag, time, record|
292
+ channel = build_channel(record)
293
+ per = tag # title per tag
294
+ ch_fields[channel] ||= {}
295
+ ch_fields[channel][per] ||= Field.new(build_title(record), '')
296
+ ch_fields[channel][per].value << "#{build_message(record)}\n"
297
+ end
298
+ ch_fields.map do |channel, fields|
299
+ fallback_text = if @verbose_fallback
300
+ fields.values.map { |f| "#{f.title} #{f.value}" }.join(' ')
301
+ else
302
+ fields.values.map(&:title).join(' ')
303
+ end
304
+
305
+ msg = {
306
+ attachments: [{
307
+ :fallback => fallback_text, # fallback is the message shown on popup
308
+ :fields => fields.values.map(&:to_h)
309
+ }.merge(common_attachment)],
310
+ }
311
+ msg.merge!(channel: channel) if channel
312
+ msg.merge!(common_payload)
313
+ end
314
+ end
315
+
316
+ def build_color_payloads(chunk)
317
+ messages = {}
318
+ chunk.msgpack_each do |tag, time, record|
319
+ channel = build_channel(record)
320
+ messages[channel] ||= ''
321
+ messages[channel] << "#{build_message(record)}\n"
322
+ end
323
+ messages.map do |channel, text|
324
+ msg = {
325
+ attachments: [{
326
+ :fallback => text,
327
+ :text => text,
328
+ }.merge(common_attachment)],
329
+ }
330
+ msg.merge!(channel: channel) if channel
331
+ msg.merge!(common_payload)
332
+ end
333
+ end
334
+
335
+ def build_plain_payloads(chunk)
336
+ messages = {}
337
+ chunk.msgpack_each do |tag, time, record|
338
+ channel = build_channel(record)
339
+ messages[channel] ||= ''
340
+ messages[channel] << "#{build_message(record)}\n"
341
+ end
342
+ messages.map do |channel, text|
343
+ msg = {text: text}
344
+ msg.merge!(channel: channel) if channel
345
+ msg.merge!(common_payload)
346
+ end
347
+ end
348
+
349
+ def build_message(record)
350
+ values = fetch_keys(record, @message_keys)
351
+ @message % values
352
+ end
353
+
354
+ def build_title(record)
355
+ return @title unless @title_keys
356
+
357
+ values = fetch_keys(record, @title_keys)
358
+ @title % values
359
+ end
360
+
361
+ def build_channel(record)
362
+ return nil if @channel.nil?
363
+ return @channel unless @channel_keys
364
+
365
+ values = fetch_keys(record, @channel_keys)
366
+ @channel % values
367
+ end
368
+
369
+ def fetch_keys(record, keys)
370
+ Array(keys).map do |key|
371
+ begin
372
+ accessor = record_accessor_create(key)
373
+ accessor.call(record).to_s
374
+ #record.fetch(key).to_s
375
+ rescue KeyError
376
+ log.warn "out_slack: the specified key '#{key}' not found in record. [#{record}]"
377
+ ''
378
+ end
379
+ end
380
+ end
381
+ end
382
+ end