lib/deforest.rb in deforest-1.0.2 vs lib/deforest.rb in deforest-1.1.0

- old
+ new

@@ -2,116 +2,101 @@ require "deforest/version" require "active_support" require "active_record" module Deforest - mattr_accessor :write_logs_to_db_every, :current_admin_method_name, :most_used_percentile_threshold, :least_used_percentile_threshold, :track_dirs, :render_source_on_browser, :last_saved_log_file_at, :saving_log_file + mattr_accessor :write_logs_to_db_every, :current_admin_method_name, :most_used_percentile_threshold, :least_used_percentile_threshold, :track_dirs, :last_saved_log_file_at, :saving_log_file def self.get_app_classes(dir) Dir["#{Rails.root}#{dir}/**/*.rb"].each do |f| idx = f.index(dir) models_heirarchy = f[idx..-1].gsub(dir,"") - exec_str = "" - loop do - parent, *children = models_heirarchy.split("/") - if children.any? - exec_str += "#{parent.camelize}::" - else - exec_str += parent.chomp(".rb").camelize - break - end - models_heirarchy = children.join("/") - end + exec_str = models_heirarchy.split("/").map(&:camelize).join("::").chomp(".rb") begin model = exec_str.constantize yield model rescue puts "Deforest warning: could not track #{exec_str}" end end end + + def self.inject_tracking_module(klass, dir, method_type) + track_methods = if method_type == 'instance' + klass.instance_methods(false) + elsif method_type == 'class' + klass.singleton_methods(false) + else + raise "Unknown method type: #{method_type}" + end + Module.new do + track_methods.each do |mname| + method_location = if method_type == 'instance' + klass.instance_method(mname).source_location + else + klass.singleton_method(mname).source_location + end + if method_location.first.ends_with?("#{klass.to_s.underscore}.rb") + define_method mname do |*args, &block| + file_name, line_no = method_location + if file_name.include?(dir) + Deforest.insert_into_logs(mname, file_name, line_no) + end + if Deforest.last_saved_log_file_at < Deforest.write_logs_to_db_every.ago && !Deforest.saving_log_file + Deforest.parse_and_save_log_file() + t = Time.zone.now + Deforest.last_saved_log_file_at = t + File.open("deforest_db_sync.#{Process.pid}.txt", "w") { |fl| fl.write(t.to_i) } + end + super(*args, &block) + end + end + end + end + end def self.initialize! if block_given? yield self end self.initialize_db_sync_file() Deforest.track_dirs.each do |dir| self.get_app_classes(dir) do |klass| if klass.present? - klass.prepend(Module.new do - klass.instance_methods(false).each do |mname| - method_location = klass.instance_method(mname).source_location - if method_location.first.ends_with?("#{klass.to_s.underscore}.rb") - define_method mname do |*args, &block| - file_name, line_no = method_location - if file_name.include?(dir) - Deforest.insert_into_logs(mname, file_name, line_no) - end - if Deforest.last_saved_log_file_at < Deforest.write_logs_to_db_every.ago && !Deforest.saving_log_file - Deforest.parse_and_save_log_file() - t = Time.zone.now - Deforest.last_saved_log_file_at = t - File.open("deforest_db_sync.txt", "w") { |fl| fl.write(t.to_i) } - end - super(*args, &block) - end - end - end - end) - - klass.singleton_class.prepend(Module.new do - klass.singleton_methods(false).each do |mname| - method_location = klass.singleton_method(mname).source_location - if method_location.first.ends_with?("#{klass.to_s.underscore}.rb") - define_method mname do |*args, &block| - file_name, line_no = method_location - if file_name.include?(dir) - Deforest.insert_into_logs(mname, file_name, line_no) - end - if Deforest.last_saved_log_file_at < Deforest.write_logs_to_db_every.ago && !Deforest.saving_log_file - Deforest.parse_and_save_log_file() - t = Time.zone.now - Deforest.last_saved_log_file_at = t - File.open("deforest_db_sync.txt", "w") { |fl| fl.write(t.to_i) } - end - super(*args, &block) - end - end - end - end) + klass.prepend(Deforest.inject_tracking_module(klass, dir, 'instance')) + klass.singleton_class.prepend(Deforest.inject_tracking_module(klass, dir, 'class')) end end end end def self.initialize_db_sync_file - File.open("deforest.log", "w") unless File.exist?("deforest.log") - if File.exist?("deforest_db_sync.txt") - Deforest.last_saved_log_file_at = Time.at(File.open("deforest_db_sync.txt").read.to_i) + File.open("deforest.#{Process.pid}.log", "w") unless File.exist?("deforest.#{Process.pid}.log") + if File.exist?("deforest_db_sync.#{Process.pid}.txt") + Deforest.last_saved_log_file_at = Time.at(File.open("deforest_db_sync.#{Process.pid}.txt").read.to_i) else - File.open("deforest_db_sync.txt", "w") do |f| + File.open("deforest_db_sync.#{Process.pid}.txt", "w") do |f| current_time = Time.zone.now Deforest.last_saved_log_file_at = current_time f.write(current_time.to_i) end end end def self.insert_into_logs(method_name, file_name, line_no) key = "#{file_name}|#{line_no}|#{method_name}\n" - log_file_name = Deforest.saving_log_file ? "deforest_tmp.log" : "deforest.log" + log_file_name = Deforest.saving_log_file ? "deforest_tmp.#{Process.pid}.log" : "deforest.#{Process.pid}.log" File.open(log_file_name, "a") do |f| f.write(key) end end def self.parse_and_save_log_file Deforest.saving_log_file = true sql_stmt = "INSERT INTO deforest_logs (file_name, line_no, method_name, count, created_at, updated_at) VALUES " hash = {} - File.foreach("deforest.log") do |line| + File.foreach("deforest.#{Process.pid}.log") do |line| line = line.chomp("\n") if hash.has_key?(line) hash[line] += 1 else hash[line] = 1 @@ -123,53 +108,38 @@ end sql_stmt.chomp!(",") sql_stmt += ";" if hash.present? ActiveRecord::Base.connection.execute(sql_stmt) - if File.exist?("deforest_tmp.log") - File.delete("deforest.log") - File.rename("deforest_tmp.log", "deforest.log") + if File.exist?("deforest_tmp.#{Process.pid}.log") + File.delete("deforest.#{Process.pid}.log") + File.rename("deforest_tmp.#{Process.pid}.log", "deforest.#{Process.pid}.log") else - File.delete("deforest.log") + File.delete("deforest.#{Process.pid}.log") end end Deforest.saving_log_file = false end - def self.prepare_file_for_render(file) - line_no_count = Log.where(file_name: file).group(:line_no).select("line_no,SUM(count) AS count_sum").inject({}) { |h, el| h.merge!(el.line_no => el.count_sum) } - stack = [] - current_highlight_color = nil - highlight = Log.get_highlight_colors_for_file(file) - prepare_for_render(File.open(file).read) do |line, idx| - idx += 1 - if line_no_count.has_key?(idx) - stack = [1] - current_highlight_color = highlight[idx] - last_log_for_current_line = Log.where(file_name: file).where(line_no: idx).order("created_at DESC").limit(1).first - "<span id='#{idx}' class='highlight-line #{current_highlight_color}'>" + - line + - "</span>&nbsp;&nbsp;" + - "<span class='method_call_count'>#{line_no_count[idx]}</span>" + - "<span class='last_accessed'>last called at: #{last_log_for_current_line.created_at.localtime.strftime('%m/%d/%Y')}</span>" - else - "<span>#{line}</span>" - end + def self.most_used_methods(dir, size=1) + query = Deforest::Log.group(:file_name, :line_no, :method_name) + if dir.present? + query = query.where("file_name like '%#{dir}/%'") end + res = query.pluck("file_name, line_no, method_name, SUM(count)") + .sort_by { |fname, lno, method, cnt| cnt } + .reverse + if size == nil + return res + else + return res.take(size) + end end - def self.prepare_for_render(source_code, add_line_number = true) - source_code.split("\n").map.with_index do |line, index| - first_letter_idx = line.chars.index { |ch| ch != " " } - if first_letter_idx && first_letter_idx >= 0 && first_letter_idx < line.size - leading_nbsp = (0...first_letter_idx).map { "&nbsp;" }.join("") - prepared_line = leading_nbsp.present? ? leading_nbsp + line.lstrip : line.strip - result_line = if block_given? - yield prepared_line + "\n", index - else - "<span>#{prepared_line}</span>" - end - "<span class='line-no'>#{index + 1}</span>" + result_line - end - end.join("<br/>") + def self.least_used_methods(dir, size=1) + if size == nil + self.most_used_methods(dir, nil).reverse + else + self.most_used_methods(dir, nil).reverse.take(size) + end end end \ No newline at end of file