#---------------------------------------------------------------# # # # (C) Copyright Rubysophic Inc. 2007-2008 # # All rights reserved. # # # # Use, duplication or disclosure of the code is not permitted # # unless licensed. # # # # Last Updated: 7/7/08 # #---------------------------------------------------------------# # # # RubyRunReport__ is responsible for generating report data in # # RSS or CSV format depending on the type of report. # # # #---------------------------------------------------------------# module RubyRunReport__ # Add entries to transaction log CSV file # metrics structure # metrics[0] Thread ID metrics[1] Timestamp of the request # metrics[2] URL metrics[3] Controller name # metrics[4] Action name metrics[5] Response time # metrics[6] Action time metrics[7] Database IO time # metrics[8] View time metrics[9] Uncaptured time # metrics[10] Dispatch wait time # CSV format is URL, thread ID, timestamp, response time, action time, # database io time, view time, dispatch wait time, uncaptured time def add_txn_log_csv_item(buffer) return if buffer.length == 0 $rubyrun_txn_log_reporter.info "\n----- Transaction Log at #{Time.now.ctime} -----" buffer.each { |metrics| $rubyrun_txn_log_reporter.info "#{metrics[2]},#{metrics[0]},#{metrics[1].strftime("%H:%M:%S")}.#{("%.3f" % metrics[1].to_f).split('.')[1]} #{metrics[1].strftime("%m/%d/%y")},#{sprintf("%0.3f", metrics[5])},#{sprintf("%0.3f", metrics[6])},#{sprintf("%0.3f", metrics[7])},#{sprintf("%0.3f", metrics[8])},#{sprintf("%0.3f", metrics[10])},#{sprintf("%0.3f", metrics[9])}" } end # Add an item to performance summary RSS channel def add_perf_summary_rss_item(req_count) return unless $rubyrun_host_with_port # Server started but no request yet # First, Throughput Summary $rubyrun_throughput.shift if $rubyrun_throughput.length == $rubyrun_report_shift_age index = $rubyrun_throughput.length $rubyrun_throughput[index] = [Time.now, req_count.to_f/$rubyrun_report_timer*60] bar_content = '' label_content = '' max = ($rubyrun_throughput.max {|a,b| a[1] <=> b[1]})[1] max = 1 if max == 0 # Avoid divided by zero below $rubyrun_throughput.reverse! $rubyrun_report_shift_age.times { |i| if $rubyrun_throughput[i] bar_content += sprintf(THROUGHPUT_BAR_TABLE, sprintf('%0.0f',$rubyrun_throughput[i][1]), ($rubyrun_throughput[i][1]*250/max).to_i) label_content += sprintf(THROUGHPUT_LABEL_TABLE, $rubyrun_throughput[i][0].strftime("%H:%M %b %d")) else bar_content += sprintf(THROUGHPUT_BAR_TABLE, '', 0) label_content += sprintf(THROUGHPUT_LABEL_TABLE, '') end } $rubyrun_throughput.reverse! html_content = THROUGHPUT_HTML.sub(/%THROUGHPUT_BAR_TABLE%/, bar_content) html_content.sub!(/%THROUGHPUT_LABEL_TABLE%/, label_content) html_content.sub!(/%APPS_NAME%/,Rails::Configuration.new.root_path.split('/').last) html_content.sub!(/%TIMESTAMP%/,Time.now.strftime("%H:%M:%S %m/%d/%Y")) # Second, Top Slowest Requests results = sort_performance_metrics table_content = '' 10.times { |i| break unless results[i] table_content += sprintf(TOP_SLOWEST_REQUESTS_TABLE, results[i][0], (150*results[i][1][0]/results[0][1][0]).round, results[i][1][0]) } (html_content << TOP_SLOWEST_REQUESTS_HTML).sub!(/%TOP_SLOWEST_REQUESTS_TABLE%/,table_content) # Third, Request Performance Breakdown odd = true table_content = '' results.each { |metrics| table_content += sprintf("#{odd ? REQ_PERF_BREAKDOWN_TABLE_ODD : REQ_PERF_BREAKDOWN_TABLE_EVEN}", metrics[0], metrics[1][6], metrics[1][0], metrics[1][1], (metrics[1][1]/metrics[1][0]*100).round, metrics[1][2], (metrics[1][2]/metrics[1][0]*100).round, metrics[1][3], (metrics[1][3]/metrics[1][0]*100).round, metrics[1][5], (metrics[1][5]/metrics[1][0]*100).round, metrics[1][4]) odd = odd ? false : true } (html_content << REQ_PERF_BREAKDOWN_HTML).sub!(/%REQ_PERF_BREAKDOWN_TABLE%/,table_content); $rubyrun_perf_summary_rss.add_item(RubyRunRSS::RUBYRUN_RSS_PERF_SUMMARY_ITEM_TITLE, RubyRunRSS::RUBYRUN_RSS_PERF_SUMMARY_ITEM_DESCRIPTION, html_content) end # Create the folder for keeping RSS XML file and HTML files # Create the RSS channel def create_rss_channels rss_folder = $rubyrun_config['RSS_PATH'] ? $rubyrun_config['RSS_PATH'] \ : "#{Rails::Configuration.new.root_path}/public/#{RubyRunRSS::RUBYRUN_RSS_FOLDER}" begin Dir.mkdir(rss_folder) unless File.exist?(rss_folder) rescue Exception rss_folder = @rubyrun_report_folder end $rubyrun_perf_summary_rss = RubyRunRSS.new \ RubyRunRSS::RUBYRUN_RSS_PERF_SUMMARY_CHANNEL_TITLE, RubyRunRSS::RUBYRUN_RSS_PERF_SUMMARY_CHANNEL_DESCRIPTION, rss_folder, RubyRunRSS::RUBYRUN_RSS_PERF_SUMMARY_CHANNEL_FILENAME, RubyRunRSS::RUBYRUN_RSS_PERF_SUMMARY_CHANNEL_ITEM_FILENAME \ unless $rubyrun_perf_summary_rss $rubyrun_throughput = Array.new end # Create the CSV files def create_csv_files $rubyrun_txn_log_reporter = Logger.new("#{@rubyrun_report_folder}/#{File.basename($0, ".*")}_#{$$.to_s}_txn_log.csv", shift_age = 10, shift_size = 4096000) $rubyrun_txn_log_reporter.info "#\n# Format: [URL],[thread ID],[timestamp],[response time],[action time],[database IO time],[view time],[dispatch delay time],[uncaptured time]\n#" end end