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 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