mashape-analytics 1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9e507b18ab91cf466429b73696d8870399718405
4
+ data.tar.gz: 84a0ff103e263238b9666266ee15711c98b8b9f6
5
+ SHA512:
6
+ metadata.gz: bf23a510a58e286407907dbc4c69562503afd900eba40b0a090779759732177e031f6794501756b8c72a003db2ba8721a6513d86ee054ddadc0f1d6c5330fbeb
7
+ data.tar.gz: 4c4c68ae3a0e35367ddc06d63d1b7f83cc34d1aaf0bad0920eecefd3e2d25e62b51d1ce9cb4f88a989d2bf19f412c9efb9a57b4b375af9e8b5b65810727c76e6
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
@@ -0,0 +1,13 @@
1
+ # http://editorconfig.org
2
+ root = true
3
+
4
+ [*]
5
+ indent_style = space
6
+ indent_size = 2
7
+ end_of_line = lf
8
+ charset = utf-8
9
+ trim_trailing_whitespace = true
10
+ insert_final_newline = true
11
+
12
+ [*.md]
13
+ trim_trailing_whitespace = false
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'rbczmq', '~> 1.7', '>= 1.7.8'
4
+
5
+ group :development do
6
+ gem 'minitest', '~> 5.5'
7
+ gem 'shoulda', '>= 0'
8
+ gem 'bundler', '~> 1.0'
9
+ gem 'jeweler', '~> 2.0', '>= 2.0.1'
10
+ gem 'simplecov', '>= 0'
11
+
12
+ # gem 'byebug' # for debugging
13
+
14
+ gem 'rails', '~> 4.1'
15
+ gem 'sinatra', '~> 1.4'
16
+ end
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Mashape Inc. (https://www.mashape.com/)
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 all
13
+ 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 THE
21
+ SOFTWARE.
@@ -0,0 +1,61 @@
1
+ # Mashape Analytics Ruby Agent
2
+
3
+ > for more information on Mashape Analytics, please visit [apianalytics.com](https://www.apianalytics.com)
4
+
5
+ ## Installation
6
+
7
+
8
+ ```sh
9
+ gem 'mashape-analytics'
10
+ bundle install
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ### Ruby on Rails
16
+
17
+ Open your `config/environment.rb` file, and within the `Rails::Initializer.run` block, add the middleware as below:
18
+
19
+ ```ruby
20
+ require 'mashape-analytics'
21
+
22
+ Rails::Initializer.run do |config|
23
+ config.middleware.use MashapeAnalytics::Frameworks::Rails, service_token: 'SERVICE_TOKEN', environment: 'production'
24
+ end
25
+ ```
26
+
27
+ *In rails 4, put the `config.middleware.use` line in the `config/application.rb` file.*
28
+
29
+
30
+ ### Sinatra
31
+
32
+ Register the middleware. Then activate it.
33
+
34
+ ```ruby
35
+ # myapp.rb
36
+ require 'sinatra'
37
+ require 'mashape-analytics'
38
+
39
+ register MashapeAnalytics::Frameworks::Sinatra
40
+
41
+ mashapeAnalytics! 'SERVICE_TOKEN', environment: 'production'
42
+ ```
43
+
44
+
45
+ ### Rack
46
+
47
+ Add the middleware.
48
+
49
+ ```ruby
50
+ require 'rack'
51
+ require 'mashape-analytics'
52
+
53
+ use MashapeAnalytics::Frameworks::Rack, service_token: 'SERVICE_TOKEN', environment: 'production'
54
+ ```
55
+
56
+
57
+ ## Copyright and License
58
+
59
+ Copyright Mashape Inc, 2015.
60
+
61
+ Licensed under [the MIT License](https://github.com/mashape/analytics-agent-ruby/blob/master/LICENSE)
@@ -0,0 +1,51 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
17
+ gem.name = "apianalytics"
18
+ gem.homepage = "http://github.com/Mashape/analytics-agent-ruby"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Ruby agent for Mashape API Analytics}
21
+ gem.description = %Q{The ruby agent reports API traffic to http://apianalytics.com}
22
+ gem.email = "kennethkl@gmail.com"
23
+ gem.authors = ["Kenneth Lee"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ desc "Code coverage detail"
36
+ task :simplecov do
37
+ ENV['COVERAGE'] = "true"
38
+ Rake::Task['test'].execute
39
+ end
40
+
41
+ task :default => :test
42
+
43
+ require 'rdoc/task'
44
+ Rake::RDocTask.new do |rdoc|
45
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
46
+
47
+ rdoc.rdoc_dir = 'rdoc'
48
+ rdoc.title = "apianalytics #{version}"
49
+ rdoc.rdoc_files.include('README*')
50
+ rdoc.rdoc_files.include('lib/**/*.rb')
51
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.1
@@ -0,0 +1,11 @@
1
+ module MashapeAnalytics
2
+ module Message
3
+ end
4
+
5
+ module Frameworks
6
+ end
7
+ end
8
+
9
+ require 'mashape-analytics/capture'
10
+ require 'mashape-analytics/message'
11
+ require 'mashape-analytics/frameworks'
@@ -0,0 +1,76 @@
1
+ require 'mashape-analytics/utils'
2
+
3
+ module MashapeAnalytics
4
+ class Capture
5
+ require 'rbczmq'
6
+
7
+ @@zmq_ctx = ZMQ::Context.new
8
+ @zmq_push = nil
9
+ @connected = false
10
+ @options = {
11
+ host: 'tcp://socket.analytics.mashape.com:5500'
12
+ }
13
+ @thread = nil
14
+
15
+ @@queue = Utils::QueueWithTimeout.new
16
+
17
+ def self.start
18
+ return unless @thread == nil
19
+
20
+ @thread = Thread.new do
21
+ # Connect
22
+ @zmq_push = @@zmq_ctx.socket(:PUSH)
23
+ @zmq_push.connect(@options[:host])
24
+ @connected = true
25
+
26
+ # Send messages
27
+ while @connected
28
+ begin
29
+ alf = @@queue.pop_with_timeout(1) # 1s timeout
30
+ @zmq_push.send 'alf_1.0.0 ' << alf.to_s
31
+ rescue => ex
32
+ # TODO log debug
33
+ end
34
+ end
35
+
36
+ # Disconnect
37
+ @zmq_push.close
38
+
39
+ # Clean up
40
+ @zmq_push = nil
41
+ @connected = false
42
+ @thread = nil
43
+ end
44
+ end
45
+
46
+ ##
47
+ # Send immediately
48
+ ##
49
+ def self.record!(alf)
50
+ if not @connected
51
+ Capture.start
52
+ end
53
+
54
+ @@queue << alf
55
+ end
56
+
57
+ ##
58
+ # Force disconnect
59
+ ##
60
+ def self.disconnect
61
+ return unless @connected
62
+
63
+ @connected = false
64
+ @thread.join
65
+ end
66
+
67
+ def self.context
68
+ @@zmq_ctx
69
+ end
70
+
71
+ def self.setOptions(options)
72
+ @options.merge! options
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,20 @@
1
+
2
+ # == Rack Hook =============================================================
3
+ if (defined?(Rack))
4
+ require 'mashape-analytics/frameworks/rack'
5
+ end
6
+
7
+ # == Sinatra Hook ==========================================================
8
+ if (defined?(Sinatra))
9
+ require 'mashape-analytics/frameworks/sinatra'
10
+ end
11
+
12
+ # == Rails Hook ============================================================
13
+
14
+ if (defined?(Rails))
15
+ require 'mashape-analytics/frameworks/rails'
16
+ end
17
+
18
+
19
+ module MashapeAnalytics::Frameworks
20
+ end
@@ -0,0 +1,201 @@
1
+ require 'mashape-analytics/capture'
2
+ require 'time'
3
+ require 'socket'
4
+ require 'rack/utils'
5
+
6
+ def status_code(status)
7
+ Rack::Utils::HTTP_STATUS_CODES[status] || ''
8
+ end
9
+
10
+ def header_hash(headers)
11
+ Rack::Utils::HeaderHash.new.merge(headers)
12
+ end
13
+
14
+ module MashapeAnalytics::Frameworks
15
+ class Rack
16
+
17
+ def initialize(app, options = {})
18
+ @app = app
19
+ @service_token = options[:service_token]
20
+ @environment = options[:environment] || ''
21
+ @send_body = options[:send_body] || false
22
+ host = options[:host] || 'socket.analytics.mashape.com:5500'
23
+
24
+ MashapeAnalytics::Capture.setOptions(host: 'tcp://' + host)
25
+ end
26
+
27
+ def call(env)
28
+ startedDateTime = Time.now
29
+ status, headers, body = @app.call(env)
30
+
31
+ if body.respond_to? :to_str
32
+ body = [body.to_str]
33
+ elsif body.respond_to?(:body)
34
+ body = [body.body]
35
+ elsif body.respond_to?(:each)
36
+ # do nothing
37
+ else
38
+ raise TypeError, "stringable or iterable required"
39
+ end
40
+
41
+ record_alf startedDateTime, env, {
42
+ :status => status,
43
+ :headers => header_hash(headers),
44
+ :body => body
45
+ }
46
+
47
+ [status, headers, body]
48
+ end
49
+
50
+ protected
51
+ def host(request)
52
+ if forwarded = request['HTTP_X_FORWARDED_HOST']
53
+ forwarded.split(/,\s?/).last
54
+ elsif (request['rack.url_scheme'] == 'http' and request['SERVER_PORT'] == '80') or (request['rack.url_scheme'] == 'https' and request['SERVER_PORT'] == '443')
55
+ request['HTTP_HOST'] || "#{request['SERVER_NAME'] || request['SERVER_ADDR']}"
56
+ else
57
+ request['HTTP_HOST'] || "#{request['SERVER_NAME'] || request['SERVER_ADDR']}:#{request['SERVER_PORT']}"
58
+ end
59
+ end
60
+
61
+ def url(request)
62
+ query_string = ''
63
+ if request['QUERY_STRING'] != '' and request['QUERY_STRING'] != nil
64
+ query_string = '?' + request['QUERY_STRING']
65
+ end
66
+
67
+ "#{request['PATH_INFO']}#{query_string}"
68
+ end
69
+
70
+ def absolute_url(request)
71
+ "#{request['rack.url_scheme']}://#{host(request)}#{url(request)}"
72
+ end
73
+
74
+ def request_headers(request)
75
+ request.select {|k,v| k.start_with? 'HTTP_'}
76
+ .map { |k,v| {name: k.sub(/^HTTP_/, '').sub(/_/, '-'), value: v} }
77
+ end
78
+
79
+ def request_header_size(request)
80
+ # {METHOD} {URL} HTTP/1.1\r\n = 12 extra characters for space between method and url, and ` HTTP/1.1\r\n`
81
+ first_line = request['REQUEST_METHOD'].length + url(request).length + 12
82
+
83
+ # {KEY}: {VALUE}\n\r = 4 extra characters for `: ` and `\n\r` minus `HTTP_` in the KEY is -1
84
+ header_fields = request.select { |k,v| k.start_with? 'HTTP_' }
85
+ .map { |k,v| k.length + v.bytesize - 1 }
86
+ .inject(0) { |sum,v| sum + v }
87
+
88
+ last_line = 2 # /r/n
89
+
90
+ first_line + header_fields + last_line
91
+ end
92
+
93
+ def request_query_string(request)
94
+ request['QUERY_STRING'].split('&')
95
+ .map do |q|
96
+ parts = q.split('=')
97
+ {name: parts.first, value: parts.length > 1 ? parts.last : nil }
98
+ end
99
+ end
100
+
101
+ def request_content_size(request)
102
+ if request['HTTP_CONTENT_LENGTH']
103
+ request['HTTP_CONTENT_LENGTH'].to_i
104
+ else
105
+ request['rack.input'].size
106
+ end
107
+ end
108
+
109
+ def response_headers(response)
110
+ response[:headers].map { |k,v| {name: k, value: v} }
111
+ end
112
+
113
+ def response_headers_size(response)
114
+ # HTTP/1.1 {STATUS} {STATUS_TEXT} = 10 extra characters
115
+ first_line = response[:status].to_s.length + status_code(response[:status]).length + 10
116
+
117
+ # {KEY}: {VALUE}\n\r
118
+ header_fields = response[:headers].map { |k,v| k.length + v.bytesize + 4 }
119
+ .inject(0) { |sum,v| sum + v }
120
+
121
+ return first_line + header_fields
122
+ end
123
+
124
+ def response_content_size(response)
125
+ if response[:headers]['Content-Length']
126
+ response[:headers]['Content-Length'].to_i
127
+ else
128
+ response[:body].inject(0) { |sum, b| sum + b.bytesize }
129
+ end
130
+ end
131
+
132
+ def record_alf(startedDateTime, request, response)
133
+ time = Time.now - startedDateTime
134
+ alf = MashapeAnalytics::Message::Alf.new @service_token, @environment
135
+
136
+ req_headers_size = request_header_size(request)
137
+ req_content_size = request_content_size(request)
138
+
139
+ res_headers_size = response_headers_size(response)
140
+ res_content_size = response_content_size(response)
141
+
142
+ entry = {
143
+ startedDateTime: startedDateTime.iso8601,
144
+ serverIpAddress: Socket.ip_address_list.detect{|intf| intf.ipv4_private?}.ip_address,
145
+ time: (time * 1000).to_i,
146
+ request: {
147
+ method: request['REQUEST_METHOD'],
148
+ url: absolute_url(request),
149
+ httpVersion: 'HTTP/1.1', # not available, default http/1.1
150
+ cookies: [],
151
+ queryString: request_query_string(request),
152
+ headers: request_headers(request),
153
+ headersSize: req_headers_size,
154
+ content: {
155
+ size: req_content_size,
156
+ mimeType: request['HTTP_CONTENT_TYPE'] || 'application/octet-stream'
157
+ },
158
+ bodySize: req_headers_size + req_content_size
159
+ },
160
+ response: {
161
+ status: response[:status],
162
+ statusText: status_code(response[:status]),
163
+ httpVersion: 'HTTP/1.1', # not available, default http/1.1
164
+ cookies: [],
165
+ headers: response_headers(response),
166
+ headersSize: res_headers_size,
167
+ content: {
168
+ size: res_content_size,
169
+ mimeType: response[:headers]['Content-Type'] || 'application/octet-stream'
170
+ },
171
+ bodySize: res_headers_size + res_content_size,
172
+ redirectURL: response[:headers]['Location'] || ''
173
+ },
174
+ cache: {},
175
+ timings: {
176
+ blocked: -1,
177
+ dns: -1,
178
+ connect: -1,
179
+ send: 0,
180
+ wait: (time * 1000).to_i,
181
+ receive: 0,
182
+ ssl: -1
183
+ }
184
+ }
185
+
186
+ if @send_body
187
+ require 'base64'
188
+ entry[:request][:content][:encoding] = 'base64'
189
+ request['rack.input'].rewind
190
+ entry[:request][:content][:text] = Base64.strict_encode64(request['rack.input'].read)
191
+
192
+ entry[:response][:content][:encoding] = 'base64'
193
+ entry[:response][:content][:text] = Base64.strict_encode64(response[:body].join())
194
+ end
195
+
196
+ alf.add_entry entry
197
+ MashapeAnalytics::Capture.record! alf
198
+ end
199
+
200
+ end
201
+ end
@@ -0,0 +1,7 @@
1
+ require 'mashape-analytics/frameworks/rack'
2
+
3
+ module MashapeAnalytics::Frameworks
4
+ class Rails < Rack
5
+ # Alias of Rack
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ require 'sinatra/base'
2
+ require 'mashape-analytics/frameworks/rack'
3
+ require 'time'
4
+ require 'socket'
5
+ require 'json'
6
+
7
+ module MashapeAnalytics::Frameworks
8
+ module Sinatra
9
+
10
+ def mashapeAnalytics!(service_token, options = {})
11
+ options[:service_token] = service_token
12
+ use MashapeAnalytics::Frameworks::Rack, options
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,4 @@
1
+ require 'mashape-analytics/message/alf'
2
+
3
+ module MashapeAnalytics::Message
4
+ end
@@ -0,0 +1,38 @@
1
+ require 'json'
2
+
3
+ module MashapeAnalytics::Message
4
+ class Alf
5
+ attr_accessor :test
6
+
7
+ def initialize(serviceToken, environment, clientIp = nil)
8
+ @entries = []
9
+ @alf = {
10
+ version: '1.0.0',
11
+ serviceToken: serviceToken,
12
+ environment: environment,
13
+ har: {
14
+ log: {
15
+ version: '1.2',
16
+ creator: {
17
+ name: 'mashape-analytics-agent-ruby',
18
+ version: '1.0.0'
19
+ },
20
+ entries: @entries
21
+ }
22
+ }
23
+ }
24
+
25
+ if clientIp
26
+ @alf.clientIpAddress = clientIp
27
+ end
28
+ end
29
+
30
+ def add_entry(entry)
31
+ @entries << entry
32
+ end
33
+
34
+ def to_s
35
+ @alf.to_json
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,33 @@
1
+ module MashapeAnalytics::Utils
2
+
3
+ # Source: http://spin.atomicobject.com/2014/07/07/ruby-queue-pop-timeout/
4
+ class QueueWithTimeout
5
+ def initialize
6
+ @mutex = Mutex.new
7
+ @queue = []
8
+ @recieved = ConditionVariable.new
9
+ end
10
+
11
+ def <<(x)
12
+ @mutex.synchronize do
13
+ @queue << x
14
+ @recieved.signal
15
+ end
16
+ end
17
+
18
+ def pop(non_block = false)
19
+ pop_with_timeout(non_block ? 0 : nil)
20
+ end
21
+
22
+ def pop_with_timeout(timeout = nil)
23
+ @mutex.synchronize do
24
+ if @queue.empty?
25
+ @recieved.wait(@mutex, timeout) if timeout != 0
26
+ #if we're still empty after the timeout, raise exception
27
+ raise ThreadError, "queue empty" if @queue.empty?
28
+ end
29
+ @queue.shift
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,83 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+ # stub: mashape-analytics 1.0.0 ruby lib
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "mashape-analytics"
9
+ s.version = "1.0.1"
10
+
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
+ s.require_paths = ["lib"]
13
+ s.authors = ["Mashape"]
14
+ s.date = "2015-06-25"
15
+ s.description = "The ruby agent that reports your API traffic to http://apianalytics.com"
16
+ s.email = "opensource@mashape.com"
17
+ s.extra_rdoc_files = [
18
+ "LICENSE",
19
+ "README.md"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ ".editorconfig",
24
+ ".travis.yml",
25
+ "Gemfile",
26
+ "LICENSE",
27
+ "README.md",
28
+ "Rakefile",
29
+ "VERSION",
30
+ "mashape-analytics.gemspec",
31
+ "lib/mashape-analytics.rb",
32
+ "lib/mashape-analytics/capture.rb",
33
+ "lib/mashape-analytics/frameworks.rb",
34
+ "lib/mashape-analytics/frameworks/rack.rb",
35
+ "lib/mashape-analytics/frameworks/rails.rb",
36
+ "lib/mashape-analytics/frameworks/sinatra.rb",
37
+ "lib/mashape-analytics/message.rb",
38
+ "lib/mashape-analytics/message/alf.rb",
39
+ "lib/mashape-analytics/utils.rb",
40
+ "test/helper.rb",
41
+ "test/test_capture.rb",
42
+ "test/test_rack.rb",
43
+ "test/test_sinatra.rb"
44
+ ]
45
+ s.homepage = "http://github.com/Mashape/analytics-agent-ruby"
46
+ s.licenses = ["MIT"]
47
+ s.rubygems_version = "2.4.6"
48
+ s.summary = "Ruby agent for Mashape Analytics"
49
+
50
+ if s.respond_to? :specification_version then
51
+ s.specification_version = 4
52
+
53
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
54
+ s.add_runtime_dependency(%q<rbczmq>, [">= 1.7.8", "~> 1.7"])
55
+ s.add_development_dependency(%q<minitest>, ["~> 5.5"])
56
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
57
+ s.add_development_dependency(%q<bundler>, ["~> 1.0"])
58
+ s.add_development_dependency(%q<jeweler>, [">= 2.0.1", "~> 2.0"])
59
+ s.add_development_dependency(%q<simplecov>, [">= 0"])
60
+ s.add_development_dependency(%q<rails>, ["~> 4.1"])
61
+ s.add_development_dependency(%q<sinatra>, ["~> 1.4"])
62
+ else
63
+ s.add_dependency(%q<rbczmq>, [">= 1.7.8", "~> 1.7"])
64
+ s.add_dependency(%q<minitest>, ["~> 5.5"])
65
+ s.add_dependency(%q<shoulda>, [">= 0"])
66
+ s.add_dependency(%q<bundler>, ["~> 1.0"])
67
+ s.add_dependency(%q<jeweler>, [">= 2.0.1", "~> 2.0"])
68
+ s.add_dependency(%q<simplecov>, [">= 0"])
69
+ s.add_dependency(%q<rails>, ["~> 4.1"])
70
+ s.add_dependency(%q<sinatra>, ["~> 1.4"])
71
+ end
72
+ else
73
+ s.add_dependency(%q<rbczmq>, [">= 1.7.8", "~> 1.7"])
74
+ s.add_dependency(%q<minitest>, ["~> 5.5"])
75
+ s.add_dependency(%q<shoulda>, [">= 0"])
76
+ s.add_dependency(%q<bundler>, ["~> 1.0"])
77
+ s.add_dependency(%q<jeweler>, [">= 2.0.1", "~> 2.0"])
78
+ s.add_dependency(%q<simplecov>, [">= 0"])
79
+ s.add_dependency(%q<rails>, ["~> 4.1"])
80
+ s.add_dependency(%q<sinatra>, ["~> 1.4"])
81
+ end
82
+ end
83
+
@@ -0,0 +1,77 @@
1
+ require 'rbczmq'
2
+ require 'rack'
3
+ require 'sinatra'
4
+
5
+ require 'simplecov'
6
+
7
+ gem 'minitest'
8
+ require 'minitest/autorun'
9
+ require 'minitest/unit'
10
+
11
+ module SimpleCov::Configuration
12
+ def clean_filters
13
+ @filters = []
14
+ end
15
+ end
16
+
17
+ SimpleCov.configure do
18
+ clean_filters
19
+ load_adapter 'test_frameworks'
20
+ end
21
+
22
+ ENV["COVERAGE"] && SimpleCov.start do
23
+ add_filter "/.rvm/"
24
+ end
25
+ require 'rubygems'
26
+ require 'bundler'
27
+ begin
28
+ Bundler.setup(:default, :development)
29
+ rescue Bundler::BundlerError => e
30
+ $stderr.puts e.message
31
+ $stderr.puts "Run `bundle install` to install missing gems"
32
+ exit e.status_code
33
+ end
34
+ # require 'test/unit'
35
+ require 'shoulda'
36
+
37
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
38
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
39
+ require 'mashape-analytics'
40
+
41
+ class MiniTest::Test
42
+ @@host = 'tcp://127.0.0.1:2200'
43
+
44
+ MashapeAnalytics::Capture.setOptions(host: @@host) # Set default host
45
+
46
+ def zmq_pull_socket(host)
47
+ pull_socket = MashapeAnalytics::Capture.context.socket(:PULL)
48
+ pull_socket.bind(host)
49
+
50
+ return pull_socket
51
+ end
52
+
53
+ def assert_ruby_agent(alf_json)
54
+ assert_equal 'mashape-analytics-agent-ruby', alf_json['har']['log']['creator']['name']
55
+ end
56
+
57
+ def assert_entry_request(entry_json, method, url)
58
+ assert_equal method, entry_json['request']['method']
59
+ assert_equal url, entry_json['request']['url']
60
+ end
61
+
62
+ def assert_entry_request_content(entry_json, encoding, text)
63
+ assert_equal encoding, entry_json['request']['content']['encoding']
64
+ assert_equal text, entry_json['request']['content']['text']
65
+ end
66
+
67
+ def assert_entry_response(entry_json, status, bodySize)
68
+ assert_equal status, entry_json['response']['status']
69
+ assert_equal bodySize, entry_json['response']['bodySize']
70
+ end
71
+
72
+ def assert_entry_response_content(entry_json, encoding, text)
73
+ assert_equal encoding, entry_json['response']['content']['encoding']
74
+ assert_equal text, entry_json['response']['content']['text']
75
+ end
76
+
77
+ end
@@ -0,0 +1,28 @@
1
+ require 'helper'
2
+ require 'json'
3
+
4
+ class TestCapture < MiniTest::Test
5
+
6
+ def setup
7
+ # Create our socket server
8
+ @zmq_pull = zmq_pull_socket(@@host)
9
+ end
10
+
11
+ def teardown
12
+ MashapeAnalytics::Capture.disconnect
13
+ @zmq_pull.close
14
+ end
15
+
16
+ should 'send ALF' do
17
+ alf = MashapeAnalytics::Message::Alf.new 'SERVICE-TOKEN', 'ENVIRONMENT'
18
+ MashapeAnalytics::Capture.record! alf
19
+
20
+ version, message = @zmq_pull.recv().split(' ', 2)
21
+
22
+ alf = JSON.parse(message)
23
+
24
+ assert_ruby_agent alf
25
+ assert_equal 'alf_1.0.0', version
26
+ end
27
+
28
+ end
@@ -0,0 +1,71 @@
1
+ require 'rack'
2
+ require 'helper'
3
+
4
+ class TestRack < MiniTest::Test
5
+ @send_body = false
6
+
7
+ def app
8
+ app = proc do
9
+ sleep 0.05
10
+ [200, {'CONTENT-TYPE' => 'application/json'}, ['{"messages": "Test Response"}']]
11
+ end
12
+ stack = MashapeAnalytics::Frameworks::Rack.new app, service_token: 'SERVICE-TOKEN', host: '127.0.0.1:2200', send_body: @send_body
13
+ Rack::MockRequest.new(stack)
14
+ end
15
+
16
+ def setup
17
+ # Create our socket server
18
+ @zmq_pull = zmq_pull_socket(@@host)
19
+ end
20
+
21
+ def teardown
22
+ MashapeAnalytics::Capture.disconnect
23
+ @zmq_pull.close
24
+ @send_body = false
25
+ end
26
+
27
+ should 'send ALF on GET /get?foo=bar&empty request' do
28
+ response = app.get('/get?foo=bar&empty', {'HTTP_ACCEPT' => 'application/json'})
29
+
30
+ version, message = @zmq_pull.recv.split(' ', 2)
31
+ alf = JSON.parse(message)
32
+
33
+ assert_ruby_agent alf
34
+
35
+ entry = alf['har']['log']['entries'].first
36
+ assert_entry_request entry, 'GET', 'http://example.org/get?foo=bar&empty'
37
+ assert_entry_response entry, 200, 76
38
+ end
39
+
40
+ should 'send ALF on POST /post request' do
41
+ response = app.post('/post', {'HTTP_ACCEPT' => 'application/json', input: 'test POST body'})
42
+
43
+ version, message = @zmq_pull.recv.split(' ', 2)
44
+ alf = JSON.parse(message)
45
+
46
+ assert_ruby_agent alf
47
+
48
+ entry = alf['har']['log']['entries'].first
49
+ assert_entry_request entry, 'POST', 'http://example.org/post'
50
+ assert_entry_response entry, 200, 76
51
+ end
52
+
53
+ should 'send ALF with body on POST /post request' do
54
+ @send_body = true
55
+ response = app.post('/post', {'HTTP_ACCEPT' => 'application/json', input: 'test POST body'})
56
+
57
+ version, message = @zmq_pull.recv.split(' ', 2)
58
+ alf = JSON.parse(message)
59
+
60
+ assert_ruby_agent alf
61
+
62
+ entry = alf['har']['log']['entries'].first
63
+ assert_entry_request entry, 'POST', 'http://example.org/post'
64
+ assert_entry_request_content entry, 'base64', 'dGVzdCBQT1NUIGJvZHk='
65
+
66
+ assert_entry_response entry, 200, 76
67
+ assert_entry_response_content entry, 'base64', 'eyJtZXNzYWdlcyI6ICJUZXN0IFJlc3BvbnNlIn0='
68
+ end
69
+
70
+
71
+ end
@@ -0,0 +1,60 @@
1
+ require 'sinatra'
2
+ require 'sinatra/base'
3
+ require 'rack'
4
+ require 'helper'
5
+
6
+
7
+ class TestSinatra < MiniTest::Test
8
+ @zmq_pull = nil
9
+
10
+ def app
11
+ Sinatra.new do
12
+ register MashapeAnalytics::Frameworks::Sinatra
13
+
14
+ mashapeAnalytics! 'MY-API-KEY', host: '127.0.0.1:2200', send_body: true
15
+
16
+ get('/get') { 'GET Endpoint' }
17
+ post('/post') { 'POST Endpoint' }
18
+ end
19
+ end
20
+
21
+ def setup
22
+ # Create our socket server
23
+ @zmq_pull = zmq_pull_socket('tcp://127.0.0.1:2200')
24
+ end
25
+
26
+ def teardown
27
+ MashapeAnalytics::Capture.disconnect
28
+ @zmq_pull.close if @zmq_pull != nil
29
+ end
30
+
31
+ should 'send ALF on GET /get?query=test request' do
32
+ request = Rack::MockRequest.new(app)
33
+ response = request.get('/get?query=test')
34
+
35
+ version, message = @zmq_pull.recv.split(' ', 2)
36
+ alf = JSON.parse(message)
37
+
38
+ assert_ruby_agent alf
39
+
40
+ entry = alf['har']['log']['entries'].first
41
+ assert_entry_request entry, 'GET', 'http://example.org/get?query=test'
42
+ assert_entry_response entry, 200, 86
43
+ end
44
+
45
+ should 'send ALF on POST /post request' do
46
+ request = Rack::MockRequest.new(app)
47
+ response = request.post('/post')
48
+
49
+ version, message = @zmq_pull.recv.split(' ', 2)
50
+ alf = JSON.parse(message)
51
+
52
+ assert_ruby_agent alf
53
+
54
+ entry = alf['har']['log']['entries'].first
55
+ assert_entry_request entry, 'POST', 'http://example.org/post'
56
+ assert_entry_response entry, 200, 87
57
+ end
58
+
59
+
60
+ end
metadata ADDED
@@ -0,0 +1,191 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mashape-analytics
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Mashape
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-06-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rbczmq
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 1.7.8
20
+ - - "~>"
21
+ - !ruby/object:Gem::Version
22
+ version: '1.7'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 1.7.8
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '1.7'
33
+ - !ruby/object:Gem::Dependency
34
+ name: minitest
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '5.5'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '5.5'
47
+ - !ruby/object:Gem::Dependency
48
+ name: shoulda
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: bundler
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '1.0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: jeweler
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: 2.0.1
82
+ - - "~>"
83
+ - !ruby/object:Gem::Version
84
+ version: '2.0'
85
+ type: :development
86
+ prerelease: false
87
+ version_requirements: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: 2.0.1
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '2.0'
95
+ - !ruby/object:Gem::Dependency
96
+ name: simplecov
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ - !ruby/object:Gem::Dependency
110
+ name: rails
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: '4.1'
116
+ type: :development
117
+ prerelease: false
118
+ version_requirements: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - "~>"
121
+ - !ruby/object:Gem::Version
122
+ version: '4.1'
123
+ - !ruby/object:Gem::Dependency
124
+ name: sinatra
125
+ requirement: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: '1.4'
130
+ type: :development
131
+ prerelease: false
132
+ version_requirements: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - "~>"
135
+ - !ruby/object:Gem::Version
136
+ version: '1.4'
137
+ description: The ruby agent that reports your API traffic to http://apianalytics.com
138
+ email: opensource@mashape.com
139
+ executables: []
140
+ extensions: []
141
+ extra_rdoc_files:
142
+ - LICENSE
143
+ - README.md
144
+ files:
145
+ - ".document"
146
+ - ".editorconfig"
147
+ - ".travis.yml"
148
+ - Gemfile
149
+ - LICENSE
150
+ - README.md
151
+ - Rakefile
152
+ - VERSION
153
+ - lib/mashape-analytics.rb
154
+ - lib/mashape-analytics/capture.rb
155
+ - lib/mashape-analytics/frameworks.rb
156
+ - lib/mashape-analytics/frameworks/rack.rb
157
+ - lib/mashape-analytics/frameworks/rails.rb
158
+ - lib/mashape-analytics/frameworks/sinatra.rb
159
+ - lib/mashape-analytics/message.rb
160
+ - lib/mashape-analytics/message/alf.rb
161
+ - lib/mashape-analytics/utils.rb
162
+ - mashape-analytics.gemspec
163
+ - test/helper.rb
164
+ - test/test_capture.rb
165
+ - test/test_rack.rb
166
+ - test/test_sinatra.rb
167
+ homepage: http://github.com/Mashape/analytics-agent-ruby
168
+ licenses:
169
+ - MIT
170
+ metadata: {}
171
+ post_install_message:
172
+ rdoc_options: []
173
+ require_paths:
174
+ - lib
175
+ required_ruby_version: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ required_rubygems_version: !ruby/object:Gem::Requirement
181
+ requirements:
182
+ - - ">="
183
+ - !ruby/object:Gem::Version
184
+ version: '0'
185
+ requirements: []
186
+ rubyforge_project:
187
+ rubygems_version: 2.4.6
188
+ signing_key:
189
+ specification_version: 4
190
+ summary: Ruby agent for Mashape Analytics
191
+ test_files: []