Repository: locustio/locust

Issue:
When there is an error in the FAILURES of the front-end page when there is a worker, there is no escape.
### Prerequisites

- [X] I am using [the latest version of Locust](https://github.com/locustio/locust/releases/)
- [X] I am reporting a bug, not asking a question

### Description

I'm using locust with 2.25.0 and have the same problem on 2.24.1, when I run locust -f 1_gloria_test.py --web-login, there is an error reported, and the page data displays fine as follows
![image](https://github.com/locustio/locust/assets/167045125/93c969ec-aedf-4c0f-8e66-30da2540a2d2)
But when I have a worker, the page doesn't show the data correctly.
master: locust -f 1_gloria_test.py --master
worker: locust -f 1_gloria_test.py --worker
After running, the front-end data looks like this
![image](https://github.com/locustio/locust/assets/167045125/13024866-7733-4d13-87f3-e7f0adf11a3d)



### Command line

locust -f 1_gloria_test.py --master

### Locustfile contents

```python3
import jmespath
from locust import HttpUser, task, TaskSet


class UserStressTest(TaskSet):

    @task(1)
    def task_3_1(self):

        request = {'method': 'GET', 'path': '/cg/v1/case/group/1',
                   'header': {'token': '5153abd76ae0a492beb2ee5f37b91035', 'Content-Type': 'application/json'},
                   'data': {}}

        with self.client.get(request['path'], headers=request['header'], params=None, timeout=10,
                             catch_response=True) as response:

            resp = {
                "status_code": response.status_code,
                "headers": response.headers,
                "body": response.json()}
            try:
                # 断言
                assert jmespath.search('status_code', resp) in [200], {resp['status_code']}
                assert jmespath.search('body.data[0].name', resp) in ['test'], f"断言失败，返回值:{resp['body']}"

            except Exception as ex:
                response.failure(ex)


class TestLocustFile(HttpUser):
    host = "http://127.0.0.1:9998"
    tasks = [UserStressTest]


```


### Python version

3.11.0

### Locust version

2.25.0

### Operating system

amzn2023.x86_64


Discussion:
Hi!

There's a ton of stuff going on in your locsustfile :)

Can you remove everything that isnt relevant to your problem? Simplify it to something like:

```
class AuthUser(UserMixin):
    @task
    def t(self):
        with self.client.post(..., catch_response=True) as response:
            assert False, "<message that breaks the UI>"
```
> Hi!
> 
> There's a ton of stuff going on in your locsustfile :)
> 
> Can you remove everything that isnt relevant to your problem? Simplify it to something like:
> 
> ```
> class AuthUser(UserMixin):
>     @task
>     def t(self):
>         with self.client.post(..., catch_response=True) as response:
>             assert False, "<message that breaks the UI>"
> ```

HI
Simplifications have been made and problems remain
Thanks! I will investigate. Probably this weekend or something...
> Thanks

Thanks
> Thanks! I will investigate. Probably this weekend or something...

Any results on this question, please? Now every time I get an error it affects my viewing of the error message!

Resolving patch:
diff --git a/locust/web.py b/locust/web.py
--- a/locust/web.py
+++ b/locust/web.py
@@ -395,11 +395,7 @@ def request_stats() -> Response:
             for s in chain(sort_stats(environment.runner.stats.entries), [environment.runner.stats.total]):
                 stats.append(s.to_dict())
 
-            for e in environment.runner.errors.values():
-                err_dict = e.serialize()
-                err_dict["name"] = escape(err_dict["name"])
-                err_dict["error"] = escape(err_dict["error"])
-                errors.append(err_dict)
+            errors = [e.serialize() for e in environment.runner.errors.values()]
 
             # Truncate the total number of stats and errors displayed since a large number of rows will cause the app
             # to render extremely slowly. Aggregate stats should be preserved.


Test patch:
diff --git a/locust/test/test_web.py b/locust/test/test_web.py
--- a/locust/test/test_web.py
+++ b/locust/test/test_web.py
@@ -183,10 +183,17 @@ def test_failure_stats_csv(self):
         self._check_csv_headers(response.headers, "failures")
 
     def test_request_stats_with_errors(self):
-        self.stats.log_error("GET", "/", Exception("Error1337"))
+        self.stats.log_error("GET", "/", Exception("Error with special characters {'foo':'bar'}"))
         response = requests.get("http://127.0.0.1:%i/stats/requests" % self.web_port)
         self.assertEqual(200, response.status_code)
-        self.assertIn("Error1337", response.text)
+
+        # escaped, old school
+        # self.assertIn(
+        #     '"Exception(&quot;Error with special characters{&#x27;foo&#x27;:&#x27;bar&#x27;}&quot;)"', response.text
+        # )
+
+        # not html escaping, leave that to the frontend
+        self.assertIn("\"Exception(\\\"Error with special characters {'foo':'bar'}\\\")", response.text)
 
     def test_reset_stats(self):
         try: