class Liquid::Profiler
Profiler enables support for profiling template rendering to help track down performance issues.
To enable profiling, first require 'liquid/profiler'. Then, to
profile a parse/render cycle, pass the profile: true
option to
Liquid::Template.parse
. After
Liquid::Template#render
is called, the template object makes
available an instance of this class via the
Liquid::Template#profiler
method.
template = Liquid::Template.parse(template_content, profile: true) output = template.render profile = template.profiler
This object contains all profiling information, containing information on what tags were rendered, where in the templates these tags live, and how long each tag took to render.
This is a tree structure that is Enumerable all the way down, and keeps
track of tags and rendering times inside of {% include %}
tags.
profile.each do |node| # Access to the node itself node.code # Which template and line number of this node. # If top level, this will be "<root>". node.partial node.line_number # Render time in seconds of this node node.render_time # If the template used {% include %}, this node will also have children. node.children.each do |child2| # ... end end
Profiler also exposes the total time of the
template's render in Liquid::Profiler#total_render_time
.
All render times are in seconds. There is a small performance hit when profiling is enabled.
Public Class Methods
# File lib/liquid/profiler.rb, line 95 def self.current_profile Thread.current[:liquid_profiler] end
# File lib/liquid/profiler.rb, line 99 def initialize @partial_stack = ["<root>"] @root_timing = Timing.new("", current_partial) @timing_stack = [@root_timing] @render_start_at = Time.now @render_end_at = @render_start_at end
# File lib/liquid/profiler.rb, line 84 def self.profile_children(template_name) if Profiler.current_profile Profiler.current_profile.push_partial(template_name) output = yield Profiler.current_profile.pop_partial output else yield end end
# File lib/liquid/profiler.rb, line 73 def self.profile_node_render(node) if Profiler.current_profile && node.respond_to?(:render) Profiler.current_profile.start_node(node) output = yield Profiler.current_profile.end_node(node) output else yield end end
Public Instance Methods
# File lib/liquid/profiler.rb, line 127 def [](idx) @root_timing.children[idx] end
# File lib/liquid/profiler.rb, line 146 def current_partial @partial_stack.last end
# File lib/liquid/profiler.rb, line 123 def each(&block) @root_timing.children.each(&block) end
# File lib/liquid/profiler.rb, line 139 def end_node(_node) timing = @timing_stack.pop timing.finish @timing_stack.last.children << timing end
# File lib/liquid/profiler.rb, line 131 def length @root_timing.children.length end
# File lib/liquid/profiler.rb, line 154 def pop_partial @partial_stack.pop end
# File lib/liquid/profiler.rb, line 150 def push_partial(partial_name) @partial_stack.push(partial_name) end
# File lib/liquid/profiler.rb, line 109 def start Thread.current[:liquid_profiler] = self @render_start_at = Time.now end
# File lib/liquid/profiler.rb, line 135 def start_node(node) @timing_stack.push(Timing.start(node, current_partial)) end
# File lib/liquid/profiler.rb, line 114 def stop Thread.current[:liquid_profiler] = nil @render_end_at = Time.now end
# File lib/liquid/profiler.rb, line 119 def total_render_time @render_end_at - @render_start_at end