fluent-plugin-google-chat 0.0.1

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.
@@ -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