gitlab-peek 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.travis.yml +12 -0
- data/CHANGELOG.md +96 -0
- data/Gemfile +30 -0
- data/Gemfile-rails42 +27 -0
- data/LICENSE.txt +22 -0
- data/README.md +253 -0
- data/Rakefile +13 -0
- data/app/assets/javascripts/peek.js +86 -0
- data/app/assets/javascripts/peek/vendor/jquery.tipsy.js +258 -0
- data/app/assets/stylesheets/peek.scss +85 -0
- data/app/assets/stylesheets/peek/vendor/tipsy.scss +22 -0
- data/app/controllers/peek/results_controller.rb +25 -0
- data/app/views/peek/_bar.html.erb +11 -0
- data/config/routes.rb +3 -0
- data/gitlab-peek.gemspec +22 -0
- data/lib/peek.rb +93 -0
- data/lib/peek/adapters/base.rb +17 -0
- data/lib/peek/adapters/elasticsearch.rb +33 -0
- data/lib/peek/adapters/memcache.rb +25 -0
- data/lib/peek/adapters/memory.rb +25 -0
- data/lib/peek/adapters/redis.rb +21 -0
- data/lib/peek/controller_helpers.rb +22 -0
- data/lib/peek/railtie.rb +37 -0
- data/lib/peek/version.rb +3 -0
- data/lib/peek/views/view.rb +124 -0
- data/test/controllers/requests_test.rb +33 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +16 -0
- data/test/dummy/app/assets/stylesheets/application.css +14 -0
- data/test/dummy/app/controllers/application_controller.rb +13 -0
- data/test/dummy/app/controllers/home_controller.rb +11 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/home/show.html.erb +5 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/app/views/peek/_test_view.html.erb +1 -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.ru +4 -0
- data/test/dummy/config/application.rb +25 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +23 -0
- data/test/dummy/config/environments/test.rb +36 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -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 +5 -0
- data/test/dummy/config/initializers/peek.rb +3 -0
- data/test/dummy/config/initializers/secret_token.rb +12 -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 +8 -0
- data/test/dummy/lib/test_view.rb +18 -0
- data/test/dummy/public/404.html +58 -0
- data/test/dummy/public/422.html +58 -0
- data/test/dummy/public/500.html +57 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/peek/views/view_test.rb +37 -0
- data/test/peek_test.rb +69 -0
- data/test/test_helper.rb +22 -0
- metadata +161 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
module Peek
|
2
|
+
class ResultsController < ApplicationController
|
3
|
+
before_action :restrict_non_access
|
4
|
+
|
5
|
+
def show
|
6
|
+
respond_to do |format|
|
7
|
+
format.json do
|
8
|
+
if request.xhr?
|
9
|
+
render json: Peek.adapter.get(params[:request_id])
|
10
|
+
else
|
11
|
+
render nothing: true, status: :not_found
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def restrict_non_access
|
20
|
+
unless peek_enabled?
|
21
|
+
raise ActionController::RoutingError.new('Not Found')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<% if peek_enabled? %>
|
2
|
+
<div id="peek" class="<%= Peek.env %><%= ' disabled' if cookies[:peek] == 'false' %>" data-request-id="<%= peek_request_id %>">
|
3
|
+
<div class="wrapper">
|
4
|
+
<% Peek.views.each do |view| %>
|
5
|
+
<div id="<%= view.dom_id %>" class="view">
|
6
|
+
<%= render view.partial_path, view: view %>
|
7
|
+
</div>
|
8
|
+
<% end %>
|
9
|
+
</div>
|
10
|
+
</div>
|
11
|
+
<% end %>
|
data/config/routes.rb
ADDED
data/gitlab-peek.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'peek/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = 'gitlab-peek'
|
8
|
+
gem.version = Peek::VERSION
|
9
|
+
gem.authors = ['Garrett Bjerkhoel']
|
10
|
+
gem.email = ['me@garrettbjerkhoel.com']
|
11
|
+
gem.description = %q{Take a peek into your Rails application.}
|
12
|
+
gem.summary = %q{Take a peek into your Rails application.}
|
13
|
+
gem.homepage = 'https://github.com/peek/peek'
|
14
|
+
gem.license = 'MIT'
|
15
|
+
|
16
|
+
gem.files = `git ls-files`.split($/)
|
17
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
18
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
|
+
gem.require_paths = ['lib']
|
20
|
+
|
21
|
+
gem.add_dependency 'railties', '>= 4.0.0'
|
22
|
+
end
|
data/lib/peek.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'peek/version'
|
2
|
+
require 'rails'
|
3
|
+
|
4
|
+
require 'peek/adapters/memory'
|
5
|
+
require 'peek/views/view'
|
6
|
+
|
7
|
+
module Peek
|
8
|
+
ALLOWED_ENVS = ['development', 'staging'].freeze
|
9
|
+
|
10
|
+
def self.adapter
|
11
|
+
@adapter
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.adapter=(*adapter_options)
|
15
|
+
adapter, *parameters = *Array.wrap(adapter_options).flatten
|
16
|
+
|
17
|
+
@adapter = case adapter
|
18
|
+
when Symbol
|
19
|
+
adapter_class_name = adapter.to_s.camelize
|
20
|
+
adapter_class =
|
21
|
+
begin
|
22
|
+
require "peek/adapters/#{adapter}"
|
23
|
+
rescue LoadError => e
|
24
|
+
raise "Could not find adapter for #{adapter} (#{e})"
|
25
|
+
else
|
26
|
+
Peek::Adapters.const_get(adapter_class_name)
|
27
|
+
end
|
28
|
+
adapter_class.new(*parameters)
|
29
|
+
when nil
|
30
|
+
Peek::Adapters::Memory.new
|
31
|
+
else
|
32
|
+
adapter
|
33
|
+
end
|
34
|
+
|
35
|
+
@adapter
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.enabled?
|
39
|
+
ALLOWED_ENVS.include?(env)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.env
|
43
|
+
Rails.env
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.views
|
47
|
+
@cached_views ||= if @views && @views.any?
|
48
|
+
@views.collect { |klass, options| klass.new(options.dup) }.select(&:enabled?)
|
49
|
+
else
|
50
|
+
[]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.results
|
55
|
+
results = {
|
56
|
+
context: {},
|
57
|
+
data: Hash.new { |h, k| h[k] = {} }
|
58
|
+
}
|
59
|
+
|
60
|
+
views.each do |view|
|
61
|
+
if view.context?
|
62
|
+
results[:context][view.key] = view.context
|
63
|
+
end
|
64
|
+
|
65
|
+
view.results.each do |key, value|
|
66
|
+
results[:data][view.key][key] = value
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
results
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.into(klass, options = {})
|
74
|
+
@views ||= []
|
75
|
+
@views << [klass, options]
|
76
|
+
end
|
77
|
+
|
78
|
+
# Clears out any and all views.
|
79
|
+
#
|
80
|
+
# Returns nothing.
|
81
|
+
def self.reset
|
82
|
+
@views = nil
|
83
|
+
@cached_views = nil
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.setup
|
87
|
+
ActiveSupport::Deprecation.warn "'Peek.setup' is deprecated and does nothing.", caller
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
require 'peek/railtie'
|
92
|
+
|
93
|
+
ActiveSupport.run_load_hooks(:peek, Peek)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Peek
|
2
|
+
module Adapters
|
3
|
+
class Base
|
4
|
+
def initialize(options = {})
|
5
|
+
|
6
|
+
end
|
7
|
+
|
8
|
+
def get(request_id)
|
9
|
+
raise "#{self.class}#get(request_id) is not yet implemented"
|
10
|
+
end
|
11
|
+
|
12
|
+
def save
|
13
|
+
raise "#{self.class}#save is not yet implemented"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'peek/adapters/base'
|
2
|
+
require 'elasticsearch'
|
3
|
+
|
4
|
+
module Peek
|
5
|
+
module Adapters
|
6
|
+
class Elasticsearch < Base
|
7
|
+
def initialize(options = {})
|
8
|
+
@client = options.fetch(:client, ::Elasticsearch::Client.new)
|
9
|
+
@expires_in = Integer(options.fetch(:expires_in, 60 * 30) * 1000)
|
10
|
+
@index = options.fetch(:index, 'peek_requests_index')
|
11
|
+
@type = options.fetch(:type, 'peek_request')
|
12
|
+
end
|
13
|
+
|
14
|
+
def get(request_id)
|
15
|
+
result = @client.get_source index: @index, type: @type, id: "#{request_id}"
|
16
|
+
result.to_json
|
17
|
+
rescue ::Elasticsearch::Transport::Transport::Errors::NotFound
|
18
|
+
# pass
|
19
|
+
end
|
20
|
+
|
21
|
+
def save(request_id)
|
22
|
+
@client.index index: @index,
|
23
|
+
type: @type,
|
24
|
+
id: "#{request_id}",
|
25
|
+
body: Peek.results.to_json,
|
26
|
+
ttl: @expires_in
|
27
|
+
rescue ::Elasticsearch::Transport::Transport::Errors::BadRequest
|
28
|
+
false
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'peek/adapters/base'
|
2
|
+
require 'dalli'
|
3
|
+
|
4
|
+
module Peek
|
5
|
+
module Adapters
|
6
|
+
class Memcache < Base
|
7
|
+
def initialize(options = {})
|
8
|
+
@client = options.fetch(:client, ::Dalli::Client.new)
|
9
|
+
@expires_in = options.fetch(:expires_in, 60 * 30)
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(request_id)
|
13
|
+
@client.get("peek:requests:#{request_id}")
|
14
|
+
rescue ::Dalli::DalliError => e
|
15
|
+
Rails.logger.error "#{e.class.name}: #{e.message}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def save(request_id)
|
19
|
+
@client.add("peek:requests:#{request_id}", Peek.results.to_json, @expires_in)
|
20
|
+
rescue ::Dalli::DalliError => e
|
21
|
+
Rails.logger.error "#{e.class.name}: #{e.message}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'peek/adapters/base'
|
2
|
+
|
3
|
+
module Peek
|
4
|
+
module Adapters
|
5
|
+
class Memory < Base
|
6
|
+
attr_accessor :requests
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
@requests = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(request_id)
|
13
|
+
@requests[request_id]
|
14
|
+
end
|
15
|
+
|
16
|
+
def save(request_id)
|
17
|
+
@requests[request_id] = Peek.results
|
18
|
+
end
|
19
|
+
|
20
|
+
def reset
|
21
|
+
@requests.clear
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'peek/adapters/base'
|
2
|
+
require 'redis'
|
3
|
+
|
4
|
+
module Peek
|
5
|
+
module Adapters
|
6
|
+
class Redis < Base
|
7
|
+
def initialize(options = {})
|
8
|
+
@client = options.fetch(:client, ::Redis.new)
|
9
|
+
@expires_in = Integer(options.fetch(:expires_in, 60 * 30))
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(request_id)
|
13
|
+
@client.get("peek:requests:#{request_id}")
|
14
|
+
end
|
15
|
+
|
16
|
+
def save(request_id)
|
17
|
+
@client.setex("peek:requests:#{request_id}", @expires_in, Peek.results.to_json)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Peek
|
2
|
+
module ControllerHelpers
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
if respond_to? :helper_method
|
7
|
+
helper_method :peek_enabled?
|
8
|
+
helper_method :peek_request_id
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def peek_enabled?
|
15
|
+
Peek.enabled?
|
16
|
+
end
|
17
|
+
|
18
|
+
def peek_request_id
|
19
|
+
request.env['action_dispatch.request_id']
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/peek/railtie.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'peek/controller_helpers'
|
2
|
+
|
3
|
+
module Peek
|
4
|
+
class Railtie < ::Rails::Engine
|
5
|
+
isolate_namespace Peek
|
6
|
+
engine_name :peek
|
7
|
+
|
8
|
+
config.peek = ActiveSupport::OrderedOptions.new
|
9
|
+
|
10
|
+
# Default adapter
|
11
|
+
config.peek.adapter = :memory
|
12
|
+
|
13
|
+
initializer 'peek.set_configs' do |app|
|
14
|
+
ActiveSupport.on_load(:peek) do
|
15
|
+
app.config.peek.each do |k,v|
|
16
|
+
send "#{k}=", v
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
initializer 'peek.persist_request_data' do
|
22
|
+
ActiveSupport::Notifications.subscribe('process_action.action_controller') do |_name, _start, _finish, _id, payload|
|
23
|
+
Peek.adapter.save(payload[:headers].env['action_dispatch.request_id'])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
initializer 'peek.include_controller_helpers' do
|
28
|
+
ActiveSupport.on_load(:action_controller) do
|
29
|
+
include Peek::ControllerHelpers
|
30
|
+
end
|
31
|
+
|
32
|
+
config.to_prepare do
|
33
|
+
Peek.views
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/peek/version.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
module Peek
|
2
|
+
module Views
|
3
|
+
class View
|
4
|
+
def initialize(options = {})
|
5
|
+
@options = options
|
6
|
+
|
7
|
+
parse_options
|
8
|
+
setup_subscribers
|
9
|
+
end
|
10
|
+
|
11
|
+
# Where any subclasses should pick and pull from @options to set any and
|
12
|
+
# all instance variables they like.
|
13
|
+
#
|
14
|
+
# Returns nothing.
|
15
|
+
def parse_options
|
16
|
+
# pass
|
17
|
+
end
|
18
|
+
|
19
|
+
# Conditionally enable views based on any gathered data. Helpful
|
20
|
+
# if you don't want views to show up when they return 0 or are
|
21
|
+
# touched during the request.
|
22
|
+
#
|
23
|
+
# Returns true.
|
24
|
+
def enabled?
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
# The path to the partial that will be rendered to the Peek bar.
|
29
|
+
#
|
30
|
+
# Examples:
|
31
|
+
#
|
32
|
+
# Peek::Views::PerformanceBar.partial_path => "peek/views/performance_bar"
|
33
|
+
# CustomResque.partial_path => "performance_bar"
|
34
|
+
#
|
35
|
+
# Returns String.
|
36
|
+
def partial_path
|
37
|
+
self.class.to_s.underscore
|
38
|
+
end
|
39
|
+
|
40
|
+
# The defer key that is derived from the classname.
|
41
|
+
#
|
42
|
+
# Examples:
|
43
|
+
#
|
44
|
+
# Peek::Views::PerformanceBar => "performance-bar"
|
45
|
+
# Peek::Views::Resque => "resque"
|
46
|
+
#
|
47
|
+
# Returns String.
|
48
|
+
def key
|
49
|
+
self.class.to_s.split('::').last.underscore.gsub(/\_/, '-')
|
50
|
+
end
|
51
|
+
alias defer_key key
|
52
|
+
|
53
|
+
# The context id that is derived from the classname.
|
54
|
+
#
|
55
|
+
# Examples:
|
56
|
+
#
|
57
|
+
# Peek::Views::PerformanceBar => "peek-context-performance-bar"
|
58
|
+
# Peek::Views::Resque => "peek-context-resque"
|
59
|
+
#
|
60
|
+
# Returns String.
|
61
|
+
def context_id
|
62
|
+
"peek-context-#{key}"
|
63
|
+
end
|
64
|
+
|
65
|
+
# The wrapper ID for the individual view in the Peek bar.
|
66
|
+
#
|
67
|
+
# Returns String.
|
68
|
+
def dom_id
|
69
|
+
"peek-view-#{key}"
|
70
|
+
end
|
71
|
+
|
72
|
+
# Additional context for any view to render tooltips for.
|
73
|
+
#
|
74
|
+
# Returns Hash.
|
75
|
+
def context
|
76
|
+
{}
|
77
|
+
end
|
78
|
+
|
79
|
+
def context?
|
80
|
+
context.any?
|
81
|
+
end
|
82
|
+
|
83
|
+
# The data results that are inserted at the end of the request for use in
|
84
|
+
# deferred placeholders in the Peek the bar.
|
85
|
+
#
|
86
|
+
# Returns Hash.
|
87
|
+
def results
|
88
|
+
{}
|
89
|
+
end
|
90
|
+
|
91
|
+
def results?
|
92
|
+
results.any?
|
93
|
+
end
|
94
|
+
|
95
|
+
def subscribe(*args)
|
96
|
+
ActiveSupport::Notifications.subscribe(*args) do |name, start, finish, id, payload|
|
97
|
+
yield name, start, finish, id, payload
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def setup_subscribers
|
104
|
+
# pass
|
105
|
+
end
|
106
|
+
|
107
|
+
# Helper method for subscribing to the event that is fired when new
|
108
|
+
# requests are made.
|
109
|
+
def before_request
|
110
|
+
subscribe 'start_processing.action_controller' do |name, start, finish, id, payload|
|
111
|
+
yield name, start, finish, id, payload
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Helper method for subscribing to the event that is fired when requests
|
116
|
+
# are finished.
|
117
|
+
def after_request
|
118
|
+
subscribe 'process_action.action_controller' do |name, start, finish, id, payload|
|
119
|
+
yield name, start, finish, id, payload
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|