lib/jmeter_perf/report/summary.rb in jmeter_perf-0.0.6 vs lib/jmeter_perf/report/summary.rb in jmeter_perf-0.0.7
- old
+ new
@@ -1,117 +1,158 @@
require "csv"
require_relative "../helpers/running_statistics"
-module JmeterPerf::Report
- class Summary
- attr_reader :name,
- :avg,
- :error_percentage,
- :max,
- :min,
- :p10,
- :p50,
- :p95,
- :requests_per_minute,
- :response_codes,
- :standard_deviation,
- :total_bytes,
- :total_elapsed_time,
- :total_errors,
- :total_latency,
- :total_requests,
- :total_sent_bytes
+module JmeterPerf
+ module Report
+ # Summary provides a statistical analysis of performance test results by processing
+ # JMeter JTL files. It calculates metrics such as average response time, error percentage,
+ # min/max response times, and percentiles, helping to understand the distribution of
+ # response times across requests.
+ class Summary
+ # @return [String] the name of the summary, usually derived from the file path
+ attr_reader :name
+ # @return [Float] the average response time
+ attr_reader :avg
+ # @return [Float] the error percentage across all requests
+ attr_reader :error_percentage
+ # @return [Integer] the maximum response time encountered
+ attr_reader :max
+ # @return [Integer] the minimum response time encountered
+ attr_reader :min
+ # @return [Float] the 10th percentile of response times
+ attr_reader :p10
+ # @return [Float] the median (50th percentile) of response times
+ attr_reader :p50
+ # @return [Float] the 95th percentile of response times
+ attr_reader :p95
+ # @return [Float] the requests per minute rate
+ attr_reader :requests_per_minute
+ # @return [Hash<String, Integer>] a hash of response codes with their respective counts
+ attr_reader :response_codes
+ # @return [Float] the standard deviation of response times
+ attr_reader :standard_deviation
+ # @return [Integer] the total number of bytes received
+ attr_reader :total_bytes
+ # @return [Integer] the total elapsed time in milliseconds
+ attr_reader :total_elapsed_time
+ # @return [Integer] the total number of errors encountered
+ attr_reader :total_errors
+ # @return [Integer] the total latency time across all requests
+ attr_reader :total_latency
+ # @return [Integer] the total number of requests processed
+ attr_reader :total_requests
+ # @return [Integer] the total number of bytes sent
+ attr_reader :total_sent_bytes
- alias_method :rpm, :requests_per_minute
- alias_method :std, :standard_deviation
- alias_method :median, :p50
+ alias_method :rpm, :requests_per_minute
+ alias_method :std, :standard_deviation
+ alias_method :median, :p50
- JTL_HEADER = %i[
- timeStamp
- elapsed
- label
- responseCode
- responseMessage
- threadName
- dataType
- success
- failureMessage
- bytes
- sentBytes
- grpThreads
- allThreads
- URL
- Latency
- IdleTime
- Connect
- ]
+ # JTL file headers used for parsing CSV rows
+ JTL_HEADER = %i[
+ timeStamp
+ elapsed
+ label
+ responseCode
+ responseMessage
+ threadName
+ dataType
+ success
+ failureMessage
+ bytes
+ sentBytes
+ grpThreads
+ allThreads
+ URL
+ Latency
+ IdleTime
+ Connect
+ ]
- def initialize(file_path, name = nil)
- @name = name || file_path.to_s.tr("/", "_")
- @finished = false
- @running_statistics_helper = JmeterPerf::RunningStatistisc.new
+ # Initializes a new Summary instance for analyzing performance data.
+ #
+ # @param file_path [String] the file path of the JTL file to analyze
+ # @param name [String, nil] an optional name for the summary, derived from the file path if not provided (default: nil)
+ def initialize(file_path, name = nil)
+ @name = name || file_path.to_s.tr("/", "_")
+ @finished = false
+ @running_statistics_helper = JmeterPerf::RunningStatistisc.new
- @max = 0
- @min = 1000000
- @response_codes = Hash.new { |h, k| h[k.to_s] = 0 }
- @total_bytes = 0
- @total_elapsed_time = 0
- @total_errors = 0
- @total_latency = 0
- @total_requests = 0
- @total_sent_bytes = 0
+ @max = 0
+ @min = 1_000_000
+ @response_codes = Hash.new { |h, k| h[k.to_s] = 0 }
+ @total_bytes = 0
+ @total_elapsed_time = 0
+ @total_errors = 0
+ @total_latency = 0
+ @total_requests = 0
+ @total_sent_bytes = 0
- @file_path = file_path
- end
+ @file_path = file_path
+ end
- def finish!
- @finished = true
- end
+ # Marks the summary as finished, allowing any pending asynchronous operations to complete.
+ #
+ # @return [void]
+ def finish!
+ @finished = true
+ end
- def stream_jtl_async
- Thread.new do
- sleep 0.1 until File.exist?(@file_path) # Wait for the file to be created
+ # Starts streaming and processing JTL file content asynchronously.
+ #
+ # @return [Thread] a thread that handles the asynchronous file streaming and parsing
+ def stream_jtl_async
+ Thread.new do
+ sleep 0.1 until File.exist?(@file_path) # Wait for the file to be created
- File.open(@file_path, "r") do |file|
- file.seek(0, IO::SEEK_END)
- until file.eof? && @finished
- line = file.gets
- if line
- parse_csv_row(line)
- else
- sleep 0.1 # Small delay to avoid busy waiting
+ File.open(@file_path, "r") do |file|
+ file.seek(0, IO::SEEK_END)
+ until file.eof? && @finished
+ line = file.gets
+ if line
+ parse_csv_row(line)
+ else
+ sleep 0.1 # Small delay to avoid busy waiting
+ end
end
end
end
end
- end
- def summarize_data!
- @p10, @p50, @p95 = @running_statistics_helper.get_percentiles(0.1, 0.5, 0.95)
- @error_percentage = (@total_errors.to_f / @total_requests) * 100
- @avg = @running_statistics_helper.avg
- @requests_per_minute = @total_elapsed_time.zero? ? 0 : @total_requests / (@total_elapsed_time / 1000)
- @standard_deviation = @running_statistics_helper.std
- end
+ # Summarizes the collected data by calculating statistical metrics and error rates.
+ #
+ # @return [void]
+ def summarize_data!
+ @p10, @p50, @p95 = @running_statistics_helper.get_percentiles(0.1, 0.5, 0.95)
+ @error_percentage = (@total_errors.to_f / @total_requests) * 100
+ @avg = @running_statistics_helper.avg
+ @requests_per_minute = @total_elapsed_time.zero? ? 0 : @total_requests / (@total_elapsed_time / 1000)
+ @standard_deviation = @running_statistics_helper.std
+ end
- private
+ private
- def parse_csv_row(csv_row)
- CSV.parse(csv_row, headers: JTL_HEADER).each do |row|
- line_item = row.to_hash
- elapsed = line_item.fetch(:elapsed).to_i
+ # Parses a single CSV row from the JTL file and updates running statistics.
+ #
+ # @param csv_row [String] a single line from the CSV-formatted JTL file
+ # @return [void]
+ def parse_csv_row(csv_row)
+ CSV.parse(csv_row, headers: JTL_HEADER).each do |row|
+ line_item = row.to_hash
+ elapsed = line_item.fetch(:elapsed).to_i
- @running_statistics_helper.add_number(elapsed)
+ @running_statistics_helper.add_number(elapsed)
- @total_requests += 1
- @total_elapsed_time += elapsed
- @response_codes[line_item.fetch(:responseCode)] += 1
- @total_errors += (line_item.fetch(:success) == "true") ? 0 : 1
- @total_bytes += line_item.fetch(:bytes, 0).to_i
- @total_sent_bytes += line_item.fetch(:sentBytes, 0).to_i
- @total_latency += line_item.fetch(:Latency).to_i
- @min = [@min, elapsed].min
- @max = [@max, elapsed].max
+ @total_requests += 1
+ @total_elapsed_time += elapsed
+ @response_codes[line_item.fetch(:responseCode)] += 1
+ @total_errors += (line_item.fetch(:success) == "true") ? 0 : 1
+ @total_bytes += line_item.fetch(:bytes, 0).to_i
+ @total_sent_bytes += line_item.fetch(:sentBytes, 0).to_i
+ @total_latency += line_item.fetch(:Latency).to_i
+ @min = [@min, elapsed].min
+ @max = [@max, elapsed].max
+ end
end
end
end
end