<s> import time <EOL> import gevent <EOL> import hashlib <EOL> import events <EOL> from exception import StopLocust <EOL> from log import console_logger <EOL> STATS_NAME_WIDTH = <NUM_LIT> <EOL> class RequestStatsAdditionError ( Exception ) : <EOL> pass <EOL> class RequestStats ( object ) : <EOL> def __init__ ( self ) : <EOL> self . entries = { } <EOL> self . errors = { } <EOL> self . num_requests = <NUM_LIT:0> <EOL> self . num_failures = <NUM_LIT:0> <EOL> self . max_requests = None <EOL> self . last_request_timestamp = None <EOL> self . start_time = None <EOL> def get ( self , name , method ) : <EOL> """<STR_LIT>""" <EOL> entry = self . entries . get ( ( name , method ) ) <EOL> if not entry : <EOL> entry = StatsEntry ( self , name , method ) <EOL> self . entries [ ( name , method ) ] = entry <EOL> return entry <EOL> def aggregated_stats ( self , name = "<STR_LIT>" , full_request_history = False ) : <EOL> """<STR_LIT>""" <EOL> total = StatsEntry ( self , name , method = None ) <EOL> for r in self . entries . itervalues ( ) : <EOL> total . extend ( r , full_request_history = full_request_history ) <EOL> return total <EOL> def reset_all ( self ) : <EOL> """<STR_LIT>""" <EOL> self . start_time = time . time ( ) <EOL> self . num_requests = <NUM_LIT:0> <EOL> self . num_failures = <NUM_LIT:0> <EOL> for r in self . entries . itervalues ( ) : <EOL> r . reset ( ) <EOL> def clear_all ( self ) : <EOL> """<STR_LIT>""" <EOL> self . num_requests = <NUM_LIT:0> <EOL> self . num_failures = <NUM_LIT:0> <EOL> self . entries = { } <EOL> self . errors = { } <EOL> self . max_requests = None <EOL> self . last_request_timestamp = None <EOL> self . start_time = None <EOL> class StatsEntry ( object ) : <EOL> """<STR_LIT>""" <EOL> name = None <EOL> """<STR_LIT>""" <EOL> method = None <EOL> """<STR_LIT>""" <EOL> num_requests = None <EOL> """<STR_LIT>""" <EOL> num_failures = None <EOL> """<STR_LIT>""" <EOL> total_response_time = None <EOL> """<STR_LIT>""" <EOL> min_response_time = None <EOL> """<STR_LIT>""" <EOL> max_response_time = None <EOL> """<STR_LIT>""" <EOL> num_reqs_per_sec = None <EOL> """<STR_LIT>""" <EOL> response_times = None <EOL> """<STR_LIT>""" <EOL> total_content_length = None <EOL> """<STR_LIT>""" <EOL> start_time = None <EOL> """<STR_LIT>""" <EOL> last_request_timestamp = None <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , stats , name , method ) : <EOL> self . stats = stats <EOL> self . name = name <EOL> self . method = method <EOL> self . reset ( ) <EOL> def reset ( self ) : <EOL> self . start_time = time . time ( ) <EOL> self . num_requests = <NUM_LIT:0> <EOL> self . num_failures = <NUM_LIT:0> <EOL> self . total_response_time = <NUM_LIT:0> <EOL> self . response_times = { } <EOL> self . min_response_time = None <EOL> self . max_response_time = <NUM_LIT:0> <EOL> self . last_request_timestamp = int ( time . time ( ) ) <EOL> self . num_reqs_per_sec = { } <EOL> self . total_content_length = <NUM_LIT:0> <EOL> def log ( self , response_time , content_length ) : <EOL> self . stats . num_requests += <NUM_LIT:1> <EOL> self . num_requests += <NUM_LIT:1> <EOL> self . _log_time_of_request ( ) <EOL> self . _log_response_time ( response_time ) <EOL> self . total_content_length += content_length <EOL> def _log_time_of_request ( self ) : <EOL> t = int ( time . time ( ) ) <EOL> self . num_reqs_per_sec [ t ] = self . num_reqs_per_sec . setdefault ( t , <NUM_LIT:0> ) + <NUM_LIT:1> <EOL> self . last_request_timestamp = t <EOL> self . stats . last_request_timestamp = t <EOL> def _log_response_time ( self , response_time ) : <EOL> self . total_response_time += response_time <EOL> if self . min_response_time is None : <EOL> self . min_response_time = response_time <EOL> self . min_response_time = min ( self . min_response_time , response_time ) <EOL> self . max_response_time = max ( self . max_response_time , response_time ) <EOL> if response_time < <NUM_LIT:100> : <EOL> rounded_response_time = response_time <EOL> elif response_time < <NUM_LIT:1000> : <EOL> rounded_response_time = int ( round ( response_time , - <NUM_LIT:1> ) ) <EOL> elif response_time < <NUM_LIT> : <EOL> rounded_response_time = int ( round ( response_time , - <NUM_LIT:2> ) ) <EOL> else : <EOL> rounded_response_time = int ( round ( response_time , - <NUM_LIT:3> ) ) <EOL> self . response_times . setdefault ( rounded_response_time , <NUM_LIT:0> ) <EOL> self . response_times [ rounded_response_time ] += <NUM_LIT:1> <EOL> def log_error ( self , error ) : <EOL> self . num_failures += <NUM_LIT:1> <EOL> self . stats . num_failures += <NUM_LIT:1> <EOL> key = StatsError . create_key ( self . method , self . name , error ) <EOL> entry = self . stats . errors . get ( key ) <EOL> if not entry : <EOL> entry = StatsError ( self . method , self . name , error ) <EOL> self . stats . errors [ key ] = entry <EOL> entry . occured ( ) <EOL> @ property <EOL> def fail_ratio ( self ) : <EOL> try : <EOL> return float ( self . num_failures ) / ( self . num_requests + self . num_failures ) <EOL> except ZeroDivisionError : <EOL> if self . num_failures > <NUM_LIT:0> : <EOL> return <NUM_LIT:1.0> <EOL> else : <EOL> return <NUM_LIT:0.0> <EOL> @ property <EOL> def avg_response_time ( self ) : <EOL> try : <EOL> return float ( self . total_response_time ) / self . num_requests <EOL> except ZeroDivisionError : <EOL> return <NUM_LIT:0> <EOL> @ property <EOL> def median_response_time ( self ) : <EOL> if not self . response_times : <EOL> return <NUM_LIT:0> <EOL> return median_from_dict ( self . num_requests , self . response_times ) <EOL> @ property <EOL> def current_rps ( self ) : <EOL> if self . stats . last_request_timestamp is None : <EOL> return <NUM_LIT:0> <EOL> slice_start_time = max ( self . stats . last_request_timestamp - <NUM_LIT:12> , int ( self . stats . start_time or <NUM_LIT:0> ) ) <EOL> reqs = [ self . num_reqs_per_sec . get ( t , <NUM_LIT:0> ) for t in range ( slice_start_time , self . stats . last_request_timestamp - <NUM_LIT:2> ) ] <EOL> return avg ( reqs ) <EOL> @ property <EOL> def total_rps ( self ) : <EOL> if not self . stats . last_request_timestamp or not self . stats . start_time : <EOL> return <NUM_LIT:0.0> <EOL> return self . num_requests / max ( self . stats . last_request_timestamp - self . stats . start_time , <NUM_LIT:1> ) <EOL> @ property <EOL> def avg_content_length ( self ) : <EOL> try : <EOL> return self . total_content_length / self . num_requests <EOL> except ZeroDivisionError : <EOL> return <NUM_LIT:0> <EOL> def extend ( self , other , full_request_history = False ) : <EOL> """<STR_LIT>""" <EOL> self . last_request_timestamp = max ( self . last_request_timestamp , other . last_request_timestamp ) <EOL> self . start_time = min ( self . start_time , other . start_time ) <EOL> self . num_requests = self . num_requests + other . num_requests <EOL> self . num_failures = self . num_failures + other . num_failures <EOL> self . total_response_time = self . total_response_time + other . total_response_time <EOL> self . max_response_time = max ( self . max_response_time , other . max_response_time ) <EOL> self . min_response_time = min ( self . min_response_time , other . min_response_time ) or other . min_response_time <EOL> self . total_content_length = self . total_content_length + other . total_content_length <EOL> if full_request_history : <EOL> for key in other . response_times : <EOL> self . response_times [ key ] = self . response_times . get ( key , <NUM_LIT:0> ) + other . response_times [ key ] <EOL> for key in other . num_reqs_per_sec : <EOL> self . num_reqs_per_sec [ key ] = self . num_reqs_per_sec . get ( key , <NUM_LIT:0> ) + other . num_reqs_per_sec [ key ] <EOL> else : <EOL> for i in xrange ( other . last_request_timestamp - <NUM_LIT:20> , other . last_request_timestamp + <NUM_LIT:1> ) : <EOL> if i in other . num_reqs_per_sec : <EOL> self . num_reqs_per_sec [ i ] = self . num_reqs_per_sec . get ( i , <NUM_LIT:0> ) + other . num_reqs_per_sec [ i ] <EOL> def serialize ( self ) : <EOL> return { <EOL> "<STR_LIT:name>" : self . name , <EOL> "<STR_LIT>" : self . method , <EOL> "<STR_LIT>" : self . last_request_timestamp , <EOL> "<STR_LIT>" : self . start_time , <EOL> "<STR_LIT>" : self . num_requests , <EOL> "<STR_LIT>" : self . num_failures , <EOL> "<STR_LIT>" : self . total_response_time , <EOL> "<STR_LIT>" : self . max_response_time , <EOL> "<STR_LIT>" : self . min_response_time , <EOL> "<STR_LIT>" : self . total_content_length , <EOL> "<STR_LIT>" : self . response_times , <EOL> "<STR_LIT>" : self . num_reqs_per_sec , <EOL> } <EOL> @ classmethod <EOL> def unserialize ( cls , data ) : <EOL> obj = cls ( None , data [ "<STR_LIT:name>" ] , data [ "<STR_LIT>" ] ) <EOL> for key in [ <EOL> "<STR_LIT>" , <EOL> "<STR_LIT>" , <EOL> "<STR_LIT>" , <EOL> "<STR_LIT>" , <EOL> "<STR_LIT>" , <EOL> "<STR_LIT>" , <EOL> "<STR_LIT>" , <EOL> "<STR_LIT>" , <EOL> "<STR_LIT>" , <EOL> "<STR_LIT>" , <EOL> ] : <EOL> setattr ( obj , key , data [ key ] ) <EOL> return obj <EOL> def get_stripped_report ( self ) : <EOL> """<STR_LIT>""" <EOL> report = self . serialize ( ) <EOL> self . reset ( ) <EOL> return report <EOL> def __str__ ( self ) : <EOL> try : <EOL> fail_percent = ( self . num_failures / float ( self . num_requests + self . num_failures ) ) * <NUM_LIT:100> <EOL> except ZeroDivisionError : <EOL> fail_percent = <NUM_LIT:0> <EOL> return ( "<STR_LIT>" + str ( STATS_NAME_WIDTH ) + "<STR_LIT>" ) % ( <EOL> self . method + "<STR_LIT:U+0020>" + self . name , <EOL> self . num_requests , <EOL> "<STR_LIT>" % ( self . num_failures , fail_percent ) , <EOL> self . avg_response_time , <EOL> self . min_response_time or <NUM_LIT:0> , <EOL> self . max_response_time , <EOL> self . median_response_time or <NUM_LIT:0> , <EOL> self . current_rps or <NUM_LIT:0> <EOL> ) <EOL> def get_response_time_percentile ( self , percent ) : <EOL> """<STR_LIT>""" <EOL> num_of_request = int ( ( self . num_requests * percent ) ) <EOL> processed_count = <NUM_LIT:0> <EOL> for response_time in sorted ( self . response_times . iterkeys ( ) , reverse = True ) : <EOL> processed_count += self . response_times [ response_time ] <EOL> if ( ( self . num_requests - processed_count ) <= num_of_request ) : <EOL> return response_time <EOL> def percentile ( self , tpl = "<STR_LIT>" + str ( STATS_NAME_WIDTH ) + "<STR_LIT>" ) : <EOL> if not self . num_requests : <EOL> raise ValueError ( "<STR_LIT>" ) <EOL> return tpl % ( <EOL> str ( self . method ) + "<STR_LIT:U+0020>" + self . name , <EOL> self . num_requests , <EOL> self . get_response_time_percentile ( <NUM_LIT:0.5> ) , <EOL> self . get_response_time_percentile ( <NUM_LIT> ) , <EOL> self . get_response_time_percentile ( <NUM_LIT> ) , <EOL> self . get_response_time_percentile ( <NUM_LIT> ) , <EOL> self . get_response_time_percentile ( <NUM_LIT> ) , <EOL> self . get_response_time_percentile ( <NUM_LIT> ) , <EOL> self . get_response_time_percentile ( <NUM_LIT> ) , <EOL> self . get_response_time_percentile ( <NUM_LIT> ) , <EOL> self . max_response_time <EOL> ) <EOL> class StatsError ( object ) : <EOL> def __init__ ( self , method , name , error , occurences = <NUM_LIT:0> ) : <EOL> self . method = method <EOL> self . name = name <EOL> self . error = error <EOL> self . occurences = occurences <EOL> @ classmethod <EOL> def create_key ( cls , method , name , error ) : <EOL> key = "<STR_LIT>" % ( method , name , error ) <EOL> return hashlib . md5 ( key ) . hexdigest ( ) <EOL> def occured ( self ) : <EOL> self . occurences += <NUM_LIT:1> <EOL> def to_name ( self ) : <EOL> return "<STR_LIT>" % ( self . method , <EOL> self . name , repr ( self . error ) ) <EOL> def to_dict ( self ) : <EOL> return { <EOL> "<STR_LIT>" : self . method , <EOL> "<STR_LIT:name>" : self . name , <EOL> "<STR_LIT:error>" : repr ( self . error ) , <EOL> "<STR_LIT>" : self . occurences <EOL> } <EOL> @ classmethod <EOL> def from_dict ( cls , data ) : <EOL> return cls ( <EOL> data [ "<STR_LIT>" ] , <EOL> data [ "<STR_LIT:name>" ] , <EOL> data [ "<STR_LIT:error>" ] , <EOL> data [ "<STR_LIT>" ] <EOL> ) <EOL> def avg ( values ) : <EOL> return sum ( values , <NUM_LIT:0.0> ) / max ( len ( values ) , <NUM_LIT:1> ) <EOL> def median_from_dict ( total , count ) : <EOL> """<STR_LIT>""" <EOL> pos = ( total - <NUM_LIT:1> ) / <NUM_LIT:2> <EOL> for k in sorted ( count . iterkeys ( ) ) : <EOL> if pos < count [ k ] : <EOL> return k <EOL> pos -= count [ k ] <EOL> global_stats = RequestStats ( ) <EOL> """<STR_LIT>""" <EOL> def on_request_success ( request_type , name , response_time , response_length ) : <EOL> if global_stats . max_requests is not None and ( global_stats . num_requests + global_stats . num_failures ) >= global_stats . max_requests : <EOL> raise StopLocust ( "<STR_LIT>" ) <EOL> global_stats . get ( name , request_type ) . log ( response_time , response_length ) <EOL> def on_request_failure ( request_type , name , response_time , exception ) : <EOL> if global_stats . max_requests is not None and ( global_stats . num_requests + global_stats . num_failures ) >= global_stats . max_requests : <EOL> raise StopLocust ( "<STR_LIT>" ) <EOL> global_stats . get ( name , request_type ) . log_error ( exception ) <EOL> def on_report_to_master ( client_id , data ) : <EOL> data [ "<STR_LIT>" ] = [ global_stats . entries [ key ] . get_stripped_report ( ) for key in global_stats . entries . iterkeys ( ) if not ( global_stats . entries [ key ] . num_requests == <NUM_LIT:0> and global_stats . entries [ key ] . num_failures == <NUM_LIT:0> ) ] <EOL> data [ "<STR_LIT>" ] = dict ( [ ( k , e . to_dict ( ) ) for k , e in global_stats . errors . iteritems ( ) ] ) <EOL> global_stats . errors = { } <EOL> def on_slave_report ( client_id , data ) : <EOL> for stats_data in data [ "<STR_LIT>" ] : <EOL> entry = StatsEntry . unserialize ( stats_data ) <EOL> request_key = ( entry . name , entry . method ) <EOL> if not request_key in global_stats . entries : <EOL> global_stats . entries [ request_key ] = StatsEntry ( global_stats , entry . name , entry . method ) <EOL> global_stats . entries [ request_key ] . extend ( entry , full_request_history = True ) <EOL> global_stats . last_request_timestamp = max ( global_stats . last_request_timestamp , entry . last_request_timestamp ) <EOL> for error_key , error in data [ "<STR_LIT>" ] . iteritems ( ) : <EOL> if error_key not in global_stats . errors : <EOL> global_stats . errors [ error_key ] = StatsError . from_dict ( error ) <EOL> else : <EOL> global_stats . errors [ error_key ] . occurences += error [ "<STR_LIT>" ] <EOL> events . request_success += on_request_success <EOL> events . request_failure += on_request_failure <EOL> events . report_to_master += on_report_to_master <EOL> events . slave_report += on_slave_report <EOL> def print_stats ( stats ) : <EOL> console_logger . info ( ( "<STR_LIT>" + str ( STATS_NAME_WIDTH ) + "<STR_LIT>" ) % ( '<STR_LIT:Name>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' ) ) <EOL> console_logger . info ( "<STR_LIT:->" * ( <NUM_LIT> + STATS_NAME_WIDTH ) ) <EOL> total_rps = <NUM_LIT:0> <EOL> total_reqs = <NUM_LIT:0> <EOL> total_failures = <NUM_LIT:0> <EOL> for key in sorted ( stats . iterkeys ( ) ) : <EOL> r = stats [ key ] <EOL> total_rps += r . current_rps <EOL> total_reqs += r . num_requests <EOL> total_failures += r . num_failures <EOL> console_logger . info ( r ) <EOL> console_logger . info ( "<STR_LIT:->" * ( <NUM_LIT> + STATS_NAME_WIDTH ) ) <EOL> try : <EOL> fail_percent = ( total_failures / float ( total_reqs ) ) * <NUM_LIT:100> <EOL> except ZeroDivisionError : <EOL> fail_percent = <NUM_LIT:0> <EOL> console_logger . info ( ( "<STR_LIT>" + str ( STATS_NAME_WIDTH ) + "<STR_LIT>" ) % ( '<STR_LIT>' , total_reqs , "<STR_LIT>" % ( total_failures , fail_percent ) , total_rps ) ) <EOL> console_logger . info ( "<STR_LIT>" ) <EOL> def print_percentile_stats ( stats ) : <EOL> console_logger . info ( "<STR_LIT>" ) <EOL> console_logger . info ( ( "<STR_LIT>" + str ( STATS_NAME_WIDTH ) + "<STR_LIT>" ) % ( '<STR_LIT:Name>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' ) ) <EOL> console_logger . info ( "<STR_LIT:->" * ( <NUM_LIT> + STATS_NAME_WIDTH ) ) <EOL> for key in sorted ( stats . iterkeys ( ) ) : <EOL> r = stats [ key ] <EOL> if r . response_times : <EOL> console_logger . info ( r . percentile ( ) ) <EOL> console_logger . info ( "<STR_LIT:->" * ( <NUM_LIT> + STATS_NAME_WIDTH ) ) <EOL> total_stats = global_stats . aggregated_stats ( ) <EOL> if total_stats . response_times : <EOL> console_logger . info ( total_stats . percentile ( ) ) <EOL> console_logger . info ( "<STR_LIT>" ) <EOL> def print_error_report ( ) : <EOL> if not len ( global_stats . errors ) : <EOL> return <EOL> console_logger . info ( "<STR_LIT>" ) <EOL> console_logger . info ( "<STR_LIT>" % ( "<STR_LIT>" , "<STR_LIT>" ) ) <EOL> console_logger . info ( "<STR_LIT:->" * ( <NUM_LIT> + STATS_NAME_WIDTH ) ) <EOL> for error in global_stats . errors . itervalues ( ) : <EOL> console_logger . info ( "<STR_LIT>" % ( error . occurences , error . to_name ( ) ) ) <EOL> console_logger . info ( "<STR_LIT:->" * ( <NUM_LIT> + STATS_NAME_WIDTH ) ) <EOL> console_logger . info ( "<STR_LIT>" ) <EOL> def stats_printer ( ) : <EOL> from runners import locust_runner <EOL> while True : <EOL> print_stats ( locust_runner . request_stats ) <EOL> gevent . sleep ( <NUM_LIT:2> ) </s>
