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
|
|
|
import os |
22
|
|
|
import logging |
23
|
|
|
|
24
|
|
|
from django.conf import settings |
25
|
|
|
|
26
|
|
|
from furl import furl |
27
|
|
|
from clom.shell import CommandError |
28
|
|
|
import requests |
29
|
|
|
|
30
|
|
|
from omaha_server.celery import app |
31
|
|
|
from crash.models import Crash |
32
|
|
|
from crash.settings import S3_MOUNT_PATH |
33
|
|
|
from crash.utils import ( |
34
|
|
|
get_stacktrace, |
35
|
|
|
FileNotFoundError, |
36
|
|
|
parse_stacktrace, |
37
|
|
|
get_signature, |
38
|
|
|
send_stacktrace_sentry, |
39
|
|
|
) |
40
|
|
|
|
41
|
|
|
|
42
|
|
|
logger = logging.getLogger(__name__) |
43
|
|
|
SENTRY_DOMAIN = getattr(settings, 'SENTRY_STACKTRACE_DOMAIN', None) |
44
|
|
|
SENTRY_ORG_SLUG = getattr(settings, 'SENTRY_STACKTRACE_ORG_SLUG', None) |
45
|
|
|
SENTRY_PROJ_SLUG = getattr(settings, 'SENTRY_STACKTRACE_PROJ_SLUG', None) |
46
|
|
|
SENTRY_API_KEY = getattr(settings, 'SENTRY_STACKTRACE_API_KEY', None) |
47
|
|
|
|
48
|
|
|
@app.task(name='tasks.processing_crash_dump', ignore_result=True, max_retries=12, bind=True) |
49
|
|
|
def processing_crash_dump(self, crash_pk): |
50
|
|
|
try: |
51
|
|
|
crash = Crash.objects.get(pk=crash_pk) |
52
|
|
|
url = furl(crash.upload_file_minidump.url) |
53
|
|
|
path = url.pathstr |
54
|
|
|
crash_dump_path = os.path.join(S3_MOUNT_PATH, *path.split('/')) |
55
|
|
|
stacktrace, errors = get_stacktrace(crash_dump_path) |
56
|
|
|
crash.stacktrace = stacktrace |
57
|
|
|
crash.stacktrace_json = parse_stacktrace(stacktrace) |
58
|
|
|
crash.signature = get_signature(crash.stacktrace_json) |
59
|
|
|
crash.save() |
60
|
|
|
send_stacktrace_sentry(crash) |
61
|
|
|
except FileNotFoundError as exc: |
62
|
|
|
logger.error('Failed processing_crash_dump', |
63
|
|
|
exc_info=True, |
64
|
|
|
extra=dict(crash_pk=crash_pk, |
65
|
|
|
crash_dump_path=crash_dump_path)) |
66
|
|
|
raise self.retry(exc=exc, countdown=2 ** processing_crash_dump.request.retries) |
67
|
|
|
except CommandError as exc: |
68
|
|
|
logger.error('Failed processing_crash_dump', |
69
|
|
|
exc_info=True, |
70
|
|
|
extra=dict(crash_pk=crash_pk, |
71
|
|
|
crash_dump_path=crash_dump_path)) |
72
|
|
|
raise exc |
73
|
|
|
|
74
|
|
|
|
75
|
|
|
@app.task(name='tasks.get_sentry_link', ignore_result=True, max_retries=6, bind=True) |
76
|
|
|
def get_sentry_link(self, crash_pk, event_id): |
77
|
|
|
try: |
78
|
|
|
if SENTRY_DOMAIN and SENTRY_ORG_SLUG and SENTRY_PROJ_SLUG and SENTRY_API_KEY: |
79
|
|
|
crash = Crash.objects.get(pk=crash_pk) |
80
|
|
|
resp = requests.get( |
81
|
|
|
'http://%s/api/0/projects/%s/%s/events/%s/' % (SENTRY_DOMAIN, SENTRY_ORG_SLUG, SENTRY_PROJ_SLUG, event_id,), |
82
|
|
|
auth=(SENTRY_API_KEY, '') |
83
|
|
|
).json() |
84
|
|
|
|
85
|
|
|
crash.groupid = resp['groupID'] |
86
|
|
|
crash.eventid = resp['id'] |
87
|
|
|
crash.save() |
88
|
|
|
else: |
89
|
|
|
logging.warning("Sentry is not congured") |
90
|
|
|
except KeyError as exc: |
91
|
|
|
logging.error("Sentry event not found") |
92
|
|
|
raise self.retry(exc=exc, countdown=2 ** get_sentry_link.request.retries) |
93
|
|
|
|