Locust with Python: No Locust Stats are showing on UI

Question:

I am new to Locust (and Python) and am trying to load test an API. My Locust UI shows no stats whatsoever – no users hatched, no API calls, etc. I need help figuring out how to get them to show up on the UI so I can get the stats.

Here is my locust.py file:

from locust import HttpUser, SequentialTaskSet, task, constant

import finops_service.locust_files.finops_fx_load_testing as load_test

class FXTransaction(SequentialTaskSet):
    def __init__(self, parent):
        super().__init__(parent)
        self.comp_data = dict()
        self.rate_lock_response = dict()
        self.transaction_response = dict()
        self.fx_providerID = '57638f08-e938-48d7-accf-325b6728a9ee'
        self.headers = {"Content-Type": "application/json"}

def on_start(self):
    load_test.login(self),

@task
def get_company_data(self):
    # Get company data
    self.comp_data = load_test.get_company_data(self)
    print("Company is: ", self.comp_data['company'])
    print("Vendor is:  ", self.comp_data['vendor'])
    print("Payment Method is:  ", self.comp_data['payment_method'])
    print("Funding Method is:  ", self.comp_data['funding_method'])

# @task
# def rate_lock(self):
    print("Starting rate lock")
    load_test.rate_lock(self)
    print("This is the returned rate lock response:")
    print(self.rate_lock_response)

# @task
# def approve_transaction(self):
#     print("Starting transaction")
#     load_test.approve_transaction(self)
#     print("This is the returned transaction response:")
#     print(self.transaction_response)


class MyUser(HttpUser):
    wait_time = constant(1)
    # weight = 1
    host = "http://localhost:8080/PaymentService/base/"
    tasks = [FXTransaction]

And here are my functions:

    import json
import random
import uuid

from utils import json_util as json_util

    enter code here

def login(self):
    try:
        with self.client.post(
                "security/login",
                headers={'Content-Type': 'application/json',
                         'Authorization': 'BASIC 0ee89b88-5c4b-4922-b1f9-c1584ab26e7e:12345'},
                name=login,
                timeout=55.6,
                catch_response=True) as response:
            if response.status_code != 200:
                response.failure("Login failed")
            else:
                response.success()
                print("Login succeeded")
            self.headers.update({'if-Match': "{}".format(response.headers["ETag"])})
    except ConnectionRefusedError:
        print("The test could not connect to {}".format("http://localhost:8080/PaymentService/security/login"))
        raise

def get_company_data(self):
    comp_index = random.randrange(0, 9)
    print("Random company data index is:  ", comp_index)
    try:
        body = json.load(open("finops_service/locust_files/load_testing_data.json", 'r'))
        comp_data = body['fx']['multipleCompanies_10']['company_data'][comp_index]
    except ConnectionRefusedError:
        print("The test could not connect to {}".format("http://localhost:8080/PaymentService/security/login"))
        raise
    return comp_data


def rate_lock(self):
    body = json_util.get_json_object(
        "/finops_service/locust_files/rate_lock_load_testing.json",
        'fx'.lower(),
        'valid_multiple_20'.lower()
    )
    body["debtorCompanyProfileId"] = self.comp_data['company']
    i = 0
    # there are 20 rate locks so need to update each request
    while i < 20:
        body["rateRequestPayments"][i]["creditorProfileId"] = self.comp_data['vendor']
        body["rateRequestPayments"][i]["debtorProfileId"] = self.comp_data['company']
        body["rateRequestPayments"][i]["paymentMethodId"] = self.comp_data['payment_method']
        random_float_no = round(random.uniform(1.11, 999.99), 2)
        body['rateRequestPayments'][i]['amount'] = random_float_no
        i += 1
    try:
        print("RIGHT BEFORE RATE LOCK CALL")
        with self.client.post("services/transaction/fx/rate/lock",
                              data=json.dumps(body),
                              headers=self.headers,
                              name="rate lock",
                              timeout=55.6,
                              catch_response=True) as response:
            if "GENERIC_FAILURE" in response.text:
                response.failure("FAIL")
                print("Rate lock call failed")
            else:
                response.success()
                print("rate lock succeeded")
            print("Rate lock response is:.........", response)
            print("Rate lock response TEXT is:.........", response.text)
            self.rate_lock_response = response.text
    except ConnectionRefusedError:
        print("The test could not connect to {}".format(
            "http://localhost:8080/PaymentService/services/transaction/fx/rate/lock"))
        raise

When I run this, I can see that the self.client.post("services/transaction/fx/rate/lock"… is happening and either succeeding or failing. However, in the Locust UI, I show 0 users hatched (console shows I hatched 5) and 0 tasks shown.

I get this error each time I run which it looks related to my stats not showing up but I don’t know why it is happening:

Traceback (most recent call last):
  File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/gevent/pywsgi.py", line 999, in handle_one_response
    self.run_application()
  File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/gevent/pywsgi.py", line 945, in run_application
    self.result = self.application(self.environ, self.start_response)
  File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/flask/app.py", line 2464, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/flask/app.py", line 2450, in wsgi_app
    response = self.handle_exception(e)
  File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/flask/app.py", line 1867, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
    raise value
  File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/flask/app.py", line 2447, in wsgi_app
    response = self.full_dispatch_request()
  File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/flask/app.py", line 1952, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/flask/app.py", line 1821, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
    raise value
  File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/flask/app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/flask/app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/locust/web.py", line 319, in wrapper
    return view_func(*args, **kwargs)
  File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/locust/util/cache.py", line 21, in wrapper
    cache["result"] = func(*args, **kwargs)
  File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/site-packages/locust/web.py", line 208, in request_stats
    "safe_name": escape(s.name, quote=False),
  File "/Users/michellegautier/.pyenv/versions/3.7.4/lib/python3.7/html/__init__.py", line 19, in escape
    s = s.replace("&", "&amp;") # Must be done first!
AttributeError: 'function' object has no attribute 'replace'
2021-03-18T16:44:29Z {'REMOTE_ADDR': '::1', 'REMOTE_PORT': '49242', 'HTTP_HOST': 'localhost:8089', (hidden keys: 25)} failed with AttributeError

Can someone please help me figure out how to make my stats show up?
Thank you!!!!

Asked By: user13842621

||

Answers:

The stats not showing up in Locust is because of that Exception you posted. If you resolve that and get to where your code runs without issues, you should see stats in the Locust UI.

There are a number of issues with your code.

I’m not sure if it’s just an issue with pasting your code into SO, but your on_start() and get_company_data() functions (and the @task decorator) need to be indented so they’re part of FXTransaction.

Also, trying to use self.client in login() or get_company_data() isn’t going to work because they aren’t part of a class so there’s no such thing as self. You’d probably want to change self in that function to just client and then pass in self.client when you call it from the on_start() function.

But what’s possibly your main issue is here:

with self.client.post(
            "security/login",
            headers={'Content-Type': 'application/json',
                     'Authorization': 'BASIC 0ee89b88-5c4b-4922-b1f9-c1584ab26e7e:12345'},
            name=login,
            …

name here is the name of the endpoint (URL) you’re hitting. This is supposed to be a string but you’re giving it your function login. So when the Locust code tries to do some thing with your name value that it wants to do, expecting it to be a string, it’s going to fail because it’s trying to do those on a function instead. That’s what AttributeError: 'function' object has no attribute 'replace' means.

I think if you fix all of those things, Locust should work.

Answered By: Solowalker
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.