Esempio n. 1
0
    def get_user_info(self, username, connection):
        # Using a bound connection, we will go fetch some LDAP attributes
        # for the user that logged in.
        connection.search(search_base=self.base_dn,
                          search_filter='({}={})'.format(
                              self.id_attribute, username),
                          search_scope=ldap3.SUBTREE,
                          attributes=[
                              ldap3.ALL_ATTRIBUTES,
                              ldap3.ALL_OPERATIONAL_ATTRIBUTES
                          ])

        add_breadcrumb(
            category='ldap_auth',
            data=connection.response,
            level='debug',
        )

        filtered_response = [x for x in connection.response if 'dn' in x]

        if len(filtered_response) < 1:
            # Found no results
            self.log.error(
                f"Received invalid LDAP response, expected 1 got none: {connection.response} for username {username}"
            )
            return None
        elif len(filtered_response) > 1:
            self.log.error(
                f"Received invalid LDAP response, expected 1 got {len(filtered_response)}: {filtered_response} for username {username}"
            )
            return None

        return connection.response[0]
Esempio n. 2
0
    def _sendCrashReport(self):
        if with_sentry_sdk:
            try:
                hub = Hub.current
                if not Logger.getLoggers():
                    # No loggers have been loaded yet, so we don't have any breadcrumbs :(
                    # So add them manually so we at least have some info...
                    add_breadcrumb(
                        level="info",
                        message="SentryLogging was not initialised yet")
                    for log_type, line in Logger.getUnloggedLines():
                        add_breadcrumb(message=line)

                event, hint = event_from_exception(
                    (self.exception_type, self.value, self.traceback))
                hub.capture_event(event, hint=hint)
                hub.flush()
            except Exception as e:  # We don't want any exception to cause problems
                Logger.logException(
                    "e",
                    "An exception occurred while trying to send crash report")
                if not self.has_started:
                    print(
                        "An exception occurred while trying to send crash report: %s"
                        % e)
        else:
            msg = "SentrySDK is not available and the report could not be sent."
            Logger.logException("e", msg)
            if not self.has_started:
                print(msg)
                print("Exception type: {}".format(self.exception_type))
                print("Value: {}".format(self.value))
                print("Traceback: {}".format(self.traceback))

        os._exit(1)
Esempio n. 3
0
def logging_error(exception, true_exception=None):
    string_exception = "\n".join(exception)
    sentry_ignore_logger.error(string_exception)

    # Log to sentry
    add_breadcrumb(
        category="500",
        message="\n".join([
            x for x in exception
            if re.search(r"(site-packages\/mlchain\/)|(\/envs\/)|(\/anaconda)",
                         x) is None
        ]),
        level='error',
    )

    try:
        the_exception_1 = exception[-2]
    except:
        the_exception_1 = ""

    try:
        the_exception_2 = exception[-1]
    except:
        the_exception_2 = ""

    if true_exception is not None:
        capture_exception(true_exception)
    else:
        capture_exception(
            RuntimeError("{0} {1}".format(the_exception_1, the_exception_2)))
Esempio n. 4
0
def start_ping(run_uuid, npart):
    with sentry_sdk.configure_scope() as scope:
        if run_uuid:
            scope.set_tag('run_uuid', run_uuid)
        scope.set_tag('npart', npart)
    sentry_sdk.add_breadcrumb(message='atlasTransform started', level='info')
    sentry_sdk.capture_message('atlasTransform started', level='info')
Esempio n. 5
0
def something():
    add_breadcrumb(
        category="db stuff",
        message="Writing to DB",
        level="info",
    )
    return "hello"
