reportsmash 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +34 -0
- data/README.rdoc +2 -0
- data/Rakefile +32 -0
- data/lib/reportsmash/control/class_methods.rb +17 -0
- data/lib/reportsmash/control/instance_methods.rb +70 -0
- data/lib/reportsmash/control.rb +11 -0
- data/lib/reportsmash/engine/engine.rb +118 -0
- data/lib/reportsmash/engine/instrumentation/external.rb +16 -0
- data/lib/reportsmash/engine/instrumentation/memcache/dalli.rb +39 -0
- data/lib/reportsmash/engine/instrumentation/memcache/mem_cache.rb +39 -0
- data/lib/reportsmash/engine/instrumentation/memcache/memcached.rb +48 -0
- data/lib/reportsmash/engine/instrumentation/memcache.rb +7 -0
- data/lib/reportsmash/engine/instrumentation/redis.rb +28 -0
- data/lib/reportsmash/engine/instrumentation/typhoeus.rb +22 -0
- data/lib/reportsmash/engine/instrumentation.rb +6 -0
- data/lib/reportsmash/engine/thread_state.rb +19 -0
- data/lib/reportsmash/engine/threading.rb +13 -0
- data/lib/reportsmash/engine/transaction.rb +116 -0
- data/lib/reportsmash/engine/worker.rb +56 -0
- data/lib/reportsmash/engine.rb +41 -0
- data/lib/reportsmash/rack/hooks.rb +37 -0
- data/lib/reportsmash/rack.rb +5 -0
- data/lib/reportsmash/version.rb +3 -0
- data/lib/reportsmash.rb +22 -0
- data/lib/tasks/reportsmash_tasks.rake +4 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/config/application.rb +23 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +37 -0
- data/test/dummy/config/environments/production.rb +78 -0
- data/test/dummy/config/environments/test.rb +39 -0
- data/test/dummy/config/initializers/assets.rb +8 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +56 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/reportsmash_test.rb +7 -0
- data/test/test_helper.rb +15 -0
- metadata +173 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a6e07dc3c76a8d907d9978bf102f4b8ed9565ee2
|
4
|
+
data.tar.gz: 8270ca13975c6396261d40c033fea7a4152780ca
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c35cb6fb18f52f6ea8db50a09a7edd13681bb8f843c6034ac819a325b38ff650143b2d9891087cfbf0971fe8d4b9c324f47dbc43de88eb2eebfac17e81d968cc
|
7
|
+
data.tar.gz: 8f9b37d5343c76fa8100bbfed9de6999b183c6fa7ba6f893e2800f408f9b9a8302bad599aadcebee274f109e9ba4d4a260f08cb85de58370d003dbee937cd0bb
|
data/LICENSE
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
Except for components included from external libraries
|
2
|
+
All source code of this product is
|
3
|
+
Copyright (c) 2015-2016 ReportsMash d.o.o. All rights reserved.
|
4
|
+
|
5
|
+
Subject to the terms of this notice, ReportsMash grants you a
|
6
|
+
nonexclusive, nontransferable license, without the right to
|
7
|
+
sublicense, to (a) install and execute one copy of these files on any
|
8
|
+
number of servers owned or controlled by you and (b) distribute
|
9
|
+
verbatim copies of these files to third parties. As a condition to the
|
10
|
+
foregoing grant, you must provide this notice along with each copy you
|
11
|
+
distribute and you must not remove, alter, or obscure this notice. All
|
12
|
+
other use, reproduction, modification, distribution, or other
|
13
|
+
exploitation of these files is strictly prohibited, except as may be set
|
14
|
+
forth in a separate written license agreement between you and ReportsMash.
|
15
|
+
The terms of any such license agreement will control over this notice.
|
16
|
+
The license stated above will be automatically terminated and revoked if
|
17
|
+
you exceed its scope or violate any of the terms of this notice.
|
18
|
+
|
19
|
+
This License does not grant permission to use the trade names,
|
20
|
+
trademarks, service marks, or product names of ReportsMash, except as
|
21
|
+
required for reasonable and customary use in describing the origin of
|
22
|
+
this file and reproducing the content of this notice. You may not
|
23
|
+
mark or brand this file with any trade name, trademarks, service
|
24
|
+
marks, or product names other than the original brand (if any)
|
25
|
+
provided by ReportsMash.
|
26
|
+
|
27
|
+
Unless otherwise expressly agreed by ReportsMash in a separate written
|
28
|
+
license agreement, these files are provided AS IS, WITHOUT WARRANTY OF
|
29
|
+
ANY KIND, including without any implied warranties of MERCHANTABILITY,
|
30
|
+
FITNESS FOR A PARTICULAR PURPOSE, TITLE, or NON-INFRINGEMENT. As a
|
31
|
+
condition to your use of these files, you are solely responsible for
|
32
|
+
such use. ReportsMash 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.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'ReportsMash'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
Bundler::GemHelper.install_tasks
|
21
|
+
|
22
|
+
require 'rake/testtask'
|
23
|
+
|
24
|
+
Rake::TestTask.new(:test) do |t|
|
25
|
+
t.libs << 'lib'
|
26
|
+
t.libs << 'test'
|
27
|
+
t.pattern = 'test/**/*_test.rb'
|
28
|
+
t.verbose = false
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
task default: :test
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ReportsMash
|
2
|
+
class Control
|
3
|
+
module ClassMethods
|
4
|
+
def instance(create=true)
|
5
|
+
@instance ||= create && new
|
6
|
+
end
|
7
|
+
|
8
|
+
# clear out memoized Control and LocalEnv instances
|
9
|
+
def reset
|
10
|
+
@instance = nil
|
11
|
+
@local_env = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
extend ClassMethods
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module ReportsMash
|
2
|
+
class Control
|
3
|
+
module InstanceMethods
|
4
|
+
attr_writer :env
|
5
|
+
attr_reader :env
|
6
|
+
def init_plugin(options={})
|
7
|
+
# initialize the engine instance
|
8
|
+
ReportsMash::Engine.engine = ReportsMash::Engine::Engine.instance
|
9
|
+
ReportsMash::Engine.options = options
|
10
|
+
|
11
|
+
$stderr.puts "Initializing plugin ReportsMash - #{Process.pid}\n"
|
12
|
+
setup_rack_hooks(options[:config])
|
13
|
+
setup_database_hooks(options[:config], ReportsMash::Engine.engine)
|
14
|
+
setup_render_hooks(options[:config], ReportsMash::Engine.engine)
|
15
|
+
|
16
|
+
# if server is forking (eg, unicorn), we should not start the worker thread here
|
17
|
+
# it will be handled by Engine.transaction_start method
|
18
|
+
ReportsMash::Engine.engine.start_worker unless server_is_forking?
|
19
|
+
end
|
20
|
+
|
21
|
+
def setup_rack_hooks(config)
|
22
|
+
return if config.nil? || !config.respond_to?(:middleware)
|
23
|
+
begin
|
24
|
+
require 'reportsmash/rack/hooks'
|
25
|
+
config.middleware.use ReportsMash::Rack::Hooks
|
26
|
+
rescue => e
|
27
|
+
#::ReportsMash::Engine.logger.warn("Error installing ReportsMash Rack middleware", e)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def setup_database_hooks(config, engine)
|
32
|
+
ActiveSupport::Notifications.subscribe('sql.active_record') do |name, start, finish, id, payload|
|
33
|
+
unless payload[:name] == 'SCHEMA'
|
34
|
+
engine.save_db_transaction(id, (finish-start)*1000.0, payload[:sql], payload[:connection_id])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def setup_render_hooks(config, engine)
|
40
|
+
ActiveSupport::Notifications.subscribe('render_template.action_view') do |name, start, finish, id, payload|
|
41
|
+
view_name = payload[:identifier].split('app/views')[1]
|
42
|
+
engine.save_render_transaction(id, (finish-start)*1000.0, 'app/views'+view_name)
|
43
|
+
end
|
44
|
+
ActiveSupport::Notifications.subscribe('render_partial.action_view') do |name, start, finish, id, payload|
|
45
|
+
view_name = payload[:identifier].split('app/views')[1]
|
46
|
+
Rails.logger.debug "#{view_name} - #{(finish-start)*1000.0}"
|
47
|
+
engine.save_render_transaction(id, (finish-start)*1000.0, 'app/views'+view_name)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def server_is_forking?
|
52
|
+
# check for unicorn server
|
53
|
+
return true if defined?(::Unicorn) && defined?(::Unicorn::HttpServer) && object_running?(::Unicorn::HttpServer)
|
54
|
+
|
55
|
+
false
|
56
|
+
end
|
57
|
+
|
58
|
+
def object_running?(o)
|
59
|
+
ObjectSpace.each_object(o) do |exists|
|
60
|
+
return true
|
61
|
+
end
|
62
|
+
return false
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
include InstanceMethods
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module ReportsMash
|
2
|
+
module Engine
|
3
|
+
class Engine
|
4
|
+
module ClassMethods
|
5
|
+
def instance
|
6
|
+
@instance ||= self.new
|
7
|
+
end
|
8
|
+
end
|
9
|
+
extend ClassMethods
|
10
|
+
|
11
|
+
attr_accessor :delivery_queue
|
12
|
+
attr_accessor :pid
|
13
|
+
attr_accessor :collector
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@transactions = {}
|
17
|
+
@engine_start = Time.now
|
18
|
+
@delivery_queue = []
|
19
|
+
@db_transactions = {}
|
20
|
+
@pid = Process.pid
|
21
|
+
@started = false
|
22
|
+
end
|
23
|
+
|
24
|
+
def boot_from_fork
|
25
|
+
return if @started
|
26
|
+
@started = true
|
27
|
+
@pid = Process.pid
|
28
|
+
@engine_start = Time.now
|
29
|
+
|
30
|
+
$stderr.puts "Initializing plugin ReportsMash in child #{Process.ppid} -> #{Process.pid}\n"
|
31
|
+
begin
|
32
|
+
start_worker
|
33
|
+
rescue => e
|
34
|
+
$stderr.puts "Error while starting worker #{e.inspect}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def transaction_start(request)
|
39
|
+
if @pid != Process.pid && !@started
|
40
|
+
# we have been forked. Make sure engine worker is running in this child
|
41
|
+
ReportsMash::Engine.boot_from_fork()
|
42
|
+
end
|
43
|
+
transaction = ReportsMash::Engine::Transaction.new(@instance, request)
|
44
|
+
ReportsMash::Engine::ThreadState.get_current_state.transaction = transaction
|
45
|
+
request["X-REPORTSMASH-TRANSACTION-ID"] = transaction.tid
|
46
|
+
@transactions[transaction.tid] = transaction
|
47
|
+
end
|
48
|
+
|
49
|
+
def transaction_end(start_time, stop_time, e, response, env)
|
50
|
+
transaction = @transactions[env["X-REPORTSMASH-TRANSACTION-ID"]]
|
51
|
+
(status_code, headers, body) = response
|
52
|
+
transaction.end(start_time, stop_time, status_code, headers)
|
53
|
+
# don't allow more than 150 transactions in queue
|
54
|
+
@delivery_queue.push transaction if @delivery_queue.count < 150
|
55
|
+
env.delete("X-REPORTSMASH-TRANSACTION-ID") if env["X-REPORTSMASH-TRANSACTION-ID"]
|
56
|
+
ReportsMash::Engine::ThreadState.clear
|
57
|
+
end
|
58
|
+
|
59
|
+
def custom_attr(new_params)
|
60
|
+
trans = ReportsMash::Engine::ThreadState.get_current_state.transaction
|
61
|
+
trans.user_params.merge!(new_params) if new_params.is_a? Array
|
62
|
+
end
|
63
|
+
|
64
|
+
def start_worker
|
65
|
+
@worker_thread = ReportsMash::Engine::Threading::WorkerThread.new do
|
66
|
+
worker_loop = ReportsMash::Engine::WorkerLoop.new
|
67
|
+
worker_loop.run
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def save_db_transaction(id, duration, sql, connection_id)
|
72
|
+
trans = ReportsMash::Engine::ThreadState.get_current_state.transaction
|
73
|
+
return unless trans
|
74
|
+
item = {
|
75
|
+
duration: duration,
|
76
|
+
sql: sql,
|
77
|
+
connection_id: connection_id
|
78
|
+
}
|
79
|
+
trans.db_transactions.push item
|
80
|
+
trans.db_duration_ms += duration
|
81
|
+
end
|
82
|
+
|
83
|
+
def save_render_transaction(id, duration, path)
|
84
|
+
trans = ReportsMash::Engine::ThreadState.get_current_state.transaction
|
85
|
+
return unless trans
|
86
|
+
item = {
|
87
|
+
duration: duration,
|
88
|
+
path: path
|
89
|
+
}
|
90
|
+
trans.render_transactions.push item
|
91
|
+
trans.render_duration_ms += duration
|
92
|
+
end
|
93
|
+
|
94
|
+
def save_external_http(item)
|
95
|
+
trans = ReportsMash::Engine::ThreadState.get_current_state.transaction
|
96
|
+
return unless trans
|
97
|
+
trans.external_http_requests.push item
|
98
|
+
trans.external_http_duration_ms += item[:duration]
|
99
|
+
end
|
100
|
+
|
101
|
+
def save_external_mc(op, duration)
|
102
|
+
trans = ReportsMash::Engine::ThreadState.get_current_state.transaction
|
103
|
+
return unless trans
|
104
|
+
h = {op.to_sym => duration}
|
105
|
+
trans.memcached_ops.push h
|
106
|
+
end
|
107
|
+
|
108
|
+
def save_external_redis(op, duration)
|
109
|
+
trans = ReportsMash::Engine::ThreadState.get_current_state.transaction
|
110
|
+
return unless trans
|
111
|
+
h = {op.to_sym => duration}
|
112
|
+
trans.redis_ops.push h
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ReportsMash::Engine::Instrumentation
|
2
|
+
module External
|
3
|
+
def self.record_http_trace(data)
|
4
|
+
ReportsMash::Engine.engine.save_external_http(data)
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.record_mc_trace(op, duration)
|
8
|
+
ReportsMash::Engine.engine.save_external_mc(op, duration)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.record_redis_trace(op, duration)
|
12
|
+
ReportsMash::Engine.engine.save_external_redis(op, duration)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module ReportsMash::Engine::Instrumentation::Memcache
|
2
|
+
module Dalli
|
3
|
+
|
4
|
+
if defined?(::Dalli) && defined?(::Dalli::Client)
|
5
|
+
::Dalli::Client.class_eval do
|
6
|
+
|
7
|
+
def reportsmash_mc_get(*args)
|
8
|
+
start_time = Time.now
|
9
|
+
rv = orig_get(*args)
|
10
|
+
ReportsMash::Engine::Instrumentation::External.record_mc_trace("get", (Time.now - start_time)*1000.0)
|
11
|
+
rv
|
12
|
+
end
|
13
|
+
alias :orig_get :get
|
14
|
+
alias :get :reportsmash_mc_get
|
15
|
+
|
16
|
+
def reportsmash_mc_set(*args)
|
17
|
+
start_time = Time.now
|
18
|
+
rv = orig_set(*args)
|
19
|
+
ReportsMash::Engine::Instrumentation::External.record_mc_trace("set", (Time.now - start_time)*1000.0)
|
20
|
+
rv
|
21
|
+
end
|
22
|
+
alias :orig_set :set
|
23
|
+
alias :set :reportsmash_mc_set
|
24
|
+
|
25
|
+
|
26
|
+
def reportsmash_mc_get_multi(*args)
|
27
|
+
start_time = Time.now
|
28
|
+
rv = orig_get_multi(*args)
|
29
|
+
ReportsMash::Engine::Instrumentation::External.record_mc_trace("get_multi", (Time.now - start_time)*1000.0)
|
30
|
+
rv
|
31
|
+
end
|
32
|
+
alias :orig_get_multi :get_multi
|
33
|
+
alias :get_multi :reportsmash_mc_get_multi
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module ReportsMash::Engine::Instrumentation::Memcache
|
2
|
+
module MemCache
|
3
|
+
|
4
|
+
if defined?(::MemCache)
|
5
|
+
::MemCache.class_eval do
|
6
|
+
|
7
|
+
def reportsmash_mc_get(*args)
|
8
|
+
start_time = Time.now
|
9
|
+
rv = orig_get(*args)
|
10
|
+
ReportsMash::Engine::Instrumentation::External.record_mc_trace("get", (Time.now - start_time)*1000.0)
|
11
|
+
rv
|
12
|
+
end
|
13
|
+
alias :orig_get :get
|
14
|
+
alias :get :reportsmash_mc_get
|
15
|
+
|
16
|
+
def reportsmash_mc_set(*args)
|
17
|
+
start_time = Time.now
|
18
|
+
rv = orig_set(*args)
|
19
|
+
ReportsMash::Engine::Instrumentation::External.record_mc_trace("set", (Time.now - start_time)*1000.0)
|
20
|
+
rv
|
21
|
+
end
|
22
|
+
alias :orig_set :set
|
23
|
+
alias :set :reportsmash_mc_set
|
24
|
+
|
25
|
+
|
26
|
+
def reportsmash_mc_get_multi(*args)
|
27
|
+
start_time = Time.now
|
28
|
+
rv = orig_get_multi(*args)
|
29
|
+
ReportsMash::Engine::Instrumentation::External.record_mc_trace("get_multi", (Time.now - start_time)*1000.0)
|
30
|
+
rv
|
31
|
+
end
|
32
|
+
alias :orig_get_multi :get_multi
|
33
|
+
alias :get_multi :reportsmash_mc_get_multi
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module ReportsMash::Engine::Instrumentation::Memcache
|
2
|
+
module Memcached
|
3
|
+
|
4
|
+
if defined?(::Memcached) && Gem::Version.new("1.8.0") <= Gem::Version.new(::Memcached::VERSION)
|
5
|
+
::Memcached.class_eval do
|
6
|
+
|
7
|
+
def reportsmash_mc_single_get(*args)
|
8
|
+
start_time = Time.now
|
9
|
+
rv = orig_single_get(*args)
|
10
|
+
ReportsMash::Engine::Instrumentation::External.record_mc_trace("get", (Time.now - start_time)*1000.0)
|
11
|
+
rv
|
12
|
+
end
|
13
|
+
alias :orig_single_get :single_get
|
14
|
+
alias :single_get :reportsmash_mc_single_get
|
15
|
+
|
16
|
+
def reportsmash_mc_multi_get(*args)
|
17
|
+
start_time = Time.now
|
18
|
+
rv = orig_multi_get(*args)
|
19
|
+
ReportsMash::Engine::Instrumentation::External.record_mc_trace("get_multi", (Time.now - start_time)*1000.0)
|
20
|
+
rv
|
21
|
+
end
|
22
|
+
alias :orig_multi_get :multi_get
|
23
|
+
alias :multi_get :reportsmash_mc_multi_get
|
24
|
+
|
25
|
+
|
26
|
+
def reportsmash_mc_single_cas(*args)
|
27
|
+
start_time = Time.now
|
28
|
+
rv = orig_single_cas(*args)
|
29
|
+
ReportsMash::Engine::Instrumentation::External.record_mc_trace("set", (Time.now - start_time)*1000.0)
|
30
|
+
rv
|
31
|
+
end
|
32
|
+
alias :orig_single_cas :single_cas
|
33
|
+
alias :single_cas :reportsmash_mc_single_cas
|
34
|
+
|
35
|
+
def reportsmash_mc_multi_cas(*args)
|
36
|
+
start_time = Time.now
|
37
|
+
rv = orig_multi_cas(*args)
|
38
|
+
ReportsMash::Engine::Instrumentation::External.record_mc_trace("set", (Time.now - start_time)*1000.0)
|
39
|
+
rv
|
40
|
+
end
|
41
|
+
alias :orig_multi_cas :multi_cas
|
42
|
+
alias :multi_cas :reportsmash_mc_multi_cas
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module ReportsMash::Engine::Instrumentation
|
2
|
+
module Redis
|
3
|
+
|
4
|
+
if defined?(::Redis)
|
5
|
+
::Redis.class_eval do
|
6
|
+
|
7
|
+
def reportsmash_redis_get(*args)
|
8
|
+
start_time = Time.now
|
9
|
+
rv = orig_get(*args)
|
10
|
+
ReportsMash::Engine::Instrumentation::External.record_redis_trace("get", (Time.now - start_time)*1000.0)
|
11
|
+
rv
|
12
|
+
end
|
13
|
+
alias :orig_get :get
|
14
|
+
alias :get :reportsmash_redis_get
|
15
|
+
|
16
|
+
def reportsmash_redis_set(*args)
|
17
|
+
start_time = Time.now
|
18
|
+
rv = orig_set(*args)
|
19
|
+
ReportsMash::Engine::Instrumentation::External.record_redis_trace("set", (Time.now - start_time)*1000.0)
|
20
|
+
rv
|
21
|
+
end
|
22
|
+
alias :orig_set :set
|
23
|
+
alias :set :reportsmash_redis_set
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ReportsMash::Engine::Instrumentation
|
2
|
+
SUPPORTED_VERSION = "0.5.3"
|
3
|
+
if defined?(::Typhoeus) && defined?(::Typhoeus::VERSION) && Gem::Version.new(SUPPORTED_VERSION) <= Gem::Version.new(::Typhoeus::VERSION)
|
4
|
+
Typhoeus.before do |request|
|
5
|
+
#start trace
|
6
|
+
start_time = Time.now
|
7
|
+
cb = Proc.new do
|
8
|
+
duration = (Time.now - start_time)*1000.0
|
9
|
+
data = {
|
10
|
+
client: "Typhoeus",
|
11
|
+
duration: duration,
|
12
|
+
response_code: request.response.response_code,
|
13
|
+
url: request.url,
|
14
|
+
method: request.original_options[:method].to_s.upcase
|
15
|
+
}
|
16
|
+
ReportsMash::Engine::Instrumentation::External.record_http_trace(data)
|
17
|
+
end
|
18
|
+
request.on_complete.unshift(cb)
|
19
|
+
true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module ReportsMash
|
2
|
+
module Engine
|
3
|
+
class ThreadState
|
4
|
+
attr_accessor :transaction
|
5
|
+
def initialize
|
6
|
+
@transaction = nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.get_current_state
|
10
|
+
Thread.current[:reportsmash_state] ||= ThreadState.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.clear
|
14
|
+
Thread.current[:reportsmash_state] = nil
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module ReportsMash::Engine
|
2
|
+
class Transaction
|
3
|
+
attr_accessor :user_params
|
4
|
+
attr_accessor :payload
|
5
|
+
attr_accessor :db_transactions, :db_duration_ms, :render_transactions, :render_duration_ms
|
6
|
+
attr_accessor :external_http_requests, :external_http_duration_ms
|
7
|
+
attr_accessor :memcached_ops, :redis_ops
|
8
|
+
|
9
|
+
def initialize(engine, request)
|
10
|
+
@engine = engine
|
11
|
+
@request = request
|
12
|
+
@response = nil
|
13
|
+
@tid = SecureRandom.uuid
|
14
|
+
@user_params = []
|
15
|
+
@start_time = nil
|
16
|
+
@total_duration_ms = 0
|
17
|
+
@db_duration_ms = 0
|
18
|
+
@render_duration_ms = 0
|
19
|
+
@payload = {}
|
20
|
+
@db_transactions = []
|
21
|
+
@render_transactions = []
|
22
|
+
@external_http_requests = []
|
23
|
+
@external_http_duration_ms = 0
|
24
|
+
@memcached_ops = []
|
25
|
+
@redis_ops = []
|
26
|
+
end
|
27
|
+
|
28
|
+
def tid
|
29
|
+
@tid
|
30
|
+
end
|
31
|
+
|
32
|
+
def add_user_params(new_params)
|
33
|
+
@user_params.merge!(new_params) if new_params.is_a? Hash
|
34
|
+
end
|
35
|
+
|
36
|
+
def end(start_time, stop_time, status_code, headers)
|
37
|
+
@start_time = start_time
|
38
|
+
response_content_type = (headers && headers["Content-Type"]) ? headers["Content-Type"] : ""
|
39
|
+
@total_duration_ms = (stop_time - start_time) * 1000.0
|
40
|
+
path_params = @request["action_dispatch.request.path_parameters"]
|
41
|
+
controller_action = "static_file_server"
|
42
|
+
if path_params.key?(:controller) && path_params.key?(:action)
|
43
|
+
controller_action = path_params[:controller]+"#"+path_params[:action]
|
44
|
+
end
|
45
|
+
|
46
|
+
@memcached_stats = {}
|
47
|
+
mc_duration_ms = 0
|
48
|
+
mc_counter = 0
|
49
|
+
if @memcached_ops.count > 0
|
50
|
+
%w[get set get_multi].each do |op|
|
51
|
+
stat = {count: 0, duration_ms: 0, avg_ms: 0}
|
52
|
+
@memcached_ops.select{|h| h.key? op.to_sym}.each do |trace|
|
53
|
+
stat[:count] += 1
|
54
|
+
stat[:duration_ms] += trace[op.to_sym]
|
55
|
+
stat[:avg_ms] = (stat[:duration_ms]/Float(stat[:count])).round(2)
|
56
|
+
@memcached_stats[op.to_sym] = stat
|
57
|
+
mc_duration_ms += stat[:duration_ms]
|
58
|
+
mc_counter += 1
|
59
|
+
end
|
60
|
+
end
|
61
|
+
#puts "GOT MC_OPS #{@memcached_ops.inspect}: #{@memcached_stats.inspect}"
|
62
|
+
end
|
63
|
+
|
64
|
+
@redis_stats = {}
|
65
|
+
redis_duration_ms = 0
|
66
|
+
redis_counter = 0
|
67
|
+
if @redis_ops.count > 0
|
68
|
+
%w[get set].each do |op|
|
69
|
+
stat = {count: 0, duration_ms: 0, avg_ms: 0}
|
70
|
+
@redis_ops.select{|h| h.key? op.to_sym}.each do |trace|
|
71
|
+
stat[:count] += 1
|
72
|
+
stat[:duration_ms] += trace[op.to_sym]
|
73
|
+
stat[:avg_ms] = (stat[:duration_ms]/Float(stat[:count])).round(2)
|
74
|
+
@redis_stats[op.to_sym] = stat
|
75
|
+
redis_duration_ms += stat[:duration_ms]
|
76
|
+
redis_counter += 1
|
77
|
+
end
|
78
|
+
end
|
79
|
+
#puts "GOT REDIS_OPS #{@redis_ops.inspect}: #{@redis_stats.inspect}"
|
80
|
+
end
|
81
|
+
|
82
|
+
@payload = {
|
83
|
+
:time_utc => @start_time.utc.to_i,
|
84
|
+
:user_ip => @request["REMOTE_ADDR"],
|
85
|
+
:user_agent => @request["HTTP_USER_AGENT"],
|
86
|
+
:method => @request["REQUEST_METHOD"],
|
87
|
+
:http_host => @request["HTTP_HOST"],
|
88
|
+
:request_uri => @request["REQUEST_URI"],
|
89
|
+
:request_path => @request["REQUEST_PATH"],
|
90
|
+
:controller_action => controller_action,
|
91
|
+
:response_content_type => response_content_type,
|
92
|
+
:status => status_code,
|
93
|
+
:total_duration_ms => @total_duration_ms.round(2),
|
94
|
+
:db_duration_ms => @db_duration_ms.round(2),
|
95
|
+
:render_duration_ms => @render_duration_ms.round(2),
|
96
|
+
:external_http_duration_ms => @external_http_duration_ms.round(2),
|
97
|
+
:external_memcache_duration_ms => mc_duration_ms.round(2),
|
98
|
+
:external_redis_duration_ms => redis_duration_ms.round(2),
|
99
|
+
:db_counter => @db_transactions.count,
|
100
|
+
:render_counter => @render_transactions.count,
|
101
|
+
:external_http_counter => @external_http_requests.count,
|
102
|
+
:external_memcache_counter => mc_counter,
|
103
|
+
:external_redis_counter => redis_counter,
|
104
|
+
:db_transactions => @db_transactions,
|
105
|
+
:render_transactions => @render_transactions,
|
106
|
+
:external_http_requests => @external_http_requests,
|
107
|
+
:external_memcache_requests => @memcached_stats,
|
108
|
+
:external_redis_requests => @redis_stats,
|
109
|
+
|
110
|
+
:custom_attributes => @user_params
|
111
|
+
}
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|