Пример #1
0
def jira_formatted_list(traceback_origin_id):
    """
        Retrieves a formatted list fit for jira, with the latest hits on this traceback

        Takes a query param with these fields:
        - traceback_origin_id: the traceback to find papertrail matches for

        The frontend is expecting this API to return a human readable string in the event of
        success (200 response code)
    """
    try:
        traceback_id = int(traceback_origin_id)
    except ValueError:
        return 'bad traceback id', 400
    if not traceback_id:
        return 'missing traceback id', 400

    # get the referenced traceback
    tb = traceback_db.get_traceback(ES, traceback_id)

    # find a list of tracebacks that use the given traceback text
    tracebacks = traceback_db.get_matching_tracebacks(ES, opentracing.tracer,
                                                      tb.traceback_text,
                                                      es_util.EXACT_MATCH, 100)
    tracebacks.sort(key=lambda tb: int(tb.origin_papertrail_id), reverse=True)

    return (traceback_formatter.create_hits_list(
        tracebacks, traceback_formatter.jira_formatted_string), 200, {
            'Content-Type': 'text/plain'
        })
Пример #2
0
def create_comment_on_existing_ticket(ES, existing_jira_issue_key: str,
                                      origin_papertrail_id: int):
    """
        Given an existing Jira ticket id, create a comment on that ticket describing a NEW (but
        related) traceback that we've encountered, referenced by L{origin_papertrail_id}.
    """
    traceback = traceback_db.get_traceback(ES, origin_papertrail_id)

    # find a list of tracebacks that use that text
    similar_tracebacks = traceback_db.get_matching_tracebacks(
        ES, opentracing.tracer, traceback.traceback_text, es_util.EXACT_MATCH,
        50)

    # get the list of jira issues that this traceback matches. if our given issue key comes back in
    # the set of matching jira issues, it means that the full traceback.text is already on our
    # ticket and we don't need to post it again
    existing_issue = None
    for issue in jira_issue_db.get_matching_jira_issues(
            ES, opentracing.tracer, traceback.traceback_text,
            es_util.EXACT_MATCH):
        if issue.key == existing_jira_issue_key:
            existing_issue = issue
            break

    # create a comment description using the list of tracebacks
    comment = ''
    if existing_issue:
        # we need only need to post the new hits. filter out any tracebacks that are after the
        # latest one already on that ticket
        latest = jira_issue_aservice.find_latest_referenced_id(existing_issue)
        if latest is not None:
            tracebacks_to_comment = [
                tb for tb in similar_tracebacks
                if int(tb.origin_papertrail_id) > latest
            ]
        else:
            # just take the them all
            tracebacks_to_comment = similar_tracebacks
        logger.info(
            'found latest papertrail id %s. taking %s tracebacks of %s total found',
            latest, len(tracebacks_to_comment), len(similar_tracebacks))
        comment = jira_issue_aservice.create_comment_with_hits_list(
            tracebacks_to_comment)
    else:
        # we need a full comment with the traceback description and all hits
        comment = jira_issue_aservice.create_description(similar_tracebacks)

    # leave the comment
    jira_issue = jira_issue_aservice.get_issue(existing_jira_issue_key)
    assert jira_issue
    jira_issue_aservice.create_comment(jira_issue, comment)

    # tell slack that we updated the ticket (async)
    channel = slack_channel.get_channel_name(traceback)
    tasks.tell_slack_about_updated_jira_ticket.delay(channel, jira_issue.key)
Пример #3
0
def create_ticket(ES, origin_papertrail_id: int,
                  assign_to: typing.Optional[str],
                  reject_if_ticket_exists: bool) -> str:
    """
        Creates a jira issue for the given traceback id
    """
    traceback = traceback_db.get_traceback(ES, origin_papertrail_id)

    if reject_if_ticket_exists:
        jira_issues = jira_issue_db.get_matching_jira_issues(
            ES, None, traceback.traceback_text, es_util.EXACT_MATCH)
        if jira_issues:
            key = jira_issues[0].key
            channel = slack_channel.get_channel_name(traceback)
            logger.info('Not creating Jira issue - already found %s', key)
            tasks.tell_slack_about_error(
                channel, "Issue has already been created as %s" % key)

    # find a list of tracebacks that use that text
    similar_tracebacks = traceback_db.get_matching_tracebacks(
        ES, opentracing.tracer, traceback.traceback_text, es_util.EXACT_MATCH,
        50)

    # create a description using the list of tracebacks
    description = jira_issue_aservice.create_description(similar_tracebacks)

    # create a title using the traceback text
    title = jira_issue_aservice.create_title(traceback.traceback_text)

    if assign_to:
        assign_to_team = jira_issue_aservice.AssignToTeam(assign_to)
    else:
        assign_to_team = jira_issue_aservice.AssignToTeam('UNASSIGNED')

    # make API call to jira
    ticket_id = jira_issue_aservice.create_jira_issue(title, description,
                                                      assign_to_team)

    # tell slack that we made a new ticket (async)
    channel = slack_channel.get_channel_name(traceback)
    tasks.tell_slack_about_new_jira_ticket.delay(channel, ticket_id)

    return ticket_id
