Class: Liquid::Profiler

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/liquid/profiler.rb

Overview

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.

Defined Under Namespace

Classes: Timing

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeProfiler

Returns a new instance of Profiler.



99
100
101
102
103
104
105
106
107
# 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

Class Method Details

.current_profileObject



95
96
97
# File 'lib/liquid/profiler.rb', line 95

def self.current_profile
  Thread.current[:liquid_profiler]
end

.profile_children(template_name) ⇒ Object



84
85
86
87
88
89
90
91
92
93
# 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

.profile_node_render(node) ⇒ Object



73
74
75
76
77
78
79
80
81
82
# 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

Instance Method Details

#[](idx) ⇒ Object



127
128
129
# File 'lib/liquid/profiler.rb', line 127

def [](idx)
  @root_timing.children[idx]
end

#current_partialObject



146
147
148
# File 'lib/liquid/profiler.rb', line 146

def current_partial
  @partial_stack.last
end

#each(&block) ⇒ Object



123
124
125
# File 'lib/liquid/profiler.rb', line 123

def each(&block)
  @root_timing.children.each(&block)
end

#end_node(_node) ⇒ Object



139
140
141
142
143
144
# File 'lib/liquid/profiler.rb', line 139

def end_node(_node)
  timing = @timing_stack.pop
  timing.finish

  @timing_stack.last.children << timing
end

#lengthObject



131
132
133
# File 'lib/liquid/profiler.rb', line 131

def length
  @root_timing.children.length
end

#pop_partialObject



154
155
156
# File 'lib/liquid/profiler.rb', line 154

def pop_partial
  @partial_stack.pop
end

#push_partial(partial_name) ⇒ Object



150
151
152
# File 'lib/liquid/profiler.rb', line 150

def push_partial(partial_name)
  @partial_stack.push(partial_name)
end

#startObject



109
110
111
112
# File 'lib/liquid/profiler.rb', line 109

def start
  Thread.current[:liquid_profiler] = self
  @render_start_at = Time.now
end

#start_node(node) ⇒ Object



135
136
137
# File 'lib/liquid/profiler.rb', line 135

def start_node(node)
  @timing_stack.push(Timing.start(node, current_partial))
end

#stopObject



114
115
116
117
# File 'lib/liquid/profiler.rb', line 114

def stop
  Thread.current[:liquid_profiler] = nil
  @render_end_at = Time.now
end

#total_render_timeObject



119
120
121
# File 'lib/liquid/profiler.rb', line 119

def total_render_time
  @render_end_at - @render_start_at
end