Repository: DataDog/dd-trace-py

Issue:
Global config of query string tracing fails with `AttributeError`
### Which version of dd-trace-py are you using?
`0.40.0`

### Which version of the libraries are you using?
on python 3.6.10

can provide library list if really necessary

### How can we reproduce your problem?
As per the instructions in [advanced usage](https://github.com/DataDog/dd-trace-py/blob/bffcaf3c612db3c6064c936a37e932d3293c878a/docs/advanced_usage.rst#query-string-tracing):

```python
from ddtrace import config

# Global config
config.http.trace_query_string = True
```

### What is the result that you get?
This fails with `AttributeError: can't set attribute`

```python
>>> from ddtrace import config
>>> config.http.trace_query_string = True
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/opt/storefrontpy/lib/python3.6/site-packages/ddtrace/utils/attrdict.py", line 34, in __setattr__
    object.__setattr__(self, key, value)
AttributeError: can't set attribute
>>>
```

### What is the result that you expected?
Should successfully configure this setting globally


Discussion:
Yep, can confirm that this has been broken since it was introduced in #886 😕.
Are there any known workarounds to enable query string tracing? I just ran into this today, and it's blocking me 🙁 
@sacharya1980 yes, you can enable it on an integration-by-integration basis. So if you're using django it would be `ddtrace.config.django.trace_query_string=True`. We're going to have a fix for it in v0.42. 

Resolving patch:
diff --git a/ddtrace/contrib/aiohttp/middlewares.py b/ddtrace/contrib/aiohttp/middlewares.py
--- a/ddtrace/contrib/aiohttp/middlewares.py
+++ b/ddtrace/contrib/aiohttp/middlewares.py
@@ -108,7 +108,7 @@ def on_prepare(request, response):
     # DEV: aiohttp is special case maintains separate configuration from config api
     trace_query_string = request[REQUEST_CONFIG_KEY].get('trace_query_string')
     if trace_query_string is None:
-        trace_query_string = config._http.trace_query_string
+        trace_query_string = config.http.trace_query_string
     if trace_query_string:
         request_span.set_tag(http.QUERY_STRING, request.query_string)
     request_span.finish()
diff --git a/ddtrace/settings/config.py b/ddtrace/settings/config.py
--- a/ddtrace/settings/config.py
+++ b/ddtrace/settings/config.py
@@ -42,7 +42,7 @@ class Config(object):
     def __init__(self):
         # use a dict as underlying storing mechanism
         self._config = {}
-        self._http = HttpConfig()
+        self.http = HttpConfig()
         # Master switch for turning on and off trace search by default
         # this weird invocation of get_env is meant to read the DD_ANALYTICS_ENABLED
         # legacy environment variable. It should be removed in the future
@@ -129,7 +129,7 @@ def trace_headers(self, whitelist):
         :return: self
         :rtype: HttpConfig
         """
-        self._http.trace_headers(whitelist)
+        self.http.trace_headers(whitelist)
         return self
 
     def header_is_traced(self, header_name):
@@ -139,7 +139,7 @@ def header_is_traced(self, header_name):
         :type header_name: str
         :rtype: bool
         """
-        return self._http.header_is_traced(header_name)
+        return self.http.header_is_traced(header_name)
 
     def _get_service(self, default=None):
         """
diff --git a/ddtrace/settings/integration.py b/ddtrace/settings/integration.py
--- a/ddtrace/settings/integration.py
+++ b/ddtrace/settings/integration.py
@@ -69,7 +69,7 @@ def copy(self):
     def trace_query_string(self):
         if self.http.trace_query_string is not None:
             return self.http.trace_query_string
-        return self.global_config._http.trace_query_string
+        return self.global_config.http.trace_query_string
 
     def header_is_traced(self, header_name):
         """


Test patch:
diff --git a/tests/tracer/test_settings.py b/tests/tracer/test_settings.py
--- a/tests/tracer/test_settings.py
+++ b/tests/tracer/test_settings.py
@@ -59,6 +59,22 @@ def test_service(self):
             config = Config()
             self.assertEqual(config.service, "my-service")
 
+    def test_http_config(self):
+        config = Config()
+        config._add("django", dict())
+        assert config.django.trace_query_string is None
+        config.http.trace_query_string = True
+        assert config.http.trace_query_string is True
+        assert config.django.trace_query_string is True
+
+        # Integration usage
+        config = Config()
+        config._add("django", dict())
+        config.django.http.trace_query_string = True
+        assert config.http.trace_query_string is None
+        assert config.django.trace_query_string is True
+        assert config.django.http.trace_query_string is True
+
 
 class TestHttpConfig(BaseTestCase):