We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Profile exporter crashes when DD_VERSION is used
The profile exporter is crashing due to `DD_VERSION` not being encoded before generating the export request. Looking at the code the same applies probably to `DD_ENV` as well.

Lines missing `.decode("utf-8")`: https://github.com/DataDog/dd-trace-py/blob/6a14a9ba75a6866d968ddf0eb84b8fee5bd3f49c/ddtrace/profiling/exporter/http.py#L144-L150

**Sentry traceback**
![image](https://user-images.githubusercontent.com/74944/80689205-43e17800-8acd-11ea-9068-87b76e106660.png)

### Which version of dd-trace-py are you using?

0.37.0

### Which version of the libraries are you using?

N/A

### How can we reproduce your problem?

```
DD_VERSION=foobar pyddprofile ...
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `ddtrace/profiling/exporter/http.py`
Content:
```
1 # -*- encoding: utf-8 -*-
2 import binascii
3 import datetime
4 import gzip
5 import os
6 import platform
7 import uuid
8 
9 import tenacity
10 
11 from ddtrace.utils import deprecation
12 from ddtrace.utils.formats import parse_tags_str
13 from ddtrace.vendor import six
14 from ddtrace.vendor.six.moves import http_client
15 from ddtrace.vendor.six.moves.urllib import error
16 from ddtrace.vendor.six.moves.urllib import request
17 
18 import ddtrace
19 from ddtrace.profiling import _attr
20 from ddtrace.profiling import _traceback
21 from ddtrace.profiling import exporter
22 from ddtrace.vendor import attr
23 from ddtrace.profiling.exporter import pprof
24 
25 
26 RUNTIME_ID = str(uuid.uuid4()).encode()
27 HOSTNAME = platform.node()
28 PYTHON_IMPLEMENTATION = platform.python_implementation().encode()
29 PYTHON_VERSION = platform.python_version().encode()
30 
31 
32 class InvalidEndpoint(exporter.ExportError):
33     pass
34 
35 
36 class RequestFailed(exporter.ExportError):
37     """Failed HTTP request."""
38 
39     def __init__(self, response, content):
40         """Create a new failed request embedding response and content."""
41         self.response = response
42         self.content = content
43         super(RequestFailed, self).__init__(
44             "Error status code received from endpoint: %d: %s" % (response.status, content)
45         )
46 
47 
48 class UploadFailed(exporter.ExportError):
49     """Upload failure."""
50 
51     def __init__(self, exception):
52         """Create a failed upload error based on raised exceptions."""
53         self.exception = exception
54         super(UploadFailed, self).__init__("Unable to upload: " + _traceback.format_exception(exception))
55 
56 
57 def _get_api_key():
58     legacy = _attr.from_env("DD_PROFILING_API_KEY", "", str)()
59     if legacy:
60         deprecation.deprecation("DD_PROFILING_API_KEY", "Use DD_API_KEY")
61         return legacy
62     return _attr.from_env("DD_API_KEY", "", str)()
63 
64 
65 ENDPOINT_TEMPLATE = "https://intake.profile.{}/v1/input"
66 
67 
68 def _get_endpoint():
69     legacy = _attr.from_env("DD_PROFILING_API_URL", "", str)()
70     if legacy:
71         deprecation.deprecation("DD_PROFILING_API_URL", "Use DD_SITE")
72         return legacy
73     site = _attr.from_env("DD_SITE", "datadoghq.com", str)()
74     return ENDPOINT_TEMPLATE.format(site)
75 
76 
77 def _get_service_name():
78     for service_name_var in ("DD_SERVICE", "DD_SERVICE_NAME", "DATADOG_SERVICE_NAME"):
79         service_name = os.environ.get(service_name_var)
80         if service_name is not None:
81             return service_name
82 
83 
84 @attr.s
85 class PprofHTTPExporter(pprof.PprofExporter):
86     """PProf HTTP exporter."""
87 
88     endpoint = attr.ib(factory=_get_endpoint, type=str)
89     api_key = attr.ib(factory=_get_api_key, type=str)
90     timeout = attr.ib(factory=_attr.from_env("DD_PROFILING_API_TIMEOUT", 10, float), type=float)
91     service_name = attr.ib(factory=_get_service_name)
92     max_retry_delay = attr.ib(default=None)
93 
94     def __attrs_post_init__(self):
95         if self.max_retry_delay is None:
96             self.max_retry_delay = self.timeout * 3
97 
98     @staticmethod
99     def _encode_multipart_formdata(fields, tags):
100         boundary = binascii.hexlify(os.urandom(16))
101 
102         # The body that is generated is very sensitive and must perfectly match what the server expects.
103         body = (
104             b"".join(
105                 b"--%s\r\n"
106                 b'Content-Disposition: form-data; name="%s"\r\n'
107                 b"\r\n"
108                 b"%s\r\n" % (boundary, field.encode(), value)
109                 for field, value in fields.items()
110                 if field != "chunk-data"
111             )
112             + b"".join(
113                 b"--%s\r\n"
114                 b'Content-Disposition: form-data; name="tags[]"\r\n'
115                 b"\r\n"
116                 b"%s:%s\r\n" % (boundary, tag.encode(), value)
117                 for tag, value in tags.items()
118             )
119             + b"--"
120             + boundary
121             + b"\r\n"
122             b'Content-Disposition: form-data; name="chunk-data"; filename="profile.pb.gz"\r\n'
123             + b"Content-Type: application/octet-stream\r\n\r\n"
124             + fields["chunk-data"]
125             + b"\r\n--%s--\r\n" % boundary
126         )
127 
128         content_type = b"multipart/form-data; boundary=%s" % boundary
129 
130         return content_type, body
131 
132     @staticmethod
133     def _get_tags(service):
134         tags = {
135             "service": service.encode("utf-8"),
136             "host": HOSTNAME.encode("utf-8"),
137             "runtime-id": RUNTIME_ID,
138             "language": b"python",
139             "runtime": PYTHON_IMPLEMENTATION,
140             "runtime_version": PYTHON_VERSION,
141             "profiler_version": ddtrace.__version__.encode("utf-8"),
142         }
143 
144         version = os.environ.get("DD_VERSION")
145         if version:
146             tags["version"] = version
147 
148         env = os.environ.get("DD_ENV")
149         if env:
150             tags["env"] = env
151 
152         user_tags = parse_tags_str(os.environ.get("DD_TAGS", {}))
153         user_tags.update(parse_tags_str(os.environ.get("DD_PROFILING_TAGS", {})))
154         tags.update({k: six.ensure_binary(v) for k, v in user_tags.items()})
155         return tags
156 
157     def export(self, events, start_time_ns, end_time_ns):
158         """Export events to an HTTP endpoint.
159 
160         :param events: The event dictionary from a `ddtrace.profiling.recorder.Recorder`.
161         :param start_time_ns: The start time of recording.
162         :param end_time_ns: The end time of recording.
163         """
164         if not self.endpoint:
165             raise InvalidEndpoint("Endpoint is empty")
166 
167         common_headers = {
168             "DD-API-KEY": self.api_key.encode(),
169         }
170 
171         profile = super(PprofHTTPExporter, self).export(events, start_time_ns, end_time_ns)
172         s = six.BytesIO()
173         with gzip.GzipFile(fileobj=s, mode="wb") as gz:
174             gz.write(profile.SerializeToString())
175         fields = {
176             "runtime-id": RUNTIME_ID,
177             "recording-start": (
178                 datetime.datetime.utcfromtimestamp(start_time_ns / 1e9).replace(microsecond=0).isoformat() + "Z"
179             ).encode(),
180             "recording-end": (
181                 datetime.datetime.utcfromtimestamp(end_time_ns / 1e9).replace(microsecond=0).isoformat() + "Z"
182             ).encode(),
183             "runtime": PYTHON_IMPLEMENTATION,
184             "format": b"pprof",
185             "type": b"cpu+alloc+exceptions",
186             "chunk-data": s.getvalue(),
187         }
188 
189         service_name = self.service_name or os.path.basename(profile.string_table[profile.mapping[0].filename])
190 
191         content_type, body = self._encode_multipart_formdata(fields, tags=self._get_tags(service_name),)
192         headers = common_headers.copy()
193         headers["Content-Type"] = content_type
194 
195         # urllib uses `POST` if `data` is supplied (Python 2 version does not handle `method` kwarg)
196         req = request.Request(self.endpoint, data=body, headers=headers)
197 
198         retry = tenacity.Retrying(
199             # Retry after 1s, 2s, 4s, 8s with some randomness
200             wait=tenacity.wait_random_exponential(multiplier=0.5),
201             stop=tenacity.stop_after_delay(self.max_retry_delay),
202             retry=tenacity.retry_if_exception_type(
203                 (error.HTTPError, error.URLError, http_client.HTTPException, OSError, IOError)
204             ),
205         )
206 
207         try:
208             retry(request.urlopen, req, timeout=self.timeout)
209         except tenacity.RetryError as e:
210             raise UploadFailed(e.last_attempt.exception())
211
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/ddtrace/profiling/exporter/http.py b/ddtrace/profiling/exporter/http.py
--- a/ddtrace/profiling/exporter/http.py
+++ b/ddtrace/profiling/exporter/http.py
@@ -143,11 +143,11 @@
 
         version = os.environ.get("DD_VERSION")
         if version:
-            tags["version"] = version
+            tags["version"] = version.encode("utf-8")
 
         env = os.environ.get("DD_ENV")
         if env:
-            tags["env"] = env
+            tags["env"] = env.encode("utf-8")
 
         user_tags = parse_tags_str(os.environ.get("DD_TAGS", {}))
         user_tags.update(parse_tags_str(os.environ.get("DD_PROFILING_TAGS", {})))

{"golden_diff": "diff --git a/ddtrace/profiling/exporter/http.py b/ddtrace/profiling/exporter/http.py\n--- a/ddtrace/profiling/exporter/http.py\n+++ b/ddtrace/profiling/exporter/http.py\n@@ -143,11 +143,11 @@\n \n         version = os.environ.get(\"DD_VERSION\")\n         if version:\n-            tags[\"version\"] = version\n+            tags[\"version\"] = version.encode(\"utf-8\")\n \n         env = os.environ.get(\"DD_ENV\")\n         if env:\n-            tags[\"env\"] = env\n+            tags[\"env\"] = env.encode(\"utf-8\")\n \n         user_tags = parse_tags_str(os.environ.get(\"DD_TAGS\", {}))\n         user_tags.update(parse_tags_str(os.environ.get(\"DD_PROFILING_TAGS\", {})))\n", "issue": "Profile exporter crashes when DD_VERSION is used\nThe profile exporter is crashing due to `DD_VERSION` not being encoded before generating the export request. Looking at the code the same applies probably to `DD_ENV` as well.\r\n\r\nLines missing `.decode(\"utf-8\")`: https://github.com/DataDog/dd-trace-py/blob/6a14a9ba75a6866d968ddf0eb84b8fee5bd3f49c/ddtrace/profiling/exporter/http.py#L144-L150\r\n\r\n**Sentry traceback**\r\n![image](https://user-images.githubusercontent.com/74944/80689205-43e17800-8acd-11ea-9068-87b76e106660.png)\r\n\r\n### Which version of dd-trace-py are you using?\r\n\r\n0.37.0\r\n\r\n### Which version of the libraries are you using?\r\n\r\nN/A\r\n\r\n### How can we reproduce your problem?\r\n\r\n```\r\nDD_VERSION=foobar pyddprofile ...\r\n```\n", "before_files": [{"content": "# -*- encoding: utf-8 -*-\nimport binascii\nimport datetime\nimport gzip\nimport os\nimport platform\nimport uuid\n\nimport tenacity\n\nfrom ddtrace.utils import deprecation\nfrom ddtrace.utils.formats import parse_tags_str\nfrom ddtrace.vendor import six\nfrom ddtrace.vendor.six.moves import http_client\nfrom ddtrace.vendor.six.moves.urllib import error\nfrom ddtrace.vendor.six.moves.urllib import request\n\nimport ddtrace\nfrom ddtrace.profiling import _attr\nfrom ddtrace.profiling import _traceback\nfrom ddtrace.profiling import exporter\nfrom ddtrace.vendor import attr\nfrom ddtrace.profiling.exporter import pprof\n\n\nRUNTIME_ID = str(uuid.uuid4()).encode()\nHOSTNAME = platform.node()\nPYTHON_IMPLEMENTATION = platform.python_implementation().encode()\nPYTHON_VERSION = platform.python_version().encode()\n\n\nclass InvalidEndpoint(exporter.ExportError):\n    pass\n\n\nclass RequestFailed(exporter.ExportError):\n    \"\"\"Failed HTTP request.\"\"\"\n\n    def __init__(self, response, content):\n        \"\"\"Create a new failed request embedding response and content.\"\"\"\n        self.response = response\n        self.content = content\n        super(RequestFailed, self).__init__(\n            \"Error status code received from endpoint: %d: %s\" % (response.status, content)\n        )\n\n\nclass UploadFailed(exporter.ExportError):\n    \"\"\"Upload failure.\"\"\"\n\n    def __init__(self, exception):\n        \"\"\"Create a failed upload error based on raised exceptions.\"\"\"\n        self.exception = exception\n        super(UploadFailed, self).__init__(\"Unable to upload: \" + _traceback.format_exception(exception))\n\n\ndef _get_api_key():\n    legacy = _attr.from_env(\"DD_PROFILING_API_KEY\", \"\", str)()\n    if legacy:\n        deprecation.deprecation(\"DD_PROFILING_API_KEY\", \"Use DD_API_KEY\")\n        return legacy\n    return _attr.from_env(\"DD_API_KEY\", \"\", str)()\n\n\nENDPOINT_TEMPLATE = \"https://intake.profile.{}/v1/input\"\n\n\ndef _get_endpoint():\n    legacy = _attr.from_env(\"DD_PROFILING_API_URL\", \"\", str)()\n    if legacy:\n        deprecation.deprecation(\"DD_PROFILING_API_URL\", \"Use DD_SITE\")\n        return legacy\n    site = _attr.from_env(\"DD_SITE\", \"datadoghq.com\", str)()\n    return ENDPOINT_TEMPLATE.format(site)\n\n\ndef _get_service_name():\n    for service_name_var in (\"DD_SERVICE\", \"DD_SERVICE_NAME\", \"DATADOG_SERVICE_NAME\"):\n        service_name = os.environ.get(service_name_var)\n        if service_name is not None:\n            return service_name\n\n\n@attr.s\nclass PprofHTTPExporter(pprof.PprofExporter):\n    \"\"\"PProf HTTP exporter.\"\"\"\n\n    endpoint = attr.ib(factory=_get_endpoint, type=str)\n    api_key = attr.ib(factory=_get_api_key, type=str)\n    timeout = attr.ib(factory=_attr.from_env(\"DD_PROFILING_API_TIMEOUT\", 10, float), type=float)\n    service_name = attr.ib(factory=_get_service_name)\n    max_retry_delay = attr.ib(default=None)\n\n    def __attrs_post_init__(self):\n        if self.max_retry_delay is None:\n            self.max_retry_delay = self.timeout * 3\n\n    @staticmethod\n    def _encode_multipart_formdata(fields, tags):\n        boundary = binascii.hexlify(os.urandom(16))\n\n        # The body that is generated is very sensitive and must perfectly match what the server expects.\n        body = (\n            b\"\".join(\n                b\"--%s\\r\\n\"\n                b'Content-Disposition: form-data; name=\"%s\"\\r\\n'\n                b\"\\r\\n\"\n                b\"%s\\r\\n\" % (boundary, field.encode(), value)\n                for field, value in fields.items()\n                if field != \"chunk-data\"\n            )\n            + b\"\".join(\n                b\"--%s\\r\\n\"\n                b'Content-Disposition: form-data; name=\"tags[]\"\\r\\n'\n                b\"\\r\\n\"\n                b\"%s:%s\\r\\n\" % (boundary, tag.encode(), value)\n                for tag, value in tags.items()\n            )\n            + b\"--\"\n            + boundary\n            + b\"\\r\\n\"\n            b'Content-Disposition: form-data; name=\"chunk-data\"; filename=\"profile.pb.gz\"\\r\\n'\n            + b\"Content-Type: application/octet-stream\\r\\n\\r\\n\"\n            + fields[\"chunk-data\"]\n            + b\"\\r\\n--%s--\\r\\n\" % boundary\n        )\n\n        content_type = b\"multipart/form-data; boundary=%s\" % boundary\n\n        return content_type, body\n\n    @staticmethod\n    def _get_tags(service):\n        tags = {\n            \"service\": service.encode(\"utf-8\"),\n            \"host\": HOSTNAME.encode(\"utf-8\"),\n            \"runtime-id\": RUNTIME_ID,\n            \"language\": b\"python\",\n            \"runtime\": PYTHON_IMPLEMENTATION,\n            \"runtime_version\": PYTHON_VERSION,\n            \"profiler_version\": ddtrace.__version__.encode(\"utf-8\"),\n        }\n\n        version = os.environ.get(\"DD_VERSION\")\n        if version:\n            tags[\"version\"] = version\n\n        env = os.environ.get(\"DD_ENV\")\n        if env:\n            tags[\"env\"] = env\n\n        user_tags = parse_tags_str(os.environ.get(\"DD_TAGS\", {}))\n        user_tags.update(parse_tags_str(os.environ.get(\"DD_PROFILING_TAGS\", {})))\n        tags.update({k: six.ensure_binary(v) for k, v in user_tags.items()})\n        return tags\n\n    def export(self, events, start_time_ns, end_time_ns):\n        \"\"\"Export events to an HTTP endpoint.\n\n        :param events: The event dictionary from a `ddtrace.profiling.recorder.Recorder`.\n        :param start_time_ns: The start time of recording.\n        :param end_time_ns: The end time of recording.\n        \"\"\"\n        if not self.endpoint:\n            raise InvalidEndpoint(\"Endpoint is empty\")\n\n        common_headers = {\n            \"DD-API-KEY\": self.api_key.encode(),\n        }\n\n        profile = super(PprofHTTPExporter, self).export(events, start_time_ns, end_time_ns)\n        s = six.BytesIO()\n        with gzip.GzipFile(fileobj=s, mode=\"wb\") as gz:\n            gz.write(profile.SerializeToString())\n        fields = {\n            \"runtime-id\": RUNTIME_ID,\n            \"recording-start\": (\n                datetime.datetime.utcfromtimestamp(start_time_ns / 1e9).replace(microsecond=0).isoformat() + \"Z\"\n            ).encode(),\n            \"recording-end\": (\n                datetime.datetime.utcfromtimestamp(end_time_ns / 1e9).replace(microsecond=0).isoformat() + \"Z\"\n            ).encode(),\n            \"runtime\": PYTHON_IMPLEMENTATION,\n            \"format\": b\"pprof\",\n            \"type\": b\"cpu+alloc+exceptions\",\n            \"chunk-data\": s.getvalue(),\n        }\n\n        service_name = self.service_name or os.path.basename(profile.string_table[profile.mapping[0].filename])\n\n        content_type, body = self._encode_multipart_formdata(fields, tags=self._get_tags(service_name),)\n        headers = common_headers.copy()\n        headers[\"Content-Type\"] = content_type\n\n        # urllib uses `POST` if `data` is supplied (Python\u00a02 version does not handle `method` kwarg)\n        req = request.Request(self.endpoint, data=body, headers=headers)\n\n        retry = tenacity.Retrying(\n            # Retry after 1s, 2s, 4s, 8s with some randomness\n            wait=tenacity.wait_random_exponential(multiplier=0.5),\n            stop=tenacity.stop_after_delay(self.max_retry_delay),\n            retry=tenacity.retry_if_exception_type(\n                (error.HTTPError, error.URLError, http_client.HTTPException, OSError, IOError)\n            ),\n        )\n\n        try:\n            retry(request.urlopen, req, timeout=self.timeout)\n        except tenacity.RetryError as e:\n            raise UploadFailed(e.last_attempt.exception())\n", "path": "ddtrace/profiling/exporter/http.py"}], "after_files": [{"content": "# -*- encoding: utf-8 -*-\nimport binascii\nimport datetime\nimport gzip\nimport os\nimport platform\nimport uuid\n\nimport tenacity\n\nfrom ddtrace.utils import deprecation\nfrom ddtrace.utils.formats import parse_tags_str\nfrom ddtrace.vendor import six\nfrom ddtrace.vendor.six.moves import http_client\nfrom ddtrace.vendor.six.moves.urllib import error\nfrom ddtrace.vendor.six.moves.urllib import request\n\nimport ddtrace\nfrom ddtrace.profiling import _attr\nfrom ddtrace.profiling import _traceback\nfrom ddtrace.profiling import exporter\nfrom ddtrace.vendor import attr\nfrom ddtrace.profiling.exporter import pprof\n\n\nRUNTIME_ID = str(uuid.uuid4()).encode()\nHOSTNAME = platform.node()\nPYTHON_IMPLEMENTATION = platform.python_implementation().encode()\nPYTHON_VERSION = platform.python_version().encode()\n\n\nclass InvalidEndpoint(exporter.ExportError):\n    pass\n\n\nclass RequestFailed(exporter.ExportError):\n    \"\"\"Failed HTTP request.\"\"\"\n\n    def __init__(self, response, content):\n        \"\"\"Create a new failed request embedding response and content.\"\"\"\n        self.response = response\n        self.content = content\n        super(RequestFailed, self).__init__(\n            \"Error status code received from endpoint: %d: %s\" % (response.status, content)\n        )\n\n\nclass UploadFailed(exporter.ExportError):\n    \"\"\"Upload failure.\"\"\"\n\n    def __init__(self, exception):\n        \"\"\"Create a failed upload error based on raised exceptions.\"\"\"\n        self.exception = exception\n        super(UploadFailed, self).__init__(\"Unable to upload: \" + _traceback.format_exception(exception))\n\n\ndef _get_api_key():\n    legacy = _attr.from_env(\"DD_PROFILING_API_KEY\", \"\", str)()\n    if legacy:\n        deprecation.deprecation(\"DD_PROFILING_API_KEY\", \"Use DD_API_KEY\")\n        return legacy\n    return _attr.from_env(\"DD_API_KEY\", \"\", str)()\n\n\nENDPOINT_TEMPLATE = \"https://intake.profile.{}/v1/input\"\n\n\ndef _get_endpoint():\n    legacy = _attr.from_env(\"DD_PROFILING_API_URL\", \"\", str)()\n    if legacy:\n        deprecation.deprecation(\"DD_PROFILING_API_URL\", \"Use DD_SITE\")\n        return legacy\n    site = _attr.from_env(\"DD_SITE\", \"datadoghq.com\", str)()\n    return ENDPOINT_TEMPLATE.format(site)\n\n\ndef _get_service_name():\n    for service_name_var in (\"DD_SERVICE\", \"DD_SERVICE_NAME\", \"DATADOG_SERVICE_NAME\"):\n        service_name = os.environ.get(service_name_var)\n        if service_name is not None:\n            return service_name\n\n\n@attr.s\nclass PprofHTTPExporter(pprof.PprofExporter):\n    \"\"\"PProf HTTP exporter.\"\"\"\n\n    endpoint = attr.ib(factory=_get_endpoint, type=str)\n    api_key = attr.ib(factory=_get_api_key, type=str)\n    timeout = attr.ib(factory=_attr.from_env(\"DD_PROFILING_API_TIMEOUT\", 10, float), type=float)\n    service_name = attr.ib(factory=_get_service_name)\n    max_retry_delay = attr.ib(default=None)\n\n    def __attrs_post_init__(self):\n        if self.max_retry_delay is None:\n            self.max_retry_delay = self.timeout * 3\n\n    @staticmethod\n    def _encode_multipart_formdata(fields, tags):\n        boundary = binascii.hexlify(os.urandom(16))\n\n        # The body that is generated is very sensitive and must perfectly match what the server expects.\n        body = (\n            b\"\".join(\n                b\"--%s\\r\\n\"\n                b'Content-Disposition: form-data; name=\"%s\"\\r\\n'\n                b\"\\r\\n\"\n                b\"%s\\r\\n\" % (boundary, field.encode(), value)\n                for field, value in fields.items()\n                if field != \"chunk-data\"\n            )\n            + b\"\".join(\n                b\"--%s\\r\\n\"\n                b'Content-Disposition: form-data; name=\"tags[]\"\\r\\n'\n                b\"\\r\\n\"\n                b\"%s:%s\\r\\n\" % (boundary, tag.encode(), value)\n                for tag, value in tags.items()\n            )\n            + b\"--\"\n            + boundary\n            + b\"\\r\\n\"\n            b'Content-Disposition: form-data; name=\"chunk-data\"; filename=\"profile.pb.gz\"\\r\\n'\n            + b\"Content-Type: application/octet-stream\\r\\n\\r\\n\"\n            + fields[\"chunk-data\"]\n            + b\"\\r\\n--%s--\\r\\n\" % boundary\n        )\n\n        content_type = b\"multipart/form-data; boundary=%s\" % boundary\n\n        return content_type, body\n\n    @staticmethod\n    def _get_tags(service):\n        tags = {\n            \"service\": service.encode(\"utf-8\"),\n            \"host\": HOSTNAME.encode(\"utf-8\"),\n            \"runtime-id\": RUNTIME_ID,\n            \"language\": b\"python\",\n            \"runtime\": PYTHON_IMPLEMENTATION,\n            \"runtime_version\": PYTHON_VERSION,\n            \"profiler_version\": ddtrace.__version__.encode(\"utf-8\"),\n        }\n\n        version = os.environ.get(\"DD_VERSION\")\n        if version:\n            tags[\"version\"] = version.encode(\"utf-8\")\n\n        env = os.environ.get(\"DD_ENV\")\n        if env:\n            tags[\"env\"] = env.encode(\"utf-8\")\n\n        user_tags = parse_tags_str(os.environ.get(\"DD_TAGS\", {}))\n        user_tags.update(parse_tags_str(os.environ.get(\"DD_PROFILING_TAGS\", {})))\n        tags.update({k: six.ensure_binary(v) for k, v in user_tags.items()})\n        return tags\n\n    def export(self, events, start_time_ns, end_time_ns):\n        \"\"\"Export events to an HTTP endpoint.\n\n        :param events: The event dictionary from a `ddtrace.profiling.recorder.Recorder`.\n        :param start_time_ns: The start time of recording.\n        :param end_time_ns: The end time of recording.\n        \"\"\"\n        if not self.endpoint:\n            raise InvalidEndpoint(\"Endpoint is empty\")\n\n        common_headers = {\n            \"DD-API-KEY\": self.api_key.encode(),\n        }\n\n        profile = super(PprofHTTPExporter, self).export(events, start_time_ns, end_time_ns)\n        s = six.BytesIO()\n        with gzip.GzipFile(fileobj=s, mode=\"wb\") as gz:\n            gz.write(profile.SerializeToString())\n        fields = {\n            \"runtime-id\": RUNTIME_ID,\n            \"recording-start\": (\n                datetime.datetime.utcfromtimestamp(start_time_ns / 1e9).replace(microsecond=0).isoformat() + \"Z\"\n            ).encode(),\n            \"recording-end\": (\n                datetime.datetime.utcfromtimestamp(end_time_ns / 1e9).replace(microsecond=0).isoformat() + \"Z\"\n            ).encode(),\n            \"runtime\": PYTHON_IMPLEMENTATION,\n            \"format\": b\"pprof\",\n            \"type\": b\"cpu+alloc+exceptions\",\n            \"chunk-data\": s.getvalue(),\n        }\n\n        service_name = self.service_name or os.path.basename(profile.string_table[profile.mapping[0].filename])\n\n        content_type, body = self._encode_multipart_formdata(fields, tags=self._get_tags(service_name),)\n        headers = common_headers.copy()\n        headers[\"Content-Type\"] = content_type\n\n        # urllib uses `POST` if `data` is supplied (Python\u00a02 version does not handle `method` kwarg)\n        req = request.Request(self.endpoint, data=body, headers=headers)\n\n        retry = tenacity.Retrying(\n            # Retry after 1s, 2s, 4s, 8s with some randomness\n            wait=tenacity.wait_random_exponential(multiplier=0.5),\n            stop=tenacity.stop_after_delay(self.max_retry_delay),\n            retry=tenacity.retry_if_exception_type(\n                (error.HTTPError, error.URLError, http_client.HTTPException, OSError, IOError)\n            ),\n        )\n\n        try:\n            retry(request.urlopen, req, timeout=self.timeout)\n        except tenacity.RetryError as e:\n            raise UploadFailed(e.last_attempt.exception())\n", "path": "ddtrace/profiling/exporter/http.py"}]}