caliper 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +34 -0
  4. data/README.md +22 -0
  5. data/Rakefile +6 -0
  6. data/caliper.gemspec +27 -0
  7. data/lib/caliper/app_error.rb +33 -0
  8. data/lib/caliper/rack.rb +33 -0
  9. data/lib/caliper/rails/append_info.rb +25 -0
  10. data/lib/caliper/rails/instrumentation.rb +27 -0
  11. data/lib/caliper/railtie.rb +42 -0
  12. data/lib/caliper/route_inspector.rb +108 -0
  13. data/lib/caliper/tasks/caliper.rake +10 -0
  14. data/lib/caliper/tracer.rb +77 -0
  15. data/lib/caliper/version.rb +3 -0
  16. data/lib/caliper.rb +60 -0
  17. data/lib/caliper_api/http.rb +62 -0
  18. data/spec/caliper/tracer_spec.rb +64 -0
  19. data/spec/data/rails_get_request_samples.txt +9 -0
  20. data/spec/data/trace.json +1 -0
  21. data/spec/dummy/.gitignore +15 -0
  22. data/spec/dummy/Gemfile +43 -0
  23. data/spec/dummy/README.rdoc +261 -0
  24. data/spec/dummy/Rakefile +7 -0
  25. data/spec/dummy/app/assets/images/rails.png +0 -0
  26. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  27. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  28. data/spec/dummy/app/controllers/application_controller.rb +4 -0
  29. data/spec/dummy/app/controllers/posts_controller.rb +18 -0
  30. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  31. data/spec/dummy/app/mailers/.gitkeep +0 -0
  32. data/spec/dummy/app/models/.gitkeep +0 -0
  33. data/spec/dummy/app/models/post.rb +3 -0
  34. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  35. data/spec/dummy/app/views/posts/index.html.erb +15 -0
  36. data/spec/dummy/config/application.rb +62 -0
  37. data/spec/dummy/config/boot.rb +6 -0
  38. data/spec/dummy/config/caliper.yml +17 -0
  39. data/spec/dummy/config/database.yml +25 -0
  40. data/spec/dummy/config/environment.rb +5 -0
  41. data/spec/dummy/config/environments/development.rb +37 -0
  42. data/spec/dummy/config/environments/production.rb +67 -0
  43. data/spec/dummy/config/environments/test.rb +37 -0
  44. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  45. data/spec/dummy/config/initializers/inflections.rb +15 -0
  46. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  47. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  48. data/spec/dummy/config/initializers/session_store.rb +8 -0
  49. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  50. data/spec/dummy/config/locales/en.yml +5 -0
  51. data/spec/dummy/config/routes.rb +8 -0
  52. data/spec/dummy/config.ru +4 -0
  53. data/spec/dummy/db/migrate/20121203233624_create_posts.rb +9 -0
  54. data/spec/dummy/db/schema.rb +22 -0
  55. data/spec/dummy/db/seeds.rb +7 -0
  56. data/spec/dummy/lib/assets/.gitkeep +0 -0
  57. data/spec/dummy/lib/tasks/.gitkeep +0 -0
  58. data/spec/dummy/log/.gitkeep +0 -0
  59. data/spec/dummy/public/404.html +26 -0
  60. data/spec/dummy/public/422.html +26 -0
  61. data/spec/dummy/public/500.html +25 -0
  62. data/spec/dummy/public/favicon.ico +0 -0
  63. data/spec/dummy/public/index.html +241 -0
  64. data/spec/dummy/public/robots.txt +5 -0
  65. data/spec/dummy/script/rails +6 -0
  66. data/spec/dummy/test/integration/.gitkeep +0 -0
  67. data/spec/dummy/test/integration/caliper_test.rb +64 -0
  68. data/spec/dummy/test/lib/caliper/route_inspector_test.rb +14 -0
  69. data/spec/dummy/test/test_helper.rb +30 -0
  70. data/spec/dummy/vendor/assets/javascripts/.gitkeep +0 -0
  71. data/spec/dummy/vendor/assets/stylesheets/.gitkeep +0 -0
  72. data/spec/dummy/vendor/plugins/.gitkeep +0 -0
  73. data/spec/spec_helper.rb +32 -0
  74. metadata +270 -0
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in caliper.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,34 @@
1
+ All other components of this product are
2
+ Copyright (c) 2012-2013 Coherence Solutions Inc. All rights reserved.
3
+
4
+ Subject to the terms of this notice, Coherence Solutions Inc grants you a
5
+ nonexclusive, nontransferable license, without the right to
6
+ sublicense, to (a) install and execute one copy of these files on any
7
+ number of workstations owned or controlled by you and (b) distribute
8
+ verbatim copies of these files to third parties. As a condition to the
9
+ foregoing grant, you must provide this notice along with each copy you
10
+ distribute and you must not remove, alter, or obscure this notice. All
11
+ other use, reproduction, modification, distribution, or other
12
+ exploitation of these files is strictly prohibited, except as may be set
13
+ forth in a separate written license agreement between you and Coherence
14
+ Solutions Inc. The terms of any such license agreement will control over this
15
+ notice. The license stated above will be automatically terminated and
16
+ revoked if you exceed its scope or violate any of the terms of this
17
+ notice.
18
+
19
+ This License does not grant permission to use the trade names,
20
+ trademarks, service marks, or product names of Coherence Solutions Inc
21
+ except as required for reasonable and customary use in describing the origin
22
+ of this file and reproducing the content of this notice. You may
23
+ not mark or brand this file with any trade name, trademarks,
24
+ servicemarks, or product names other than the original brand
25
+ (if any)provided by Coherence Solutions Inc.
26
+
27
+ Unless otherwise expressly agreed by Coherence Solutions Inc, in a
28
+ separate written license agreement, these files are provided AS IS,
29
+ WITHOUT WARRANTY OF ANY KIND, including without any implied warranties
30
+ of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, or NON-INFRINGEMENT.
31
+ As a condition to your use of these files, you are solely responsible for
32
+ such use. Coherence Solutions Inc will have no liability to you for direct,
33
+ indirect, consequential, incidental, special, or punitive damages or
34
+ for lost profits or data.
data/README.md ADDED
@@ -0,0 +1,22 @@
1
+ # Caliper
2
+
3
+ To use this gem please register for a beta invite at
4
+ [http://caliper.io](http://caliper.io)
5
+
6
+ ## Tests
7
+
8
+ Caliper gem:
9
+
10
+ bundle exec rake
11
+
12
+ Caliper rails dummy app (could only get rack middleware working with
13
+ IntegrationTest for now):
14
+
15
+ cd spec/dummy; bundle exec rake
16
+
17
+ ## Contributing
18
+
19
+ We welcome pull requests for fixing bugs or new features. We follow the
20
+ [rails coding
21
+ conventions](http://guides.rubyonrails.org/contributing_to_ruby_on_rails.html#follow-the-coding-conventions)
22
+ as best we can.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ # TODO: sort out later
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ task :default => :spec
data/caliper.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'caliper/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "caliper"
8
+ gem.version = Caliper::VERSION
9
+ gem.authors = ["Kalvir Sandhu"]
10
+ gem.email = ["kalv@coherence.io"]
11
+ gem.description = %q{Caliper your rails applications}
12
+ gem.summary = %q{Caliper profiles your rails application giving you insight on customers performance}
13
+ gem.homepage = "http://caliper.io"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^spec/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency(%q<rack>, [">=0"])
21
+ gem.add_dependency(%q<yajl-ruby>, [">= 0"])
22
+ gem.add_dependency(%q<uuid>, [">= 0"])
23
+
24
+ gem.add_development_dependency(%q<rspec>, [">= 0"])
25
+ gem.add_development_dependency(%q<activesupport>, [">= 3.2.9"])
26
+ gem.add_development_dependency(%q<rake>,[">=10.0.2"])
27
+ end
@@ -0,0 +1,33 @@
1
+ module Caliper
2
+ module AppError
3
+ def self.create(exception, request_env)
4
+ req = ::Rack::Request.new(request_env)
5
+
6
+ remote_ip = request_env["action_dispatch.remote_ip"]
7
+ remote_ip = remote_ip.first if remote_ip.is_a?(Array)
8
+
9
+ error_attributes = {
10
+ "message" => exception.message,
11
+ "class_name" => exception.class.name,
12
+ "host" => Socket.gethostname,
13
+ "request_data" => {
14
+ "http_method" => request_env["REQUEST_METHOD"],
15
+ "uri" => request_env["REQUEST_URI"],
16
+ "path" => request_env["PATH_INFO"],
17
+ "remote_ip" => "#{remote_ip}",
18
+ "parameters" => req.params,
19
+ "session_data" => req.session,
20
+ "HTTP_USER_AGENT" => request_env["HTTP_USER_AGENT"],
21
+ "HTTP_HOST" => request_env["HTTP_HOST"],
22
+ "HTTP_X_REAL_IP" => request_env["HTTP_X_REAL_IP"],
23
+ "HTTP_X_FORWARDED_FOR" => request_env["HTTP_X_FORWARDED_FOR"]
24
+ }
25
+ }
26
+ error_attributes["backtrace"] = exception.backtrace.join("\n") if exception.backtrace
27
+
28
+ CaliperApi.create_error(
29
+ Yajl::Encoder.encode({"error" => error_attributes})
30
+ )
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ module Caliper
2
+ class Rack
3
+ def initialize(app, options = {}, &blk)
4
+ @app = app
5
+
6
+ yield self if block_given?
7
+ end
8
+
9
+ def call(env)
10
+ if Caliper.config[:enabled] && !env['PATH_INFO'][/^\/assets/]
11
+ env['caliper.tracer'] = Caliper::Tracer.new(env)
12
+ end
13
+
14
+ @status, @headers, @response = @app.call(env)
15
+
16
+ # check for routing error in rails way
17
+ if @status == 404 && @headers['X-Cascade'] == 'pass'
18
+ Caliper::AppError.create(
19
+ ActionController::RoutingError.new("No route matches [#{env['REQUEST_METHOD']}] #{env['PATH_INFO'].inspect}"),
20
+ env
21
+ )
22
+ elsif env['caliper.tracer']
23
+ env['caliper.tracer'].finish
24
+ end
25
+
26
+ [@status, @headers, @response]
27
+ rescue Exception => exception
28
+ Caliper::AppError.create(exception, env)
29
+ raise exception
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,25 @@
1
+ # add the resolved controller and action to the trace
2
+ module Caliper
3
+ module Rails
4
+ module AppendInfo
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ before_filter :add_request_info_to_tracer
9
+ end
10
+
11
+ def add_request_info_to_tracer
12
+ return true unless env['caliper.tracer'] # elegantly fail if something went wrong with middleware and also when errors are handled
13
+ request.env["caliper.tracer"].reqs = "#{params[:controller]}##{params[:action]}"
14
+
15
+ # check if developer has added customer data
16
+ if defined? self.add_to_caliper_trace
17
+ request.env["caliper.tracer"].add_to_trace(self.add_to_caliper_trace)
18
+ end
19
+
20
+ # TODO: add other parameters for the trace?
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,27 @@
1
+ # monkey patch the action controller to get reference to middleware caliper tracer
2
+ module ActionController
3
+ module Instrumentation
4
+ def process_action(action, *args)
5
+ raw_payload = {
6
+ :controller => self.class.name,
7
+ :action => self.action_name,
8
+ :params => request.filtered_parameters,
9
+ :formats => request.formats.map(&:to_sym),
10
+ :method => request.method,
11
+ :path => (request.fullpath rescue "unknown"),
12
+
13
+ # Need payload to reference the request env tracer
14
+ :caliper_tracer => request.env['caliper.tracer']
15
+ }
16
+
17
+ ActiveSupport::Notifications.instrument("start_processing.action_controller", raw_payload.dup)
18
+
19
+ ActiveSupport::Notifications.instrument("process_action.action_controller", raw_payload) do |payload|
20
+ result = super
21
+ payload[:status] = response.status
22
+ append_info_to_payload(payload)
23
+ result
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,42 @@
1
+ require 'caliper/rails/instrumentation'
2
+ require 'caliper/rails/append_info'
3
+
4
+ module Caliper
5
+ class Railtie < ::Rails::Railtie
6
+ rake_tasks do
7
+ load "caliper/tasks/caliper.rake"
8
+ end
9
+
10
+ config.caliper = ActiveSupport::OrderedOptions.new
11
+
12
+ initializer "caliper.initialize" do |app|
13
+ app.middleware.use Caliper::Rack
14
+
15
+ ActiveSupport.on_load(:action_controller) do
16
+ ActionController::Base.send(:include, Caliper::Rails::AppendInfo)
17
+ end
18
+
19
+ ActiveSupport::Notifications.subscribe(/(^render|action_controller|active_record)/) do |*args|
20
+ event = ActiveSupport::Notifications::Event.new(*args)
21
+
22
+ # set this so that sql and view notifications has access to caliper tracer
23
+ if event.name == 'start_processing.action_controller'
24
+ @caliper_tracer = event.payload[:caliper_tracer]
25
+ end
26
+
27
+ @caliper_tracer.record(event) if @caliper_tracer
28
+ end
29
+
30
+ end
31
+
32
+ # update routes to Caliper
33
+ config.after_initialize do
34
+ ::Rails.application.reload_routes!
35
+ inspector = Caliper::RouteInspector.new
36
+ all_routes = ::Rails.application.routes.routes
37
+ CaliperApi.update_routes(
38
+ Yajl::Encoder.encode({"routes" => inspector.routes(all_routes)})
39
+ )
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,108 @@
1
+ # Influenced by ActionDispatch::Routing::RoutesInspector
2
+ require 'delegate'
3
+
4
+ module Caliper
5
+
6
+ class RouteWrapper < SimpleDelegator
7
+ def endpoint
8
+ unless rack_app
9
+ "#{controller}##{action}"
10
+ end
11
+ # ignore rack apps for now (don't want to know about redirects)
12
+ #rack_app ? rack_app.inspect : "#{controller}##{action}"
13
+ end
14
+
15
+ def constraints
16
+ requirements.except(:controller, :action)
17
+ end
18
+
19
+ def rack_app(app = self.app)
20
+ @rack_app ||= begin
21
+ class_name = app.class.name.to_s
22
+ if class_name == "ActionDispatch::Routing::Mapper::Constraints"
23
+ rack_app(app.app)
24
+ elsif ActionDispatch::Routing::Redirect === app || class_name !~ /^ActionDispatch::Routing/
25
+ app
26
+ end
27
+ end
28
+ end
29
+
30
+ def verb
31
+ super.source.gsub(/[$^]/, '')
32
+ end
33
+
34
+ def path
35
+ super.spec.to_s
36
+ end
37
+
38
+ def name
39
+ super.to_s
40
+ end
41
+
42
+ def reqs
43
+ @reqs ||= begin
44
+ reqs = endpoint
45
+ # commenting out for now until tested and really required
46
+ #reqs += " #{constraints.to_s}" unless constraints.empty?
47
+ reqs
48
+ end
49
+ end
50
+
51
+ def controller
52
+ requirements[:controller] || ':controller'
53
+ end
54
+
55
+ def action
56
+ requirements[:action] || ':action'
57
+ end
58
+
59
+ def internal?
60
+ path =~ %r{/rails/info.*|^#{::Rails.application.config.assets.prefix}}
61
+ end
62
+
63
+ def engine?
64
+ rack_app && rack_app.respond_to?(:routes)
65
+ end
66
+ end
67
+
68
+ class RouteInspector
69
+ def initialize
70
+ @engines = Hash.new
71
+ end
72
+
73
+ def routes(all_routes)
74
+ routes = collect_routes(all_routes)
75
+
76
+ routes + routes_for_engines
77
+ end
78
+
79
+ def collect_routes(routes)
80
+ routes = routes.collect do |route|
81
+ RouteWrapper.new(route)
82
+ end.reject do |route|
83
+ route.internal?
84
+ end.collect do |route|
85
+ collect_engine_routes(route)
86
+
87
+ {:name => route.name, :verb => route.verb, :path => route.path, :reqs => route.reqs } unless route.reqs.nil?
88
+ end.compact
89
+ end
90
+
91
+ def collect_engine_routes(route)
92
+ name = route.endpoint
93
+ return unless route.engine?
94
+ return if @engines[name]
95
+
96
+ routes = route.rack_app.routes
97
+ if routes.is_a?(ActionDispatch::Routing::RouteSet)
98
+ @engines[name] = collect_routes(routes.routes)
99
+ end
100
+ end
101
+
102
+ def routes_for_engines
103
+ @engines.map do |name, routes|
104
+ formatted_routes(routes)
105
+ end.flatten
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,10 @@
1
+ namespace :caliper do
2
+
3
+ desc "Send a test call to Caliper to ensure everything is working correctly"
4
+ task :test => :environment do
5
+ Rails.logger = Logger.new(STDOUT)
6
+ puts "Posting a test message to Caliper with API KEY: #{Caliper.config[:api_key]} to #{Caliper.config[:api_host]}"
7
+ CaliperApi.test_post
8
+ puts "Test sent. Go ahead and deploy and view data on #{Caliper.config[:api_host]}"
9
+ end
10
+ end
@@ -0,0 +1,77 @@
1
+ require 'uuid'
2
+ require 'yajl'
3
+ require 'socket'
4
+
5
+ module Caliper
6
+ class Tracer
7
+ attr_accessor :uuid, :http_method, :uri, :path, :remote_ip, :samples, :host, :reqs, :extra_info
8
+
9
+ def initialize(env)
10
+ @uuid = UUID.generate
11
+
12
+ @http_method = env['REQUEST_METHOD']
13
+ @uri = env['REQUEST_URI'] # full URI
14
+ @path = env['PATH_INFO'] # user path_info because it's in the rack spec rather than REQUEST_PATH
15
+
16
+ @remote_ip = env["action_dispatch.remote_ip"] #requesting ip
17
+ @remote_ip = @remote_ip.first if @remote_ip.is_a?(Array)
18
+
19
+ @host = Socket.gethostname
20
+
21
+ @samples = []
22
+ end
23
+
24
+ def record(event)
25
+ event.payload.delete(:caliper_tracer) if event.payload[:caliper_tracer]
26
+ return if event.name[/active_record/] && (event.payload[:name] == nil || event.payload[:name][/SCHEMA/])
27
+
28
+ # strip un-required payload data for activerecord notifications
29
+ if event.name[/active_record/]
30
+ ["binds", "connection_id"].each do |key|
31
+ event.payload.delete(key)
32
+ end
33
+ end
34
+
35
+ #Caliper.logger.debug [event.name, event.time, event.end, event.transaction_id, event.payload].join("||")
36
+ @samples << event
37
+ end
38
+
39
+ def add_to_trace(data = {})
40
+ @extra_info = data
41
+ end
42
+
43
+ def finish
44
+ return true if samples.size == 0
45
+
46
+ trace_data = {
47
+ "uuid" => uuid,
48
+ "http_method" => http_method,
49
+ "uri" => uri,
50
+ "path" => path,
51
+ "remote_ip" => remote_ip.to_s,
52
+ "host" => host,
53
+ "reqs" => reqs,
54
+ "extra_info" => extra_info,
55
+ "samples" => []
56
+ }
57
+
58
+ samples.each do |sample|
59
+ trace_data["samples"] << {
60
+ "name" => sample.name,
61
+ "duration" => sample.duration,
62
+ #"start" => sample.time,
63
+ #"end" => sample.end,
64
+ "payload" => sample.payload
65
+ }
66
+ if sample.name[/process_action.action_controller/]
67
+ trace_data["view_runtime"] = sample.payload[:view_runtime]
68
+ trace_data["db_runtime"] = sample.payload[:db_runtime]
69
+ trace_data["duration"] = sample.duration
70
+ end
71
+ end
72
+ CaliperApi.create_trace(
73
+ Yajl::Encoder.encode({ "trace" => trace_data })
74
+ )
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,3 @@
1
+ module Caliper
2
+ VERSION = "0.0.1"
3
+ end
data/lib/caliper.rb ADDED
@@ -0,0 +1,60 @@
1
+ require 'uuid'
2
+ require 'logger'
3
+
4
+ require 'caliper/version'
5
+ require 'caliper/tracer'
6
+ require 'caliper/rack'
7
+ require 'caliper/route_inspector'
8
+ require 'caliper/app_error'
9
+
10
+ require 'caliper_api/http'
11
+
12
+
13
+ if defined? ::Rails
14
+ if ::Rails::VERSION::MAJOR >= 3
15
+ require 'caliper/railtie'
16
+ else
17
+ raise "Your Rails application is currently not supported with Caliper, get in touch we can make it so soon"
18
+ end
19
+ elsif !ENV["CALIPER_API_HOST"] #(might be in testing mode)
20
+ raise "Your Ruby application is currently not supported with Caliper, get in touch, we can make it so soon"
21
+ end
22
+
23
+ module Caliper
24
+ def self.logger
25
+ unless @logger
26
+ # if in Rails use Rails logger
27
+ if defined? ::Rails
28
+ @logger = ::Rails.logger
29
+ else
30
+ @logger = Logger.new(STDOUT)
31
+ @logger.level = Logger::INFO
32
+ end
33
+ end
34
+
35
+ @logger
36
+ end
37
+
38
+ def self.config
39
+ if defined? ::Rails
40
+ config_path = ::Rails.root
41
+ env = ::Rails.env
42
+ else
43
+ config_path = File.new("./")
44
+ env = "test"
45
+ end
46
+ begin
47
+ @config ||= YAML.load_file("#{config_path.join("config", "caliper.yml")}")[::Rails.env].symbolize_keys
48
+
49
+ Caliper.logger.error "No API Key set in caliper.yml" unless @config[:api_key]
50
+
51
+ # set host
52
+ @config[:api_host] = ENV["CALIPER_API_HOST"] || 'http://alpha.caliper.io/'
53
+
54
+ @config
55
+ rescue StandardError => e
56
+ Caliper.logger.error "No caliper.yml config file could be found!"
57
+ raise e
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,62 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+ require 'singleton'
4
+
5
+ module CaliperApi
6
+
7
+ class Poster
8
+ include Singleton
9
+
10
+ def initialize
11
+ @base_uri = Caliper.config[:api_host]
12
+ end
13
+
14
+ def self.send(url, data)
15
+ instance.post(url, data)
16
+ end
17
+
18
+ def post(url, data = "")
19
+ begin
20
+ uri = URI.parse(@base_uri + url)
21
+ http = Net::HTTP.new(uri.host, uri.port)
22
+
23
+ http.open_timeout = 5 # in seconds
24
+ http.read_timeout = 5 # in seconds
25
+
26
+ request = Net::HTTP::Post.new(uri.request_uri)
27
+ request["X_API_KEY"] = Caliper.config[:api_key]
28
+ request["Content-Type"] = "application/json"
29
+ request["Accept"] = "application/json"
30
+
31
+ request.body = data
32
+
33
+ response = http.request(request)
34
+
35
+ status = response.code.to_i
36
+ if status == 401
37
+ Caliper.logger.error "CaliperApi: Error: Not authorized check your API key on #{Caliper.config[:api_host]}"
38
+ elsif status > 400
39
+ Caliper.logger.error "CaliperApi: Error: got #{response.code} from server"
40
+ end
41
+ rescue Exception => e
42
+ Caliper.logger.error "CaliperApi: Http error: #{e.message}"
43
+ end
44
+ end
45
+ end
46
+
47
+ def self.test_post
48
+ Poster.send("/api/test", "")
49
+ end
50
+
51
+ def self.create_trace(tracer_json)
52
+ Poster.send("/api/traces", tracer_json)
53
+ end
54
+
55
+ def self.create_error(error_json)
56
+ Poster.send("/api/errors", error_json)
57
+ end
58
+
59
+ def self.update_routes(routes_json)
60
+ Poster.send("/api/routes", routes_json)
61
+ end
62
+ end
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ describe Caliper::Tracer do
4
+
5
+ it 'should generate a uid on creation' do
6
+ tracer = Caliper::Tracer.new({"REQEUEST_METHOD" => "POST", "REQUEST_PATH" => "/users"})
7
+ tracer.uuid.should_not be_nil
8
+ end
9
+
10
+ context "When storing 2 events" do
11
+ before do
12
+ @tracer = Caliper::Tracer.new({"REQEUEST_METHOD" => "GET", "REQUEST_PATH" => "/users"})
13
+ @events = []
14
+ 2.times {
15
+ event = mock_event
16
+ @tracer.record(event)
17
+ @events << event
18
+ }
19
+ end
20
+
21
+ it 'should store the two events to referencing later' do
22
+ @tracer.samples.should_not be_nil
23
+ @tracer.samples.size.should eq 2
24
+ end
25
+
26
+ it 'should post data to CaliperAPI when finished' do
27
+ CaliperApi.should_receive(:create_trace)
28
+ @tracer.finish
29
+ end
30
+ end
31
+
32
+ context "Given a tracer with no samples" do
33
+ before do
34
+ @tracer = Caliper::Tracer.new({"REQUEST_METHOD" => "GET", "REQUEST_PATH" => "/users"})
35
+ end
36
+
37
+ it 'should not post data to CaliperAPI when finished' do
38
+ CaliperApi.should_not_receive(:create_trace)
39
+ @tracer.finish
40
+ end
41
+ end
42
+
43
+ context "A typical rails controller request trace" do
44
+ before do
45
+ @tracer = Caliper::Tracer.new({"REQEUEST_METHOD" => "GET", "REQUEST_PATH" => "/users"})
46
+
47
+ replay_into_tracer(@tracer, "rails_get_request_samples")
48
+ end
49
+
50
+ it 'should have stored correct amount of samples ignoring SCHEMA named events' do
51
+ @tracer.samples.each do |sample|
52
+ if sample.name[/active_record/]
53
+ sample.payload[:name].should_not eq "SCHEMA"
54
+ end
55
+ end
56
+ @tracer.samples.size.should eq 6
57
+ end
58
+
59
+ it 'should dump the correct json data' do
60
+ pending
61
+ end
62
+ end
63
+
64
+ end
@@ -0,0 +1,9 @@
1
+ start_processing.action_controller||2012-11-30 15:07:13 -0800||2012-11-30 15:07:13 -0800||36dc476cf70478c5aecb||{:controller=>"PostsController", :action=>"index", :params=>{"action"=>"index", "controller"=>"posts"}, :formats=>[:html], :method=>"GET", :path=>"/posts"}
2
+ sql.active_record||2012-11-30 15:07:13 -0800||2012-11-30 15:07:13 -0800||36dc476cf70478c5aecb||{:sql=>"PRAGMA table_info(\"posts\")", :name=>"SCHEMA", :connection_id=>70199742565160, :binds=>[]}
3
+ sql.active_record||2012-11-30 15:07:13 -0800||2012-11-30 15:07:13 -0800||36dc476cf70478c5aecb||{:sql=>" SELECT name\n FROM sqlite_master\n WHERE type = 'table' AND NOT name = 'sqlite_sequence'\n AND name = \"posts\"", :name=>"SCHEMA", :connection_id=>70199742565160, :binds=>[]}
4
+ sql.active_record||2012-11-30 15:07:13 -0800||2012-11-30 15:07:13 -0800||36dc476cf70478c5aecb||{:sql=>"PRAGMA table_info(\"posts\")", :name=>"SCHEMA", :connection_id=>70199742565160, :binds=>[]}
5
+ sql.active_record||2012-11-30 15:07:13 -0800||2012-11-30 15:07:13 -0800||36dc476cf70478c5aecb||{:sql=>"SELECT \"posts\".* FROM \"posts\" ", :name=>"Post Load", :connection_id=>70199742565160, :binds=>[]}
6
+ !render_template.action_view||2012-11-30 15:07:13 -0800||2012-11-30 15:07:13 -0800||36dc476cf70478c5aecb||{:virtual_path=>"posts/index"}
7
+ render_template.action_view||2012-11-30 15:07:13 -0800||2012-11-30 15:07:13 -0800||36dc476cf70478c5aecb||{:identifier=>"/Users/kalv/Development/ruby/test-caliper/app/views/posts/index.html.erb", :layout=>"layouts/application"}
8
+ !render_template.action_view||2012-11-30 15:07:13 -0800||2012-11-30 15:07:13 -0800||36dc476cf70478c5aecb||{:virtual_path=>"layouts/application"}
9
+ process_action.action_controller||2012-11-30 15:07:13 -0800||2012-11-30 15:07:13 -0800||36dc476cf70478c5aecb||{:controller=>"PostsController", :action=>"index", :params=>{"action"=>"index", "controller"=>"posts"}, :formats=>[:html], :method=>"GET", :path=>"/posts", :status=>200, :view_runtime=>22.308999999999997, :db_runtime=>1.735}