Skip to content

Commit

Permalink
Added method and name for failures
Browse files Browse the repository at this point in the history
  • Loading branch information
Jahaja committed Jul 12, 2013
1 parent 8ef9f34 commit 08796d9
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 18 deletions.
68 changes: 53 additions & 15 deletions locust/stats.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import time
import gevent
import hashlib
from copy import copy

import events
Expand Down Expand Up @@ -138,12 +139,6 @@ def log(self, response_time, content_length):

# increase total content-length
self.total_content_length += content_length

def log_error(self, error):
self.num_failures += 1
key = "%r: %s" % (error, repr(str(error)))
self.stats.errors.setdefault(key, 0)
self.stats.errors[key] += 1

def _log_time_of_request(self):
t = int(time.time())
Expand Down Expand Up @@ -178,10 +173,14 @@ def _log_response_time(self, response_time):

def log_error(self, error):
self.num_failures += 1
key = "%r: %s" % (error, repr(str(error)))
self.stats.errors.setdefault(key, 0)
self.stats.errors[key] += 1

key = StatsError.create_key(self.method, self.name, error)
entry = self.stats.errors.get(key)
if not entry:
entry = StatsError(self.method, self.name, error)
self.stats.errors[key] = entry

entry.occured()

@property
def fail_ratio(self):
try:
Expand Down Expand Up @@ -353,6 +352,42 @@ def percentile(self, tpl=" %-" + str(STATS_NAME_WIDTH) + "s %8d %6d %6d %6d %6d
self.max_response_time
)

class StatsError(object):
def __init__(self, method, name, error, occurences=0):
self.method = method
self.name = name
self.error = error
self.occurences = occurences

@classmethod
def create_key(cls, method, name, error):
key = "%s.%s.%r" % (method, name, error)
return hashlib.md5(key).hexdigest()

def occured(self):
self.occurences += 1

def to_name(self):
return "%s %s: %r" % (self.method,
self.name, repr(self.error))

def to_dict(self):
return {
"method": self.method,
"name": self.name,
"error": repr(self.error),
"occurences": self.occurences
}

@classmethod
def from_dict(cls, data):
return cls(
data["method"],
data["name"],
data["error"],
data["occurences"]
)


def avg(values):
return sum(values, 0.0) / max(len(values), 1)
Expand Down Expand Up @@ -385,7 +420,7 @@ def on_request_failure(method, name, response_time, error, response=None):

def on_report_to_master(client_id, data):
data["stats"] = [global_stats.entries[key].get_stripped_report() for key in global_stats.entries.iterkeys() if not (global_stats.entries[key].num_requests == 0 and global_stats.entries[key].num_failures == 0)]
data["errors"] = global_stats.errors
data["errors"] = dict([(k, e.to_dict()) for k, e in global_stats.errors.iteritems()])
global_stats.errors = {}

def on_slave_report(client_id, data):
Expand All @@ -397,8 +432,11 @@ def on_slave_report(client_id, data):
global_stats.entries[request_key].extend(entry, full_request_history=True)
global_stats.last_request_timestamp = max(global_stats.last_request_timestamp, entry.last_request_timestamp)

for err_message, err_count in data["errors"].iteritems():
global_stats.errors[err_message] = global_stats.errors.setdefault(err_message, 0) + err_count
for error_key, error in data["errors"].iteritems():
if error_key not in global_stats.errors:
global_stats.errors[error_key] = StatsError.from_dict(error)
else:
global_stats.errors[error_key].occurences += error["occurences"]

events.request_success += on_request_success
events.request_failure += on_request_failure
Expand Down Expand Up @@ -447,8 +485,8 @@ def print_error_report():
console_logger.info("Error report")
console_logger.info(" %-18s %-100s" % ("# occurences", "Error"))
console_logger.info("-" * (80 + STATS_NAME_WIDTH))
for error, count in global_stats.errors.iteritems():
console_logger.info(" %-18i %-100s" % (count, error))
for error in global_stats.errors.itervalues():
console_logger.info(" %-18i %-100s" % (error.occurences, error.to_name()))
console_logger.info("-" * (80 + STATS_NAME_WIDTH))
console_logger.info("")

Expand Down
8 changes: 6 additions & 2 deletions locust/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ <h2>Ramping</h2>
<table id="errors" class="stats">
<thead>
<th class="error_count stats_label" data-sortkey="1"># fails</th>
<th class="stats_label" href="#" data-sortkey="method">Method</th>
<th class="stats_label" href="#" data-sortkey="name">Name</th>
<th class="error_type stats_label" data-sortkey="0">Type</th>
</thead>
<tbody>
Expand Down Expand Up @@ -241,8 +243,10 @@ <h1>Version</h1>
<script type="text/x-jqote-template" id="errors-template">
<![CDATA[
<tr class="<%=(alternate ? "dark" : "")%>">
<td><%= this[1] %></td>
<td><%= function(e) { return e.replace("<", "&lt;"); }(this[0]) %></td>
<td><%= this.occurences %></td>
<td><%= this.method %></td>
<td><%= this.name %></td>
<td><%= function(e) { return e.replace("<", "&lt;"); }(this.error) %></td>
</tr>
<% alternate = !alternate; %>
]]>
Expand Down
2 changes: 1 addition & 1 deletion locust/web.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ def request_stats():
"avg_content_length": s.avg_content_length,
})

report = {"stats":stats, "errors":list(runners.locust_runner.errors.iteritems())}
report = {"stats":stats, "errors":[e.to_dict() for e in runners.locust_runner.errors.itervalues()]}
if stats:
report["total_rps"] = stats[len(stats)-1]["current_rps"]
report["fail_ratio"] = runners.locust_runner.stats.aggregated_stats("Total").fail_ratio
Expand Down

0 comments on commit 08796d9

Please sign in to comment.