Repository: DataDog/dd-trace-py

Issue:
Flask integration unicode support
I ran into a small issue where the Flask integration is unable to set tags when they contain unicode characters.

The specific case we have is when unicode was in the url.

https://github.com/DataDog/dd-trace-py/blob/8a9a7a59312de544d9c774e19872eb5e97cd8307/ddtrace/contrib/flask/middleware.py#L119

```
2016-10-28 13:47:58,953 - ERROR - error finishing trace
Traceback (most recent call last):
  File "/home/vagrant/.virtualenvs/kennel/local/lib/python2.7/site-packages/ddtrace/contrib/flask/middleware.py", line 150, in _request_finished
    self._finish_span(response=response)
  File "/home/vagrant/.virtualenvs/kennel/local/lib/python2.7/site-packages/ddtrace/contrib/flask/middleware.py", line 119, in _finish_span
    span.set_tag(http.URL, str(request.base_url or ""))
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe8' in position 31: ordinal not in range(128)
```

Happy to submit a PR for a fix, not sure how you would like to go about it, my thinking was:

``` python
from ...compat import stringify

# Use `stringify` instead of `str` throughout the module
span.set_tag(http.URL, stringify(request.base_url or ""))
```



Discussion:
@brettlangdon feel free to patch or we can :)


Resolving patch:
diff --git a/ddtrace/contrib/flask/middleware.py b/ddtrace/contrib/flask/middleware.py
--- a/ddtrace/contrib/flask/middleware.py
+++ b/ddtrace/contrib/flask/middleware.py
@@ -9,6 +9,7 @@
 import logging
 
 # project
+from ... import compat
 from ...ext import http, errors, AppTypes
 
 # 3p
@@ -115,8 +116,8 @@ def _finish_span(self, response=None, exception=None):
                     span.set_tag(errors.ERROR_TYPE, type(exception))
                     span.set_tag(errors.ERROR_MSG, exception)
 
-                span.resource = str(request.endpoint or "").lower()
-                span.set_tag(http.URL, str(request.base_url or ""))
+                span.resource = compat.to_unicode(request.endpoint or '').lower()
+                span.set_tag(http.URL, compat.to_unicode(request.base_url or ''))
                 span.set_tag(http.STATUS_CODE, code)
                 span.error = error
             span.finish()


Test patch:
diff --git a/tests/contrib/flask/test_flask.py b/tests/contrib/flask/test_flask.py
--- a/tests/contrib/flask/test_flask.py
+++ b/tests/contrib/flask/test_flask.py
@@ -1,5 +1,4 @@
-
-
+# -*- coding: utf-8 -*-
 # stdlib
 import time
 import logging
@@ -67,6 +66,17 @@ def child():
         return 'child'
 
 
+def unicode_view():
+    return u'üŋïĉóđē'
+
+# DEV: Manually register endpoint so we can control the endpoint name
+app.add_url_rule(
+    u'/üŋïĉóđē',
+    u'üŋïĉóđē',
+    unicode_view,
+)
+
+
 @app.errorhandler(TestError)
 def handle_my_exception(e):
     assert isinstance(e, TestError)
@@ -248,3 +258,24 @@ def test_fatal(self):
         msg = s.meta.get(errors.ERROR_MSG)
         assert "by zero" in msg, msg
 
+    def test_unicode(self):
+        start = time.time()
+        rv = app.get(u'/üŋïĉóđē')
+        end = time.time()
+
+        # ensure request worked
+        eq_(rv.status_code, 200)
+        eq_(rv.data, b'\xc3\xbc\xc5\x8b\xc3\xaf\xc4\x89\xc3\xb3\xc4\x91\xc4\x93')
+
+        # ensure trace worked
+        assert not tracer.current_span(), tracer.current_span().pprint()
+        spans = writer.pop()
+        eq_(len(spans), 1)
+        s = spans[0]
+        eq_(s.service, service)
+        eq_(s.resource, u'üŋïĉóđē')
+        assert s.start >= start
+        assert s.duration <= end - start
+        eq_(s.error, 0)
+        eq_(s.meta.get(http.STATUS_CODE), '200')
+        eq_(s.meta.get(http.URL), u'http://localhost/üŋïĉóđē')