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

#initialize(partial_name = "<root>") ⇒ Profiler

Returns a new instance of Profiler.


112
113
114
115
116
117
118
119
120
# File 'lib/liquid/profiler.rb', line 112

def initialize(partial_name = "<root>")
  @partial_stack = [partial_name]

  @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


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

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

.profile_children(template_name) ⇒ Object


97
98
99
100
101
102
103
104
105
106
# File 'lib/liquid/profiler.rb', line 97

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


86
87
88
89
90
91
92
93
94
95
# File 'lib/liquid/profiler.rb', line 86

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


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

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

#current_partialObject


159
160
161
# File 'lib/liquid/profiler.rb', line 159

def current_partial
  @partial_stack.last
end

#each(&block) ⇒ Object


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

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

#end_node(_node) ⇒ Object


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

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

  @timing_stack.last.children << timing
end

#lengthObject


144
145
146
# File 'lib/liquid/profiler.rb', line 144

def length
  @root_timing.children.length
end

#pop_partialObject


167
168
169
# File 'lib/liquid/profiler.rb', line 167

def pop_partial
  @partial_stack.pop
end

#push_partial(partial_name) ⇒ Object


163
164
165
# File 'lib/liquid/profiler.rb', line 163

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

#startObject


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

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

#start_node(node) ⇒ Object


148
149
150
# File 'lib/liquid/profiler.rb', line 148

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

#stopObject


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

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

#total_render_timeObject


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

def total_render_time
  @render_end_at - @render_start_at
end