fluent-plugin-deskcom 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5641dbda7a204f52d882965061aea9a383f83730
4
+ data.tar.gz: 9170d67ca166201d7bc734efec235d927c92a017
5
+ SHA512:
6
+ metadata.gz: 9057d3893407ec129cc8cf68f6280fb329ce1578c51628085ac5c19bc61a5f2dc970c28ec47d6414fe0ca05529522fe9894e3fee4f24ce2c3363f03a0384f0aa
7
+ data.tar.gz: 3ccee42a011fa0a5c40fb3c3890c8808b0bcde0a52b971764746303757749750bccb5f061017660763553a1fccf06adc706341ab5504d50e742c17e1b70777db
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /.idea/
11
+ *.bundle
12
+ *.so
13
+ *.o
14
+ *.a
15
+ *.gem
16
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fluent-plugin-deskcom.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Toru Takahashi
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,170 @@
1
+ Deskcom plugin for Fluentd
2
+ ===========================
3
+
4
+ Fluentd Input plugin to collect data from Your Deskcom.
5
+ It is useful to improve your support quality.
6
+ This plugin is still experimental.
7
+ This plugin depends on [desk library](https://github.com/chriswarren/desk)
8
+ Also, please see [Desk API v2](http://dev.desk.com/)
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'fluent-plugin-deskcom'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install fluent-plugin-deskcom
25
+
26
+ ## Usage
27
+
28
+ ### Cases Config Sample
29
+
30
+ ```ruby
31
+ <source>
32
+ type deskcom
33
+ subdomain DESKCOM_SUBDOMAIN # Required (<subdomain>.desk.com)
34
+ consumer_key DESKCOM_CONSUMER_KEY # Required
35
+ consumer_secret DESKCOM_CONSUMER_SECRET # Required
36
+ oauth_token DESKCOM_OAUTH_TOKEN # Required
37
+ oauth_token_secret DESKCOM_OAUTH_TOKEN_SECRET # Required
38
+ store_file /var/log/cases.yml # Optional (filepath)
39
+ output_format simple # Optional (simple(default))
40
+ input_api cases # Optional (cases(default) or replies)
41
+ tag deskcom.cases # Required
42
+ time_format updated_at # Optional
43
+ </source>
44
+ ```
45
+
46
+ ```ruby
47
+ {
48
+ "id": 150,
49
+ "blurb": ": "",
50
+ "priority": 4,
51
+ "external_id": null,
52
+ "locked_until": null,
53
+ "label_ids": [],
54
+ "active_at": null,
55
+ "changed_at": "2013-02-10T14:18:56Z",
56
+ "created_at": "2013-01-15T11:12:20Z",
57
+ "updated_at": "2013-02-10T14:18:56Z",
58
+ "first_opened_at": null,
59
+ "opened_at": null,
60
+ "first_resolved_at": "2013-01-27T13:54:13Z",
61
+ "resolved_at": "2013-01-27T13:54:13Z",
62
+ "status": "closed",
63
+ "description": null,
64
+ "language": null,
65
+ "received_at": "2013-01-15T11:12:20Z",
66
+ "type": "email",
67
+ "labels": [],
68
+ "subject": "Chat transcript: no operator and Japan #6642",
69
+ "custom_fields": "{\"custom1_\":null,\"custom2_\":null}"
70
+ }
71
+ ```
72
+
73
+ ### Replies Config Sample
74
+
75
+ ```ruby
76
+ <source>
77
+ type deskcom
78
+ subdomain DESKCOM_SUBDOMAIN # Required (<subdomain>.desk.com)
79
+ consumer_key DESKCOM_CONSUMER_KEY # Required
80
+ consumer_secret DESKCOM_CONSUMER_SECRET # Required
81
+ oauth_token DESKCOM_OAUTH_TOKEN # Required
82
+ oauth_token_secret DESKCOM_OAUTH_TOKEN_SECRET # Required
83
+ store_file /var/log/replies.yml # Optional (filepath)
84
+ output_format simple # Optional (simple(default))
85
+ input_api replies # Optional (cases(default) or replies)
86
+ tag deskcom.replies # Required
87
+ </source>
88
+ ```
89
+
90
+ ```ruby
91
+ {
92
+ "case_id": 1
93
+ "id": 159057281,
94
+ "created_at": "2013-01-14T22:18:14Z",
95
+ "updated_at": "2013-01-14T22:18:14Z",
96
+ "sent_at": null,
97
+ "erased_at": null,
98
+ "hidden_by": null,
99
+ "hidden_at": null,
100
+ "body": "",
101
+ "from": "Toru Takahashi <torutakahashi.ayashi@gmail.com>",
102
+ "to": "\"test user\" <test@user.co.jp>",
103
+ "cc": "",
104
+ "bcc": null,
105
+ "client_type": "apple_mail",
106
+ "direction": "in",
107
+ "status": "received",
108
+ "subject": "subject",
109
+ "hidden": false
110
+ }
111
+ ```
112
+
113
+ ### Config Sample (Deskcom -> TreasureData)
114
+
115
+ ```ruby
116
+ # fluent.conf
117
+ <source>
118
+ type deskcom
119
+ subdomain DESKCOM_SUBDOMAIN # Required (<subdomain>.desk.com)
120
+ consumer_key DESKCOM_CONSUMER_KEY # Required
121
+ consumer_secret DESKCOM_CONSUMER_SECRET # Required
122
+ oauth_token DESKCOM_OAUTH_TOKEN # Required
123
+ oauth_token_secret DESKCOM_OAUTH_TOKEN_SECRET # Required
124
+ store_file /var/log/cases.yml # Optional (filepath)
125
+ output_format simple # Optional (simple(default))
126
+ input_api cases # Optional (cases(default) or replies)
127
+ tag deskcom.cases # Required
128
+ time_column updated_at
129
+ </source>
130
+
131
+ <source>
132
+ type deskcom
133
+ subdomain DESKCOM_SUBDOMAIN # Required (<subdomain>.desk.com)
134
+ consumer_key DESKCOM_CONSUMER_KEY # Required
135
+ consumer_secret DESKCOM_CONSUMER_SECRET # Required
136
+ oauth_token DESKCOM_OAUTH_TOKEN # Required
137
+ oauth_token_secret DESKCOM_OAUTH_TOKEN_SECRET # Required
138
+ store_file /var/log/replies.yml # Optional (filepath)
139
+ output_format simple # Optional (simple(default))
140
+ input_api replies # Optional (cases(default) or replies)
141
+ tag deskcom.replies # Required
142
+ time_column created_at
143
+ </source>
144
+
145
+ <match **>
146
+ type tdlog
147
+ apikey TREASUREDATA_API_KEY
148
+
149
+ auto_create_table
150
+ buffer_path /var/log/td-agent/tdlog
151
+ </match>
152
+ ```
153
+
154
+ Please check store_file's permission to write by fluentd.
155
+
156
+ ## TO DO
157
+
158
+ - Allows over 2 input_api (Ex. input_api cases,replies)
159
+ - Add other input_api
160
+ - Add Rate Limits
161
+ - Add feature to remind last collect cases or replies when forced termination.
162
+
163
+ ## Copyright
164
+
165
+ Copyright (c) 2014 Toru Takahashi
166
+
167
+ ## License
168
+
169
+ MIT License
170
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake/testtask'
4
+ Rake::TestTask.new(:test) do |test|
5
+ test.libs << 'lib' << 'test'
6
+ test.pattern = 'test/**/test_*.rb'
7
+ test.verbose = true
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "fluent-plugin-deskcom"
6
+ spec.version = "0.0.1"
7
+ spec.authors = ["Toru Takahashi"]
8
+ spec.email = ["torutakahashi.ayashi@gmail.com"]
9
+ spec.summary = %q{Input plugin to collect data from Deskcom.}
10
+ spec.description = %q{fluent Input plugin to collect data from Deskcom.}
11
+ spec.homepage = "https://github.com/toru-takahashi/fluent-plugin-deskcom"
12
+ spec.license = "MIT"
13
+
14
+ spec.files = `git ls-files`.split("\n")
15
+ spec.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ spec.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_development_dependency "bundler", "~> 1.7"
20
+ spec.add_development_dependency "rake", "~> 10.0"
21
+ spec.add_runtime_dependency "fluentd"
22
+ spec.add_runtime_dependency "desk"
23
+ end
@@ -0,0 +1,167 @@
1
+ module Fluent
2
+ class DeskcomInput < Fluent::Input
3
+ Fluent::Plugin.register_input('deskcom', self)
4
+
5
+ # un-support yet: nest flat
6
+ OUTPUT_FORMAT_TYPE = %w(simple)
7
+ # un-support yet: brand article reply ~
8
+ INPUT_API_TYPE = %w(cases replies)
9
+ DEFAULT_PER_PAGE = 50
10
+
11
+ config_param :subdomain, :string, :default => nil
12
+ config_param :consumer_key, :string, :default => nil
13
+ config_param :consumer_secret, :string, :default => nil
14
+ config_param :oauth_token, :string, :default => nil
15
+ config_param :oauth_token_secret, :string, :default => nil
16
+ config_param :store_file, :string, :default => nil
17
+ config_param :output_format, :string, :default => 'simple'
18
+ config_param :input_api, :string, :default => 'cases'
19
+ config_param :tag, :string, :default => nil
20
+ config_param :time_column, :string, :default => nil
21
+
22
+ def initialize
23
+ super
24
+ require 'desk'
25
+ require 'yaml'
26
+ require 'pathname'
27
+ end
28
+
29
+
30
+ def configure(conf)
31
+ super
32
+ if !OUTPUT_FORMAT_TYPE.include?(@output_format)
33
+ raise Fluent::ConfigError, "output_format value undefined #{@output_format}"
34
+ end
35
+
36
+ if !INPUT_API_TYPE.include?(@input_api)
37
+ raise Fluent::ConfigError, "input_api value undefined #{@input_api}"
38
+ end
39
+
40
+ if !@consumer_key || !@consumer_secret || !@oauth_token || !@oauth_token_secret
41
+ raise Fluent::ConfigError, "missing values in consumer_key or consumer_secret or oauth_token or oauth_token_secret"
42
+ end
43
+
44
+ if !@store_file
45
+ $log.warn("stored_time_file path is missing")
46
+ end
47
+
48
+
49
+ @stored_time = load_store_file
50
+ @started_time = Time.now.to_i
51
+ @per_page = DEFAULT_PER_PAGE
52
+
53
+ Desk.configure do |config|
54
+ config.subdomain = @subdomain
55
+ config.consumer_key = @consumer_key
56
+ config.consumer_secret = @consumer_secret
57
+ config.oauth_token = @oauth_token
58
+ config.oauth_token_secret = @oauth_token_secret
59
+ end
60
+ end
61
+
62
+ def start
63
+ super
64
+ @thread = Thread.new(&method(:run))
65
+ end
66
+
67
+ def shutdown
68
+ @thread.kill
69
+ end
70
+
71
+ def run
72
+ page = 1
73
+ if @input_api == 'cases' then
74
+ begin
75
+ cases = Desk.cases(:since_updated_at => @stored_time, :page => page, :per_page => @per_page)
76
+ cases.each do |c|
77
+ get_content(c)
78
+ end
79
+ page = page + 1
80
+ end while cases.total_entries > (@per_page*page)
81
+ elsif @input_api == 'replies'
82
+ begin
83
+ cases = Desk.cases(:since_updated_at => @stored_time, :page => page, :per_page => @per_page)
84
+ cases.each do |c|
85
+ Desk.case_replies(c.id).each do |r|
86
+ r[:case_id] = c.id
87
+ get_content(r) if c.count > 0
88
+ end
89
+ end
90
+ page = page + 1
91
+ end while cases.total_entries > (@per_page*page)
92
+ end
93
+ save_store_file unless !@store_file
94
+ rescue => e
95
+ $log.error "deskcom run: #{e.message}"
96
+ end
97
+
98
+ def get_content(status)
99
+ case @output_format
100
+ when 'simple'
101
+ record = Hash.new
102
+ status.each_pair do |k,v|
103
+ # @stored_time <= store data's updated time < @started_time
104
+ if (k == 'updated_at') then
105
+ at_time = Time.parse(v).to_i
106
+ if (at_time >= @started_time) || (at_time < @stored_time) then
107
+ next
108
+ end
109
+ end
110
+
111
+ if (!@time_column.nil? && k == "#{@time_column}") then
112
+ @time_value = Time.parse(v).to_i rescue nil
113
+ end
114
+
115
+ if (k == '_links') then
116
+ next
117
+ end
118
+
119
+ if v.kind_of? Hashie::Deash then
120
+ record.store(k, v.to_json)
121
+ else
122
+ record.store(k, v)
123
+ end
124
+ end
125
+ end
126
+
127
+ if !@time_value.nil? then
128
+ Engine.emit(@tag, @time_value, record)
129
+ else
130
+ Engine.emit(@tag, @started_time, record)
131
+ end
132
+ rescue => e
133
+ $log.error "deskcom get_content: #{e.message}"
134
+ end
135
+
136
+ # => int
137
+ def load_store_file
138
+ begin
139
+ f = Pathname.new(@store_file)
140
+ stored_time = 0
141
+ f.open('r') do |f|
142
+ stored = YAML.load_file(f)
143
+ stored_time = stored[:time].to_i
144
+ end
145
+ $log.info "deskcom: Load #{@store_file}: #{@stored_time}"
146
+ rescue => e
147
+ $log.warn "deskcom: Can't load store_file #{e.message}"
148
+ return 0
149
+ end
150
+ return stored_time
151
+ end
152
+
153
+ def save_store_file
154
+ begin
155
+ f = Pathname.new(@store_file)
156
+ f.open('w') do |f|
157
+ data = {:time => @started_time}
158
+ YAML.dump(data, f)
159
+ end
160
+ $log.info "deskcom: Save started_time: #{@started_time} to #{@store_file}"
161
+ rescue => e
162
+ $log.warn "deskcom: Can't save store_file #{e.message}"
163
+ end
164
+ end
165
+
166
+ end
167
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,28 @@
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
+
12
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
13
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
14
+ require 'fluent/test'
15
+ unless ENV.has_key?('VERBOSE')
16
+ nulllogger = Object.new
17
+ nulllogger.instance_eval {|obj|
18
+ def method_missing(method, *args)
19
+ # pass
20
+ end
21
+ }
22
+ $log = nulllogger
23
+ end
24
+
25
+ require 'fluent/plugin/in_deskcom'
26
+
27
+ class Test::Unit::TestCase
28
+ end
@@ -0,0 +1,41 @@
1
+ require 'helper'
2
+
3
+ class DeskcomInputTest < Test::Unit::TestCase
4
+ def setup
5
+ Fluent::Test.setup
6
+ end
7
+
8
+ CONFIG = %[
9
+ subdomain SUBDOMAIN
10
+ consumer_key CONSUMER_KEY
11
+ consumer_secret CONSUMER_SECRET
12
+ oauth_token OAUTH_TOKEN
13
+ oauth_token_secret OAUTH_TOKEN_SECRET
14
+ store_file /tmp/pos.yml
15
+ output_format simple
16
+ input_api cases
17
+ tag deskcom.cases
18
+ ]
19
+
20
+ def create_driver(conf=CONFIG, tag='test', use_v1=false)
21
+ Fluent::Test::InputTestDriver.new(Fluent::DeskcomInput).configure(conf, use_v1)
22
+ end
23
+
24
+ def test_configure
25
+ d = create_driver
26
+
27
+ assert_equal 'SUBDOMAIN', d.instance.subdomain
28
+ assert_equal 'CONSUMER_KEY', d.instance.consumer_key
29
+ assert_equal 'CONSUMER_SECRET', d.instance.consumer_secret
30
+ assert_equal 'OAUTH_TOKEN', d.instance.oauth_token
31
+ assert_equal 'OAUTH_TOKEN_SECRET', d.instance.oauth_token_secret
32
+ assert_equal '/tmp/pos.yml', d.instance.store_file
33
+ assert_equal 'simple', d.instance.output_format
34
+ assert_equal 'cases', d.instance.input_api
35
+ assert_equal 'deskcom.cases', d.instance.tag
36
+ end
37
+
38
+ def test_get_content
39
+ # TO DO: write actual code
40
+ end
41
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-deskcom
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Toru Takahashi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-02 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.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: fluentd
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: desk
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 Input plugin to collect data from Deskcom.
70
+ email:
71
+ - torutakahashi.ayashi@gmail.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-deskcom.gemspec
82
+ - lib/fluent/plugin/in_deskcom.rb
83
+ - test/helper.rb
84
+ - test/plugin/test_in_deskcom.rb
85
+ homepage: https://github.com/toru-takahashi/fluent-plugin-deskcom
86
+ licenses:
87
+ - MIT
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.0.14
106
+ signing_key:
107
+ specification_version: 4
108
+ summary: Input plugin to collect data from Deskcom.
109
+ test_files:
110
+ - test/helper.rb
111
+ - test/plugin/test_in_deskcom.rb