13
13
import urllib2
14
14
import zlib
15
15
import base64
16
+ from os .path import splitext
16
17
from collections import namedtuple
17
18
from simplejson import JSONDecodeError
18
- from urlparse import urljoin
19
+ from urlparse import urljoin , urlsplit
19
20
20
- from sentry .constants import SOURCE_FETCH_TIMEOUT
21
+ from sentry .constants import SOURCE_FETCH_TIMEOUT , MAX_CULPRIT_LENGTH
21
22
from sentry .utils .cache import cache
22
23
from sentry .utils .sourcemaps import sourcemap_to_index , find_source
24
+ from sentry .utils .strings import truncatechars
23
25
24
26
25
27
BAD_SOURCE = - 1
29
31
DEFAULT_ENCODING = 'utf-8'
30
32
BASE64_SOURCEMAP_PREAMBLE = 'data:application/json;base64,'
31
33
BASE64_PREAMBLE_LENGTH = len (BASE64_SOURCEMAP_PREAMBLE )
34
+ CLEAN_MODULE_RE = re .compile (r"""^(?:(?:
35
+ (?:java)?scripts?|js|build|static|_\w*| # common folder prefixes
36
+ v?(?:\d+\.)*\d+| # version numbers, v1, 1.0.0
37
+ [a-f0-9]{7,8}| # short sha
38
+ [a-f0-9]{32}| # md5
39
+ [a-f0-9]{40} # sha1
40
+ )/)+""" , re .X | re .I )
32
41
33
42
UrlResult = namedtuple ('UrlResult' , ['url' , 'headers' , 'body' ])
34
43
@@ -333,6 +342,7 @@ def expand_javascript_source(data, **kwargs):
333
342
frame .function = state .name
334
343
frame .abs_path = abs_path
335
344
frame .filename = state .src
345
+ frame .module = generate_module (state .src ) or '<unknown module>'
336
346
elif sourcemap in sourmap_idxs :
337
347
frame .data = {
338
348
'sourcemap' : sourcemap ,
@@ -348,3 +358,25 @@ def expand_javascript_source(data, **kwargs):
348
358
logger .debug ('Updating stacktraces with expanded source context' )
349
359
for exception , stacktrace in itertools .izip (data ['sentry.interfaces.Exception' ]['values' ], stacktraces ):
350
360
exception ['stacktrace' ] = stacktrace .serialize ()
361
+
362
+ # Attempt to fix the culrpit now that we have useful information
363
+ culprit_frame = stacktraces [0 ].frames [0 ]
364
+ if culprit_frame .module and culprit_frame .function :
365
+ data ['culprit' ] = truncatechars (generate_culprit (culprit_frame ), MAX_CULPRIT_LENGTH )
366
+
367
+
368
+ def generate_module (src ):
369
+ """
370
+ Converts a url into a made-up module name by doing the following:
371
+ * Extract just the path name
372
+ * Trimming off the initial /
373
+ * Trimming off the file extension
374
+ * Removes off useless folder prefixes
375
+
376
+ e.g. http://google.com/js/v1.0/foo/bar/baz.js -> foo/bar/baz
377
+ """
378
+ return CLEAN_MODULE_RE .sub ('' , splitext (urlsplit (src ).path [1 :])[0 ])
379
+
380
+
381
+ def generate_culprit (frame ):
382
+ return '%s in %s' % (frame .module , frame .function )
0 commit comments