Repository: lightstep/lightstep-tracer-python

Issue:
B3 headers value not passed as str
We've instrumented our service with LightStep and OpenTracing but have run into a snag when using B3 propagation.

```python
    opentracing.tracer = lightstep.Tracer(
        component_name=c.SERVICE_NAME,
        access_token=OPEN_TRACE_ACCESS_TOKEN,
        tags=tags
    )
    opentracing.tracer.register_propagator(Format.TEXT_MAP, B3Propagator())
    opentracing.tracer.register_propagator(
        Format.HTTP_HEADERS, B3Propagator()
    )
```

this is the error I'm seeing in developer satellite:

```
error
     message:
     "Value for header {x-b3-sampled: 1} must be of type str or bytes, not <class 'int'>"
     error.object:
     "Value for header {x-b3-sampled: 1} must be of type str or bytes, not <class 'int'>"
     error.kind:
     "InvalidHeader"
```

stack trace:

```
"line 51, in get response = requests.get( File "/usr/local/lib/python3.8/site-packages/requests/api.py", line 75, in get return request('get', url, params=params, **kwargs) File "/usr/local/lib/python3.8/site-packages/requests/api.py", line 60, in request return session.request(method=method, url=url, **kwargs) File "/usr/local/lib/python3.8/site-packages/requests/sessions.py", line 519, in request prep = self.prepare_request(req) File "/usr/local/lib/python3.8/site-packages/requests/sessions.py", line 452, in prepare_request p.prepare( File "/usr/local/lib/python3.8/site-packages/requests/models.py", line 314, in prepare self.prepare_headers(headers) File "/usr/local/lib/python3.8/site-packages/requests/models.py", line 448, in prepare_headers check_header_validity(header) File "/usr/local/lib/python3.8/site-packages/requests/utils.py", line 944, in check_header_validity raise InvalidHeader("Value for header {%s: %s} must be of type str or " "
```

Appears to be failing python requests library's [header validation](https://github.com/psf/requests/issues/3477)

Discussion:

Patch:
diff --git a/lightstep/b3_propagator.py b/lightstep/b3_propagator.py
index 940a86b..1d4568c 100644
--- a/lightstep/b3_propagator.py
+++ b/lightstep/b3_propagator.py
@@ -36,12 +36,12 @@ class B3Propagator(Propagator):
 
         flags = baggage.pop(_FLAGS, None)
         if flags is not None:
-            carrier[_FLAGS] = flags
+            carrier[_FLAGS] = str(flags)
 
         sampled = baggage.pop(_SAMPLED, None)
 
         if sampled is None:
-            carrier[_SAMPLED] = 1
+            carrier[_SAMPLED] = "1"
         else:
             if flags == 1:
                 _LOG.warning(
@@ -56,16 +56,17 @@ class B3Propagator(Propagator):
                             int(sampled), sampled
                         )
                     )
-                carrier[_SAMPLED] = sampled
+                carrier[_SAMPLED] = str(sampled)
 
         if sampled is flags is (traceid and spanid) is None:
             warn(
                 "If not propagating only the sampling state, traceid and "
                 "spanid must be defined, setting sampling state to 1."
             )
-            carrier[_SAMPLED] = 1
+            carrier[_SAMPLED] = "1"
 
-        carrier.update(baggage)
+        for key, value in baggage.items():
+            carrier[key] = str(value)
 
         if traceid is not None:
             carrier[_TRACEID] = format(traceid, "x")


Test patch:
diff --git a/tests/b3_propagator_test.py b/tests/b3_propagator_test.py
index 4728711..17ca55e 100644
--- a/tests/b3_propagator_test.py
+++ b/tests/b3_propagator_test.py
@@ -32,7 +32,7 @@ class B3PropagatorTest(TestCase):
             {
                 "x-b3-traceid": format(span.context.trace_id, "x"),
                 "x-b3-spanid": format(span.context.span_id, "x"),
-                "x-b3-sampled": 1,
+                "x-b3-sampled": "1",
                 "checked": "baggage"
             }
         )
@@ -47,7 +47,7 @@ class B3PropagatorTest(TestCase):
             {
                 "x-b3-traceid": format(span.context.trace_id, "x"),
                 "x-b3-spanid": format(span.context.span_id, "x"),
-                "x-b3-flags": 1,
+                "x-b3-flags": "1",
             }
         )
 
@@ -174,9 +174,7 @@ class B3PropagatorTest(TestCase):
             carrier = {}
             tracer.inject(inject_span.context, Format.HTTP_HEADERS, carrier)
 
-            self.assertTrue(
-                isinstance(carrier["x-b3-sampled"], type(sampled_value))
-            )
+            self.assertTrue(isinstance(carrier["x-b3-sampled"], str))
 
             extract_span_context = tracer.extract(Format.HTTP_HEADERS, carrier)
 
@@ -200,7 +198,7 @@ class B3PropagatorTest(TestCase):
 
         tracer.inject(inject_span.context, Format.HTTP_HEADERS, carrier)
 
-        self.assertEqual(carrier["x-b3-sampled"], 1)
+        self.assertEqual(carrier["x-b3-sampled"], "1")
 
         extract_span_context = tracer.extract(Format.HTTP_HEADERS, carrier)