77from wrapt import ObjectProxy
88
99# project
10- from ...compat import iteritems
10+ from ...compat import iteritems , json
1111from ...ext import AppTypes
1212from ...ext import mongo as mongox
1313from ...ext import net as netx
14- from .parse import parse_spec , parse_query , Command
14+ from .parse import parse_spec , parse_query , parse_msg
1515
1616
1717log = logging .getLogger (__name__ )
@@ -39,38 +39,44 @@ def __init__(self, tracer, service, sock):
3939 def command (self , dbname , spec , * args , ** kwargs ):
4040 cmd = None
4141 try :
42- cmd = parse_spec (spec )
42+ cmd = parse_spec (spec , dbname )
4343 except Exception :
4444 log .exception ("error parsing spec. skipping trace" )
4545
4646 # skip tracing if we don't have a piece of data we need
4747 if not dbname or not cmd :
4848 return self .__wrapped__ .command (dbname , spec , * args , ** kwargs )
4949
50- with self .__trace (dbname , cmd ):
50+ cmd .db = dbname
51+ with self .__trace (cmd ):
5152 return self .__wrapped__ .command (dbname , spec , * args , ** kwargs )
5253
53- def write_command (self , * args , ** kwargs ):
54- # FIXME[matt] parse the db name and collection from the
55- # message.
56- coll = ""
57- db = ""
58- cmd = Command ("insert_many" , coll )
59- with self .__trace (db , cmd ) as s :
60- s .resource = "insert_many"
61- result = self .__wrapped__ .write_command (* args , ** kwargs )
54+ def write_command (self , request_id , msg ):
55+ cmd = None
56+ try :
57+ cmd = parse_msg (msg )
58+ except Exception :
59+ log .exception ("error parsing msg" )
60+
61+ # if we couldn't parse it, don't try to trace it.
62+ if not cmd :
63+ return self .__wrapped__ .write_command (request_id , msg )
64+
65+ with self .__trace (cmd ) as s :
66+ s .resource = _resource_from_cmd (cmd )
67+ result = self .__wrapped__ .write_command (request_id , msg )
6268 if result :
6369 s .set_metric (mongox .ROWS , result .get ("n" , - 1 ))
6470 return result
6571
66- def __trace (self , db , cmd ):
72+ def __trace (self , cmd ):
6773 s = self ._tracer .trace (
6874 "pymongo.cmd" ,
6975 span_type = mongox .TYPE ,
7076 service = self ._srv )
7177
72- if db :
73- s .set_tag (mongox .DB , db )
78+ if cmd . db :
79+ s .set_tag (mongox .DB , cmd . db )
7480 if cmd :
7581 s .set_tag (mongox .COLLECTION , cmd .coll )
7682 s .set_tags (cmd .tags )
@@ -93,31 +99,35 @@ def __init__(self, tracer, service, topology):
9399 self ._srv = service
94100
95101 def send_message_with_response (self , operation , * args , ** kwargs ):
96-
97- # if we're processing something unexpected, just skip tracing.
98- if getattr (operation , 'name' , None ) != 'find' :
102+ cmd = None
103+ # Only try to parse something we think is a query.
104+ if self ._is_query (operation ):
105+ try :
106+ cmd = parse_query (operation )
107+ except Exception :
108+ log .exception ("error parsing query" )
109+
110+ # if we couldn't parse or shouldn't trace the message, just go.
111+ if not cmd :
99112 return self .__wrapped__ .send_message_with_response (
100113 operation ,
101114 * args ,
102115 ** kwargs )
103116
104- # trace the given query.
105- cmd = parse_query (operation )
106117 with self ._tracer .trace (
107118 "pymongo.cmd" ,
108119 span_type = mongox .TYPE ,
109120 service = self ._srv ) as span :
110121
111122 span .resource = _resource_from_cmd (cmd )
112- span .set_tag (mongox .DB , operation .db )
123+ span .set_tag (mongox .DB , cmd .db )
113124 span .set_tag (mongox .COLLECTION , cmd .coll )
114125 span .set_tags (cmd .tags )
115126
116127 result = self .__wrapped__ .send_message_with_response (
117128 operation ,
118129 * args ,
119- ** kwargs
120- )
130+ ** kwargs )
121131
122132 if result and result .address :
123133 _set_address_tags (span , result .address )
@@ -131,6 +141,12 @@ def get_socket(self, *args, **kwargs):
131141 else :
132142 yield TracedSocket (self ._tracer , self ._srv , s )
133143
144+ @staticmethod
145+ def _is_query (op ):
146+ # NOTE: _Query should alwyas have a spec field
147+ return hasattr (op , 'spec' )
148+
149+
134150class TracedTopology (ObjectProxy ):
135151
136152 _tracer = None
@@ -155,6 +171,10 @@ class TracedMongoClient(ObjectProxy):
155171 _srv = None
156172
157173 def __init__ (self , tracer , service , client ):
174+ # NOTE[matt] the TracedMongoClient attempts to trace all of the network
175+ # calls in the trace library. This is good because it measures the
176+ # actual network time. It's bad because it uses a private API which
177+ # could change. We'll see how this goes.
158178 client ._topology = TracedTopology (tracer , service , client ._topology )
159179 super (TracedMongoClient , self ).__init__ (client )
160180 self ._tracer = tracer
@@ -189,6 +209,9 @@ def _set_address_tags(span, address):
189209def _resource_from_cmd (cmd ):
190210 if cmd .query is not None :
191211 nq = normalize_filter (cmd .query )
192- return "%s %s %s" % (cmd .name , cmd .coll , nq )
212+ # needed to dump json so we don't get unicode
213+ # dict keys like {u'foo':'bar'}
214+ q = json .dumps (nq )
215+ return "%s %s %s" % (cmd .name , cmd .coll , q )
193216 else :
194217 return "%s %s" % (cmd .name , cmd .coll )
0 commit comments