Completed
Push — master ( b0fc82...6c4ac7 )
by
unknown
02:17 queued 12s
created

get_os()   A

Complexity

Conditions 2

Size

Total Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
dl 0
loc 2
rs 10
c 1
b 0
f 0
1
# coding: utf8
2
3
"""
4
This software is licensed under the Apache 2 license, quoted below.
5
6
Copyright 2014 Crystalnix Limited
7
8
Licensed under the Apache License, Version 2.0 (the "License"); you may not
9
use this file except in compliance with the License. You may obtain a copy of
10
the License at
11
12
    http://www.apache.org/licenses/LICENSE-2.0
13
14
Unless required by applicable law or agreed to in writing, software
15
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17
License for the specific language governing permissions and limitations under
18
the License.
19
"""
20
21
from builtins import str
22
23
import os
24
import re
25
26
from django.conf import settings
27
28
from clom import clom
29
from raven import Client
30
from celery import signature
31
32
from crash.settings import MINIDUMP_STACKWALK_PATH, SYMBOLS_PATH
33
from crash.stacktrace_to_json import pipe_dump_to_json_dump
34
35
36
client = Client(getattr(settings, 'RAVEN_DSN_STACKTRACE', None), name=getattr(settings, 'HOST_NAME', None),
37
                release=getattr(settings, 'APP_VERSION', None))
38
39
40
class FileNotFoundError(Exception):
41
    pass
42
43
44
minidump_stackwalk = clom[MINIDUMP_STACKWALK_PATH].with_opts('-m')
45
46
47
def get_stacktrace(crashdump_path):
48
    if not os.path.isfile(crashdump_path):
49
        raise FileNotFoundError
50
51
    rezult = minidump_stackwalk(crashdump_path, SYMBOLS_PATH).shell()
52
    return rezult, rezult.stderr
53
54
55
def add_signature_to_frame(frame):
56
    frame = frame.copy()
57
    if 'function' in frame:
58
        # Remove spaces before all stars, ampersands, and commas
59
        function = re.sub(' (?=[\*&,])', '', frame['function'])
60
        # Ensure a space after commas
61
        function = re.sub(',(?! )', ', ', function)
62
        frame['function'] = function
63
        signature = function
64
    elif 'abs_path' in frame and 'lineno' in frame:
65
        signature = '%s#%d' % (frame['abs_path'], frame['lineno'])
66
    elif 'filename' in frame and 'module_offset' in frame:
67
        signature = '%s@%s' % (frame['filename'], frame['module_offset'])
68
    else:
69
        signature = '@%s' % frame['offset']
70
    frame['signature'] = signature
71
    frame['short_signature'] = re.sub('\(.*\)', '', signature)
72
    return frame
73
74
75
def parse_stacktrace(stacktrace):
76
    stacktrace_dict = pipe_dump_to_json_dump(str(stacktrace).splitlines())
77
    stacktrace_dict['crashing_thread']['frames'] = list(
78
        map(add_signature_to_frame,
79
            stacktrace_dict['crashing_thread']['frames']))
80
    return dict(stacktrace_dict)
81
82
83
def get_signature(stacktrace):
84
    try:
85
        frame = stacktrace['crashing_thread']['frames'][0]
86
        signature = frame['signature']
87
    except (KeyError, IndexError):
88
        signature = 'EMPTY: no frame data available'
89
    return signature
90
91
92
def get_os(stacktrace):
93
    return stacktrace.get('system_info', {}).get('os', '') if stacktrace else ''
94
95
96
def send_stacktrace_sentry(crash):
97
    stacktrace = crash.stacktrace_json
98
    exception = {
99
        "values": [
100
            {
101
                "type": stacktrace.get('crash_info', {}).get('type', 'unknown exception'),
102
                "value": stacktrace.get('crash_info', {}).get('crash_address', '0x0'),
103
                "stacktrace": stacktrace['crashing_thread']
104
            }
105
        ]
106
    }
107
108
    data = {'sentry.interfaces.Exception': exception}
109
110
    if crash.userid:
111
        data['sentry.interfaces.User'] = dict(id=crash.userid)
112
113
    extra = dict(
114
        crash_admin_panel_url='http://{}{}'.format(
115
            settings.HOST_NAME,
116
            '/admin/crash/crash/%s/' % crash.pk),
117
        crashdump_url=crash.upload_file_minidump.url,
118
    )
119
120
    tags = {}
121
    if crash.meta:
122
        extra.update(crash.meta)
123
        ver = crash.meta.get('ver')
124
        if ver:
125
            tags['ver'] = ver
126
    if crash.archive:
127
        extra['archive_url'] = crash.archive.url
128
129
    tags.update(stacktrace.get('system_info', {}))
130
131
    if crash.appid:
132
        tags['appid'] = crash.appid
133
134
    event_id = client.capture(
135
        'raven.events.Message',
136
        message=crash.signature,
137
        extra=extra,
138
        tags=tags,
139
        data=data
140
    )
141
    signature("tasks.get_sentry_link", args=(crash.pk, event_id)).apply_async(queue='private', countdown=1)
142
143
144
def parse_debug_meta_info(head, exception=Exception):
145
    head = head.decode()
146
    head_list = head.split(' ', 4)
147
    if head_list[0] != 'MODULE':
148
        raise exception(u"The file contains invalid data.")
149
    return dict(debug_id=head_list[-2],
150
                debug_file=head_list[-1])
151