fluent-plugin-mixpanel 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d8d9a539d77b2b4338ad6de2f4389095fd034816
4
- data.tar.gz: 62760bebcef57a117db6191fd5610d99a079ca7e
3
+ metadata.gz: 491a99b98d20fddb7832d1057d7ff25c2dc89dba
4
+ data.tar.gz: 9a8b0b46a1f990178fd3352ac480cd884c779de4
5
5
  SHA512:
6
- metadata.gz: 9383f6371b857b50d34892e334193b308124378497f70f9baaf4c21af058acc89a34e6ecf3222fa3f4800e6435ea8360caaa8fe2aa2fd69f9d0a45b2d264324c
7
- data.tar.gz: f4c3f7cc40d6879ef48dd827a655a50d8caa583ba2a69578632f5db62ce9638ac17349941354423e82566feec5a8d1144fa4f23801aaed009790bc49b02eedd5
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
- ```xml
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 )
@@ -0,0 +1,2 @@
1
+ #!/bin/sh
2
+ ruby -rwebrick -e'WEBrick::HTTPServer.new(:Port => 8000, :DocumentRoot => Dir.pwd).start'
@@ -0,0 +1,13 @@
1
+ <source>
2
+ type http_mixpanel
3
+ bind 127.0.0.1
4
+ port 8888
5
+ body_size_limit 10m
6
+ keepalive_timeout 5
7
+ add_http_headers true
8
+ access_control_allow_origin http://0.0.0.0:8000
9
+ </source>
10
+
11
+ <match mixpanel.**>
12
+ type stdout
13
+ </match>
@@ -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.1"
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
@@ -1,8 +1,5 @@
1
1
  require 'helper'
2
2
  require 'uri'
3
- require 'webmock/test_unit'
4
-
5
- WebMock.disable_net_connect!
6
3
 
7
4
  class MixpanelOutputTest < Test::Unit::TestCase
8
5
 
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.1
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 00:00:00.000000000 Z
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