fluent-plugin-google-chat 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a06d61a542fae23221eb956df8a0f23157c1a94a6475135d4e844c453a238501
4
+ data.tar.gz: dc7104521deeb08323c4de39c1c0dea7a4e5cea52ac482f3e63f9565941f20d5
5
+ SHA512:
6
+ metadata.gz: 299a8bf7403aba535cbf8d2d609b4ef9252b3b88dcbaacb6ab426e90ebe159bdd954a3ac3380afadcd9fd2f53fc2dd83abf7b48ee2cae5e0b1590f183824ff99
7
+ data.tar.gz: ed60576f6b3638038062aaf8f6d9e5b4ed73edf448ee7ae4b6f849bce9b6f8f4e58d54d580994045b27df594f44dd43dcfebfddbec5d9e6b22cf4a8633c4c4aa
@@ -0,0 +1,10 @@
1
+ /fluent/
2
+ /pkg/
3
+ /coverage/
4
+ /vendor/
5
+ Gemfile.lock
6
+ tmp/
7
+ .ruby-version
8
+ .env
9
+ .bundle
10
+ .idea
@@ -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,61 @@
1
+ # fluent-plugin-google-chat [![Build Status](https://travis-ci.org/treasuryspring/fluent-plugin-google-chat.svg)](https://travis-ci.org/treasuryspring/fluent-plugin-google-chat)
2
+
3
+ This plugin is largely inspired by [fluent-plugin-slack](https://github.com/sowawa/fluent-plugin-slack).
4
+
5
+ # Installation
6
+
7
+ ```
8
+ $ fluent-gem install fluent-plugin-google-chat
9
+ ```
10
+
11
+ # Usage (Web API a.k.a. Bots)
12
+
13
+ ```apache
14
+ <match google_chat>
15
+ @type google_chat
16
+ keyfile /tmp/mykeyfile.json
17
+ space AAABBBcdefG
18
+ flush_interval 60s
19
+ </match>
20
+ ```
21
+
22
+ ```ruby
23
+ fluent_logger.post('google_chat', {
24
+ :message => 'Hello<br>World!'
25
+ })
26
+ ```
27
+
28
+ ### Parameter
29
+
30
+ |parameter|description|default|
31
+ |---|---|---|
32
+ |keyfile|Private key file generated on Google Cloud Platform. See https://developers.google.com/hangouts/chat/how-tos/bots-publish#enabling_the_hangouts_chat_api||
33
+ |space|Room name to send messages. Can be found in the URL of the chat room.||
34
+ |space_keys|keys used to format space. %s will be replaced with value specified by space_keys if this option is used|nil|
35
+ |message|message format. %s will be replaced with value specified by message_keys|%s|
36
+ |message_keys|keys used to format messages|message|
37
+ |https_proxy|https proxy url such as `https://proxy.foo.bar:443`|nil|
38
+ |verbose_fallback|If this option is set to be `true`, messages are included to the fallback attribute|false|
39
+
40
+ `fluent-plugin-google-chat` uses `SetTimeKeyMixin` and `SetTagKeyMixin`, so you can also use:
41
+
42
+ |parameter|description|default|
43
+ |---|---|---|
44
+ |timezone|timezone such as `Asia/Tokyo`||
45
+ |localtime|use localtime as timezone|true|
46
+ |utc|use utc as timezone||
47
+ |time_key|key name for time used in xxx_keys|time|
48
+ |time_format|time format. This will be formatted with Time#strftime.|%H:%M:%S|
49
+ |tag_key|key name for tag used in xxx_keys|tag|
50
+
51
+ `fluent-plugin-google-chat` is a kind of BufferedOutput plugin, so you can also use [Buffer Parameters](http://docs.fluentd.org/articles/out_exec#buffer-parameters).
52
+
53
+ ## ChangeLog
54
+
55
+ See [CHANGELOG.md](CHANGELOG.md) for details.
56
+
57
+ # Copyright
58
+
59
+ * Copyright:: Copyright (c) 2020 - TreasurySpring
60
+ * License:: Apache License, Version 2.0
61
+
@@ -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.0.1
@@ -0,0 +1 @@
1
+ docker run --rm -ti
@@ -0,0 +1,12 @@
1
+ <source>
2
+ @type forward
3
+ </source>
4
+
5
+ <match tag>
6
+ @type google_chat
7
+ keyfile "#{ENV['KEYFILE']}"
8
+ space "#{ENV['SPACE']}"
9
+ message %s %s
10
+ message_keys tag,message
11
+ flush_interval 1s # slack API has limit as a post / sec
12
+ </match>
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.name = "fluent-plugin-google-chat"
6
+ gem.description = "fluent Google Chat plugin"
7
+ gem.homepage = "https://github.com/treasuryspring/fluent-plugin-google-chat"
8
+ gem.license = "Apache-2.0"
9
+ gem.summary = gem.description
10
+ gem.version = File.read("VERSION").strip
11
+ gem.authors = ["Lionel Gabaude"]
12
+ gem.email = ["tech@treasuryspring.com"]
13
+ gem.files = `git ls-files`.split("\n")
14
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
+ gem.require_paths = ['lib']
17
+
18
+ gem.add_dependency "fluentd", ">= 0.12.0"
19
+ gem.add_dependency "googleauth"
20
+ gem.add_dependency "google-api-client", "~> 0.34"
21
+
22
+ gem.add_development_dependency "rake", ">= 10.1.1"
23
+ gem.add_development_dependency "rr", ">= 1.0.0"
24
+ gem.add_development_dependency "pry"
25
+ gem.add_development_dependency "pry-nav"
26
+ gem.add_development_dependency "test-unit", "~> 3.0.2"
27
+ gem.add_development_dependency "test-unit-rr", "~> 1.0.3"
28
+ gem.add_development_dependency "dotenv"
29
+ end
@@ -0,0 +1,92 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+ require 'net/https'
4
+ require 'logger'
5
+ require 'googleauth'
6
+ require 'google/apis/chat_v1'
7
+ require_relative 'google_chat_client/error'
8
+
9
+ Chat = Google::Apis::ChatV1
10
+
11
+ module Fluent
12
+ module GoogleChatClient
13
+ # The base framework of google_chat client
14
+ class Base
15
+ SCOPE = 'https://www.googleapis.com/auth/chat.bot'.freeze
16
+
17
+ attr_accessor :log, :debug_dev
18
+ attr_reader :keyfile, :https_proxy
19
+
20
+ # @param [String] endpoint
21
+ #
22
+ # (Incoming Webhook) required
23
+ # https://hooks.slack.com/services/XXX/XXX/XXX
24
+ #
25
+ # (Slackbot) required
26
+ # https://xxxx.slack.com/services/hooks/slackbot?token=XXXXX
27
+ #
28
+ # (Web API) optional and default to be
29
+ # https://slack.com/api/
30
+ #
31
+ # @param [String] https_proxy (optional)
32
+ #
33
+ # https://proxy.foo.bar:port
34
+ #
35
+ def initialize(keyfile = nil, https_proxy = nil)
36
+ self.keyfile = keyfile if keyfile
37
+ self.https_proxy = https_proxy if https_proxy
38
+ @log = Logger.new('/dev/null')
39
+ end
40
+
41
+ ##
42
+ # Ensure valid credentials, either by restoring from the saved credentials
43
+ # files or intitiating an OAuth2 authorization. If authorization is required,
44
+ # the user's default browser will be launched to approve the request.
45
+ #
46
+ # @return [Google::Auth::UserRefreshCredentials] OAuth2 credentials
47
+ def authorize
48
+ credentials = Google::Auth::ServiceAccountCredentials.make_creds(
49
+ json_key_io: File.open(self.keyfile),
50
+ scope: SCOPE
51
+ )
52
+ credentials
53
+ end
54
+
55
+ def keyfile=(keyfile)
56
+ @keyfile = keyfile
57
+ end
58
+
59
+ def https_proxy=(https_proxy)
60
+ @https_proxy = URI.parse(https_proxy)
61
+ @proxy_class = Net::HTTP.Proxy(@https_proxy.host, @https_proxy.port)
62
+ end
63
+
64
+ def proxy_class
65
+ @proxy_class ||= Net::HTTP
66
+ end
67
+
68
+ def post(params)
69
+ chat = Chat::HangoutsChatService.new
70
+ chat.authorization = authorize
71
+ message = Chat::Message.new
72
+ message.text = params[:text]
73
+
74
+ chat.create_space_message(
75
+ 'spaces/%s' % params[:space],
76
+ message
77
+ )
78
+ end
79
+ end
80
+
81
+ # GoogleChat client
82
+ class WebApi < Base
83
+ # Sends a message to a space.
84
+ def post_message(params = {})
85
+ log.info { "out_google_chat: post_message #{params}" }
86
+ post(params)
87
+ end
88
+
89
+ private
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,24 @@
1
+ require 'net/http'
2
+
3
+ module Fluent
4
+ module GoogleChatClient
5
+ class Error < StandardError
6
+ attr_reader :res, :req_params
7
+
8
+ def initialize(res, req_params = {})
9
+ @res = res
10
+ @req_params = req_params.dup
11
+ end
12
+
13
+ def message
14
+ @req_params[:token] = '[FILTERED]' if @req_params[:token]
15
+ "res.code:#{@res.code}, res.body:#{@res.body}, req_params:#{@req_params}"
16
+ end
17
+
18
+ alias :to_s :message
19
+ end
20
+
21
+ class SpaceNotFoundError < Error; end
22
+ class NameTakenError < Error; end
23
+ end
24
+ end
@@ -0,0 +1 @@
1
+ lib/fluent/plugin/Users/lgabaude/Documents/ts/fluent-plugin-google-chat/lib/fluent/plugin/out_google
@@ -0,0 +1,171 @@
1
+ require_relative 'google_chat_client'
2
+
3
+ module Fluent
4
+ class GoogleChatOutput < Fluent::BufferedOutput
5
+ Fluent::Plugin.register_output('buffered_google_chat', self) # old version compatiblity
6
+ Fluent::Plugin.register_output('google_chat', self)
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
+
16
+ include SetTimeKeyMixin
17
+ include SetTagKeyMixin
18
+
19
+ config_set_default :include_time_key, true
20
+ config_set_default :include_tag_key, true
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 :keyfile, :string, default: nil
27
+ desc "Private key file."
28
+ config_param :https_proxy, :string, default: nil
29
+
30
+ desc "space to send messages (room id)."
31
+ config_param :space, :string, default: nil
32
+ desc <<-DESC
33
+ Keys used to format space.
34
+ %s will be replaced with value specified by space_keys if this option is used.
35
+ DESC
36
+ config_param :space_keys, default: nil do |val|
37
+ val.split(',')
38
+ end
39
+ desc <<-DESC
40
+ Message format.
41
+ %s will be replaced with value specified by message_keys.
42
+ DESC
43
+ config_param :message, :string, default: nil
44
+ desc "Keys used to format messages."
45
+ config_param :message_keys, default: nil do |val|
46
+ val.split(',')
47
+ end
48
+
49
+ desc "Include messages to the fallback attributes"
50
+ config_param :verbose_fallback, :bool, default: false
51
+
52
+ # for test
53
+ attr_reader :google_chat, :time_format, :localtime, :timef, :mrkdwn_in, :post_message_opts
54
+
55
+ def initialize
56
+ super
57
+ require 'uri'
58
+ end
59
+
60
+ def configure(conf)
61
+ conf['time_format'] ||= '%H:%M:%S' # old version compatiblity
62
+ conf['localtime'] ||= true unless conf['utc']
63
+
64
+ super
65
+
66
+ if @space
67
+ @space = URI.unescape(@space) # old version compatibility
68
+ else
69
+ raise Fluent::ConfigError.new("`space` is required")
70
+ end
71
+
72
+ if @keyfile
73
+ if @keyfile.empty?
74
+ raise Fluent::ConfigError.new("`keyfile` is an empty string")
75
+ end
76
+ if @keyfile.nil?
77
+ raise Fluent::ConfigError.new("`keyfile` parameter required for Google Chat")
78
+ end
79
+ @google_chat = Fluent::GoogleChatClient::WebApi.new(@keyfile)
80
+ else
81
+ raise Fluent::ConfigError.new("`keyfile` is required")
82
+ end
83
+ @google_chat.log = log
84
+ @google_chat.debug_dev = log.out if log.level <= Fluent::Log::LEVEL_TRACE
85
+
86
+ if @https_proxy
87
+ @google_chat.https_proxy = @https_proxy
88
+ end
89
+
90
+ @message ||= '%s'
91
+ @message_keys ||= %w[message]
92
+ begin
93
+ @message % (['1'] * @message_keys.length)
94
+ rescue ArgumentError
95
+ raise Fluent::ConfigError, "string specifier '%s' for `message` and `message_keys` specification mismatch"
96
+ end
97
+ if @space_keys
98
+ begin
99
+ @space % (['1'] * @space_keys.length)
100
+ rescue ArgumentError
101
+ raise Fluent::ConfigError, "string specifier '%s' for `space` and `space_keys` specification mismatch"
102
+ end
103
+ end
104
+ end
105
+
106
+ def format(tag, time, record)
107
+ [tag, time, record].to_msgpack
108
+ end
109
+
110
+ def write(chunk)
111
+ begin
112
+ payloads = build_payloads(chunk)
113
+ payloads.each {|payload| @google_chat.post_message(payload) }
114
+ rescue Timeout::Error => e
115
+ log.warn "out_google_chat:", :error => e.to_s, :error_class => e.class.to_s
116
+ raise e # let Fluentd retry
117
+ rescue => e
118
+ log.error "out_google_chat:", :error => e.to_s, :error_class => e.class.to_s
119
+ log.warn_backtrace e.backtrace
120
+ # discard. @todo: add more retriable errors
121
+ end
122
+ end
123
+
124
+ private
125
+
126
+ def build_payloads(chunk)
127
+ build_plain_payloads(chunk)
128
+ end
129
+
130
+ Field = Struct.new("Field", :title, :value)
131
+ # ruby 1.9.x does not provide #to_h
132
+ Field.send(:define_method, :to_h) { {title: title, value: value} }
133
+
134
+ def build_plain_payloads(chunk)
135
+ messages = {}
136
+ chunk.msgpack_each do |tag, time, record|
137
+ space = build_space(record)
138
+ messages[space] ||= ''
139
+ messages[space] << "#{build_message(record)}\n"
140
+ end
141
+ messages.map do |space, text|
142
+ msg = {text: text}
143
+ msg.merge!(space: space) if space
144
+ end
145
+ end
146
+
147
+ def build_message(record)
148
+ values = fetch_keys(record, @message_keys)
149
+ @message % values
150
+ end
151
+
152
+ def build_space(record)
153
+ return nil if @space.nil?
154
+ return @space unless @space_keys
155
+
156
+ values = fetch_keys(record, @space_keys)
157
+ @space % values
158
+ end
159
+
160
+ def fetch_keys(record, keys)
161
+ Array(keys).map do |key|
162
+ begin
163
+ record.fetch(key).to_s
164
+ rescue KeyError
165
+ log.warn "out_google_chat: the specified key '#{key}' not found in record. [#{record}]"
166
+ ''
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
data/test.sh ADDED
@@ -0,0 +1,2 @@
1
+ #!/bin/bash
2
+ echo '{"message":"message"}' | bundle exec fluent-cat tag
@@ -0,0 +1,130 @@
1
+ require_relative '../test_helper'
2
+ require 'fluent/plugin/google_chat_client'
3
+ require 'time'
4
+ require 'dotenv'
5
+ require 'webrick'
6
+ require 'webrick/httpproxy'
7
+
8
+ # HOW TO RUN
9
+ #
10
+ # Create .env file with contents as:
11
+ #
12
+ # WEBHOOK_URL=https://hooks.slack.com/services/XXXX/YYYY/ZZZZ
13
+ # SLACKBOt_URL=https://xxxx.slack.com/services/hooks/slackbot?token=XXXX
14
+ # SLACK_API_TOKEN=XXXXX
15
+ #
16
+ Dotenv.load
17
+ if ENV['WEBHOOK_URL'] and ENV['SLACKBOT_URL'] and ENV['SLACK_API_TOKEN']
18
+ class TestProxyServer
19
+ def initialize
20
+ @proxy = WEBrick::HTTPProxyServer.new(
21
+ :BindAddress => '127.0.0.1',
22
+ :Port => unused_port,
23
+ )
24
+ end
25
+
26
+ def proxy_url
27
+ "https://127.0.0.1:#{unused_port}"
28
+ end
29
+
30
+ def start
31
+ @thread = Thread.new do
32
+ @proxy.start
33
+ end
34
+ end
35
+
36
+ def shutdown
37
+ @proxy.shutdown
38
+ end
39
+
40
+ def unused_port
41
+ return @unused_port if @unused_port
42
+ s = TCPServer.open(0)
43
+ port = s.addr[1]
44
+ s.close
45
+ @unused_port = port
46
+ end
47
+ end
48
+
49
+ class GoogleChatClientTest < Test::Unit::TestCase
50
+ class << self
51
+ attr_reader :proxy
52
+
53
+ def startup
54
+ @proxy = TestProxyServer.new.tap {|proxy| proxy.start }
55
+ end
56
+
57
+ def shutdown
58
+ @proxy.shutdown
59
+ end
60
+ end
61
+
62
+ def setup
63
+ super
64
+ @api = Fluent::GoogleChatClient::WebApi.new
65
+
66
+ proxy_url = self.class.proxy.proxy_url
67
+ @api_proxy = Fluent::GoogleChatClient::WebApi.new(nil, proxy_url)
68
+ end
69
+
70
+ def default_payload(client)
71
+ {
72
+ space: 'space',
73
+ keyfile: 'xxxx.json'
74
+ }
75
+ end
76
+
77
+ def valid_utf8_encoded_string
78
+ "space \xE3\x82\xA4\xE3\x83\xB3\xE3\x82\xB9\xE3\x83\x88\xE3\x83\xBC\xE3\x83\xAB\n"
79
+ end
80
+
81
+ def invalid_ascii8bit_encoded_utf8_string
82
+ str = "space \xE3\x82\xA4\xE3\x83\xB3\xE3\x82\xB9\xE3\x83\x88\xE3\x83\xBC\xE3\x83\xAB\x81\n"
83
+ str.force_encoding(Encoding::ASCII_8BIT)
84
+ end
85
+
86
+ # Notification via Highlight Words works with only Slackbot with plain text payload
87
+ # NOTE: Please add `sowawa1` to Highlight Words
88
+ def test_post_message_plain_payload
89
+ [@api].each do |gc|
90
+ assert_nothing_raised do
91
+ gc.post_message(default_payload(gc).merge({
92
+ text: "treasuryspring\n",
93
+ }))
94
+ end
95
+ end
96
+ end
97
+
98
+ def test_post_via_proxy
99
+ [@api_proxy].each do |gc|
100
+ assert_nothing_raised do
101
+ gc.post_message(default_payload(gc).merge({
102
+ text: "treasuryspring\n"
103
+ }))
104
+ end
105
+ end
106
+ end
107
+
108
+ # IncomingWebhook posts "space インストール"
109
+ def test_post_message_utf8_encoded_text
110
+ [@incoming].each do |gc|
111
+ assert_nothing_raised do
112
+ gc.post_message(default_payload(gc).merge({
113
+ text: valid_utf8_encoded_string,
114
+ }))
115
+ end
116
+ end
117
+ end
118
+
119
+ # IncomingWebhook posts "space インストール?"
120
+ def test_post_message_ascii8bit_encoded_utf8_text
121
+ [@incoming].each do |gc|
122
+ assert_nothing_raised do
123
+ gc.post_message(default_payload(gc).merge({
124
+ text: invalid_ascii8bit_encoded_utf8_string,
125
+ }))
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,223 @@
1
+ require_relative '../test_helper'
2
+ require 'fluent/plugin/out_google_chat'
3
+ require 'time'
4
+
5
+ class GoogleChatOutputTest < Test::Unit::TestCase
6
+
7
+ def setup
8
+ super
9
+ Fluent::Test.setup
10
+ end
11
+
12
+ CONFIG = %[
13
+ space space
14
+ ]
15
+
16
+ def default_payload
17
+ {
18
+ space: 'space'
19
+ }
20
+ end
21
+
22
+ def create_driver(conf = CONFIG)
23
+ Fluent::Test::BufferedOutputTestDriver.new(Fluent::GoogleChatOutput).configure(conf)
24
+ end
25
+
26
+ # old version compatibility with v0.4.0"
27
+ def test_old_config
28
+ # default check
29
+ d = create_driver
30
+ assert_equal true, d.instance.localtime
31
+
32
+ assert_nothing_raised do
33
+ create_driver(CONFIG + %[api_key testtoken])
34
+ end
35
+
36
+ # incoming webhook endpoint was changed. team option should be ignored
37
+ assert_nothing_raised do
38
+ create_driver(CONFIG + %[team treasuryspring])
39
+ end
40
+
41
+ # rtm? it was not calling `rtm.start`. rtm option was removed and should be ignored
42
+ assert_nothing_raised do
43
+ create_driver(CONFIG + %[rtm true])
44
+ end
45
+
46
+ # channel should be URI.unescape-ed
47
+ d = create_driver(CONFIG + %[space %23test])
48
+ assert_equal 'test', d.instance.space
49
+
50
+ # timezone should work
51
+ d = create_driver(CONFIG + %[timezone Asia/Tokyo])
52
+ assert_equal 'Asia/Tokyo', d.instance.timezone
53
+ end
54
+
55
+ def test_configure
56
+ d = create_driver(%[
57
+ space space
58
+ time_format %Y/%m/%d %H:%M:%S
59
+ keyfile xxxx.json
60
+ message %s
61
+ message_keys message
62
+ ])
63
+ assert_equal 'space', d.instance.space
64
+ assert_equal '%Y/%m/%d %H:%M:%S', d.instance.time_format
65
+ assert_equal 'xxxx.json', d.instance.keyfile
66
+ assert_equal '%s', d.instance.message
67
+ assert_equal ['message'], d.instance.message_keys
68
+
69
+ # Allow DM
70
+ d = create_driver(CONFIG + %[space @test])
71
+ assert_equal '@test', d.instance.space
72
+
73
+ assert_raise(Fluent::ConfigError) do
74
+ create_driver(CONFIG + %[message %s %s\nmessage_keys foo])
75
+ end
76
+
77
+ assert_raise(Fluent::ConfigError) do
78
+ create_driver(CONFIG + %[space %s %s\nspace_keys foo])
79
+ end
80
+ end
81
+
82
+ def test_google_chat_configure
83
+ # keyfile is missing
84
+ assert_raise(Fluent::ConfigError) do
85
+ create_driver(%[space foo])
86
+ end
87
+
88
+ # keyfile is an empty string
89
+ assert_raise(Fluent::ConfigError) do
90
+ create_driver(%[space foo\nkeyfile])
91
+ end
92
+
93
+ # space is missing
94
+ assert_raise(Fluent::ConfigError) do
95
+ create_driver(%[keyfile xxxx.json])
96
+ end
97
+
98
+ # space is an empty string
99
+ assert_raise(Fluent::ConfigError) do
100
+ create_driver(%[space\nkeyfile xxxx.json])
101
+ end
102
+
103
+ # space and keyfile filled
104
+ assert_nothing_raised do
105
+ create_driver(%[space space\nkeyfile xxxx.json])
106
+ end
107
+ end
108
+
109
+ def test_timezone_configure
110
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
111
+
112
+ d = create_driver(CONFIG + %[localtime])
113
+ with_timezone('Asia/Tokyo') do
114
+ assert_equal true, d.instance.localtime
115
+ assert_equal "07:00:00", d.instance.timef.format(time)
116
+ end
117
+
118
+ d = create_driver(CONFIG + %[utc])
119
+ with_timezone('Asia/Tokyo') do
120
+ assert_equal false, d.instance.localtime
121
+ assert_equal "22:00:00", d.instance.timef.format(time)
122
+ end
123
+
124
+ d = create_driver(CONFIG + %[timezone Asia/Taipei])
125
+ with_timezone('Asia/Tokyo') do
126
+ assert_equal "Asia/Taipei", d.instance.timezone
127
+ assert_equal "06:00:00", d.instance.timef.format(time)
128
+ end
129
+ end
130
+
131
+ def test_time_format_configure
132
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
133
+
134
+ d = create_driver(CONFIG + %[time_format %Y/%m/%d %H:%M:%S])
135
+ with_timezone('Asia/Tokyo') do
136
+ assert_equal "2014/01/02 07:00:00", d.instance.timef.format(time)
137
+ end
138
+ end
139
+
140
+ def test_buffer_configure
141
+ assert_nothing_raised do
142
+ create_driver(CONFIG + %[buffer_type file\nbuffer_path tmp/])
143
+ end
144
+ end
145
+
146
+ def test_https_proxy_configure
147
+ # default
148
+ d = create_driver(CONFIG)
149
+ assert_equal nil, d.instance.slack.https_proxy
150
+ assert_equal Net::HTTP, d.instance.slack.proxy_class
151
+
152
+ # https_proxy
153
+ d = create_driver(CONFIG + %[https_proxy https://proxy.foo.bar:443])
154
+ assert_equal URI.parse('https://proxy.foo.bar:443'), d.instance.slack.https_proxy
155
+ assert_not_equal Net::HTTP, d.instance.slack.proxy_class # Net::HTTP.Proxy
156
+ end
157
+
158
+ def test_default_google_chat_api
159
+ d = create_driver(%[
160
+ space space
161
+ keyfile xxxx.json
162
+ ])
163
+ assert_equal Fluent::SlackClient::WebApi, d.instance.slack.class
164
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
165
+ d.tag = 'test'
166
+ mock(d.instance.google_chat).post_message(default_payload.merge({
167
+ text: "treasury\nspring\n",
168
+ }), {})
169
+ with_timezone('Asia/Tokyo') do
170
+ d.emit({message: 'treasury'}, time)
171
+ d.emit({message: 'spring'}, time)
172
+ d.run
173
+ end
174
+ end
175
+
176
+ def test_plain_payload
177
+ d = create_driver(CONFIG)
178
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
179
+ d.tag = 'test'
180
+ # attachments field should be changed to show the title
181
+ mock(d.instance.slack).post_message(default_payload.merge({
182
+ text: "sowawa1\nsowawa2\n",
183
+ }), {})
184
+ with_timezone('Asia/Tokyo') do
185
+ d.emit({message: 'sowawa1'}, time)
186
+ d.emit({message: 'sowawa2'}, time)
187
+ d.run
188
+ end
189
+ end
190
+
191
+ def test_message_keys
192
+ d = create_driver(CONFIG + %[message [%s] %s %s\nmessage_keys time,tag,message])
193
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
194
+ d.tag = 'test'
195
+ mock(d.instance.slack).post_message(default_payload.merge({
196
+ text: "[07:00:00] test sowawa1\n[07:00:00] test sowawa2\n",
197
+ }), {})
198
+ with_timezone('Asia/Tokyo') do
199
+ d.emit({message: 'sowawa1'}, time)
200
+ d.emit({message: 'sowawa2'}, time)
201
+ d.run
202
+ end
203
+ end
204
+
205
+ def test_space_keys
206
+ d = create_driver(CONFIG + %[space %s\nspace_keys space])
207
+ time = Time.parse("2014-01-01 22:00:00 UTC").to_i
208
+ d.tag = 'test'
209
+ mock(d.instance.slack).post_message(default_payload.merge({
210
+ space: 'space1',
211
+ text: "treasury\n",
212
+ }), {})
213
+ mock(d.instance.slack).post_message(default_payload.merge({
214
+ space: 'space2',
215
+ text: "spring\n",
216
+ }), {})
217
+ with_timezone('Asia/Tokyo') do
218
+ d.emit({message: 'treasury', space: 'space1'}, time)
219
+ d.emit({message: 'spring', space: 'space2'}, time)
220
+ d.run
221
+ end
222
+ end
223
+ end
@@ -0,0 +1,32 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ begin
5
+ Bundler.setup(:default, :development)
6
+ rescue Bundler::BundlerError => e
7
+ $stderr.puts e.message
8
+ $stderr.puts "Run `bundle install` to install missing gems"
9
+ exit e.status_code
10
+ end
11
+ require 'test/unit'
12
+ require 'test/unit/rr'
13
+
14
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
15
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
16
+ require 'fluent/test'
17
+ unless ENV.has_key?('VERBOSE')
18
+ nulllogger = Object.new
19
+ nulllogger.instance_eval {|obj|
20
+ def method_missing(method, *args)
21
+ # pass
22
+ end
23
+ }
24
+ $log = nulllogger
25
+ end
26
+
27
+ def with_timezone(tz)
28
+ oldtz, ENV['TZ'] = ENV['TZ'], tz
29
+ yield
30
+ ensure
31
+ ENV['TZ'] = oldtz
32
+ end
@@ -0,0 +1,13 @@
1
+ require './lib/fluent/plugin/google_chat_client'
2
+
3
+ # API: FluentLogger.new(tag_prefix, options)
4
+ client = Fluent::GoogleChatClient::WebApi.new("./keyfile.json")
5
+ message = {text: "Hello", space: "AAAAcmBaNCg"}
6
+ client.post(message)
7
+
8
+ client = Fluent::GoogleChatOutput.new
9
+ client.write("Hello")
10
+ # log.post('google_chat', {
11
+ # :message => 'Hello<br>World!'
12
+ # })
13
+ log.warn("some application running.")
metadata ADDED
@@ -0,0 +1,206 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-google-chat
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Lionel Gabaude
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-06-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fluentd
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.12.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.12.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: googleauth
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: google-api-client
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.34'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.34'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 10.1.1
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 10.1.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: rr
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 1.0.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 1.0.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry-nav
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: test-unit
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 3.0.2
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 3.0.2
125
+ - !ruby/object:Gem::Dependency
126
+ name: test-unit-rr
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 1.0.3
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 1.0.3
139
+ - !ruby/object:Gem::Dependency
140
+ name: dotenv
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ description: fluent Google Chat plugin
154
+ email:
155
+ - tech@treasuryspring.com
156
+ executables: []
157
+ extensions: []
158
+ extra_rdoc_files: []
159
+ files:
160
+ - ".gitignore"
161
+ - ".travis.yml"
162
+ - CHANGELOG.md
163
+ - Gemfile
164
+ - Gemfile.fluentd.0.12
165
+ - README.md
166
+ - Rakefile
167
+ - VERSION
168
+ - docker.sh
169
+ - example.conf
170
+ - fluent-plugin-google-chat.gemspec
171
+ - lib/fluent/plugin/google_chat_client.rb
172
+ - lib/fluent/plugin/google_chat_client/error.rb
173
+ - lib/fluent/plugin/out_buffered_google_chat.rb
174
+ - lib/fluent/plugin/out_google_chat.rb
175
+ - test.sh
176
+ - test/plugin/test_google_chat_client.rb
177
+ - test/plugin/test_out_google_chat.rb
178
+ - test/test_helper.rb
179
+ - todelete.rb
180
+ homepage: https://github.com/treasuryspring/fluent-plugin-google-chat
181
+ licenses:
182
+ - Apache-2.0
183
+ metadata: {}
184
+ post_install_message:
185
+ rdoc_options: []
186
+ require_paths:
187
+ - lib
188
+ required_ruby_version: !ruby/object:Gem::Requirement
189
+ requirements:
190
+ - - ">="
191
+ - !ruby/object:Gem::Version
192
+ version: '0'
193
+ required_rubygems_version: !ruby/object:Gem::Requirement
194
+ requirements:
195
+ - - ">="
196
+ - !ruby/object:Gem::Version
197
+ version: '0'
198
+ requirements: []
199
+ rubygems_version: 3.0.3
200
+ signing_key:
201
+ specification_version: 4
202
+ summary: fluent Google Chat plugin
203
+ test_files:
204
+ - test/plugin/test_google_chat_client.rb
205
+ - test/plugin/test_out_google_chat.rb
206
+ - test/test_helper.rb