123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- import contextlib
- import logging
- import tempfile
- from hashlib import sha1
- from celery import shared_task
- from symbolic import Archive
- from apps.difs.models import DebugInformationFile
- from apps.difs.stacktrace_processor import StacktraceProcessor
- from apps.event_ingest.schema import ErrorIssueEventSchema, StackTraceFrame
- from apps.files.models import File, FileBlob
- from apps.projects.models import Project
- def getLogger():
- return logging.getLogger("glitchtip.difs")
- class ChecksumMismatched(Exception):
- pass
- class UnsupportedFile(Exception):
- pass
- DIF_STATE_CREATED = "created"
- DIF_STATE_OK = "ok"
- DIF_STATE_NOT_FOUND = "not_found"
- @shared_task
- def difs_assemble(project_slug, name, checksum, chunks, debug_id):
- try:
- project = Project.objects.filter(slug=project_slug).get()
- file = difs_get_file_from_chunks(checksum, chunks)
- if file is None:
- file = difs_create_file_from_chunks(name, checksum, chunks)
- difs_create_difs(project, name, file)
- except ChecksumMismatched:
- getLogger().error("difs_assemble: Checksum mismatched: %s", name)
- except Exception as err:
- getLogger().error("difs_assemble: %s", err)
- def event_difs_resolve_stacktrace(event: ErrorIssueEventSchema, project_id: int):
- difs = DebugInformationFile.objects.filter(project_id=project_id).order_by(
- "-created"
- )
- resolved_stracktrackes = []
- event_json = event.dict()
- for dif in difs:
- if StacktraceProcessor.is_supported(event_json, dif) is False:
- continue
- blobs = [dif.file.blob]
- with difs_concat_file_blobs_to_disk(blobs) as symbol_file:
- remapped_stacktrace = StacktraceProcessor.resolve_stacktrace(
- event_json, symbol_file.name
- )
- if remapped_stacktrace is not None and remapped_stacktrace.score > 0:
- resolved_stracktrackes.append(remapped_stacktrace)
- if len(resolved_stracktrackes) > 0:
- best_remapped_stacktrace = max(
- resolved_stracktrackes, key=lambda item: item.score
- )
- update_frames(event, best_remapped_stacktrace.frames)
- def update_frames(event: ErrorIssueEventSchema, frames):
- # This should be rewritten
- try:
- new_frames = [StackTraceFrame(**frame) for frame in frames]
- event.exception.values[0].stacktrace.frames = new_frames
- except Exception as e:
- getLogger().error(f"StacktraceProcessor: Unexpected error: {e}")
- pass
- def difs_get_file_from_chunks(checksum, chunks):
- files = File.objects.filter(checksum=checksum)
- for file in files:
- blob = file.blob
- file_chunks = [blob.checksum]
- if file_chunks == chunks:
- return file
- return None
- def difs_create_file_from_chunks(name, checksum, chunks):
- blobs = FileBlob.objects.filter(checksum__in=chunks)
- total_checksum = sha1(b"")
- size = 0
- for blob in blobs:
- size = size + blob.blob.size
- with open(blob.blob.path, "rb") as binary_file:
- content = binary_file.read()
- total_checksum.update(content)
- total_checksum = total_checksum.hexdigest()
- if checksum != total_checksum:
- raise ChecksumMismatched()
- file = File(name=name, headers={}, size=size, checksum=checksum)
- file.blob = blobs[0]
- file.save()
- return file
- @contextlib.contextmanager
- def difs_concat_file_blobs_to_disk(blobs):
- output = tempfile.NamedTemporaryFile(delete=False)
- for blob in blobs:
- with open(blob.blob.path, "rb") as binary_file:
- content = binary_file.read()
- output.write(content)
- output.flush()
- output.seek(0)
- try:
- yield output
- finally:
- output.close()
- def difs_extract_metadata_from_file(file):
- with difs_concat_file_blobs_to_disk([file.blob]) as _input:
- # Only one kind of file format is supported now
- try:
- archive = Archive.open(_input.name)
- except Exception as err:
- getLogger().error("Extract metadata error: %s", err)
- raise UnsupportedFile() from err
- else:
- return [
- {
- "arch": obj.arch,
- "file_format": obj.file_format,
- "code_id": obj.code_id,
- "debug_id": obj.debug_id,
- "kind": obj.kind,
- "features": list(obj.features),
- "symbol_type": "native",
- }
- for obj in archive.iter_objects()
- ]
- def difs_create_difs(project, name, file):
- metadatalist = difs_extract_metadata_from_file(file)
- for metadata in metadatalist:
- dif = DebugInformationFile.objects.filter(
- project_id=project.id, file=file
- ).first()
- if dif is not None:
- continue
- code_id = metadata["code_id"]
- debug_id = metadata["debug_id"]
- arch = metadata["arch"]
- kind = metadata["kind"]
- features = metadata["features"]
- symbol_type = metadata["symbol_type"]
- dif = DebugInformationFile(
- project=project,
- name=name,
- file=file,
- data={
- "arch": arch,
- "debug_id": debug_id,
- "code_id": code_id,
- "kind": kind,
- "features": features,
- "symbol_type": symbol_type,
- },
- )
- dif.save()
|