fluent-plugin-amplitude 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 +7 -0
- data/.gitignore +1 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +78 -0
- data/Rakefile +14 -0
- data/fluent-plugin-amplitude.gemspec +28 -0
- data/lib/fluent/plugin/out_amplitude.rb +130 -0
- data/spec/out_amplitude_spec.rb +191 -0
- data/spec/spec_helper.rb +13 -0
- metadata +178 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 757d43474f5a6517ea2efdd15f43655fd6ca3edd
|
|
4
|
+
data.tar.gz: 7be8f650adad1bd3565391b92cf970fcc0db223f
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 1c307bc96c613dca51aed3360b2bde8871e16685dd84bb3c00db8e00960dadadc9bb89075a9f729188ecafc9325fa41a23c031cd769b0ac018489f753044860d
|
|
7
|
+
data.tar.gz: e6f941184f8d4deb9d57d7cf9674fac275d6ff99815e4993ed1776ce265a2c79346b80009e2a6a0fc086db4fd9d448559c80f40edd8d752c842fac49792d44e0
|
data/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Gemfile.lock
|
data/Gemfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2016 Vijay Ramesh <vijay@change.org>
|
|
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,78 @@
|
|
|
1
|
+
# fluent-plugin-amplitude
|
|
2
|
+
Output plugin for [Fluentd](http://fluentd.org) to [Amplitude](https://amplitude.com/)
|
|
3
|
+
|
|
4
|
+
This plugin uses the [amplitude-api](https://github.com/toothrot/amplitude-api) gem, which itself talks to Amplitude's [HTTP API](https://amplitude.zendesk.com/hc/en-us/articles/204771828-HTTP-API).
|
|
5
|
+
|
|
6
|
+
## Installation
|
|
7
|
+
Install with gem or fluent-gem command as:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# for fluentd
|
|
11
|
+
$ gem install fluent-plugin-amplitude
|
|
12
|
+
|
|
13
|
+
# for td-agent
|
|
14
|
+
$ sudo /usr/lib64/fluent/ruby/bin/fluent-gem install fluent-plugin-amplitude
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Configuration
|
|
18
|
+
|
|
19
|
+
#### Example configuration
|
|
20
|
+
```xml
|
|
21
|
+
<match output.amplitude.*>
|
|
22
|
+
@type amplitude
|
|
23
|
+
api_key XXXXXX
|
|
24
|
+
user_id_key user_id
|
|
25
|
+
device_id_key uuid
|
|
26
|
+
user_properties first_name, last_name
|
|
27
|
+
event_properties current_source
|
|
28
|
+
properties_blacklist user
|
|
29
|
+
events_whitelist petition_view, petition_share
|
|
30
|
+
flush_interval 5s
|
|
31
|
+
retry_limit 2
|
|
32
|
+
remove_tag_prefix output.amplitude.
|
|
33
|
+
<secondary>
|
|
34
|
+
@type file
|
|
35
|
+
path /var/log/fluent/forward-failed
|
|
36
|
+
</secondary>
|
|
37
|
+
</match>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
#### api_key
|
|
41
|
+
AmplitudeOutput needs your Amplitude `api_key` ([see Amplitude for more information](https://amplitude.zendesk.com/hc/en-us/articles/206728448-Where-can-I-find-my-app-s-API-Key-or-Secret-Key-))
|
|
42
|
+
|
|
43
|
+
#### user_id_key and device_id_key
|
|
44
|
+
You must set at least one of `user_id_key` and `device_id_key`. They will be used to pull out the `user_id` and `device_id` values from the record to send to the Amplitude API.
|
|
45
|
+
|
|
46
|
+
#### user_properties and event_properties
|
|
47
|
+
You can optionally specify lists of `user_properties` and `event_properties` to pull from the record.
|
|
48
|
+
|
|
49
|
+
If `user_properties` are specified, only those properties will be included as `user_properties` in the Amplitude API call. Otherwise no `user_properties` will be sent.
|
|
50
|
+
|
|
51
|
+
If `event_properties` are specified, only those properties will be included as `event_properties` in the Amplitude API call. Otherwise the entire record (minus the key/value for `user_id_key` and `device_id_key`, and minus any `user_properties`) will be sent as `event_properties` to Amplitude.
|
|
52
|
+
|
|
53
|
+
#### event type
|
|
54
|
+
The event_type is the tag. To modify this, fluent-plugin-amplitude includes the `HandleTagNameMixin` mixin which allows the following options:
|
|
55
|
+
|
|
56
|
+
```xml
|
|
57
|
+
remove_tag_prefix <tag_prefix_to_remove_including_the_dot>
|
|
58
|
+
remove_tag_suffix <tag_suffix_to_remove_including_the_dot>
|
|
59
|
+
add_tag_prefix <tag_prefix_to_add_including_the_dot>
|
|
60
|
+
add_tag_suffix <tag_suffix_to_add_including_the_dot>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
#### properties_blacklist
|
|
64
|
+
Any properties included in the blacklist will be scrubbed from the record.
|
|
65
|
+
|
|
66
|
+
#### events_whitelist
|
|
67
|
+
If your `<match>` is using a wildcard, you can specify specific events to whitelist. If the `events_whitelist` is empty all events will be sent to Amplitude. Note the event name here is the `event_type` (so should not include, e.g., any prefixes that were removed via `remove_tag_prefix`)
|
|
68
|
+
|
|
69
|
+
#### Error handling
|
|
70
|
+
Any error will result in the message retrying. In the case of an incorrectly configured API key, this can result in the messages infinitely retrying. You should set the normal [buffered output plugin options](http://docs.fluentd.org/articles/buffer-plugin-overview) to prevent this (and to preserve data in the case of misconfigured records failing to be submitted to Amplitude).
|
|
71
|
+
|
|
72
|
+
## Contributing
|
|
73
|
+
|
|
74
|
+
1. Fork it ( http://github.com/change/fluent-plugin-amplitude/fork )
|
|
75
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
76
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
77
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
78
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require 'bundler/gem_tasks'
|
|
2
|
+
require 'rubocop/rake_task'
|
|
3
|
+
|
|
4
|
+
RuboCop::RakeTask.new
|
|
5
|
+
|
|
6
|
+
begin
|
|
7
|
+
require 'rspec/core/rake_task'
|
|
8
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
9
|
+
rescue LoadError
|
|
10
|
+
puts 'Unable to load rspec. Have you run `bundle install`?'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
task(:default).clear
|
|
14
|
+
task default: ['rubocop:auto_correct', :spec]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# -*- encoding: 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-amplitude'
|
|
7
|
+
spec.version = '0.0.1'
|
|
8
|
+
spec.authors = ['Vijay Ramesh']
|
|
9
|
+
spec.email = ['vijay@change.org']
|
|
10
|
+
spec.summary = 'Fluentd plugin to output event data to Amplitude'
|
|
11
|
+
spec.description = 'Fluentd plugin to output event data to Amplitude'
|
|
12
|
+
spec.homepage = 'https://github.com/change/fluent-plugin-amplitude'
|
|
13
|
+
|
|
14
|
+
spec.files = `git ls-files -z`.split("\x0")
|
|
15
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
16
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
17
|
+
spec.require_paths = ['lib']
|
|
18
|
+
|
|
19
|
+
spec.add_runtime_dependency 'fluentd', '>= 0.10.55'
|
|
20
|
+
spec.add_runtime_dependency 'amplitude-api', '~> 0.0.9'
|
|
21
|
+
spec.add_runtime_dependency 'msgpack', '~> 1.0', '>= 1.0.2'
|
|
22
|
+
|
|
23
|
+
spec.add_development_dependency 'rake', '~> 11.3'
|
|
24
|
+
spec.add_development_dependency 'rspec', '~> 3.5'
|
|
25
|
+
spec.add_development_dependency 'test-unit', '~> 3.2', '>= 3.2.1'
|
|
26
|
+
spec.add_development_dependency 'rspec-mocks', '~> 3.5'
|
|
27
|
+
spec.add_development_dependency 'rubocop', '~> 0.44.1'
|
|
28
|
+
end
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
module Fluent
|
|
2
|
+
# Fluent::AmplitudeOutput plugin
|
|
3
|
+
class AmplitudeOutput < Fluent::BufferedOutput
|
|
4
|
+
Fluent::Plugin.register_output('amplitude', self)
|
|
5
|
+
|
|
6
|
+
include Fluent::HandleTagNameMixin
|
|
7
|
+
|
|
8
|
+
config_param :api_key, :string, secret: true
|
|
9
|
+
config_param :device_id_key, :string
|
|
10
|
+
config_param :user_id_key, :string
|
|
11
|
+
config_param :user_properties, :array, default: nil
|
|
12
|
+
config_param :event_properties, :array, default: nil
|
|
13
|
+
config_param :properties_blacklist, :array, default: nil
|
|
14
|
+
config_param :events_whitelist, :array, default: nil
|
|
15
|
+
class AmplitudeError < StandardError
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def initialize
|
|
19
|
+
super
|
|
20
|
+
require 'amplitude-api'
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def configure(conf)
|
|
24
|
+
super
|
|
25
|
+
raise Fluent::ConfigError, "'api_key' must be specified." if @api_key.nil?
|
|
26
|
+
|
|
27
|
+
invalid = @device_id_key.nil? && @user_id_key.nil?
|
|
28
|
+
raise Fluent::ConfigError,
|
|
29
|
+
"'device_id_key' or 'user_id_key' must be specified." if invalid
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def start
|
|
33
|
+
super
|
|
34
|
+
AmplitudeAPI.api_key = @api_key
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def format(tag, time, record)
|
|
38
|
+
return if @events_whitelist && !@events_whitelist.include?(tag)
|
|
39
|
+
|
|
40
|
+
amplitude_hash = { event_type: tag }
|
|
41
|
+
|
|
42
|
+
filter_properties_blacklist!(record)
|
|
43
|
+
extract_user_and_device_or_fail!(amplitude_hash, record)
|
|
44
|
+
extract_user_properties!(amplitude_hash, record)
|
|
45
|
+
extract_event_properties!(amplitude_hash, record)
|
|
46
|
+
|
|
47
|
+
[tag, time, amplitude_hash].to_msgpack
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def write(chunk)
|
|
51
|
+
records = []
|
|
52
|
+
chunk.msgpack_each do |_tag, _time, record|
|
|
53
|
+
records << AmplitudeAPI::Event.new(simple_symbolize_keys(record))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
send_to_amplitude(records)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def filter_properties_blacklist!(record)
|
|
62
|
+
return unless @properties_blacklist
|
|
63
|
+
record.reject! { |k, _| @properties_blacklist.include?(k) }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def extract_user_and_device_or_fail!(amplitude_hash, record)
|
|
67
|
+
if @user_id_key && record[@user_id_key]
|
|
68
|
+
amplitude_hash[:user_id] = record.delete(@user_id_key)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
if @device_id_key && record[@device_id_key]
|
|
72
|
+
amplitude_hash[:device_id] = record.delete(@device_id_key)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
verify_user_and_device_or_fail(amplitude_hash)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def verify_user_and_device_or_fail(amplitude_hash)
|
|
79
|
+
return if amplitude_hash[:user_id] || amplitude_hash[:device_id]
|
|
80
|
+
raise AmplitudeError, 'Error: either user_id or device_id must be set'
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def extract_user_properties!(amplitude_hash, record)
|
|
84
|
+
# if user_properties are specified, pull them off of the record
|
|
85
|
+
return unless @user_properties
|
|
86
|
+
amplitude_hash[:user_properties] = {}.tap do |user_properties|
|
|
87
|
+
@user_properties.each do |prop|
|
|
88
|
+
next unless record[prop]
|
|
89
|
+
user_properties[prop.to_sym] = record.delete(prop)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def extract_event_properties!(amplitude_hash, record)
|
|
95
|
+
# if event_properties are specified, pull them off of the record
|
|
96
|
+
# otherwise, use the remaining record (minus any user_properties)
|
|
97
|
+
amplitude_hash[:event_properties] = begin
|
|
98
|
+
if @event_properties
|
|
99
|
+
record.select do |k, _v|
|
|
100
|
+
@event_properties.include?(k)
|
|
101
|
+
end
|
|
102
|
+
else
|
|
103
|
+
record
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def send_to_amplitude(records)
|
|
109
|
+
log.info("sending #{records.length} to amplitude")
|
|
110
|
+
begin
|
|
111
|
+
res = AmplitudeAPI.track(records)
|
|
112
|
+
unless res.response_code == 200
|
|
113
|
+
raise "Got #{res.response_code} #{res.body} from AmplitudeAPI"
|
|
114
|
+
end
|
|
115
|
+
rescue StandardError => e
|
|
116
|
+
raise AmplitudeError, "Error: #{e.message}"
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def simple_symbolize_keys(hsh)
|
|
121
|
+
Hash[hsh.map do |k, v|
|
|
122
|
+
begin
|
|
123
|
+
[k.to_sym, v]
|
|
124
|
+
rescue
|
|
125
|
+
[k, v]
|
|
126
|
+
end
|
|
127
|
+
end]
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'amplitude-api'
|
|
3
|
+
describe Fluent::AmplitudeOutput do
|
|
4
|
+
let(:amplitude_api) { double(:amplitude_api) }
|
|
5
|
+
let(:now) { Time.now.to_i }
|
|
6
|
+
let(:tag) { 'after_sign' }
|
|
7
|
+
let(:amplitude) do
|
|
8
|
+
Fluent::Test::BufferedOutputTestDriver.new(
|
|
9
|
+
Fluent::AmplitudeOutput.new
|
|
10
|
+
).configure(conf)
|
|
11
|
+
end
|
|
12
|
+
let(:conf) do
|
|
13
|
+
%(
|
|
14
|
+
api_key XXXXXX
|
|
15
|
+
user_id_key user_id
|
|
16
|
+
device_id_key uuid
|
|
17
|
+
user_properties first_name, last_name
|
|
18
|
+
event_properties current_source
|
|
19
|
+
)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
before do
|
|
23
|
+
Fluent::Test.setup
|
|
24
|
+
expect(AmplitudeAPI).to receive(:api_key=).with('XXXXXX')
|
|
25
|
+
allow(AmplitudeAPI).to receive(:track).with(kind_of(Array)).and_return(
|
|
26
|
+
double(:response, response_code: 200)
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe '#format' do
|
|
31
|
+
before do
|
|
32
|
+
amplitude.tag = tag
|
|
33
|
+
amplitude.emit(event, now)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
context 'everything is set' do
|
|
37
|
+
let(:event) do
|
|
38
|
+
{
|
|
39
|
+
'user_id' => 42,
|
|
40
|
+
'uuid' => 'e6153b00-85d8-11e6-b1bc-43192d1e493f',
|
|
41
|
+
'first_name' => 'Bobby',
|
|
42
|
+
'last_name' => 'Weir',
|
|
43
|
+
'state' => 'CA',
|
|
44
|
+
'current_source' => 'fb_share',
|
|
45
|
+
'recruiter_id' => 710
|
|
46
|
+
}
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
let(:formatted_event) do
|
|
50
|
+
{
|
|
51
|
+
event_type: tag,
|
|
52
|
+
user_id: 42,
|
|
53
|
+
device_id: 'e6153b00-85d8-11e6-b1bc-43192d1e493f',
|
|
54
|
+
user_properties: {
|
|
55
|
+
first_name: 'Bobby',
|
|
56
|
+
last_name: 'Weir'
|
|
57
|
+
},
|
|
58
|
+
event_properties: {
|
|
59
|
+
current_source: 'fb_share'
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it 'produces the expected output' do
|
|
65
|
+
amplitude.expect_format [tag, now, formatted_event].to_msgpack
|
|
66
|
+
amplitude.run
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
context 'the input only contains the user_id_key' do
|
|
71
|
+
let(:event) do
|
|
72
|
+
{
|
|
73
|
+
'user_id' => 42,
|
|
74
|
+
'first_name' => 'Bobby',
|
|
75
|
+
'last_name' => 'Weir',
|
|
76
|
+
'state' => 'CA',
|
|
77
|
+
'current_source' => 'fb_share',
|
|
78
|
+
'recruiter_id' => 710
|
|
79
|
+
}
|
|
80
|
+
end
|
|
81
|
+
let(:formatted_event) do
|
|
82
|
+
{
|
|
83
|
+
event_type: tag,
|
|
84
|
+
user_id: 42,
|
|
85
|
+
user_properties: {
|
|
86
|
+
first_name: 'Bobby',
|
|
87
|
+
last_name: 'Weir'
|
|
88
|
+
},
|
|
89
|
+
event_properties: {
|
|
90
|
+
current_source: 'fb_share'
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
end
|
|
94
|
+
it 'produces the expected output without device_id' do
|
|
95
|
+
amplitude.expect_format [tag, now, formatted_event].to_msgpack
|
|
96
|
+
amplitude.run
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
context 'the input only contains the device_id field' do
|
|
101
|
+
let(:event) do
|
|
102
|
+
{
|
|
103
|
+
'uuid' => 'e6153b00-85d8-11e6-b1bc-43192d1e493f',
|
|
104
|
+
'first_name' => 'Bobby',
|
|
105
|
+
'last_name' => 'Weir',
|
|
106
|
+
'state' => 'CA',
|
|
107
|
+
'current_source' => 'fb_share',
|
|
108
|
+
'recruiter_id' => 710
|
|
109
|
+
}
|
|
110
|
+
end
|
|
111
|
+
let(:formatted_event) do
|
|
112
|
+
{
|
|
113
|
+
event_type: tag,
|
|
114
|
+
device_id: 'e6153b00-85d8-11e6-b1bc-43192d1e493f',
|
|
115
|
+
user_properties: {
|
|
116
|
+
first_name: 'Bobby',
|
|
117
|
+
last_name: 'Weir'
|
|
118
|
+
},
|
|
119
|
+
event_properties: {
|
|
120
|
+
current_source: 'fb_share'
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
end
|
|
124
|
+
it 'produces the expected output without user_id' do
|
|
125
|
+
amplitude.expect_format [tag, now, formatted_event].to_msgpack
|
|
126
|
+
amplitude.run
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
context 'the input only contains neither user_id nor device_id field' do
|
|
131
|
+
let(:event) do
|
|
132
|
+
{
|
|
133
|
+
'first_name' => 'Bobby',
|
|
134
|
+
'last_name' => 'Weir',
|
|
135
|
+
'state' => 'CA',
|
|
136
|
+
'current_source' => 'fb_share',
|
|
137
|
+
'recruiter_id' => 710
|
|
138
|
+
}
|
|
139
|
+
end
|
|
140
|
+
it 'raises a Fluent::AmplitudeOutput::AmplitudeError' do
|
|
141
|
+
expect { amplitude.run }.to raise_error(
|
|
142
|
+
Fluent::AmplitudeOutput::AmplitudeError
|
|
143
|
+
)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
context 'properties_blacklist is specified' do
|
|
148
|
+
let(:conf) do
|
|
149
|
+
%(
|
|
150
|
+
api_key XXXXXX
|
|
151
|
+
user_id_key user_id
|
|
152
|
+
device_id_key uuid
|
|
153
|
+
user_properties first_name, last_name
|
|
154
|
+
properties_blacklist foo, state
|
|
155
|
+
)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
let(:event) do
|
|
159
|
+
{
|
|
160
|
+
'user_id' => 42,
|
|
161
|
+
'uuid' => 'e6153b00-85d8-11e6-b1bc-43192d1e493f',
|
|
162
|
+
'first_name' => 'Bobby',
|
|
163
|
+
'last_name' => 'Weir',
|
|
164
|
+
'state' => 'CA',
|
|
165
|
+
'current_source' => 'fb_share',
|
|
166
|
+
'recruiter_id' => 710,
|
|
167
|
+
'foo' => 'bar'
|
|
168
|
+
}
|
|
169
|
+
end
|
|
170
|
+
let(:formatted_event) do
|
|
171
|
+
{
|
|
172
|
+
event_type: tag,
|
|
173
|
+
user_id: 42,
|
|
174
|
+
device_id: 'e6153b00-85d8-11e6-b1bc-43192d1e493f',
|
|
175
|
+
user_properties: {
|
|
176
|
+
first_name: 'Bobby',
|
|
177
|
+
last_name: 'Weir'
|
|
178
|
+
},
|
|
179
|
+
event_properties: {
|
|
180
|
+
current_source: 'fb_share',
|
|
181
|
+
recruiter_id: 710
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
end
|
|
185
|
+
it 'produces the expected output without blacklisted properties' do
|
|
186
|
+
amplitude.expect_format [tag, now, formatted_event].to_msgpack
|
|
187
|
+
amplitude.run
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
require 'rubygems'
|
|
3
|
+
require 'bundler'
|
|
4
|
+
Bundler.setup(:default, :test)
|
|
5
|
+
Bundler.require(:default, :test)
|
|
6
|
+
|
|
7
|
+
require 'fluent/test'
|
|
8
|
+
require 'rspec'
|
|
9
|
+
|
|
10
|
+
Test::Unit::AutoRunner.need_auto_run = false if defined?(Test::Unit::AutoRunner)
|
|
11
|
+
|
|
12
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
|
13
|
+
require 'fluent/plugin/out_amplitude'
|
metadata
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: fluent-plugin-amplitude
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Vijay Ramesh
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2016-10-28 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.10.55
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: 0.10.55
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: amplitude-api
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: 0.0.9
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: 0.0.9
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: msgpack
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '1.0'
|
|
48
|
+
- - ">="
|
|
49
|
+
- !ruby/object:Gem::Version
|
|
50
|
+
version: 1.0.2
|
|
51
|
+
type: :runtime
|
|
52
|
+
prerelease: false
|
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
54
|
+
requirements:
|
|
55
|
+
- - "~>"
|
|
56
|
+
- !ruby/object:Gem::Version
|
|
57
|
+
version: '1.0'
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: 1.0.2
|
|
61
|
+
- !ruby/object:Gem::Dependency
|
|
62
|
+
name: rake
|
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '11.3'
|
|
68
|
+
type: :development
|
|
69
|
+
prerelease: false
|
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - "~>"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '11.3'
|
|
75
|
+
- !ruby/object:Gem::Dependency
|
|
76
|
+
name: rspec
|
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - "~>"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '3.5'
|
|
82
|
+
type: :development
|
|
83
|
+
prerelease: false
|
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - "~>"
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '3.5'
|
|
89
|
+
- !ruby/object:Gem::Dependency
|
|
90
|
+
name: test-unit
|
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - "~>"
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '3.2'
|
|
96
|
+
- - ">="
|
|
97
|
+
- !ruby/object:Gem::Version
|
|
98
|
+
version: 3.2.1
|
|
99
|
+
type: :development
|
|
100
|
+
prerelease: false
|
|
101
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
102
|
+
requirements:
|
|
103
|
+
- - "~>"
|
|
104
|
+
- !ruby/object:Gem::Version
|
|
105
|
+
version: '3.2'
|
|
106
|
+
- - ">="
|
|
107
|
+
- !ruby/object:Gem::Version
|
|
108
|
+
version: 3.2.1
|
|
109
|
+
- !ruby/object:Gem::Dependency
|
|
110
|
+
name: rspec-mocks
|
|
111
|
+
requirement: !ruby/object:Gem::Requirement
|
|
112
|
+
requirements:
|
|
113
|
+
- - "~>"
|
|
114
|
+
- !ruby/object:Gem::Version
|
|
115
|
+
version: '3.5'
|
|
116
|
+
type: :development
|
|
117
|
+
prerelease: false
|
|
118
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
119
|
+
requirements:
|
|
120
|
+
- - "~>"
|
|
121
|
+
- !ruby/object:Gem::Version
|
|
122
|
+
version: '3.5'
|
|
123
|
+
- !ruby/object:Gem::Dependency
|
|
124
|
+
name: rubocop
|
|
125
|
+
requirement: !ruby/object:Gem::Requirement
|
|
126
|
+
requirements:
|
|
127
|
+
- - "~>"
|
|
128
|
+
- !ruby/object:Gem::Version
|
|
129
|
+
version: 0.44.1
|
|
130
|
+
type: :development
|
|
131
|
+
prerelease: false
|
|
132
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
133
|
+
requirements:
|
|
134
|
+
- - "~>"
|
|
135
|
+
- !ruby/object:Gem::Version
|
|
136
|
+
version: 0.44.1
|
|
137
|
+
description: Fluentd plugin to output event data to Amplitude
|
|
138
|
+
email:
|
|
139
|
+
- vijay@change.org
|
|
140
|
+
executables: []
|
|
141
|
+
extensions: []
|
|
142
|
+
extra_rdoc_files: []
|
|
143
|
+
files:
|
|
144
|
+
- ".gitignore"
|
|
145
|
+
- Gemfile
|
|
146
|
+
- LICENSE
|
|
147
|
+
- README.md
|
|
148
|
+
- Rakefile
|
|
149
|
+
- fluent-plugin-amplitude.gemspec
|
|
150
|
+
- lib/fluent/plugin/out_amplitude.rb
|
|
151
|
+
- spec/out_amplitude_spec.rb
|
|
152
|
+
- spec/spec_helper.rb
|
|
153
|
+
homepage: https://github.com/change/fluent-plugin-amplitude
|
|
154
|
+
licenses: []
|
|
155
|
+
metadata: {}
|
|
156
|
+
post_install_message:
|
|
157
|
+
rdoc_options: []
|
|
158
|
+
require_paths:
|
|
159
|
+
- lib
|
|
160
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
161
|
+
requirements:
|
|
162
|
+
- - ">="
|
|
163
|
+
- !ruby/object:Gem::Version
|
|
164
|
+
version: '0'
|
|
165
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
166
|
+
requirements:
|
|
167
|
+
- - ">="
|
|
168
|
+
- !ruby/object:Gem::Version
|
|
169
|
+
version: '0'
|
|
170
|
+
requirements: []
|
|
171
|
+
rubyforge_project:
|
|
172
|
+
rubygems_version: 2.4.5.1
|
|
173
|
+
signing_key:
|
|
174
|
+
specification_version: 4
|
|
175
|
+
summary: Fluentd plugin to output event data to Amplitude
|
|
176
|
+
test_files:
|
|
177
|
+
- spec/out_amplitude_spec.rb
|
|
178
|
+
- spec/spec_helper.rb
|