fluent-plugin-typetalk 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.
- checksums.yaml +15 -0
- data/.gitignore +20 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +13 -0
- data/README.md +68 -0
- data/Rakefile +10 -0
- data/fluent-plugin-typetalk.gemspec +24 -0
- data/lib/fluent/plugin/out_typetalk.rb +130 -0
- data/test/helper.rb +29 -0
- data/test/plugin/test_out_typetalk.rb +47 -0
- metadata +111 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
YjIwYTlmMzRhMTFhNTk5NDAxODU1ODVkYjEzOTViYTY1MGJlNTRiNA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NTRhNDIxMWNiMmEwMmViNTlkOGFmNjIyZDA4NTQ2ZDA5NThiNzczOA==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZDQ4NmQxNTZiNjYyMDdiODRmN2ViZDY0ZTdlN2MwNmFiZmUyZmQxYmVkMTRm
|
10
|
+
NjQ4NTQ4ZmIxY2I5NTAyNWZiZTc5ZDAzYTc2MDE0NjAwZGI3N2Y0MzcxYWYw
|
11
|
+
NWVlM2Y3ZGU1MDk0OGJjZjZjNDE2NzhmNjU4MTk4MGM4YTY0M2E=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YWIyYjc2YWJhMDM0ZjI0OTA1ZDdkMDAxYTc3MmNiOTI5NmVjZTY0OGU5ZWRk
|
14
|
+
ZTcxZGI2NWE3YTNmOTQ1ZTYwZTc0MDY3OTkwMGViOTE0MTE1MzE1MjMzMDZm
|
15
|
+
ZjU1MjIwMjQ3ODAwMWZkMmY3MjUwMzk3Y2Q5N2JhMTIyNGEzNzA=
|
data/.gitignore
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
.idea
|
19
|
+
vendor/bundle
|
20
|
+
test_out_typetalk_send.rb
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright (c) 2014- SOMEDA Takashi
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# fluent-plugin-typetalk
|
2
|
+
|
3
|
+
## Overview
|
4
|
+
|
5
|
+
[Fluentd](http://fluentd.org) plugin to emit notifications to Typetalk.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Install with gem or fluent-gem command as:
|
10
|
+
|
11
|
+
```
|
12
|
+
# for fluentd
|
13
|
+
$ gem install fluent-plugin-typetalk
|
14
|
+
|
15
|
+
# for td-agent
|
16
|
+
$ sudo /usr/lib64/fluent/ruby/bin/fluent-gem install fluent-plugin-typetalk
|
17
|
+
```
|
18
|
+
|
19
|
+
## Configuration
|
20
|
+
|
21
|
+
### Usage
|
22
|
+
|
23
|
+
This plugin uses client credentials for authentication. See [the developer document](http://developers.typetalk.in/oauth.html) how to get your own credential.
|
24
|
+
```
|
25
|
+
<match ...>
|
26
|
+
type typetalk
|
27
|
+
client_id YOUR_CLIENT_ID
|
28
|
+
client_secret YOUR_CLIENT_SECRET
|
29
|
+
topic_id YOUR_TOPIC_ID
|
30
|
+
</match>
|
31
|
+
```
|
32
|
+
|
33
|
+
The default output format is "<%= tag %> at <%= Time.at(time).localtime %>\n<%= record.to_json %>" and an example output is like this:
|
34
|
+
```
|
35
|
+
test at 2014-05-13 01:21:30 0900
|
36
|
+
{"message":"test1"}
|
37
|
+
```
|
38
|
+
|
39
|
+
To change output format, you can set "template" parameter as follows:
|
40
|
+
```
|
41
|
+
<match ...>
|
42
|
+
type typetalk
|
43
|
+
client_id YOUR_CLIENT_ID
|
44
|
+
client_secret YOUR_CLIENT_SECRET
|
45
|
+
topic_id YOUR_TOPIC_ID
|
46
|
+
template "Check! <%= record.to_json %>"
|
47
|
+
</match>
|
48
|
+
```
|
49
|
+
Then you'll get the output like this:
|
50
|
+
```
|
51
|
+
Check! {"message":"test1"}
|
52
|
+
```
|
53
|
+
|
54
|
+
## TODO
|
55
|
+
|
56
|
+
Pull requests are very welcome!!
|
57
|
+
|
58
|
+
## For developers
|
59
|
+
|
60
|
+
To run tests, do the following.
|
61
|
+
```
|
62
|
+
$ VERBOSE=1 bundle exec rake test
|
63
|
+
```
|
64
|
+
|
65
|
+
## Copyright
|
66
|
+
|
67
|
+
Copyright : Copyright (c) 2014- Takashi Someda (@tksmd)
|
68
|
+
License : Apache License, Version 2.0
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "fluent-plugin-typetalk"
|
7
|
+
spec.version = "0.0.1"
|
8
|
+
spec.authors = ["tksmd"]
|
9
|
+
spec.email = ["someda@isenshi.com"]
|
10
|
+
spec.description = %q{fluent plugin to send message to typetalk}
|
11
|
+
spec.summary = spec.description
|
12
|
+
spec.homepage = "https://github.com/tksmd/fluent-plugin-typetalk"
|
13
|
+
spec.license = "Apache-2.0"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
21
|
+
spec.add_development_dependency "rake"
|
22
|
+
spec.add_development_dependency "rr", ">= 1.0.0"
|
23
|
+
spec.add_runtime_dependency "fluentd"
|
24
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module Fluent
|
2
|
+
class TypetalkOutput < Fluent::BufferedOutput
|
3
|
+
Fluent::Plugin.register_output('typetalk', self)
|
4
|
+
|
5
|
+
config_param :client_id, :string
|
6
|
+
config_param :client_secret, :string
|
7
|
+
config_param :topic_id, :integer
|
8
|
+
config_param :template, :string, :default => "<%= tag %> at <%= Time.at(time).localtime %>\n<%= record.to_json %>"
|
9
|
+
config_param :flush_interval, :time, :default => 1
|
10
|
+
|
11
|
+
attr_reader :typetalk
|
12
|
+
|
13
|
+
# Define `log` method for v0.10.42 or earlier
|
14
|
+
# see http://blog.livedoor.jp/sonots/archives/36150373.html
|
15
|
+
unless method_defined?(:log)
|
16
|
+
define_method("log") { $log }
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
super
|
21
|
+
require 'erb'
|
22
|
+
end
|
23
|
+
|
24
|
+
def configure(conf)
|
25
|
+
super
|
26
|
+
@typetalk = Typetalk.new(conf['client_id'], conf['client_secret'])
|
27
|
+
end
|
28
|
+
|
29
|
+
def start
|
30
|
+
super
|
31
|
+
end
|
32
|
+
|
33
|
+
def shutdown
|
34
|
+
super
|
35
|
+
end
|
36
|
+
|
37
|
+
def format(tag, time, record)
|
38
|
+
[tag, time, record].to_msgpack
|
39
|
+
end
|
40
|
+
|
41
|
+
def write(chunk)
|
42
|
+
chunk.msgpack_each do |(tag,time,record)|
|
43
|
+
begin
|
44
|
+
send_message(tag, time, record)
|
45
|
+
rescue => e
|
46
|
+
log.error("out_typetalk:", :error_class => e.class, :error => e.message)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def send_message(tag, time, record)
|
52
|
+
message = ERB.new(@template).result(binding)
|
53
|
+
@typetalk.post(@topic_id, message)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
class Typetalk
|
59
|
+
|
60
|
+
def initialize(client_id, client_secret)
|
61
|
+
require 'net/http'
|
62
|
+
require 'uri'
|
63
|
+
require 'json'
|
64
|
+
|
65
|
+
@client_id = client_id
|
66
|
+
@client_secret = client_secret
|
67
|
+
|
68
|
+
@http = Net::HTTP.new('typetalk.in', 443)
|
69
|
+
@http.use_ssl = true
|
70
|
+
end
|
71
|
+
|
72
|
+
def post(topic_id, message)
|
73
|
+
check_token()
|
74
|
+
$log.debug("Typetalk access_token : #{@access_token}")
|
75
|
+
|
76
|
+
res = @http.post(
|
77
|
+
"/api/v1/topics/#{topic_id}",
|
78
|
+
"message=#{message}",
|
79
|
+
{ 'Authorization' => "Bearer #{@access_token}" }
|
80
|
+
)
|
81
|
+
|
82
|
+
# todo: handling 429
|
83
|
+
unless res and res.is_a?(Net::HTTPSuccess)
|
84
|
+
raise TypetalkError, "failed to post to typetalk.in, code: #{res && res.code}"
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
def check_token
|
90
|
+
|
91
|
+
if @access_token.nil?
|
92
|
+
update_token()
|
93
|
+
elsif Time.now >= @expires
|
94
|
+
update_token(true)
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
def update_token(refresh = false)
|
100
|
+
params = "client_id=#{@client_id}&client_secret=#{@client_secret}"
|
101
|
+
unless refresh
|
102
|
+
params << "&grant_type=client_credentials&scope=topic.post"
|
103
|
+
else
|
104
|
+
params << "&grant_type=refresh_token&refresh_token=#{@refresh_token}"
|
105
|
+
end
|
106
|
+
|
107
|
+
res = @http.post(
|
108
|
+
"/oauth2/access_token",
|
109
|
+
params
|
110
|
+
)
|
111
|
+
|
112
|
+
if res.is_a?(Net::HTTPUnauthorized)
|
113
|
+
raise TypetalkError, "invalid credentials used. check client_id and client_secret in your configuration."
|
114
|
+
end
|
115
|
+
|
116
|
+
unless res.is_a?(Net::HTTPSuccess)
|
117
|
+
raise TypetalkError, "unexpected error occured in getting access_token, code: #{res && res.code}"
|
118
|
+
end
|
119
|
+
|
120
|
+
json = JSON.parse(res.body)
|
121
|
+
@expires = Time.now + json['expires_in'].to_i
|
122
|
+
@refresh_token = json['refresh_token']
|
123
|
+
@access_token = json['access_token']
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
class TypetalkError < RuntimeError; end
|
129
|
+
|
130
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
require 'rr'
|
12
|
+
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
|
+
require 'fluent/test'
|
16
|
+
unless ENV.has_key?('VERBOSE')
|
17
|
+
nulllogger = Object.new
|
18
|
+
nulllogger.instance_eval {|obj|
|
19
|
+
def method_missing(method, *args)
|
20
|
+
# pass
|
21
|
+
end
|
22
|
+
}
|
23
|
+
$log = nulllogger
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'fluent/plugin/out_typetalk'
|
27
|
+
|
28
|
+
class Test::Unit::TestCase
|
29
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'helper'
|
4
|
+
|
5
|
+
class TypetalkOutputTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
Fluent::Test.setup
|
9
|
+
end
|
10
|
+
|
11
|
+
CONFIG = %[
|
12
|
+
type typetalk
|
13
|
+
client_id 123456
|
14
|
+
client_secret secret
|
15
|
+
topic_id 1
|
16
|
+
template <%= record.to_json %>
|
17
|
+
]
|
18
|
+
|
19
|
+
def create_driver(conf = CONFIG, tag = 'test')
|
20
|
+
Fluent::Test::BufferedOutputTestDriver.new(Fluent::TypetalkOutput, tag).configure(conf)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_configure
|
24
|
+
d = create_driver()
|
25
|
+
assert_equal d.instance.typetalk.instance_variable_get(:@client_id), '123456'
|
26
|
+
assert_equal d.instance.typetalk.instance_variable_get(:@client_secret), 'secret'
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_write
|
30
|
+
d = create_driver()
|
31
|
+
stub(d.instance.typetalk).post(1, '{"message":"test1"}')
|
32
|
+
d.emit({'message' => 'test1'})
|
33
|
+
d.run()
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_template
|
37
|
+
d = create_driver(CONFIG, 'warn')
|
38
|
+
d.instance.template = "<%= tag %> at <%= Time.at(time).localtime %>\n<%= record.to_json %>"
|
39
|
+
stub(d.instance.typetalk).post(1, "warn at 2014-05-13 01:05:38 +0900\n{\"message\":\"test1\"}")
|
40
|
+
|
41
|
+
ENV["TZ"]="Asia/Tokyo"
|
42
|
+
t = Time.strptime('2014-05-13 01:05:38', '%Y-%m-%d %T')
|
43
|
+
d.emit({'message' => 'test1'}, t)
|
44
|
+
d.run()
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fluent-plugin-typetalk
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- tksmd
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
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: rr
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.0.0
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.0.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: fluentd
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: fluent plugin to send message to typetalk
|
70
|
+
email:
|
71
|
+
- someda@isenshi.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- Gemfile
|
78
|
+
- LICENSE.txt
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- fluent-plugin-typetalk.gemspec
|
82
|
+
- lib/fluent/plugin/out_typetalk.rb
|
83
|
+
- test/helper.rb
|
84
|
+
- test/plugin/test_out_typetalk.rb
|
85
|
+
homepage: https://github.com/tksmd/fluent-plugin-typetalk
|
86
|
+
licenses:
|
87
|
+
- Apache-2.0
|
88
|
+
metadata: {}
|
89
|
+
post_install_message:
|
90
|
+
rdoc_options: []
|
91
|
+
require_paths:
|
92
|
+
- lib
|
93
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ! '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ! '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
requirements: []
|
104
|
+
rubyforge_project:
|
105
|
+
rubygems_version: 2.2.2
|
106
|
+
signing_key:
|
107
|
+
specification_version: 4
|
108
|
+
summary: fluent plugin to send message to typetalk
|
109
|
+
test_files:
|
110
|
+
- test/helper.rb
|
111
|
+
- test/plugin/test_out_typetalk.rb
|