13
13
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
14
# See the License for the specific language governing permissions and
15
15
# limitations under the License.
16
+ from contextlib import ExitStack
16
17
from logging import getLogger
17
18
from typing import Any , Type , TypeVar
18
- from urllib .parse import quote as urllib_quote
19
19
20
20
# pylint: disable=no-name-in-module
21
21
from django import conf , get_version
22
- from django .db import connection
22
+ from django .db import connections
23
23
from django .db .backends .utils import CursorDebugWrapper
24
24
25
+ from opentelemetry .instrumentation .utils import (
26
+ _generate_sql_comment ,
27
+ _get_opentelemetry_values ,
28
+ )
25
29
from opentelemetry .trace .propagation .tracecontext import (
26
30
TraceContextTextMapPropagator ,
27
31
)
@@ -44,7 +48,13 @@ def __init__(self, get_response) -> None:
44
48
self .get_response = get_response
45
49
46
50
def __call__ (self , request ) -> Any :
47
- with connection .execute_wrapper (_QueryWrapper (request )):
51
+ with ExitStack () as stack :
52
+ for db_alias in connections :
53
+ stack .enter_context (
54
+ connections [db_alias ].execute_wrapper (
55
+ _QueryWrapper (request )
56
+ )
57
+ )
48
58
return self .get_response (request )
49
59
50
60
@@ -105,49 +115,7 @@ def __call__(self, execute: Type[T], sql, params, many, context) -> T:
105
115
sql += sql_comment
106
116
107
117
# Add the query to the query log if debugging.
108
- if context ["cursor" ]. __class__ is CursorDebugWrapper :
118
+ if isinstance ( context ["cursor" ], CursorDebugWrapper ) :
109
119
context ["connection" ].queries_log .append (sql )
110
120
111
121
return execute (sql , params , many , context )
112
-
113
-
114
- def _generate_sql_comment (** meta ) -> str :
115
- """
116
- Return a SQL comment with comma delimited key=value pairs created from
117
- **meta kwargs.
118
- """
119
- key_value_delimiter = ","
120
-
121
- if not meta : # No entries added.
122
- return ""
123
-
124
- # Sort the keywords to ensure that caching works and that testing is
125
- # deterministic. It eases visual inspection as well.
126
- return (
127
- " /*"
128
- + key_value_delimiter .join (
129
- f"{ _url_quote (key )} ={ _url_quote (value )!r} "
130
- for key , value in sorted (meta .items ())
131
- if value is not None
132
- )
133
- + "*/"
134
- )
135
-
136
-
137
- def _url_quote (value ) -> str :
138
- if not isinstance (value , (str , bytes )):
139
- return value
140
- _quoted = urllib_quote (value )
141
- # Since SQL uses '%' as a keyword, '%' is a by-product of url quoting
142
- # e.g. foo,bar --> foo%2Cbar
143
- # thus in our quoting, we need to escape it too to finally give
144
- # foo,bar --> foo%%2Cbar
145
- return _quoted .replace ("%" , "%%" )
146
-
147
-
148
- def _get_opentelemetry_values () -> dict or None :
149
- """
150
- Return the OpenTelemetry Trace and Span IDs if Span ID is set in the
151
- OpenTelemetry execution context.
152
- """
153
- return _propagator .inject ({})
0 commit comments