fluent-plugin-ncmb 0.1.0

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: c3e2983ba819aa5da64ae6216e57190a184c7c65
4
+ data.tar.gz: 6649e8c8be26ee4d02338f4e890aa045ac332fc1
5
+ SHA512:
6
+ metadata.gz: 46c951ee79313cbe92660b726cf21197db0d73e0aebe6a055adcf32cfb0b26dfa445f73d03558bc4058beda5afba676a6c9b75feb3a1d93ffa5bbac488407816
7
+ data.tar.gz: 53fe82d9933830435f17aff6381ca777e02f5dc0c33a987b126f14b9c846d90187610bc1b7d36cc65631947fa9c1e31c3f9d388e76a2f66fea5d5e6e5b4485ed
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.gem
11
+ pos_file
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.3
4
+ before_install: gem install bundler -v 1.10.3
@@ -0,0 +1,13 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
6
+
7
+ Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
+
13
+ This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fluent-plugin-ncmb.gemspec
4
+ gem 'test-unit', '3.1.2'
5
+ gem 'fluentd', '0.12.12'
6
+ gem 'ncmb-ruby-client'
7
+ gem 'test-unit-rr', '1.0.3'
8
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 suzuki.yuta
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,51 @@
1
+ fluent-plugin-ncmb: NIFTYCloud-mbaas plugin for Fluentd
2
+ ====
3
+
4
+
5
+ ## Installation
6
+
7
+ ```
8
+ $ gem install fluent-plugin-ncmb
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### input configulation
14
+
15
+ ```
16
+ <source>
17
+ type ncmb
18
+ tag TAG
19
+ application_key YOUR_APPLICATION_KEY
20
+ client_key YOUR_CLIENT_KEY
21
+ class_name CLASS_NAME
22
+ api_version YYYY-MM-DD (default: 2013-09-01)
23
+ pos_file_path POS_FILE_PATH (default: ./pos_file)
24
+
25
+ interval [min] (default: 10)
26
+ field [field] (default: all)
27
+ start_date [YYYY-MM-DD HH:MM:SS] (default: now)
28
+ limit [limit] (default: 1000)
29
+ </source>
30
+ ```
31
+
32
+ ### output configulation
33
+
34
+ ```
35
+ <match **>
36
+ type ncmb
37
+ application_key YOUR_APPLICATION_KEY
38
+ client_key YOUR_CLIENT_KEY
39
+ api_version YYYY-MM-DD (default: 2013-09-01)
40
+ class_name CLASS_NAME
41
+
42
+ buffer_path [path]
43
+ failed_log_path [path] (defualt: /var/log/fluent/ncmb)
44
+ buffer_chunk_limit [byte] (default: 32m)
45
+ flush_interval [second] (default: 60)
46
+ </match>
47
+ ```
48
+
49
+ ### Supported Ruby Versions
50
+ - Ruby 2.1
51
+ - Ruby 2.2
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require "rake/testtask"
4
+
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
+
11
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "fluent/plugin/ncmb"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,34 @@
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-ncmb"
7
+ spec.version = "0.1.0"
8
+ spec.authors = ["suzuki.yuta", "goya.tomohiro"]
9
+ spec.email = ["suzuki.yuta@nifty.co.jp", "goya.tomohiro@nifty.co.jp"]
10
+
11
+ spec.summary = "This gem is a fluentd plugin of NiftyCloud-MobileBackend"
12
+ spec.homepage = 'http://mb.cloud.nifty.com/'
13
+ spec.license = "MIT"
14
+
15
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
16
+ # delete this section to allow pushing this gem to any host.
17
+ if spec.respond_to?(:metadata)
18
+ else
19
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
20
+ end
21
+
22
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
23
+ spec.bindir = "exe"
24
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
+ spec.require_paths = ["lib"]
26
+
27
+ spec.add_development_dependency "bundler", "~> 1.10"
28
+ spec.add_development_dependency "rake", "~> 10.0"
29
+ spec.add_development_dependency "fluentd", [">= 0.10.9", "< 2"]
30
+ spec.add_development_dependency "ncmb-ruby-client", "~> 0.1"
31
+ spec.add_development_dependency "test-unit-rr", ">= 1.0.0"
32
+ spec.add_development_dependency "pry"
33
+ spec.add_development_dependency "rb-readline"
34
+ end
@@ -0,0 +1,47 @@
1
+
2
+ module Fluent
3
+ class FilePositionEntry
4
+ require 'pathname'
5
+
6
+ def initialize(file_path)
7
+ @pos_file = file_path
8
+ end
9
+
10
+ def update_pos(pos)
11
+ return unless @pos_file
12
+
13
+ begin
14
+ f = Pathname.new(@pos_file)
15
+ f.open('wb') do |fp|
16
+ Marshal.dump({
17
+ :date => "#{pos[:date]}",
18
+ :id => "#{pos[:id]}",
19
+ }, fp)
20
+ end
21
+ rescue => e
22
+ $log.warn "Can't write pos_file #{e}"
23
+ end
24
+ end
25
+
26
+ def read_pos
27
+ min_date = "0000-01-01T00:00:00.000Z"
28
+
29
+ return unless @pos_file
30
+ f = Pathname.new(@pos_file)
31
+ unless f.exist? then
32
+ return ({:date=> min_date, :id=> ""})
33
+ end
34
+
35
+ pos = {}
36
+ begin
37
+ f.open('rb') do |_f|
38
+ pos = Marshal.load(_f)
39
+ end
40
+ rescue => e
41
+ return ({:date=> min_date, :id=> ""})
42
+ end
43
+
44
+ return (pos)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,129 @@
1
+ module Fluent
2
+ class NcmbInput < Fluent::Input
3
+ Fluent::Plugin.register_input('ncmb', self);
4
+
5
+ require 'date'
6
+ require 'ncmb'
7
+ require './lib/fluent/plugin/file_pos_entry'
8
+ include NCMB
9
+
10
+ config_param :tag, :string, :default => nil
11
+ config_param :application_key, :string, :default => nil
12
+ config_param :client_key, :string, :default => nil
13
+ config_param :class_name, :string, :default => nil
14
+ config_param :api_version, :string, :default => '2013-09-01'
15
+ config_param :pos_file_path, :string, :default => './pos_file'
16
+
17
+ config_param :interval, :integer, :default => 10
18
+ config_param :field, :string, :default => nil
19
+ config_param :start_date, :string, :default => nil
20
+ config_param :limit, :integer, :default => 1000
21
+
22
+ SORT_FIELD = "createDate,objectId"
23
+ attr_reader :pos_entry
24
+ attr_reader :last_pos
25
+
26
+ def configure(conf)
27
+ super
28
+
29
+ raise Fluent::ConfigError.new("ConfigError: Please input tag") if @tag.nil?
30
+ raise Fluent::ConfigError.new("ConfigError: Please input application_key") if @application_key.nil?
31
+ raise Fluent::ConfigError.new("ConfigError: Please input client_key") if @client_key.nil?
32
+ raise Fluent::ConfigError.new("ConfigError: Please input class_name") if @class_name.nil?
33
+ raise Fluent::ConfigError.new("ConfigError: Please input pos_file_path") if @pos_file_path.nil?
34
+
35
+ @ncmb_client = NCMB.initialize application_key: @application_key, client_key: @client_key
36
+ @pos_entry = FilePositionEntry.new(@pos_file_path)
37
+ @last_pos = @pos_entry.read_pos()
38
+
39
+ @path = "/#{@api_version}/classes/#{@class_name}"
40
+
41
+ unless @start_date.nil? then
42
+ @start_date = DateTime.parse(@start_date)
43
+ else
44
+ @start_date = DateTime.now
45
+ end
46
+ end
47
+
48
+ def start()
49
+ super;
50
+
51
+ @ncmb_thread = Thread.new(&method(:run))
52
+ end
53
+
54
+ def shutdown()
55
+ @pos_entry.update_pos(@last_pos)
56
+ @ncmb_thread.terminate()
57
+ end
58
+
59
+ def run()
60
+ loop {
61
+ loop {
62
+ records = load_records();
63
+ if records.length == 0 then
64
+ break;
65
+ end
66
+
67
+ time = Time.now.to_i;
68
+ @router.emit(@tag, time, records)
69
+ }
70
+
71
+ sleep(@interval * 60);
72
+ }
73
+ end
74
+
75
+ def load_records()
76
+ queries = {}
77
+ queries[:limit] = @limit + 1
78
+ queries[:order] = SORT_FIELD
79
+ queries[:where] = create_where_query(@start_date)
80
+
81
+ items = @ncmb_client.get @path, queries
82
+ items = remove_emitted_record(items)
83
+
84
+ if items.length > 0 then
85
+ @last_pos[:date] = items[-1][:createDate]
86
+ @last_pos[:id] = items[-1][:objectId]
87
+ end
88
+
89
+ records = []
90
+ if @field.nil? then
91
+ records = items
92
+ else
93
+ items.each do |item|
94
+ records << {@field.intern => item[@field.intern]}
95
+ end
96
+ end
97
+
98
+ return (records)
99
+ end
100
+
101
+ def remove_emitted_record(items)
102
+ result_items = []
103
+ items[:results].each do |item|
104
+ if item[:createDate] > @last_pos[:date] then
105
+ result_items << item
106
+ elsif item[:createDate] == @last_pos[:date] then
107
+ if item[:objectId] > @last_pos[:id] then
108
+ result_items << item
109
+ end
110
+ end
111
+ end
112
+
113
+ return result_items
114
+ end
115
+
116
+ def create_where_query(conf_start_date)
117
+ start_date = DateTime.parse(@last_pos[:date])
118
+ if conf_start_date > start_date then
119
+ start_date = conf_start_date
120
+ end
121
+
122
+ query = ""
123
+ start_date_str = start_date.strftime("%FT%T.%LZ")
124
+ query = "{\"createDate\": {\"$gte\": {\"__type\":\"Date\", \"iso\":\"#{start_date_str}\"}}}"
125
+
126
+ return (query)
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,101 @@
1
+ module Fluent
2
+ class NcmbOutput < Fluent::BufferedOutput
3
+ # First, register the plugin. NAME is the name of this plugin
4
+ # and identifies the plugin in the configuration file.
5
+ Fluent::Plugin.register_output('ncmb', self)
6
+
7
+ # required
8
+ config_param :application_key, :string, default: nil
9
+ config_param :client_key, :string, default: nil
10
+ config_param :class_name, :string, default: nil
11
+
12
+ config_param :api_version, :string, default: '2013-09-01'
13
+ config_param :failed_log_path, :string, default: '/var/log/fluent/ncmb_failed.log'
14
+ config_param :buffer_type, :string, default: 'file'
15
+ config_param :retry_limit, :integer, default: 3
16
+
17
+ attr_reader :ncmb
18
+
19
+ # This method is called before starting.
20
+ def configure(conf)
21
+ super
22
+
23
+ raise Fluent::ConfigError.new("ConfigError: Please input application_key") if @application_key.nil?
24
+ raise Fluent::ConfigError.new("ConfigError: Please input client_key") if @client_key.nil?
25
+ raise Fluent::ConfigError.new("ConfigError: Please input class_name") if @class_name.nil?
26
+
27
+ require 'ncmb'
28
+ @ncmb = NCMB.initialize(application_key: @application_key, client_key: @client_key)
29
+ end
30
+
31
+ # This method is called when starting.
32
+ def start
33
+ super
34
+
35
+ @path = "/#{@api_version}/classes/#{@class_name}"
36
+ @mutex = Mutex.new
37
+ end
38
+
39
+ # This method is called when shutting down.
40
+ def shutdown
41
+ super
42
+ end
43
+
44
+ def format(tag, time, record)
45
+ [tag, time, record].to_msgpack
46
+ end
47
+
48
+ def write(chunk)
49
+ records = []
50
+ failed_records = []
51
+
52
+ @mutex.lock
53
+ begin
54
+ chunk.msgpack_each do |tag, time, record|
55
+ records << [tag, time, record]
56
+ end
57
+ ensure
58
+ @mutex.unlock
59
+ end
60
+
61
+ # batchAPIの件数上限が50のため、50件毎に実行する
62
+ records.each_slice(50) do |slice|
63
+ bulk_insert(slice)
64
+ end
65
+ end
66
+
67
+ def bulk_insert(records)
68
+ requests = records.map {|tag, time, record|
69
+ {path: @path, method: :POST, body: {tag: tag, time: time, record: record}}
70
+ }
71
+ cnt = 0
72
+ while cnt < @retry_limit
73
+ begin
74
+ res = @ncmb.post("/#{@api_version}/batch", requests: requests)
75
+ rescue
76
+ # リクエストが失敗した場合
77
+ next cnt += 1
78
+ end
79
+
80
+ # レスポンスがエラーだった場合
81
+ if res.is_a?(Hash) && res.has_key?(:code)
82
+ next cnt += 1
83
+ else
84
+ return
85
+ end
86
+ end
87
+
88
+ # retry上限を超えても送信できなかった場合、送信失敗logに書き込む
89
+ write_failed_log(records)
90
+ return
91
+ end
92
+
93
+ def write_failed_log(records)
94
+ msgpack = records.map{|record| format(*record)}.to_msgpack
95
+ File.open(@failed_log_path, 'a+') do |file|
96
+ file.sync = true
97
+ file.write(msgpack)
98
+ end
99
+ end
100
+ end
101
+ end
metadata ADDED
@@ -0,0 +1,163 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-ncmb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - suzuki.yuta
8
+ - goya.tomohiro
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2015-07-22 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.10'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.10'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '10.0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '10.0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: fluentd
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: 0.10.9
49
+ - - "<"
50
+ - !ruby/object:Gem::Version
51
+ version: '2'
52
+ type: :development
53
+ prerelease: false
54
+ version_requirements: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: 0.10.9
59
+ - - "<"
60
+ - !ruby/object:Gem::Version
61
+ version: '2'
62
+ - !ruby/object:Gem::Dependency
63
+ name: ncmb-ruby-client
64
+ requirement: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.1'
69
+ type: :development
70
+ prerelease: false
71
+ version_requirements: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.1'
76
+ - !ruby/object:Gem::Dependency
77
+ name: test-unit-rr
78
+ requirement: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 1.0.0
83
+ type: :development
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 1.0.0
90
+ - !ruby/object:Gem::Dependency
91
+ name: pry
92
+ requirement: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ type: :development
98
+ prerelease: false
99
+ version_requirements: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ - !ruby/object:Gem::Dependency
105
+ name: rb-readline
106
+ requirement: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ type: :development
112
+ prerelease: false
113
+ version_requirements: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ description:
119
+ email:
120
+ - suzuki.yuta@nifty.co.jp
121
+ - goya.tomohiro@nifty.co.jp
122
+ executables: []
123
+ extensions: []
124
+ extra_rdoc_files: []
125
+ files:
126
+ - ".gitignore"
127
+ - ".travis.yml"
128
+ - CODE_OF_CONDUCT.md
129
+ - Gemfile
130
+ - LICENSE.txt
131
+ - README.md
132
+ - Rakefile
133
+ - bin/console
134
+ - bin/setup
135
+ - fluent-plugin-ncmb.gemspec
136
+ - lib/fluent/plugin/file_pos_entry.rb
137
+ - lib/fluent/plugin/in_ncmb.rb
138
+ - lib/fluent/plugin/out_ncmb.rb
139
+ homepage: http://mb.cloud.nifty.com/
140
+ licenses:
141
+ - MIT
142
+ metadata: {}
143
+ post_install_message:
144
+ rdoc_options: []
145
+ require_paths:
146
+ - lib
147
+ required_ruby_version: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ required_rubygems_version: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - ">="
155
+ - !ruby/object:Gem::Version
156
+ version: '0'
157
+ requirements: []
158
+ rubyforge_project:
159
+ rubygems_version: 2.4.5
160
+ signing_key:
161
+ specification_version: 4
162
+ summary: This gem is a fluentd plugin of NiftyCloud-MobileBackend
163
+ test_files: []