Пример #4
0
def index():
    # parse the query params
    days_ago_raw = flask.request.args.get('days_ago')
    if days_ago_raw is not None:
        try:
            days_ago_int = int(days_ago_raw)
        except ValueError:
            return 'bad params', 400
    else:
        days_ago_int = 0
    filter_text = flask.request.args.get('filter')
    if filter_text is not None:
        filter_text = urllib.parse.unquote_plus(filter_text)
        if filter_text not in FILTERS:
            return 'bad filter: %s' % filter_text, 400
    if filter_text is None:
        filter_text = 'All Tracebacks'

    # create a set of traceback ids that match all the traceback texts the user has hidden
    span = flask.g.tracer_root_span
    tracer = opentracing.tracer
    with span_in_context(span):
        # TODO: do we need to set something to declare what this span block is doing?
        hidden_traceback_ids = set()
        if flask.session.get(text_keys.HIDDEN_TRACEBACK) is not None:
            for traceback_text in flask.session.get(
                    text_keys.HIDDEN_TRACEBACK):
                for tb in traceback_db.get_matching_tracebacks(
                        ES, tracer, traceback_text, es_util.EXACT_MATCH,
                        10000):
                    hidden_traceback_ids.add(tb.origin_papertrail_id)
            logger.info('found %s traceback ids we need to hide',
                        len(hidden_traceback_ids))

    with span_in_context(span):
        span.set_tag('filter', filter_text)
        return api_aservice.render_main_page(ES, tracer, days_ago_int,
                                             filter_text, set())
Пример #5
0
def get_tracebacks_for_day(
    ES,
    tracer,
    date_to_analyze: datetime.date,
    filter_text: str,
    hidden_traceback_ids: set,
) -> typing.List[TracebackPlusMetadata]:
    """
        Retrieves the Tracebacks for the given date_to_analyze date.

        If provided, only returns Tracebacks which match filter_text.

        Only returns Tracebacks whose ids aren't in hidden_traceback_ids.
    """
    tracer = tracer or opentracing.tracer
    root_span = get_current_span()

    # get all tracebacks
    with tracer.start_span('get all tracebacks', child_of=root_span) as span:
        with span_in_context(span):
            tracebacks = traceback_db.get_tracebacks(ES, tracer,
                                                     date_to_analyze,
                                                     date_to_analyze)
    logger.debug('found %s tracebacks', len(tracebacks))

    # filter out tracebacks the user has hidden. we use a namedlist to store each traceback + some
    # metadata we'll use when rendering the html page
    tb_meta = [
        TracebackPlusMetadata(traceback=t) for t in tracebacks
        if t.origin_papertrail_id not in hidden_traceback_ids
    ]

    # get a list of matching jira issues
    with tracer.start_span('for each traceback, get matching jira issues',
                           child_of=root_span) as span:
        with span_in_context(span):
            for tb in tb_meta:
                tb.jira_issues = jira_issue_db.get_matching_jira_issues(
                    ES, tracer, tb.traceback.traceback_text,
                    es_util.EXACT_MATCH)
                matching_jira_keys = set(jira_issue.key
                                         for jira_issue in tb.jira_issues)
                similar_jira_issues = jira_issue_db.get_matching_jira_issues(
                    ES, tracer, tb.traceback.traceback_text,
                    es_util.SIMILAR_MATCH)
                tb.similar_jira_issues = [
                    similar_jira_issue
                    for similar_jira_issue in similar_jira_issues
                    if similar_jira_issue.key not in matching_jira_keys
                ]

    # apply user's filters
    if filter_text == 'Has Ticket':
        tb_meta = [tb for tb in tb_meta if tb.jira_issues]
    elif filter_text == 'No Ticket':
        tb_meta = [tb for tb in tb_meta if not tb.jira_issues]
    elif filter_text == 'No Recent Ticket':
        tb_meta_without_recent_ticket = []
        for tb in tb_meta:
            has_recent_issues = False
            for issue in tb.jira_issues:
                if issue.updated > TWO_WEEKS_AGO:
                    has_recent_issues = True
                    break
            if not has_recent_issues:
                tb_meta_without_recent_ticket.append(tb)
        tb_meta = tb_meta_without_recent_ticket
    elif filter_text == 'Has Open Ticket':
        tb_meta = [
            tb for tb in tb_meta
            if [issue for issue in tb.jira_issues if issue.status != 'Closed']
        ]
    else:
        tb_meta = tb_meta

    # we take at most 100 tracebacks, due to performance issues of having more
    tb_meta = tb_meta[:100]

    # for each traceback, get all similar tracebacks
    with tracer.start_span('for each traceback, get similar tracebacks',
                           child_of=root_span) as span:
        with span_in_context(span):
            for tb in tb_meta:
                tb.similar_tracebacks = []
                tb.similar_tracebacks = traceback_db.get_matching_tracebacks(
                    ES, tracer, tb.traceback.traceback_text,
                    es_util.EXACT_MATCH, 100)

    return tb_meta