Esempio n. 6
0
def answer(question, printable=False):
    """Simulates a magic 8 ball answer to a user's question.

    Keyword arguments:
    question -- a question made by the user
    printable -- prints answer when True, returns it otherwise (default: False)
    """
    answers = [
        "It is certain.", "It is decidedly so.", "Without a doubt.",
        "Yes - definitely.", "You may rely on it.", "As I see it, yes.",
        "Most likely.", "Outlook good.", "Yes.", "Signs point to yes.",
        "Reply hazy, try again.", "Ask again later.",
        "Better not tell you now.", "Cannot predict now.",
        "Concentrate and ask again.", "Don't count on it.", "My reply is no.",
        "My sources say no.", "Outlook not so good.", "Very doubtful."
    ]

    random.seed(question)
    sentry_sdk.add_breadcrumb(category="input",
                              message="Question: {}".format(question),
                              level="info")
    answer = random.choice(answers)
    sentry_sdk.add_breadcrumb(category="output",
                              message="Answer: {}".format(answer),
                              level="info")

    if not printable:
        return answer

    print(answer)
Esempio n. 7
0
    def process(self, element):
        """Returns an iterator over the words of this element.

        The element is a line of text.  If the line is blank, note that, too.

        Args:
        element: the element being processed

        Returns:
        The processed element.
        """

        add_breadcrumb(
            level="info",
            message="processed {}".format(element)
        )

        text_line = element.strip()
        if not text_line:
            self.empty_line_counter.inc(1)
        words = re.findall(r"[\w\']+", text_line, re.UNICODE)

        # ERROR HERE
        if "Beam SDK" in text_line:
            l = 3 / 0

        for w in words:
            self.words_counter.inc()
            self.word_lengths_counter.inc(len(w))
            self.word_lengths_dist.update(len(w))
        return words
Esempio n. 8
0
    def _send_request(self, func, **params):
        """Send a request"""
        params['function'] = func

        if 'sessionId' not in params.keys():
            if self.sessionId is not None:
                params['sessionId'] = self.sessionId

        # self.logger.debug("send %s" % hide_dict_values(params))
        start = time.time()
        response = requests.get(self.url, params=params)
        elapsed_rq = time.time() - start

        response.encoding = 'UTF-8'
        data = response.text

        add_breadcrumb(category='api', message="{}".format(data))

        element = ET.fromstring(data)
        try:
            self._parse_error(element)
        except Exception as e:
            logger.error("{}".format(params))
            logger.error("{}".format(data))
            #raise e

        if 'hash' in params and params['hash']:
            d_hash = hashlib.md5(data.encode('utf-8')).hexdigest()
            return {'element': element, 'hash': d_hash}
        return element
Esempio n. 9
0
    def do_consume(self, consume_func: Callable[[List[Dict[str, Any]]], None],
                   events: List[Dict[str, Any]]) -> None:
        consume_time_seconds: Optional[float] = None
        with configure_scope() as scope:
            scope.clear_breadcrumbs()
            add_breadcrumb(
                type='debug',
                category='queue_processor',
                message=f"Consuming {self.queue_name}",
                data={"events": events, "queue_size": self.get_remaining_queue_size()},
            )
        try:
            time_start = time.time()
            consume_func(events)
            consume_time_seconds = time.time() - time_start
            self.consumed_since_last_emptied += len(events)
        except Exception:
            self._handle_consume_exception(events)
        finally:
            flush_per_request_caches()
            reset_queries()

            if consume_time_seconds is not None:
                self.recent_consume_times.append((len(events), consume_time_seconds))

            remaining_queue_size = self.get_remaining_queue_size()
            if remaining_queue_size == 0:
                self.queue_last_emptied_timestamp = time.time()
                self.consumed_since_last_emptied = 0

            self.consume_interation_counter += 1
            if self.consume_interation_counter >= self.CONSUME_ITERATIONS_BEFORE_UPDATE_STATS_NUM:

                self.consume_interation_counter = 0
                self.update_statistics(remaining_queue_size)
Esempio n. 10
0
def test_view_exceptions(
    get_client, route, sentry_init, capture_events, capture_exceptions
):
    sentry_init(integrations=[PyramidIntegration()])
    events = capture_events()
    exceptions = capture_exceptions()

    add_breadcrumb({"message": "hi"})

    @route("/errors")
    def errors(request):
        add_breadcrumb({"message": "hi2"})
        1 / 0

    client = get_client()
    with pytest.raises(ZeroDivisionError):
        client.get("/errors")

    error, = exceptions
    assert isinstance(error, ZeroDivisionError)

    event, = events
    breadcrumb, = event["breadcrumbs"]
    assert breadcrumb["message"] == "hi2"
    assert event["exception"]["values"][0]["mechanism"]["type"] == "pyramid"
Esempio n. 11
0
def handle_tex_compiler_error(latex_file_path, ext):
    # TODO zmd: fix extension parsing
    log_file_path = latex_file_path[:-3] + "log"
    errors = [f"Error occured, log file {log_file_path} not found."]
    with contextlib.suppress(FileNotFoundError, UnicodeDecodeError):
        with Path(log_file_path).open(encoding="utf-8") as latex_log:
            print_context = 25
            lines = []
            relevant_line = -print_context
            for idx, line in enumerate(latex_log):
                if "fatal" in line.lower() or "error" in line.lower():
                    relevant_line = idx
                    lines.append(line)
                elif idx - relevant_line < print_context:
                    lines.append(line)

            errors = "\n".join(lines)
    logger.debug("%s ext=%s", errors, ext)
    with contextlib.suppress(ImportError):
        import sentry_sdk

        sentry_sdk.add_breadcrumb(message="luatex call",
                                  data=errors,
                                  type="cmd")

    raise FailureDuringPublication(errors)
Esempio n. 12
0
def main(*args, **kwargs):
    # init sentry
    sentry_dsn = os.environ.get('SENTRY')
    if sentry_dsn:
        sentry_sdk.init(sentry_dsn,
                        environment=os.environ.get("MODE", "undefined"))
        sentry_sdk.add_breadcrumb(args[0])

    payload = args[0]
    device_id = payload['client_id']

    # Add measurements to database
    for measurement_type, measurement_raws in payload['data'].items():
        measurements = []
        try:
            for timestamp, value in measurement_raws:
                measurements.append({
                    'device_id': device_id,
                    'timestamp': timestamp,
                    'value': value,
                    'measurement_type': measurement_type
                })
            MeasurementService.create_measurements(measurements)
        except Exception as exception:
            logging.exception(
                f"Exception occurred while adding measurements to database: {exception} "
                f"\n Inputs: {measurement_type}, {measurement_raws}")
            sentry_sdk.capture_exception(exception)
Esempio n. 13
0
def test_transport_works(
    httpserver,
    request,
    capsys,
    caplog,
    debug,
    make_client,
    client_flush_method,
    use_pickle,
    maybe_monkeypatched_threading,
):
    httpserver.serve_content("ok", 200)
    caplog.set_level(logging.DEBUG)
    client = make_client(debug=debug)

    if use_pickle:
        client = pickle.loads(pickle.dumps(client))

    Hub.current.bind_client(client)
    request.addfinalizer(lambda: Hub.current.bind_client(None))

    add_breadcrumb(level="info",
                   message="i like bread",
                   timestamp=datetime.utcnow())
    capture_message("löl")

    getattr(client, client_flush_method)()

    out, err = capsys.readouterr()
    assert not err and not out
    assert httpserver.requests

    assert any("Sending event" in record.msg
               for record in caplog.records) == debug
Esempio n. 14
0
def test_breadcrumbs(sentry_init, capture_events):
    sentry_init(max_breadcrumbs=10)
    events = capture_events()

    for i in range(20):
        add_breadcrumb(category="auth",
                       message="Authenticated user %s" % i,
                       level="info")

    capture_exception(ValueError())
    event, = events

    assert len(event["breadcrumbs"]) == 10
    assert "user 10" in event["breadcrumbs"][0]["message"]
    assert "user 19" in event["breadcrumbs"][-1]["message"]

    del events[:]

    for i in range(2):
        add_breadcrumb(category="auth",
                       message="Authenticated user %s" % i,
                       level="info")

    with configure_scope() as scope:
        scope.clear()

    capture_exception(ValueError())
    event, = events
    assert len(event["breadcrumbs"]) == 0
Esempio n. 15
0
def convert_file(tmpfile_name: str, orig_fname: str) -> Optional[str]:
    detected = get_mimetype(tmpfile_name)

    add_breadcrumb(category="printing",
                   message="Detected file type {}".format(detected),
                   level="debug")

    no_conversion = ["application/pdf", "text/plain"]
    soffice_convert = [
        "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
        "application/msword",
        "application/vnd.oasis.opendocument.text",
    ]
    if detected in no_conversion:
        return tmpfile_name

    # .docx
    if detected in soffice_convert:
        return convert_soffice(tmpfile_name)

    if detected == "application/postscript":
        return convert_pdf(tmpfile_name, "pdf2ps")

    # Not detected

    if orig_fname.endswith((".doc", ".docx")):
        raise InvalidInputPrintingError(
            "Invalid file type {}<br>Note: It looks like you are trying to print a Word document. Word documents don't always print correctly, so we "
            "recommend that you convert to a PDF before printing.".format(
                detected))

    raise InvalidInputPrintingError("Invalid file type {}".format(detected))
Esempio n. 16
0
async def on_command_error(ctx, error):
    sentry_sdk.add_breadcrumb(category='discord.command_name',
                              message='Error on command %s' %
                              ctx.command.qualified_name,
                              level='info')
    sentry_sdk.capture_exception(error)
    await ctx.send(str(error))
Esempio n. 17
0
def captureBreadcrumb(**kwargs):
    site = api.portal.get()
    dsn = site.error_log.getsentry_dsn
    dsn = dsn and dsn or os.environ.get(DSN_ENV_VAR, '')
    if dsn:
        client = get_or_create_client(dsn)
        if client:
            sentry_sdk.add_breadcrumb(**kwargs)
Esempio n. 18
0
def something_else():
    add_breadcrumb(
        category="db stuff",
        message="Writing to DB",
        level="info",
    )
    var1 += sdsdsdsds
    return "hello"
def echo(text: Any, err: bool = False, nl: bool = True, notify_value: int = None, color: Any = None,
         output_machine: bool = True, ctx: Optional[click.Context] = None):
    add_breadcrumb(message=text, category='echo')
    if ismachineoutput(ctx):
        if output_machine:
            return _machine_notify('echo', {'text': str(text) + ('\n' if nl else '')}, notify_value)
    else:
        return click.echo(str(text), nl=nl, err=err, color=color)
Esempio n. 20
0
 def add_breadcrumb(cls, message, **data):
     # Add breadcrumb only if settings are already loaded,
     # we do not want to force loading settings early
     if settings.configured and getattr(settings, "SENTRY_DSN", None):
         add_breadcrumb(category="vcs",
                        message=message,
                        data=data,
                        level="info")
Esempio n. 21
0
def something_else_2():
    add_breadcrumb(
        category="level1",
        message="Level 1 message",
        level="info",
    )
    var2 += wewewewewe
    return "hello"
Esempio n. 22
0
def register_sentry(argv, settings, topsrcdir):
    if not is_telemetry_enabled(settings):
        return NoopErrorReporter()

    sentry_sdk.init(
        _SENTRY_DSN, before_send=lambda event, _: _process_event(event, topsrcdir)
    )
    sentry_sdk.add_breadcrumb(message="./mach {}".format(" ".join(argv)))
    return SentryErrorReporter()
Esempio n. 23
0
 def get(self, request):
     add_breadcrumb(
         category='URL Endpoints',
         message='In the unhandled function',
         level='info',
     )
     obj = {}
     obj['keyDoesntExist']
     return Response()
Esempio n. 24
0
    def get(self, request):
        add_breadcrumb(
            category='URL Endpoints',
            message='In the Capture Message function',
            level='info',
        )
        sentry_sdk.capture_message("You caught me!")

        return Response()
Esempio n. 25
0
def add_breadcrumb(category: str, message: str, level: str = "info", **data):
    # Add breadcrumb only if settings are already loaded,
    # we do not want to force loading settings early
    if not settings.configured or not getattr(settings, "SENTRY_DSN", None):
        return
    sentry_sdk.add_breadcrumb(category=category,
                              message=message,
                              level=level,
                              data=data)
Esempio n. 26
0
    def do_consume(self, consume_func: Callable[[List[Dict[str, Any]]], None],
                   events: List[Dict[str, Any]]) -> None:
        consume_time_seconds: Optional[float] = None
        with configure_scope() as scope:
            scope.clear_breadcrumbs()
            add_breadcrumb(
                type='debug',
                category='queue_processor',
                message=f"Consuming {self.queue_name}",
                data={"events": events, "queue_size": self.get_remaining_queue_size()},
            )
        try:
            if self.idle:
                # We're reactivating after having gone idle due to emptying the queue.
                # We should update the stats file to keep it fresh and to make it clear
                # that the queue started processing, in case the event we're about to process
                # makes us freeze.
                self.idle = False
                self.update_statistics(self.get_remaining_queue_size())

            time_start = time.time()
            if self.MAX_CONSUME_SECONDS and self.ENABLE_TIMEOUTS:
                signal.signal(signal.SIGALRM, functools.partial(timer_expired, self.MAX_CONSUME_SECONDS, len(events)))
                signal.alarm(self.MAX_CONSUME_SECONDS * len(events))
                consume_func(events)
                signal.alarm(0)
            else:
                consume_func(events)
            consume_time_seconds = time.time() - time_start
            self.consumed_since_last_emptied += len(events)
        except Exception as e:
            self._handle_consume_exception(events, e)
        finally:
            flush_per_request_caches()
            reset_queries()

            if consume_time_seconds is not None:
                self.recent_consume_times.append((len(events), consume_time_seconds))

            remaining_queue_size = self.get_remaining_queue_size()
            if remaining_queue_size == 0:
                self.queue_last_emptied_timestamp = time.time()
                self.consumed_since_last_emptied = 0
                # We've cleared all the events from the queue, so we don't
                # need to worry about the small overhead of doing a disk write.
                # We take advantage of this to update the stats file to keep it fresh,
                # especially since the queue might go idle until new events come in.
                self.update_statistics(0)
                self.idle = True
                return

            self.consume_iteration_counter += 1
            if (self.consume_iteration_counter >= self.CONSUME_ITERATIONS_BEFORE_UPDATE_STATS_NUM
                    or time.time() - self.last_statistics_update_time >= self.MAX_SECONDS_BEFORE_UPDATE_STATS):
                self.consume_iteration_counter = 0
                self.update_statistics(remaining_queue_size)
Esempio n. 27
0
def sentry_observer(event):
    # Handle breadcrumbs...
    if not event.get('isError') or 'failure' not in event:
        add_breadcrumb(level=event.get('log_level').name,
                       message=event.get('log_format'),
                       category=event.get('log_namespace'))
        return

    # ...Handle Failures
    f = event['failure']
    capture_exception((f.type, f.value, f.getTracebackObject()))
Esempio n. 28
0
 def get(self, request):
     add_breadcrumb(
         category='URL Endpoints',
         message='In the handled function',
         level='info',
     )
     try:
         '2' + 2
     except Exception as err:
         sentry_sdk.capture_exception(err)
     return Response()
Esempio n. 29
0
def test_max_breadcrumbs_option(sentry_init, capture_events, sdk_options,
                                expected_breadcrumbs):
    sentry_init(sdk_options)
    events = capture_events()

    for _ in range(1231):
        add_breadcrumb({"type": "sourdough"})

    capture_message("dogs are great")

    assert len(events[0]["breadcrumbs"]["values"]) == expected_breadcrumbs
Esempio n. 30
0
 def geocode_location(self):
     nr = requests.get('https://nominatim.openstreetmap.org/reverse',
                       params={
                           'format': 'jsonv2',
                           'lat': self.location.y,
                           'lon': self.location.x,
                           'accept-language': 'en'
                       })
     self.location_address = nr.json().get('address', None)
     if self.location_address is None:
         add_breadcrumb(category='nominatim', level='error', data=nr.json())
Esempio n. 31
0
def main():
    """Entry point"""
    from nipype import logging as nlogging
    from multiprocessing import set_start_method, Process, Manager
    from ..viz.reports import generate_reports
    from ..utils.bids import write_derivative_description
    set_start_method('forkserver')

    warnings.showwarning = _warn_redirect
    opts = get_parser().parse_args()

    exec_env = os.name

    # special variable set in the container
    if os.getenv('IS_DOCKER_8395080871'):
        exec_env = 'singularity'
        cgroup = Path('/proc/1/cgroup')
        if cgroup.exists() and 'docker' in cgroup.read_text():
            exec_env = 'docker'
            if os.getenv('DOCKER_VERSION_8395080871'):
                exec_env = 'fmriprep-docker'

    sentry_sdk = None
    if not opts.notrack:
        import sentry_sdk
        from ..__about__ import __version__
        environment = "prod"
        release = __version__
        if not __version__:
            environment = "dev"
            release = "dev"
        elif bool(int(os.getenv('FMRIPREP_DEV', 0))) or ('+' in __version__):
            environment = "dev"

        def before_send(event, hints):
            # Filtering log messages about crashed nodes
            if 'logentry' in event and 'message' in event['logentry']:
                msg = event['logentry']['message']
                if msg.startswith("could not run node:"):
                    return None
                elif msg.startswith("Saving crash info to "):
                    return None
                elif re.match("Node .+ failed to run on host .+", msg):
                    return None

            if 'breadcrumbs' in event and isinstance(event['breadcrumbs'], list):
                fingerprints_to_propagate = ['no-disk-space', 'memory-error', 'permission-denied',
                                             'keyboard-interrupt']
                for bc in event['breadcrumbs']:
                    msg = bc.get('message', 'empty-msg')
                    if msg in fingerprints_to_propagate:
                        event['fingerprint'] = [msg]
                        break

            return event

        sentry_sdk.init("https://[email protected]/1137693",
                        release=release,
                        environment=environment,
                        before_send=before_send)
        with sentry_sdk.configure_scope() as scope:
            scope.set_tag('exec_env', exec_env)

            if exec_env == 'fmriprep-docker':
                scope.set_tag('docker_version', os.getenv('DOCKER_VERSION_8395080871'))

            free_mem_at_start = round(psutil.virtual_memory().free / 1024**3, 1)
            scope.set_tag('free_mem_at_start', free_mem_at_start)
            scope.set_tag('cpu_count', cpu_count())

            # Memory policy may have a large effect on types of errors experienced
            overcommit_memory = Path('/proc/sys/vm/overcommit_memory')
            if overcommit_memory.exists():
                policy = {'0': 'heuristic',
                          '1': 'always',
                          '2': 'never'}.get(overcommit_memory.read_text().strip(), 'unknown')
                scope.set_tag('overcommit_memory', policy)
                if policy == 'never':
                    overcommit_kbytes = Path('/proc/sys/vm/overcommit_memory')
                    kb = overcommit_kbytes.read_text().strip()
                    if kb != '0':
                        limit = '{}kB'.format(kb)
                    else:
                        overcommit_ratio = Path('/proc/sys/vm/overcommit_ratio')
                        limit = '{}%'.format(overcommit_ratio.read_text().strip())
                    scope.set_tag('overcommit_limit', limit)
                else:
                    scope.set_tag('overcommit_limit', 'n/a')
            else:
                scope.set_tag('overcommit_memory', 'n/a')
                scope.set_tag('overcommit_limit', 'n/a')

            for k, v in vars(opts).items():
                scope.set_tag(k, v)

    # Validate inputs
    if not opts.skip_bids_validation:
        print("Making sure the input data is BIDS compliant (warnings can be ignored in most "
              "cases).")
        validate_input_dir(exec_env, opts.bids_dir, opts.participant_label)

    # FreeSurfer license
    default_license = str(Path(os.getenv('FREESURFER_HOME')) / 'license.txt')
    # Precedence: --fs-license-file, $FS_LICENSE, default_license
    license_file = opts.fs_license_file or os.getenv('FS_LICENSE', default_license)
    if not os.path.exists(license_file):
        raise RuntimeError(
            'ERROR: a valid license file is required for FreeSurfer to run. '
            'FMRIPREP looked for an existing license file at several paths, in this '
            'order: 1) command line argument ``--fs-license-file``; 2) ``$FS_LICENSE`` '
            'environment variable; and 3) the ``$FREESURFER_HOME/license.txt`` path. '
            'Get it (for free) by registering at https://'
            'surfer.nmr.mgh.harvard.edu/registration.html')
    os.environ['FS_LICENSE'] = license_file

    # Retrieve logging level
    log_level = int(max(25 - 5 * opts.verbose_count, logging.DEBUG))
    # Set logging
    logger.setLevel(log_level)
    nlogging.getLogger('nipype.workflow').setLevel(log_level)
    nlogging.getLogger('nipype.interface').setLevel(log_level)
    nlogging.getLogger('nipype.utils').setLevel(log_level)

    errno = 0

    # Call build_workflow(opts, retval)
    with Manager() as mgr:
        retval = mgr.dict()
        p = Process(target=build_workflow, args=(opts, retval))
        p.start()
        p.join()

        if p.exitcode != 0:
            sys.exit(p.exitcode)

        fmriprep_wf = retval['workflow']
        plugin_settings = retval['plugin_settings']
        bids_dir = retval['bids_dir']
        output_dir = retval['output_dir']
        work_dir = retval['work_dir']
        subject_list = retval['subject_list']
        run_uuid = retval['run_uuid']
        if not opts.notrack:
            with sentry_sdk.configure_scope() as scope:
                scope.set_tag('run_uuid', run_uuid)
                scope.set_tag('npart', len(subject_list))

        retcode = retval['return_code']

    if fmriprep_wf is None:
        sys.exit(1)

    if opts.write_graph:
        fmriprep_wf.write_graph(graph2use="colored", format='svg', simple_form=True)

    if opts.reports_only:
        sys.exit(int(retcode > 0))

    if opts.boilerplate:
        sys.exit(int(retcode > 0))

    # Sentry tracking
    if not opts.notrack:
        sentry_sdk.add_breadcrumb(message='fMRIPrep started', level='info')
        sentry_sdk.capture_message('fMRIPrep started', level='info')

    # Check workflow for missing commands
    missing = check_deps(fmriprep_wf)
    if missing:
        print("Cannot run fMRIPrep. Missing dependencies:")
        for iface, cmd in missing:
            print("\t{} (Interface: {})".format(cmd, iface))
        sys.exit(2)

    # Clean up master process before running workflow, which may create forks
    gc.collect()
    try:
        fmriprep_wf.run(**plugin_settings)
    except RuntimeError as e:
        errno = 1
        if "Workflow did not execute cleanly" not in str(e):
            sentry_sdk.capture_exception(e)
            raise
    finally:
        # Generate reports phase
        errno += generate_reports(subject_list, output_dir, work_dir, run_uuid,
                                  sentry_sdk=sentry_sdk)
        write_derivative_description(bids_dir, str(Path(output_dir) / 'fmriprep'))

    if not opts.notrack and errno == 0:
        sentry_sdk.capture_message('fMRIPrep finished without errors', level='info')
    sys.exit(int(errno > 0))