fluent-plugin-mixpanel 0.0.1 → 0.0.2
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 +4 -4
- data/README.md +23 -1
- data/example/http_server.sh +2 -0
- data/example/in_http_mixpanel.conf +13 -0
- data/example/index.html +32 -0
- data/fluent-plugin-mixpanel.gemspec +1 -1
- data/lib/fluent/plugin/in_http_mixpanel.rb +31 -0
- data/test/helper.rb +10 -0
- data/test/plugin/test_in_http_mixpanel.rb +116 -0
- data/test/plugin/test_out_mixpanel.rb +0 -3
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 491a99b98d20fddb7832d1057d7ff25c2dc89dba
|
4
|
+
data.tar.gz: 9a8b0b46a1f990178fd3352ac480cd884c779de4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94563b6483f2e5f6b4bff5953ed2a5d258c37839409de91ff8c552499bcbec900c055308b2712201c0a929a1d89a292178a12c0212ecb8411c6ff3e408fdce38
|
7
|
+
data.tar.gz: f8551e6232f9ea49f87585e3de4b9cd1f956b7c6f3b45f7350aac4e6d164977128485fff69e29a089fa6ae6f8d5e7f43a5a519f4c4f8202c23e36146e8adaab5
|
data/README.md
CHANGED
@@ -8,6 +8,10 @@
|
|
8
8
|
|
9
9
|
[Fluentd](http://fluentd.org) plugin to send event track data to [mixpanel](https://mixpanel.com).
|
10
10
|
|
11
|
+
### HttpMixpanelInput
|
12
|
+
|
13
|
+
[Fluentd](http://fluentd.org) plugin to integrate [mixpanel javascript libraries](https://mixpanel.com/docs/integration-libraries/javascript).
|
14
|
+
|
11
15
|
## Installation
|
12
16
|
|
13
17
|
Install with gem or fluent-gem command as:
|
@@ -27,7 +31,7 @@ $ sudo /usr/lib64/fluent/ruby/bin/fluent-gem install fluent-plugin-mixpanel
|
|
27
31
|
MixpanelOutput needs mixpanel's `project_token`, that can get from your mixpanel project settings.
|
28
32
|
You should also specify property key name by `distinct_id_key` and `event_key`.
|
29
33
|
|
30
|
-
```
|
34
|
+
```
|
31
35
|
<match output.mixpanel.*>
|
32
36
|
type mixpanel
|
33
37
|
project_token YOUR_PROJECT_TOKEN
|
@@ -49,6 +53,24 @@ tracker = Mixpanel::Tracker.new(YOUR_PROJECT_TOKEN)
|
|
49
53
|
tracker.track("123", "event1", { key1: "value1", key2: "value2" })
|
50
54
|
```
|
51
55
|
|
56
|
+
### HttpMixpanelInput
|
57
|
+
|
58
|
+
HttpMixpanelInput is very similar to [http Input Plugin](http://docs.fluentd.org/en/articles/in_http). Only difference is that it needs `access_control_allow_origin`, to accept [Cross-site HTTP requests](https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS).
|
59
|
+
|
60
|
+
```
|
61
|
+
<source>
|
62
|
+
type http_mixpanel
|
63
|
+
bind 127.0.0.1
|
64
|
+
port 8888
|
65
|
+
body_size_limit 10m
|
66
|
+
keepalive_timeout 5
|
67
|
+
add_http_headers true
|
68
|
+
access_control_allow_origin http://0.0.0.0:8000
|
69
|
+
</source>
|
70
|
+
```
|
71
|
+
|
72
|
+
In example folder, you can see example configuration and HTML.
|
73
|
+
|
52
74
|
## Contributing
|
53
75
|
|
54
76
|
1. Fork it ( http://github.com/hakobera/fluent-plugin-mixpanel/fork )
|
data/example/index.html
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<title>in_http_mixpanel example</title>
|
6
|
+
</head>
|
7
|
+
<body>
|
8
|
+
<ul>
|
9
|
+
<li><button data-event='event1' data-value="1">Event1</button></li>
|
10
|
+
<li><button data-event='event2' data-value="2">Event2</button></li>
|
11
|
+
<li><button data-event='event3' data-value="3">Event3</button></li>
|
12
|
+
</ul>
|
13
|
+
<script type="text/javascript">
|
14
|
+
(function(c,a){window.mixpanel=a;var b,d,h,e;b=c.createElement("script");
|
15
|
+
b.type="text/javascript";b.async=!0;b.src=("https:"===c.location.protocol?"https:":"http:")+'//cdn.mxpnl.com/libs/mixpanel-2.2.min.js';d=c.getElementsByTagName("script")[0];d.parentNode.insertBefore(b,d);a._i=[];a.init=function(b,c,f){function d(a,b){var c=b.split(".");2==c.length&&(a=a[c[0]],b=c[1]);a[b]=function(){a.push([b].concat(Array.prototype.slice.call(arguments,0)))}}var g=a;"undefined"!==typeof f?g=a[f]=[]:f="mixpanel";g.people=g.people||[];h=['disable','track','track_pageview','track_links','track_forms','register','register_once','unregister','identify','alias','name_tag','set_config','people.set','people.set_once','people.increment','people.track_charge','people.append'];for(e=0;e<h.length;e++)d(g,h[e]);a._i.push([b,c,f])};a.__SV=1.2;})(document,window.mixpanel||[]);
|
16
|
+
mixpanel.init("dummy", {
|
17
|
+
api_host: 'http://0.0.0.0:8888',
|
18
|
+
debug: true
|
19
|
+
});
|
20
|
+
</script>
|
21
|
+
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
|
22
|
+
<script>
|
23
|
+
$(function () {
|
24
|
+
$('button').on('click', function () {
|
25
|
+
var evt = $(this).data('event');
|
26
|
+
var value = $(this).data('value');
|
27
|
+
mixpanel.track(evt, { value: value });
|
28
|
+
});
|
29
|
+
});
|
30
|
+
</script>
|
31
|
+
</body>
|
32
|
+
</html>
|
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "fluent-plugin-mixpanel"
|
7
|
-
spec.version = "0.0.
|
7
|
+
spec.version = "0.0.2"
|
8
8
|
spec.authors = ["Kazuyuki Honda"]
|
9
9
|
spec.email = ["hakobera@gmail.com"]
|
10
10
|
spec.summary = %q{Fluentd plugin to send event track data to mixpanel}
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'fluent/plugin/in_http'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
class Fluent::HttpMixpanelInput < Fluent::HttpInput
|
5
|
+
Fluent::Plugin.register_input('http_mixpanel', self)
|
6
|
+
|
7
|
+
config_param :access_control_allow_origin
|
8
|
+
config_param :tag_prefix, :default => 'mixpanel'
|
9
|
+
|
10
|
+
def on_request(path_info, params)
|
11
|
+
data = Base64.decode64(params['data']).force_encoding('utf-8')
|
12
|
+
json = JSON.parse(data)
|
13
|
+
path = "/#{tag_prefix}.#{json['event']}"
|
14
|
+
params['json'] = json['properties'].to_json
|
15
|
+
params['time'] = (params['_'].to_i / 1000).to_s if params['_']
|
16
|
+
|
17
|
+
ret = super(path, params)
|
18
|
+
|
19
|
+
headers = {
|
20
|
+
'Access-Control-Allow-Credentials' => true,
|
21
|
+
'Access-Control-Allow-Headers' => 'X-Requested-With',
|
22
|
+
'Access-Control-Allow-Methods' => 'GET, POST, OPTIONS',
|
23
|
+
'Access-Control-Allow-Origin' => access_control_allow_origin,
|
24
|
+
'Access-Control-Max-Age' => 1728000,
|
25
|
+
'Cache-Control' => 'no-cache, no-store',
|
26
|
+
'Content-type' => 'text/plain'
|
27
|
+
}
|
28
|
+
|
29
|
+
[ret[0], headers, (ret[0] == 200 ? 1 : 0)]
|
30
|
+
end
|
31
|
+
end
|
data/test/helper.rb
CHANGED
@@ -8,6 +8,8 @@ rescue Bundler::BundlerError => e
|
|
8
8
|
exit e.status_code
|
9
9
|
end
|
10
10
|
require 'test/unit'
|
11
|
+
require 'webmock/test_unit'
|
12
|
+
WebMock.disable_net_connect!(:allow_localhost => true)
|
11
13
|
|
12
14
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
13
15
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
@@ -22,7 +24,15 @@ unless ENV.has_key?('VERBOSE')
|
|
22
24
|
$log = nulllogger
|
23
25
|
end
|
24
26
|
|
27
|
+
def unused_port
|
28
|
+
s = TCPServer.open(0)
|
29
|
+
port = s.addr[1]
|
30
|
+
s.close
|
31
|
+
port
|
32
|
+
end
|
33
|
+
|
25
34
|
require 'fluent/plugin/out_mixpanel'
|
35
|
+
require 'fluent/plugin/in_http_mixpanel'
|
26
36
|
|
27
37
|
class Test::Unit::TestCase
|
28
38
|
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'net/http'
|
3
|
+
require 'base64'
|
4
|
+
|
5
|
+
class HttpMixpanelInputTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
Fluent::Test.setup
|
9
|
+
end
|
10
|
+
|
11
|
+
PORT = unused_port
|
12
|
+
CONFIG = %[
|
13
|
+
port #{PORT}
|
14
|
+
bind 127.0.0.1
|
15
|
+
body_size_limit 10m
|
16
|
+
keepalive_timeout 5
|
17
|
+
access_control_allow_origin http://foo.example
|
18
|
+
]
|
19
|
+
|
20
|
+
def create_driver(conf=CONFIG)
|
21
|
+
Fluent::Test::InputTestDriver.new(Fluent::HttpMixpanelInput).configure(conf)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_configure
|
25
|
+
d = create_driver
|
26
|
+
assert_equal PORT, d.instance.port
|
27
|
+
assert_equal '127.0.0.1', d.instance.bind
|
28
|
+
assert_equal 10*1024*1024, d.instance.body_size_limit
|
29
|
+
assert_equal 5, d.instance.keepalive_timeout
|
30
|
+
assert_equal false, d.instance.add_http_headers
|
31
|
+
assert_equal 'http://foo.example', d.instance.access_control_allow_origin
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_time
|
35
|
+
d = create_driver
|
36
|
+
|
37
|
+
time = Time.parse("2011-01-02 13:14:15 UTC").to_i
|
38
|
+
Fluent::Engine.now = time
|
39
|
+
|
40
|
+
d.expect_emit "mixpanel.tag1", time, {"a"=>1}
|
41
|
+
d.expect_emit "mixpanel.tag2", time, {"a"=>2}
|
42
|
+
|
43
|
+
d.run do
|
44
|
+
d.expected_emits.each {|tag,time,record|
|
45
|
+
res = track("#{tag}", {"json"=>record})
|
46
|
+
assert_equal "200", res.code
|
47
|
+
assert_equal 'true', res.header['access-control-allow-credentials']
|
48
|
+
assert_equal 'X-Requested-With', res.header['access-control-allow-headers']
|
49
|
+
assert_equal 'GET, POST, OPTIONS', res.header['access-control-allow-methods']
|
50
|
+
assert_equal d.instance.access_control_allow_origin, res.header['access-control-allow-origin']
|
51
|
+
assert_equal '1728000', res.header['access-control-max-age']
|
52
|
+
assert_equal 'no-cache, no-store', res.header['cache-control']
|
53
|
+
}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_json
|
58
|
+
d = create_driver
|
59
|
+
|
60
|
+
time = Time.parse("2011-01-02 13:14:15 UTC").to_i
|
61
|
+
|
62
|
+
d.expect_emit "mixpanel.tag1", time, {"a"=>1}
|
63
|
+
d.expect_emit "mixpanel.tag2", time, {"a"=>2}
|
64
|
+
|
65
|
+
d.run do
|
66
|
+
d.expected_emits.each {|tag,time,record|
|
67
|
+
res = track("#{tag}", {"json"=>record, "time"=>time.to_s})
|
68
|
+
assert_equal "200", res.code
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
d.emit_streams.each { |tag, es|
|
73
|
+
assert !include_http_header?(es.first[1])
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_json_with_add_http_headers
|
78
|
+
d = create_driver(CONFIG + "add_http_headers true")
|
79
|
+
|
80
|
+
time = Time.parse("2011-01-02 13:14:15 UTC").to_i
|
81
|
+
|
82
|
+
records = [["mixpanel.tag1", time, {"a"=>1}], ["mixpanel.tag2", time, {"a"=>2}]]
|
83
|
+
|
84
|
+
d.run do
|
85
|
+
records.each {|tag,time,record|
|
86
|
+
res = track("#{tag}", {"json"=>record, "time"=>time.to_s})
|
87
|
+
assert_equal "200", res.code
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
d.emit_streams.each { |tag, es|
|
92
|
+
assert include_http_header?(es.first[1])
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
96
|
+
def track(tag, params)
|
97
|
+
event = tag.sub(/^mixpanel\.(.+)$/, '\1')
|
98
|
+
data = {
|
99
|
+
event: event,
|
100
|
+
properties: params['json']
|
101
|
+
}
|
102
|
+
data = URI.escape(Base64.encode64(data.to_json))
|
103
|
+
query = "data=#{data}"
|
104
|
+
query += "&ip=1"
|
105
|
+
query += "&_=#{params['time']}000" if params['time']
|
106
|
+
path = "/track/?#{query}"
|
107
|
+
|
108
|
+
http = Net::HTTP.new("127.0.0.1", PORT)
|
109
|
+
req = Net::HTTP::Get.new(path)
|
110
|
+
http.request(req)
|
111
|
+
end
|
112
|
+
|
113
|
+
def include_http_header?(record)
|
114
|
+
record.keys.find { |header| header.start_with?('HTTP_') }
|
115
|
+
end
|
116
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-mixpanel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kazuyuki Honda
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-02-
|
11
|
+
date: 2014-02-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fluentd
|
@@ -79,9 +79,14 @@ files:
|
|
79
79
|
- LICENSE.txt
|
80
80
|
- README.md
|
81
81
|
- Rakefile
|
82
|
+
- example/http_server.sh
|
83
|
+
- example/in_http_mixpanel.conf
|
84
|
+
- example/index.html
|
82
85
|
- fluent-plugin-mixpanel.gemspec
|
86
|
+
- lib/fluent/plugin/in_http_mixpanel.rb
|
83
87
|
- lib/fluent/plugin/out_mixpanel.rb
|
84
88
|
- test/helper.rb
|
89
|
+
- test/plugin/test_in_http_mixpanel.rb
|
85
90
|
- test/plugin/test_out_mixpanel.rb
|
86
91
|
homepage: https://github.com/hakobera/fluent-plugin-mixpanel
|
87
92
|
licenses:
|
@@ -109,4 +114,5 @@ specification_version: 4
|
|
109
114
|
summary: Fluentd plugin to send event track data to mixpanel
|
110
115
|
test_files:
|
111
116
|
- test/helper.rb
|
117
|
+
- test/plugin/test_in_http_mixpanel.rb
|
112
118
|
- test/plugin/test_out_mixpanel.rb
|