reportsmash 0.3.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 +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
|
+
|