Skip to content

Instantly share code, notes, and snippets.

@lackac
Created November 18, 2010 14:46
Show Gist options
  • Save lackac/705063 to your computer and use it in GitHub Desktop.
Save lackac/705063 to your computer and use it in GitHub Desktop.
Custom Memprof Tracer and a Controller/View pair to browse traces
require 'memprof/tracer'
class CustomTracer
def initialize(app, opts = {})
@app = app
@options = opts
@options[:except] = %r{^/(?:memprof|admin)\b}
end
def call(env)
if memprof_request?(env)
ret = trace(env)
GC.start if @options[:force_gc]
ret
else
@app.call(env)
end
end
private
def memprof_request?(env)
env['REQUEST_URI'] !~ @options[:except]
end
def trace(env)
::Memprof.trace_filename ||= @options[:tracer_file] || "/tmp/memprof_tracer-#{Process.pid}.json"
::Memprof.trace_request(env) { @app.call(env) }
end
end
!!! 5
%html
%head
%meta(charset="utf-8")
%title Memprof Traces
= javascript_include_tag "http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"
= stylesheet_link_tag "http://jquery.bassistance.de/treeview/demo/screen.css"
= stylesheet_link_tag "http://jquery.bassistance.de/treeview/jquery.treeview.css"
= javascript_include_tag "http://jquery.bassistance.de/treeview/jquery.treeview.js"
:javascript
$(function() {
$('#traces > ul').treeview({ collapsed: true });
$('#diff-traces > ul').treeview({ collapsed: true });
$('input.filter').change(function(e) {
var traces = $(this).next().find('> li');
var expr = $(this).val().split(/\s*,\s*/);
traces.each(function() {
var trace = $(this), match = true;
$.each(expr, function(i, ex) {
var m;
if (m = ex.match(/(.*)\s*(?:<|<=|==|>=|>)\s*(?:[\d\.]+)/)) {
var selector = m[1].split(".").map(function(v,i) { return ".key:iseq("+v+")"; }).join(" + ul "), key;
if ((key = $(selector, trace).first()).length == 0) {
return match = false;
}
var value = key.next();
if (!value.is('span') || !eval(ex.replace(m[1], value.text()))) {
return match = false;
}
} else {
var re = new RegExp(ex.trim());
if (!re.test(trace.find('.key:first').text())) {
return match = false;
}
}
});
match ? trace.show() : trace.hide();
});
});
});
$.expr[":"].iseq = function(obj, index, meta, stack) {
return (obj.textContent || obj.innerText || $(obj).text() || "").toLowerCase().trim() == meta[3].toLowerCase();
}
:css
#traces h3, #diff-traces h3 {
margin-bottom: 0.5em;
}
#traces {
float: left;
width: 50%;
}
#diff-traces {
float: right;
width: 49%;
border-left: 1px solid #ccc;
padding-left: 0.9%;
}
.key { font-weight: bold; }
%body
.container
#content
#traces
- unless @pid == Process.pid.to_s
= link_to "current process", url_for(:pid => nil, :diff_with => params[:diff_with]), :style => "float: right; margin-right: 1em"
%h3== Traces for process ##{@pid}
- if @traces.present?
%input.filter
%ul
- @traces.each do |trace|
%li
%span.key= trace['request']['PATH_INFO']
%span== (#{trace['time']}s)
= hash_to_tree(trace)
- else
%p No traces yet.
- if @diff_pid
#diff-traces
= link_to "go back", url_for(:diff_with => nil, :pid => params[:pid]), :style => "float: right; margin-right: 1em"
%h3== Traces for process ##{@diff_pid}
- if @diff_with.is_a?(String)
%p= @diff_with
- elsif @diff_with.present?
%input.filter
%ul
- @diff_with.each do |trace|
%li
%span.key= trace['request']['PATH_INFO']
%span== (#{trace['time']}s)
= hash_to_tree(trace)
- else
%p No traces for this process.
- elsif @old_traces.present?
#diff-traces
%h3 Compare with...
%ul
- @old_traces.each do |pid, mtime|
%li
%span.key= link_to "##{pid}", url_for(:diff_with => pid, :pid => params[:pid])
%span== (#{time_ago_in_words(mtime)} old)
%footer
Copyright &copy; 2010, Secret Sauce Partners, Inc.
class MemprofTracesController < ActionController::Base
def index
@pid = params[:pid] || Process.pid.to_s
traces_file = "/tmp/memprof_tracer-#{@pid}.json"
if File.exists?(traces_file)
@traces = File.readlines(traces_file)
@traces.map! {|json| JSON.parse(json)}
end
if @diff_pid = params[:diff_with]
diff_file = "/tmp/memprof_tracer-#{@diff_pid}.json"
@diff_with =
if File.exists?(diff_file)
File.readlines(diff_file).map! {|json| JSON.parse(json)}
else
"Diff file #{diff_file} doesn't exist"
end
end
@old_traces =
Dir["/tmp/memprof_tracer-*.json"].
map { |f| [f[/-(\d+)\.json$/, 1], File.mtime(f)] }.
sort_by { |_,m| -m.to_i }.
reject { |f,_| f.blank? or f == @pid }
end
end
module MemprofTracesHelper
def hash_to_tree(hash)
case hash
when Hash
items = hash.map do |key, value|
item = content_tag(:span, key, :class => "key") + ": " + hash_to_tree(value)
content_tag(:li, item)
end
content_tag(:ul, items.join.html_safe)
else
content_tag(:span, hash.inspect)
end.html_safe
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment