debugbar 0.0.1 → 0.1.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.
- checksums.yaml +7 -0
- data/.prettierrc +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +5 -0
- data/Rakefile +4 -0
- data/app/channels/debugbar/debugbar_channel.rb +26 -0
- data/app/controllers/debugbar/application_controller.rb +4 -0
- data/app/controllers/debugbar/assets_controller.rb +15 -0
- data/app/helpers/debugbar/tag_helpers.rb +19 -0
- data/app/models/debugbar/application_record.rb +5 -0
- data/build.sh +7 -0
- data/config/routes.rb +7 -0
- data/debugbar.gemspec +43 -0
- data/lib/debugbar/buffers/memory_buffer.rb +34 -0
- data/lib/debugbar/buffers/null_buffer.rb +18 -0
- data/lib/debugbar/buffers/request_buffer.rb +31 -0
- data/lib/debugbar/config.rb +50 -0
- data/lib/debugbar/current.rb +18 -0
- data/lib/debugbar/engine.rb +88 -5
- data/lib/debugbar/loggers/simple_logger.rb +34 -0
- data/lib/debugbar/middlewares/track_current_request.rb +35 -0
- data/lib/debugbar/request.rb +98 -0
- data/lib/debugbar/subscribers/action_controller.rb +33 -0
- data/lib/debugbar/subscribers/active_job.rb +158 -0
- data/lib/debugbar/subscribers/active_record.rb +65 -0
- data/lib/debugbar/subscribers/active_support.rb +30 -0
- data/lib/debugbar/version.rb +5 -0
- data/lib/debugbar.rb +79 -5
- data/sig/debugbar.rbs +4 -0
- metadata +91 -47
- data/README.textile +0 -18
- data/lib/debugbar/railties/tasks.rake +0 -1
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5380fa3760a1309aacd1404c077e3e6c78ed94d21bde373eb0f96f90da96abe6
|
4
|
+
data.tar.gz: 7e9f86653a25e202c9ebf4c64b8d74f5816aaadbee1f2e2d75b46423fa17a8dd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: '08f084f414d3520d4f7f287b3ffcde2a1a322b7bc04492bcf80ca0087b7fe1a853db6dac041bafceaa352944d8c09ed8d12ecf47bfa30cbc03643f29e2573179'
|
7
|
+
data.tar.gz: 2836203deb352f9d344d8784423b801d6ca6ff26e7e48adaec4ea58b142434999ef145f32207de68ba80cf499dba137e8f41d507d97bb9f025d84084a205ac65
|
data/.prettierrc
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2023 Julien Bourdeau
|
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
|
13
|
+
all 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
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module Debugbar
|
2
|
+
class DebugbarChannel < ActionCable::Channel::Base
|
3
|
+
def subscribed
|
4
|
+
stream_from "debugbar_channel"
|
5
|
+
end
|
6
|
+
|
7
|
+
def receive(data)
|
8
|
+
if data["clear"]
|
9
|
+
RequestBuffer.clear!
|
10
|
+
end
|
11
|
+
|
12
|
+
if data["ids"].present?
|
13
|
+
RequestBuffer.remove(data["ids"])
|
14
|
+
end
|
15
|
+
|
16
|
+
Debugbar.connect!
|
17
|
+
|
18
|
+
data = RequestBuffer.all.map(&:to_h)
|
19
|
+
ActionCable.server.broadcast("debugbar_channel", data)
|
20
|
+
end
|
21
|
+
|
22
|
+
def unsubscribed
|
23
|
+
Debugbar.disconnect!
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Debugbar
|
2
|
+
class AssetsController < ApplicationController
|
3
|
+
def js
|
4
|
+
render file: File.join(Gem.loaded_specs['debugbar'].full_gem_path, 'public', 'debugbar.js'),
|
5
|
+
layout: false,
|
6
|
+
content_type: 'text/javascript'
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def verify_same_origin_request
|
12
|
+
true # YOLO
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Debugbar::TagHelpers
|
2
|
+
def debugbar_javascript(opt = {})
|
3
|
+
html = <<-HTML
|
4
|
+
<div id="__debugbar"></div>
|
5
|
+
HTML
|
6
|
+
|
7
|
+
html += <<-HTML
|
8
|
+
<script type="text/javascript">
|
9
|
+
window._debugbarConfigOptions = #{opt.to_json}
|
10
|
+
</script>
|
11
|
+
HTML
|
12
|
+
|
13
|
+
html += <<-HTML
|
14
|
+
<script defer src="#{Debugbar.config.prefix}/assets/script"></script>
|
15
|
+
HTML
|
16
|
+
|
17
|
+
raw html
|
18
|
+
end
|
19
|
+
end
|
data/build.sh
ADDED
data/config/routes.rb
ADDED
data/debugbar.gemspec
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/debugbar/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "debugbar"
|
7
|
+
spec.version = Debugbar::VERSION
|
8
|
+
spec.authors = ["Julien Bourdeau"]
|
9
|
+
spec.email = ["julien@debugbar.dev"]
|
10
|
+
|
11
|
+
spec.summary = "Powerful devtools for Ruby on Rails"
|
12
|
+
spec.description = "Get a better understanding of your application performance and behavior (SQL queries, jobs, cache, routes, logs, etc)"
|
13
|
+
spec.homepage = "https://debugbar.dev"
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.required_ruby_version = ">= 2.6.0"
|
16
|
+
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
18
|
+
spec.metadata["source_code_uri"] = "https://github.com/julienbourdeau/debugbar"
|
19
|
+
spec.metadata["changelog_uri"] = "https://debugbar.dev/changelog/"
|
20
|
+
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
22
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
+
files_to_remove = %w[
|
24
|
+
bin/ test/ spec/ features/ fixtures/
|
25
|
+
client/
|
26
|
+
.git .circleci appveyor Gemfile package.json package-lock.json
|
27
|
+
]
|
28
|
+
spec.files = Dir.chdir(__dir__) do
|
29
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
30
|
+
(File.expand_path(f) == __FILE__) ||
|
31
|
+
f.start_with?(*files_to_remove)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
spec.bindir = "exe"
|
35
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
36
|
+
spec.require_paths = ["lib"]
|
37
|
+
|
38
|
+
spec.add_dependency "rails" #, ">= 7.1.1"
|
39
|
+
spec.add_dependency "actioncable" #, ">= 7.1.1"
|
40
|
+
|
41
|
+
# For more information and examples about making a new gem, check out our
|
42
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
43
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Debugbar
|
2
|
+
class MemoryBuffer
|
3
|
+
def initialize
|
4
|
+
@collection = {}
|
5
|
+
end
|
6
|
+
|
7
|
+
def push(request)
|
8
|
+
@collection[request.id] = request
|
9
|
+
nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def remove(ids)
|
13
|
+
ids = Array.wrap(ids)
|
14
|
+
ids.each do |id|
|
15
|
+
@collection.delete(id)
|
16
|
+
end
|
17
|
+
:self
|
18
|
+
end
|
19
|
+
|
20
|
+
def all
|
21
|
+
@collection.values
|
22
|
+
end
|
23
|
+
|
24
|
+
def each(&block)
|
25
|
+
@collection.each(&block)
|
26
|
+
:self
|
27
|
+
end
|
28
|
+
|
29
|
+
def clear!
|
30
|
+
@collection = {}
|
31
|
+
:self
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Debugbar
|
2
|
+
class RequestBuffer
|
3
|
+
class << self
|
4
|
+
def init(adapter)
|
5
|
+
@enabled = false
|
6
|
+
@adapter = adapter
|
7
|
+
end
|
8
|
+
|
9
|
+
def enable!
|
10
|
+
@enabled = true
|
11
|
+
send_all
|
12
|
+
end
|
13
|
+
|
14
|
+
def disable!
|
15
|
+
@enabled = false
|
16
|
+
end
|
17
|
+
|
18
|
+
def send_all
|
19
|
+
data = @collection.values.map(&:to_h)
|
20
|
+
ActionCable.server.broadcast("debugbar_channel", data)
|
21
|
+
end
|
22
|
+
|
23
|
+
%w(push each all remove clear!).each do |name|
|
24
|
+
define_method(name) do |*args, &block|
|
25
|
+
ret = @adapter.send(name, *args, &block)
|
26
|
+
ret == :self ? self : ret
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Debugbar
|
2
|
+
class Config
|
3
|
+
attr_accessor :enabled, :prefix, :buffer_adapter, :ignore_request,
|
4
|
+
:active_record, :action_controller, :active_job,
|
5
|
+
:min_log_level
|
6
|
+
|
7
|
+
alias_method :enabled?, :enabled
|
8
|
+
|
9
|
+
def initialize(options = {})
|
10
|
+
opt = defaults.merge options
|
11
|
+
@enabled = opt[:enabled] && !defined?(Rails::Console)
|
12
|
+
@prefix = opt[:prefix]
|
13
|
+
@active_record = opt[:active_record]
|
14
|
+
@action_controller = opt[:action_controller]
|
15
|
+
@active_job = opt[:active_job]
|
16
|
+
@min_log_level = opt[:min_log_level]
|
17
|
+
@buffer_adapter = opt[:buffer_adapter]
|
18
|
+
end
|
19
|
+
|
20
|
+
def defaults
|
21
|
+
{
|
22
|
+
enabled: Rails.env.development?,
|
23
|
+
prefix: "/_debugbar",
|
24
|
+
active_record: true,
|
25
|
+
action_controller: true,
|
26
|
+
active_job: true,
|
27
|
+
min_log_level: -1,
|
28
|
+
buffer_adapter: :memory,
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def ignore_request?(env)
|
33
|
+
if ignore_request.is_a? Proc
|
34
|
+
ignore_request.call(env)
|
35
|
+
else
|
36
|
+
[Debugbar.config.prefix, "/assets"].any? { |s| env['PATH_INFO'].start_with? s }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def use_logger?
|
41
|
+
@enabled && @min_log_level >= 0
|
42
|
+
end
|
43
|
+
|
44
|
+
%w(active_record action_controller active_job).each do |name|
|
45
|
+
define_method("#{name}?") do
|
46
|
+
@enabled && instance_variable_get("@#{name}")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Debugbar
|
4
|
+
class Current < ActiveSupport::CurrentAttributes
|
5
|
+
attribute :request
|
6
|
+
attribute :ignore
|
7
|
+
|
8
|
+
alias_method :ignore?, :ignore
|
9
|
+
|
10
|
+
def new_request!(request_id)
|
11
|
+
self.request = Request.new(request_id)
|
12
|
+
end
|
13
|
+
|
14
|
+
def pop_request!
|
15
|
+
request.tap { self.request = nil }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/debugbar/engine.rb
CHANGED
@@ -1,10 +1,93 @@
|
|
1
|
+
require_relative 'config'
|
2
|
+
require_relative 'middlewares/track_current_request'
|
3
|
+
|
1
4
|
module Debugbar
|
2
|
-
class Engine < Rails::Engine
|
3
|
-
|
4
|
-
|
5
|
+
class Engine < ::Rails::Engine
|
6
|
+
isolate_namespace Debugbar
|
7
|
+
|
8
|
+
initializer 'debugbar.config' do |app|
|
9
|
+
app.config.debugbar = ::Debugbar.config
|
10
|
+
end
|
11
|
+
|
12
|
+
initializer 'debugbar.init' do |app|
|
13
|
+
adapter = case(app.config.debugbar.buffer_adapter)
|
14
|
+
when :memory
|
15
|
+
require_relative 'buffers/memory_buffer'
|
16
|
+
MemoryBuffer.new
|
17
|
+
when :null
|
18
|
+
require_relative 'buffers/null_buffer'
|
19
|
+
NullBuffer.new
|
20
|
+
else
|
21
|
+
throw "Invalid RequestBuffer adapter"
|
22
|
+
end
|
23
|
+
|
24
|
+
Debugbar::RequestBuffer.init(adapter)
|
25
|
+
end
|
26
|
+
|
27
|
+
initializer 'debugbar.helper' do
|
28
|
+
ActiveSupport.on_load(:action_controller) do
|
29
|
+
ActionController::Base.helper(Debugbar::TagHelpers)
|
30
|
+
end
|
31
|
+
|
32
|
+
ActiveSupport.on_load(:action_view) do
|
33
|
+
include Debugbar::TagHelpers
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
initializer 'debugbar.inject_middlewares' do |app|
|
38
|
+
next unless Debugbar.config.enabled?
|
39
|
+
app.middleware.insert_after ActionDispatch::RequestId, Debugbar::TrackCurrentRequest
|
40
|
+
end
|
41
|
+
|
42
|
+
initializer 'debugbar.subscribe' do
|
43
|
+
if Debugbar.config.active_record?
|
44
|
+
require_relative 'subscribers/active_record'
|
45
|
+
subscribe "Debugbar::ActiveRecordEventSubscriber" => "sql.active_record"
|
46
|
+
end
|
47
|
+
|
48
|
+
if Debugbar.config.action_controller?
|
49
|
+
require_relative 'subscribers/action_controller'
|
50
|
+
subscribe "Debugbar::ActionControllerEventSubscriber" => %w[
|
51
|
+
start_processing.action_controller process_action.action_controller
|
52
|
+
]
|
53
|
+
end
|
54
|
+
|
55
|
+
if Debugbar.config.active_job?
|
56
|
+
require_relative 'subscribers/active_job'
|
57
|
+
subscribe "Debugbar::ActiveJobEventSubscriber" => ["enqueue.active_job", "enqueue_at.active_job"]
|
58
|
+
end
|
59
|
+
|
60
|
+
require_relative 'subscribers/active_support'
|
61
|
+
subscribe "Debugbar::ActiveSupportEventSubscriber.cache" => %w(
|
62
|
+
cache_read.active_support
|
63
|
+
cache_generate.active_support
|
64
|
+
cache_fetch_hit.active_support
|
65
|
+
cache_write.active_support
|
66
|
+
cache_delete.active_support
|
67
|
+
cache_exist?.active_support
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
71
|
+
initializer 'debugbar.track_models' do
|
72
|
+
next unless Debugbar.config.active_record?
|
73
|
+
ActiveSupport.on_load(:active_record) do
|
74
|
+
after_initialize do |model|
|
75
|
+
Debugbar::Tracker.inc_model(model.class.name)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
5
79
|
|
6
|
-
|
7
|
-
|
80
|
+
def subscribe(config)
|
81
|
+
config.each do |subscriber, event_names|
|
82
|
+
event_names = Array.wrap(event_names)
|
83
|
+
class_name, class_method_name = subscriber.split('.')
|
84
|
+
event_names.each do |name|
|
85
|
+
method_name = class_method_name || name.split('.').first
|
86
|
+
ActiveSupport::Notifications.subscribe name do |event|
|
87
|
+
class_name.constantize.send method_name, event
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
8
91
|
end
|
9
92
|
end
|
10
93
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Debugbar
|
2
|
+
class SimpleLogger < ::Logger
|
3
|
+
def initialize(min_level= 2)
|
4
|
+
@min_level = min_level
|
5
|
+
end
|
6
|
+
|
7
|
+
def add(severity, message = nil, progname = nil)
|
8
|
+
# We normally rely on the Tracker to know if the current request is set or nil and log an error to STDOUT,
|
9
|
+
# but in this case, it happens so often that the logs are annoying.
|
10
|
+
# In ActiveCable, only the first call goes through the Rake middleware, so every following communication
|
11
|
+
# doesn't go through TrackCurrentRequest, which initializes the request.
|
12
|
+
return if ::Debugbar::Current.request.nil?
|
13
|
+
|
14
|
+
return if severity < @min_level
|
15
|
+
|
16
|
+
if message.nil?
|
17
|
+
if block_given?
|
18
|
+
message = yield
|
19
|
+
else
|
20
|
+
message = progname
|
21
|
+
progname = nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
Debugbar::Tracker.add_log({
|
26
|
+
time: Time.now.strftime(Debugbar::TIME_FORMAT),
|
27
|
+
severity: severity,
|
28
|
+
severity_label: SEV_LABEL[severity],
|
29
|
+
message: message,
|
30
|
+
progname: progname,
|
31
|
+
})
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Debugbar
|
2
|
+
class TrackCurrentRequest
|
3
|
+
def initialize(app)
|
4
|
+
@app = app
|
5
|
+
end
|
6
|
+
|
7
|
+
def call(env)
|
8
|
+
Debugbar::Current.ignore = Debugbar.config.ignore_request?(env)
|
9
|
+
|
10
|
+
return @app.call(env) if Debugbar::Current.ignore?
|
11
|
+
|
12
|
+
Debugbar::Current.new_request!(env['action_dispatch.request_id'])
|
13
|
+
|
14
|
+
res = @app.call(env)
|
15
|
+
|
16
|
+
# TODO: Remove this if statement?
|
17
|
+
if Debugbar::Current.request&.id
|
18
|
+
# filename = "#{Time.now.to_i}--#{Debugbar::Current.request.meta.dig(:params, :controller)}_#{Debugbar::Current.request.meta.dig(:params, :action).gsub('/', '_')}.json"
|
19
|
+
# File.open(Rails.root.join('_requests', filename), "w") do |f|
|
20
|
+
# f.write(Debugbar::Current.request.to_json)
|
21
|
+
# end
|
22
|
+
|
23
|
+
RequestBuffer.push(Debugbar::Current.pop_request!)
|
24
|
+
|
25
|
+
if Debugbar.connected?
|
26
|
+
data = RequestBuffer.all.map(&:to_h)
|
27
|
+
ActionCable.server.broadcast("debugbar_channel", data)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
res
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module Debugbar
|
2
|
+
class Request
|
3
|
+
attr_reader :request_id, :meta,
|
4
|
+
:models, :queries, :jobs,
|
5
|
+
:messages, :cache, :logs
|
6
|
+
attr_accessor :request, :response, :headers
|
7
|
+
|
8
|
+
def initialize(request_id)
|
9
|
+
@request_id = request_id
|
10
|
+
@models = {}
|
11
|
+
@queries = []
|
12
|
+
@jobs = []
|
13
|
+
@messages = []
|
14
|
+
@cache = []
|
15
|
+
@logs = []
|
16
|
+
end
|
17
|
+
|
18
|
+
alias_method :id, :request_id
|
19
|
+
|
20
|
+
def meta=(meta)
|
21
|
+
meta.delete(:headers)
|
22
|
+
meta.delete(:request)
|
23
|
+
meta.delete(:response)
|
24
|
+
@meta = meta
|
25
|
+
end
|
26
|
+
|
27
|
+
def inc_model(name)
|
28
|
+
if @models[name]
|
29
|
+
@models[name] += 1
|
30
|
+
else
|
31
|
+
@models[name] = 1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_query(query)
|
36
|
+
@queries << query
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_job(job)
|
40
|
+
@jobs << job
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_msg(msg, extra)
|
44
|
+
@messages << {msg: msg, extra: extra}
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_cache(c)
|
48
|
+
@cache << c
|
49
|
+
end
|
50
|
+
|
51
|
+
def add_log(l)
|
52
|
+
@logs << l
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_h
|
56
|
+
{
|
57
|
+
id: request_id,
|
58
|
+
meta: meta,
|
59
|
+
request: request_hash,
|
60
|
+
response: response_hash,
|
61
|
+
models: models,
|
62
|
+
queries: queries,
|
63
|
+
jobs: jobs,
|
64
|
+
messages: messages,
|
65
|
+
cache: cache,
|
66
|
+
logs: logs,
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_json
|
71
|
+
JSON.pretty_generate(to_h)
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def request_hash
|
77
|
+
{
|
78
|
+
method: request.method,
|
79
|
+
path: request.path,
|
80
|
+
format: meta.dig(:format),
|
81
|
+
params: meta.dig(:params),
|
82
|
+
headers: request.env.select { |k,v| k.start_with? 'HTTP_'} # https://stackoverflow.com/a/55406700/1001125
|
83
|
+
.transform_keys { |k| k.sub(/^HTTP_/, '').split('_').map(&:capitalize).join('-') }
|
84
|
+
.sort.to_h
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
def response_hash
|
89
|
+
return nil if response.nil?
|
90
|
+
|
91
|
+
{
|
92
|
+
status: response.status,
|
93
|
+
headers: response.headers.to_h.transform_keys { |s| s.split('-').map(&:capitalize).join('-') },
|
94
|
+
body: response.body,
|
95
|
+
}
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Debugbar
|
2
|
+
class ActionControllerEventSubscriber
|
3
|
+
class << self
|
4
|
+
def start_processing(event)
|
5
|
+
return if Debugbar::Current.ignore?
|
6
|
+
|
7
|
+
Debugbar::Tracker.request = event.payload[:request]
|
8
|
+
end
|
9
|
+
|
10
|
+
def process_action(event)
|
11
|
+
return if Debugbar::Current.ignore?
|
12
|
+
|
13
|
+
meta = event.payload
|
14
|
+
|
15
|
+
meta.delete :headers
|
16
|
+
request = meta.delete :request
|
17
|
+
response = meta.delete :response
|
18
|
+
|
19
|
+
meta.merge!({
|
20
|
+
duration: event.duration,
|
21
|
+
cpu_time: event.cpu_time,
|
22
|
+
idle_time: event.idle_time,
|
23
|
+
allocations: event.allocations,
|
24
|
+
})
|
25
|
+
|
26
|
+
Debugbar::Tracker.request = request
|
27
|
+
Debugbar::Tracker.response = response
|
28
|
+
Debugbar::Tracker.meta = meta
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Debugbar
|
4
|
+
class ActiveJobEventSubscriber
|
5
|
+
class_attribute :backtrace_cleaner, default: ActiveSupport::BacktraceCleaner.new
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def enqueue(event)
|
9
|
+
return if Debugbar::Current.ignore?
|
10
|
+
|
11
|
+
job = event.payload[:job]
|
12
|
+
ex = event.payload[:exception_object] || job.enqueue_error
|
13
|
+
|
14
|
+
logs = []
|
15
|
+
logs << if ex
|
16
|
+
"Failed enqueuing #{job.class.name} to #{queue_name(event)}: #{ex.class} (#{ex.message})"
|
17
|
+
elsif event.payload[:aborted]
|
18
|
+
"Failed enqueuing #{job.class.name} to #{queue_name(event)}, a before_enqueue callback halted the enqueuing execution."
|
19
|
+
else
|
20
|
+
"Enqueued #{job.class.name} (Job ID: #{job.job_id}) to #{queue_name(event)}" + args_info(job)
|
21
|
+
end
|
22
|
+
logs << log_enqueue_source
|
23
|
+
|
24
|
+
Debugbar::Tracker.add_job({
|
25
|
+
id: job.job_id,
|
26
|
+
class: job.class.name,
|
27
|
+
queue: queue_name(event),
|
28
|
+
args: job.arguments.map { |arg| format(arg) },
|
29
|
+
successfully_enqueued: job.successfully_enqueued?,
|
30
|
+
scheduled_at: scheduled_at(job),
|
31
|
+
logs: logs,
|
32
|
+
})
|
33
|
+
end
|
34
|
+
# subscribe_log_level :enqueue, :info # ???
|
35
|
+
|
36
|
+
def enqueue_at(event)
|
37
|
+
return if Debugbar::Current.ignore?
|
38
|
+
|
39
|
+
job = event.payload[:job]
|
40
|
+
ex = event.payload[:exception_object] || job.enqueue_error
|
41
|
+
|
42
|
+
logs = []
|
43
|
+
logs << if ex
|
44
|
+
"Failed enqueuing #{job.class.name} to #{queue_name(event)}: #{ex.class} (#{ex.message})"
|
45
|
+
elsif event.payload[:aborted]
|
46
|
+
"Failed enqueuing #{job.class.name} to #{queue_name(event)}, a before_enqueue callback halted the enqueuing execution."
|
47
|
+
else
|
48
|
+
"Enqueued #{job.class.name} (Job ID: #{job.job_id}) to #{queue_name(event)} at #{scheduled_at(job)}" + args_info(job)
|
49
|
+
end
|
50
|
+
logs << log_enqueue_source
|
51
|
+
|
52
|
+
Debugbar::Tracker.add_job({
|
53
|
+
id: job.job_id,
|
54
|
+
class: job.class.name,
|
55
|
+
queue: queue_name(event),
|
56
|
+
args: job.arguments.map { |arg| format(arg) },
|
57
|
+
successfully_enqueued: job.successfully_enqueued?,
|
58
|
+
scheduled_at: scheduled_at(job),
|
59
|
+
logs: logs,
|
60
|
+
})
|
61
|
+
end
|
62
|
+
# subscribe_log_level :enqueue_at, :info
|
63
|
+
|
64
|
+
# def enqueue_all(event)
|
65
|
+
# info do
|
66
|
+
# jobs = event.payload[:jobs]
|
67
|
+
# adapter = event.payload[:adapter]
|
68
|
+
# enqueued_count = event.payload[:enqueued_count]
|
69
|
+
#
|
70
|
+
# if enqueued_count == jobs.size
|
71
|
+
# enqueued_jobs_message(adapter, jobs)
|
72
|
+
# elsif jobs.any?(&:successfully_enqueued?)
|
73
|
+
# enqueued_jobs = jobs.select(&:successfully_enqueued?)
|
74
|
+
#
|
75
|
+
# failed_enqueue_count = jobs.size - enqueued_count
|
76
|
+
# if failed_enqueue_count == 0
|
77
|
+
# enqueued_jobs_message(adapter, enqueued_jobs)
|
78
|
+
# else
|
79
|
+
# "#{enqueued_jobs_message(adapter, enqueued_jobs)}. "\
|
80
|
+
# "Failed enqueuing #{failed_enqueue_count} #{'job'.pluralize(failed_enqueue_count)}"
|
81
|
+
# end
|
82
|
+
# else
|
83
|
+
# failed_enqueue_count = jobs.size - enqueued_count
|
84
|
+
# "Failed enqueuing #{failed_enqueue_count} #{'job'.pluralize(failed_enqueue_count)} "\
|
85
|
+
# "to #{ActiveJob.adapter_name(adapter)}"
|
86
|
+
# end
|
87
|
+
# end
|
88
|
+
# end
|
89
|
+
# # subscribe_log_level :enqueue_all, :info
|
90
|
+
|
91
|
+
private
|
92
|
+
def queue_name(event)
|
93
|
+
ActiveJob.adapter_name(event.payload[:adapter]) + "(#{event.payload[:job].queue_name})"
|
94
|
+
end
|
95
|
+
|
96
|
+
def args_info(job)
|
97
|
+
if job.class.log_arguments? && job.arguments.any?
|
98
|
+
" with arguments: " +
|
99
|
+
job.arguments.map { |arg| format(arg).inspect }.join(", ")
|
100
|
+
else
|
101
|
+
""
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def format(arg)
|
106
|
+
case arg
|
107
|
+
when Hash
|
108
|
+
arg.transform_values { |value| format(value) }
|
109
|
+
when Array
|
110
|
+
arg.map { |value| format(value) }
|
111
|
+
when GlobalID::Identification
|
112
|
+
arg.to_global_id rescue arg
|
113
|
+
else
|
114
|
+
arg
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def scheduled_at(job)
|
119
|
+
Time.at(job.scheduled_at).utc if job.scheduled_at
|
120
|
+
end
|
121
|
+
|
122
|
+
def logger
|
123
|
+
ActiveJob::Base.logger
|
124
|
+
end
|
125
|
+
|
126
|
+
def info(progname = nil, &block)
|
127
|
+
return unless super
|
128
|
+
|
129
|
+
if ActiveJob.verbose_enqueue_logs
|
130
|
+
log_enqueue_source
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def error(progname = nil, &block)
|
135
|
+
return unless super
|
136
|
+
|
137
|
+
if ActiveJob.verbose_enqueue_logs
|
138
|
+
log_enqueue_source
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def log_enqueue_source
|
143
|
+
extract_enqueue_source_location(caller)
|
144
|
+
end
|
145
|
+
|
146
|
+
def extract_enqueue_source_location(locations)
|
147
|
+
backtrace_cleaner.clean(locations.lazy).first
|
148
|
+
end
|
149
|
+
|
150
|
+
def enqueued_jobs_message(adapter, enqueued_jobs)
|
151
|
+
enqueued_count = enqueued_jobs.size
|
152
|
+
job_classes_counts = enqueued_jobs.map(&:class).tally.sort_by { |_k, v| -v }
|
153
|
+
"Enqueued #{enqueued_count} #{'job'.pluralize(enqueued_count)} to #{ActiveJob.adapter_name(adapter)}"\
|
154
|
+
" (#{job_classes_counts.map { |klass, count| "#{count} #{klass}" }.join(', ')})"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Debugbar
|
4
|
+
class ActiveRecordEventSubscriber
|
5
|
+
class_attribute :backtrace_cleaner, default: ActiveSupport::BacktraceCleaner.new
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def sql(event)
|
9
|
+
return if Debugbar::Current.ignore?
|
10
|
+
|
11
|
+
payload = event.payload
|
12
|
+
|
13
|
+
return if payload[:name]&.starts_with? "SCHEMA"
|
14
|
+
|
15
|
+
title = if payload[:async]
|
16
|
+
"ASYNC #{payload[:name]} (#{payload[:lock_wait].round(1)}ms) (db time #{event.duration.round(1)}ms)"
|
17
|
+
else
|
18
|
+
"#{payload[:name] || "Unnamed"} (#{event.duration.round(1)}ms)"
|
19
|
+
end
|
20
|
+
title = "CACHE #{title}" if payload[:cached]
|
21
|
+
|
22
|
+
sql = payload[:sql]&.gsub(/\/\*.*\*\//, "") # remove comments
|
23
|
+
|
24
|
+
binds = nil
|
25
|
+
if payload[:binds]&.any?
|
26
|
+
casted_params = type_casted_binds(payload[:type_casted_binds])
|
27
|
+
|
28
|
+
binds = []
|
29
|
+
payload[:binds].each_with_index do |attr, i|
|
30
|
+
attribute_name = if attr.respond_to?(:name)
|
31
|
+
attr.name
|
32
|
+
elsif attr.respond_to?(:[]) && attr[i].respond_to?(:name)
|
33
|
+
attr[i].name
|
34
|
+
else
|
35
|
+
nil
|
36
|
+
end
|
37
|
+
|
38
|
+
filtered_params = filter(attribute_name, casted_params[i])
|
39
|
+
|
40
|
+
binds << render_bind(attr, filtered_params)
|
41
|
+
end
|
42
|
+
binds = binds.inspect
|
43
|
+
binds.prepend(" ")
|
44
|
+
end
|
45
|
+
|
46
|
+
Debugbar::Tracker.add_query({
|
47
|
+
id: event.transaction_id,
|
48
|
+
title: title,
|
49
|
+
name: payload[:name],
|
50
|
+
sql: sql,
|
51
|
+
cached: payload[:cached].present?,
|
52
|
+
async: payload[:async],
|
53
|
+
duration: event.duration.round(1),
|
54
|
+
lock_wait: payload[:lock_wait]&.round(1),
|
55
|
+
binds: binds,
|
56
|
+
source: query_source_location&.split(":in"),
|
57
|
+
})
|
58
|
+
end
|
59
|
+
|
60
|
+
def query_source_location
|
61
|
+
backtrace_cleaner.clean(caller(3))[0]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Debugbar
|
2
|
+
class ActiveSupportEventSubscriber
|
3
|
+
class << self
|
4
|
+
def cache(event)
|
5
|
+
evt = event.payload
|
6
|
+
evt[:name] = event.name
|
7
|
+
evt[:transaction_id] = event.transaction_id
|
8
|
+
evt[:time] = Time.at(event.time).strftime(Debugbar::TIME_FORMAT)
|
9
|
+
evt[:label] = case event.name
|
10
|
+
when "cache_read.active_support"
|
11
|
+
"read"
|
12
|
+
when "cache_generate.active_support"
|
13
|
+
"generate"
|
14
|
+
when "cache_fetch_hit.active_support"
|
15
|
+
"fetch hit"
|
16
|
+
when "cache_write.active_support"
|
17
|
+
"write"
|
18
|
+
when "cache_delete.active_support"
|
19
|
+
"delete"
|
20
|
+
when "cache_exist?.active_support"
|
21
|
+
"exist?"
|
22
|
+
else
|
23
|
+
"unknown"
|
24
|
+
end
|
25
|
+
|
26
|
+
Debugbar::Tracker.add_cache evt
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/debugbar.rb
CHANGED
@@ -1,8 +1,82 @@
|
|
1
|
-
|
2
|
-
require 'debugbar/engine' if defined?(Rails) && Rails::VERSION::MAJOR >= 3
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
module
|
5
|
-
|
6
|
-
|
3
|
+
module Debugbar
|
4
|
+
autoload :VERSION, "debugbar/version"
|
5
|
+
autoload :Current, "debugbar/current"
|
6
|
+
autoload :Request, "debugbar/request"
|
7
|
+
autoload :RequestBuffer, "debugbar/buffers/request_buffer"
|
8
|
+
autoload :SimpleLogger, "debugbar/loggers/simple_logger"
|
9
|
+
|
10
|
+
TIME_FORMAT = "%H:%M:%S.%L"
|
11
|
+
|
12
|
+
module Tracker
|
13
|
+
class << self
|
14
|
+
SETTERS = %i[request response headers meta].freeze
|
15
|
+
METHODS = %i[inc_model add_query add_job add_cache add_log].freeze
|
16
|
+
|
17
|
+
SETTERS.each do |m|
|
18
|
+
define_method("#{m}=") do |val|
|
19
|
+
if Current.request.nil?
|
20
|
+
# TODO: Much, much better logging needed
|
21
|
+
puts "The current request is not set yet. Was trying to set #{m}=[#{val.class.name}]."
|
22
|
+
else
|
23
|
+
Current.request.send("#{m}=", val)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
METHODS.each do |m|
|
29
|
+
define_method(m) do |*args, &block|
|
30
|
+
if Current.request
|
31
|
+
return Current.request.send(m, *args, &block)
|
32
|
+
end
|
33
|
+
|
34
|
+
if Current.request.nil? && ENV["DEBUGBAR_VERBOSE_MODE"] == "true"
|
35
|
+
puts "The current request is not set yet. Was trying to call #{m}(#{args.map{ _1.class.name}.join(',')})."
|
36
|
+
pp args
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def msg(msg, *extra)
|
43
|
+
if Current.request.nil?
|
44
|
+
puts "The current request is not set yet. Printing to STDOUT instead."
|
45
|
+
puts msg, extra
|
46
|
+
else
|
47
|
+
Current.request.add_msg(msg, extra)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
include Tracker
|
54
|
+
|
55
|
+
class << self
|
56
|
+
def config
|
57
|
+
@config ||= Config.new(enabled: true)
|
58
|
+
end
|
59
|
+
|
60
|
+
def configure
|
61
|
+
yield config
|
62
|
+
end
|
63
|
+
|
64
|
+
def connect!
|
65
|
+
@connected = true
|
66
|
+
end
|
67
|
+
|
68
|
+
def disconnect!
|
69
|
+
@connected = false
|
70
|
+
end
|
71
|
+
|
72
|
+
def connected?
|
73
|
+
@connected
|
74
|
+
end
|
75
|
+
|
76
|
+
def msg(msg, *extra)
|
77
|
+
Tracker.msg(msg, *extra)
|
78
|
+
end
|
7
79
|
end
|
8
80
|
end
|
81
|
+
|
82
|
+
require 'debugbar/engine'
|
data/sig/debugbar.rbs
ADDED
metadata
CHANGED
@@ -1,59 +1,103 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: debugbar
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
version: 0.0.1
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
6
5
|
platform: ruby
|
7
|
-
authors:
|
8
|
-
-
|
9
|
-
autorequire:
|
10
|
-
bindir:
|
6
|
+
authors:
|
7
|
+
- Julien Bourdeau
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
11
10
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
11
|
+
date: 2024-02-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: actioncable
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: Get a better understanding of your application performance and behavior
|
42
|
+
(SQL queries, jobs, cache, routes, logs, etc)
|
43
|
+
email:
|
44
|
+
- julien@debugbar.dev
|
19
45
|
executables: []
|
20
|
-
|
21
46
|
extensions: []
|
22
|
-
|
23
|
-
|
24
|
-
-
|
25
|
-
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- ".prettierrc"
|
50
|
+
- LICENSE.txt
|
51
|
+
- README.md
|
52
|
+
- Rakefile
|
53
|
+
- app/channels/debugbar/debugbar_channel.rb
|
54
|
+
- app/controllers/debugbar/application_controller.rb
|
55
|
+
- app/controllers/debugbar/assets_controller.rb
|
56
|
+
- app/helpers/debugbar/tag_helpers.rb
|
57
|
+
- app/models/debugbar/application_record.rb
|
58
|
+
- build.sh
|
59
|
+
- config/routes.rb
|
60
|
+
- debugbar.gemspec
|
26
61
|
- lib/debugbar.rb
|
62
|
+
- lib/debugbar/buffers/memory_buffer.rb
|
63
|
+
- lib/debugbar/buffers/null_buffer.rb
|
64
|
+
- lib/debugbar/buffers/request_buffer.rb
|
65
|
+
- lib/debugbar/config.rb
|
66
|
+
- lib/debugbar/current.rb
|
27
67
|
- lib/debugbar/engine.rb
|
28
|
-
- lib/debugbar/
|
29
|
-
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
-
|
37
|
-
|
68
|
+
- lib/debugbar/loggers/simple_logger.rb
|
69
|
+
- lib/debugbar/middlewares/track_current_request.rb
|
70
|
+
- lib/debugbar/request.rb
|
71
|
+
- lib/debugbar/subscribers/action_controller.rb
|
72
|
+
- lib/debugbar/subscribers/active_job.rb
|
73
|
+
- lib/debugbar/subscribers/active_record.rb
|
74
|
+
- lib/debugbar/subscribers/active_support.rb
|
75
|
+
- lib/debugbar/version.rb
|
76
|
+
- sig/debugbar.rbs
|
77
|
+
homepage: https://debugbar.dev
|
78
|
+
licenses:
|
79
|
+
- MIT
|
80
|
+
metadata:
|
81
|
+
homepage_uri: https://debugbar.dev
|
82
|
+
source_code_uri: https://github.com/julienbourdeau/debugbar
|
83
|
+
changelog_uri: https://debugbar.dev/changelog/
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options: []
|
86
|
+
require_paths:
|
38
87
|
- lib
|
39
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
40
|
-
|
41
|
-
requirements:
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
42
90
|
- - ">="
|
43
|
-
- !ruby/object:Gem::Version
|
44
|
-
version:
|
45
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
46
|
-
|
47
|
-
requirements:
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 2.6.0
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
48
95
|
- - ">="
|
49
|
-
- !ruby/object:Gem::Version
|
50
|
-
version:
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
51
98
|
requirements: []
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
specification_version: 3
|
57
|
-
summary: Debugbar gem for Rails 3
|
99
|
+
rubygems_version: 3.4.20
|
100
|
+
signing_key:
|
101
|
+
specification_version: 4
|
102
|
+
summary: Powerful devtools for Ruby on Rails
|
58
103
|
test_files: []
|
59
|
-
|
data/README.textile
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
h1. Debug Bar Gem v0.0.1
|
2
|
-
|
3
|
-
h2. Installation
|
4
|
-
|
5
|
-
Add the following to your Gemfile:
|
6
|
-
|
7
|
-
<pre><code>gem 'debugbar'</code></pre>
|
8
|
-
|
9
|
-
And restart your application with:
|
10
|
-
|
11
|
-
<pre><code>bundle install
|
12
|
-
touch tmp/restart.txt</code></pre>
|
13
|
-
|
14
|
-
h2. Introduction
|
15
|
-
|
16
|
-
DebugBar provides a Django/Symfony like Debug Bar for Ruby on Rails 3.
|
17
|
-
|
18
|
-
This project is only in it's infancy...
|
@@ -1 +0,0 @@
|
|
1
|
-
# Put your custom rake tasks here
|