Repository: scoutapp/scout_apm_python

Issue:
[2.9.0] UnicodeEncodeError raised on create_filtered_path
Hi,

so we still use Python2, and got an UnicodeErrorException in create_filtered_path, ligne 53: 

```python
return path + "?" + urlencode(filtered_params)
```

filtered_params value:
```python
filtered_params = [[u'search', u'Clos du Chêne, Montévrain, France'],]
```
query_params has the same value

As it is the output from Sentry, I do not know whether the strings were really Unicode as implied by the "u".


Discussion:
Hi @nMustaki 

Thanks for the error report. Can you provide some of the traceback? I can probably fix the error from the information you've provided but it would be helpful to see a bit more information.

I'll have a look this evening.

Thanks,

Adam
I'm copying it through Sentry, I hope it's enough ?

UnicodeEncodeError: 'ascii' codec can't encode character u'\xea' in position 10: ordinal not in range(128)

```python
# urllib.py in urlencode at line 1342
    v = quote_plus(str(v))
# scout_apm/core/web_requests.py in create_filtered_path at line 53
    return path + "?" + urlencode(filtered_params)
# scout_apm/django/middleware.py in track_request_view_data at line 119
    path, [(k, v) for k, vs in request.GET.lists() for v in vs]
# scout_apm/django/middleware.py in process_view at line 226
    track_request_view_data(request, tracked_request)
# django/core/handlers/base.py in _get_response at line 178
    response = middleware_method(request, callback, callback_args, callback_kwargs)
# django/core/handlers/exception.py in inner at line 41
    response = get_response(request)
```

Resolving patch:
diff --git a/src/scout_apm/core/web_requests.py b/src/scout_apm/core/web_requests.py
--- a/src/scout_apm/core/web_requests.py
+++ b/src/scout_apm/core/web_requests.py
@@ -42,10 +42,18 @@
 def create_filtered_path(path, query_params):
     if scout_config.value("uri_reporting") == "path":
         return path
+    # Python 2 unicode compatibility: force all keys and values to bytes
     filtered_params = sorted(
         (
-            (k, "[FILTERED]" if k.lower() in FILTER_PARAMETERS else v)
-            for k, v in query_params
+            (
+                key.encode("utf-8"),
+                (
+                    b"[FILTERED]"
+                    if key.lower() in FILTER_PARAMETERS
+                    else value.encode("utf-8")
+                ),
+            )
+            for key, value in query_params
         )
     )
     if not filtered_params:


Test patch:
diff --git a/tests/unit/core/test_web_requests.py b/tests/unit/core/test_web_requests.py
--- a/tests/unit/core/test_web_requests.py
+++ b/tests/unit/core/test_web_requests.py
@@ -24,7 +24,9 @@
         ("/", [], "/"),
         ("/foo/", [], "/foo/"),
         ("/", [("bar", "1")], "/?bar=1"),
-        ("/", [("baz", 2), ("bar", "1")], "/?bar=1&baz=2"),
+        ("/", [("bar", "unicØde")], "/?bar=unic%C3%98de"),
+        ("/", [("unicØde", "foo")], "/?unic%C3%98de=foo"),
+        ("/", [("baz", "2"), ("bar", "1")], "/?bar=1&baz=2"),
         ("/", [("bar", "1"), ("bar", "2")], "/?bar=1&bar=2"),
         ("/", [("password", "hunter2")], "/?password=%5BFILTERED%5D"),
         ("/", [("PASSWORD", "hunter2")], "/?PASSWORD=%5BFILTERED%5D"),