From 18fe5b6f7f09b161bad55ba04e209c8f3452f4d4 Mon Sep 17 00:00:00 2001 From: pvincent Date: Wed, 25 Sep 2024 11:20:03 +0400 Subject: [PATCH] action_view memoize partials --- config/initializers/backtrace_cleaning.rb | 5 ++- lib/semantic/abstract_formatter.rb | 23 ++---------- lib/semantic/helper.rb | 26 ++++++++++++++ lib/semantic/subscribers/action_view.rb | 43 +++++++++++++++++++---- 4 files changed, 68 insertions(+), 29 deletions(-) create mode 100644 lib/semantic/helper.rb diff --git a/config/initializers/backtrace_cleaning.rb b/config/initializers/backtrace_cleaning.rb index dee9506..10855d1 100644 --- a/config/initializers/backtrace_cleaning.rb +++ b/config/initializers/backtrace_cleaning.rb @@ -1,3 +1,2 @@ -bc = Rails.backtrace_cleaner -# bc.add_silencer { |line| %r{^lib/(monkey_patches|semantic)}.match?(line) } -bc.add_silencer { |line| %r{^lib/(monkey_patches)}.match?(line) } +Rails.backtrace_cleaner + .add_silencer { |line| %r{^lib/(monkey_patches)}.match?(line) } diff --git a/lib/semantic/abstract_formatter.rb b/lib/semantic/abstract_formatter.rb index 0f653db..c31bd88 100644 --- a/lib/semantic/abstract_formatter.rb +++ b/lib/semantic/abstract_formatter.rb @@ -28,11 +28,9 @@ module Semantic clazz = colorize("#{exc.class}\n", color_map[:fatal]) message = colorize(exc.message.chomp(''), color_map[:error]) - - # TODO: backtrace_cleaner might be optionally disable from Live::Constant - backtrace = stackisize(Rails.backtrace_cleaner.clean(exc.backtrace)) - - "#{clazz}#{message}#{backtrace}" + backtrace = exc.backtrace + stack = Helper.stackisize(*backtrace) + ["#{clazz}#{message}", stack].compact.join("\n") end def origin @@ -41,21 +39,6 @@ module Semantic colorize(centerize(log.name), taint) end - def ansi_trace(trace, symbol) - match = trace.match(/(↳ )?(.*:\d+)(:in `)?(.*'?)/) # only m2(=file) and m4(=optional function) are useful - return trace unless match - - _, m2, _, m4 = match.captures - "#{symbol} #{m2} #{BOLD}#{m4.chop}#{CLEAR}" - end - - def stackisize(items) - return '' if items.empty? - - traces = items.map { |item| ansi_trace(item, '➟') } - "\n#{traces.join("\n")}" - end - def tags first_tag, taint = log.tags.empty? ? [TAG_NONE, CLEAR] : [log.tags.first, BG_GRAY + TEXT_YELLOW] colorize(centerize(first_tag, TAG_FIXED_LENGTH), taint) diff --git a/lib/semantic/helper.rb b/lib/semantic/helper.rb new file mode 100644 index 0000000..b6eb00a --- /dev/null +++ b/lib/semantic/helper.rb @@ -0,0 +1,26 @@ +module Semantic + # useful public functions + module Helper + class << self + include AnsiColors + def stackisize(*items) + return if items.empty? + + Rails.backtrace_cleaner + .clean(items) + .map { |item| ansi_trace(item, '➟') } + .join("\n") + end + + private + + def ansi_trace(trace, symbol) + match = trace.match(/(↳ )?(.*:\d+)(:in `)?(.*'?)/) # only m2(=file) and m4(=optional function) are useful + return trace unless match + + _, m2, _, m4 = match.captures + "#{symbol} #{m2} #{BOLD}#{m4.chop}#{CLEAR}" + end + end + end +end diff --git a/lib/semantic/subscribers/action_view.rb b/lib/semantic/subscribers/action_view.rb index 0b1a2eb..0cbe8c6 100644 --- a/lib/semantic/subscribers/action_view.rb +++ b/lib/semantic/subscribers/action_view.rb @@ -6,12 +6,19 @@ module Semantic REGEX_BASEDIR = %r{^#{Rails.root}/(.*)} - def initialize(*) = super(:view) + def initialize(*) + super(:view) + @partials = {} + end def render_partial(event) identifier = pathname(event.payload[:identifier]) - # logger.debug("Rendered partial #{identifier}", event.payload[:locals]) if identifier - logger.debug("Rendered partial #{identifier}") if identifier + partial_savings = @partials[event.transaction_id] ||= {} + partial_saving = partial_savings[identifier] ||= { + count: 0, + first_origin: Rails.backtrace_cleaner.clean(caller)[1] + } + partial_saving[:count] += 1 end def render_template(event) @@ -19,23 +26,47 @@ module Semantic return unless layout identifier = pathname(event.payload[:identifier]) - logger.debug { "Rendered template #{identifier}" } if identifier + return unless identifier + + logger.debug do + pop_partial_savings(event.transaction_id) + "Rendered template #{identifier}" + end end def render_collection(event) identifier = pathname(event.payload[:identifier]) + return unless identifier + count = event.payload[:count] cache_hits = event.payload[:cache_hits] || 0 - logger.debug { "Rendered collection #{identifier} (#{count} times, #{cache_hits} cached)" } if identifier + logger.debug do + pop_partial_savings(event.transaction_id) + "Rendered collection #{identifier} (#{count} times, #{cache_hits} cached)" + end end def render_layout(event) identifier = pathname(event.payload[:identifier]) - logger.debug { "Rendered layout #{identifier}" } if identifier + return unless identifier + + logger.debug do + pop_partial_savings(event.transaction_id) + "Rendered layout #{identifier}" + end end private + def pop_partial_savings(transaction_id) + partial_savings = @partials.delete(transaction_id) + partial_savings.each do |partial, saving| + count_info = " (#{saving[:count]} times)" if saving[:count] > 1 + logger.debug("Rendered partial #{partial}#{count_info}") + logger.debug(Semantic::Helper.stackisize(saving[:first_origin])) + end + end + def pathname(location) m = REGEX_BASEDIR.match(location) m[1] if m