def get_tags(event): tag_list = event.tags if not tag_list: return "" return ", ".join([": ".join([tagstore.get_tag_key_label(k), tagstore.get_tag_value_label(k, v)]) for k, v in tag_list])
def _get_tags(self, event): tag_list = event.get_tags() if not tag_list: return () return ((tagstore.get_tag_key_label(k), tagstore.get_tag_value_label(k, v)) for k, v in tag_list)
def get_group_tag_keys_and_top_values(self, project_id, group_id, environment_id, user=None): from sentry import tagstore start, end = self.get_time_range() filters = { 'project_id': [project_id], 'environment': [environment_id], 'issue': [group_id], } aggregations = [ ['topK(10)', 'tags.value', 'top'], ['count', '', 'count'], ['uniq', 'tags.key', 'uniq'], ] results = snuba.query(start, end, ['tags.key'], None, filters, aggregations, arrayjoin='tags') return [{ 'id': key, 'name': tagstore.get_tag_key_label(key), 'key': tagstore.get_standardized_key(key), 'uniqueValues': res['uniq'], 'totalValues': res['count'], 'topValues': [{ 'id': val, 'name': tagstore.get_tag_value_label(key, val), 'key': tagstore.get_standardized_key(key), 'value': val, } for val in res['top']], } for key, res in six.iteritems(results)]
def data_fn(offset, limit): with sentry_sdk.start_span(op="discover.endpoint", description="discover_query"): referrer = "api.organization-events-facets-performance-histogram.top-tags" tag_data = query_tag_data( filter_query=filter_query, aggregate_column=aggregate_column, referrer=referrer, params=params, ) if not tag_data: return {"data": []} results = query_facet_performance_key_histogram( tag_data=tag_data, tag_key=tag_key, filter_query=filter_query, aggregate_column=aggregate_column, referrer=referrer, orderby=self.get_orderby(request), params=params, limit=limit, ) if not results: return {"data": []} for row in results["data"]: row["tags_value"] = tagstore.get_tag_value_label( row["tags_key"], row["tags_value"]) row["tags_key"] = tagstore.get_standardized_key( row["tags_key"]) return results
def get_attrs(self, item_list, user): result = {} for item in item_list: result[item] = { 'name': tagstore.get_tag_value_label(item.key, item.value), } return result
def data_fn(offset, limit): with sentry_sdk.start_span(op="discover.endpoint", description="discover_query"): with self.handle_query_errors(): facets = discover.get_performance_facets( query=request.GET.get("query"), params=params, referrer="api.organization-events-facets-performance.top-tags", aggregate_column=aggregate_column, orderby=orderby, offset=offset, limit=limit, ) with sentry_sdk.start_span( op="discover.endpoint", description="populate_results" ) as span: span.set_data("facet_count", len(facets or [])) resp = defaultdict(lambda: {"key": "", "value": {}}) for row in facets: values = resp[row.key] values["key"] = tagstore.get_standardized_key(row.key) values["value"] = { "name": tagstore.get_tag_value_label(row.key, row.value), "value": row.value, "count": row.count, "frequency": row.frequency, "aggregate": row.performance, "comparison": row.comparison, "sumdelta": row.sumdelta, } return {"data": list(resp.values())}
def get_group_tag_keys_and_top_values(self, project_id, group_id, environment_id, user=None): from sentry import tagstore start, end = self.get_time_range() filters = { 'project_id': [project_id], 'environment': [environment_id], 'issue': [group_id], } aggregations = [ ['count()', '', 'count'], ['topK(10)', 'tags_value', 'top'], ['uniq', 'tags_value', 'uniq'], ] conditions = [ ['tags_value', 'IS NOT NULL', None], ] results = snuba.query(start, end, ['tags_key'], conditions, filters, aggregations) return [{ 'id': key, 'name': tagstore.get_tag_key_label(key), 'key': tagstore.get_standardized_key(key), 'uniqueValues': res['uniq'], 'totalValues': res['count'], 'topValues': [{ 'id': val, 'name': tagstore.get_tag_value_label(key, val), 'key': tagstore.get_standardized_key(key), 'value': val, } for val in res['top']], } for key, res in six.iteritems(results)]
def get(self, request, organization): with sentry_sdk.start_span(op="discover.endpoint", description="filter_params") as span: span.set_data("organization", organization) if not features.has("organizations:discover-basic", organization, actor=request.user): return Response(status=404) try: params = self.get_filter_params(request, organization) except NoProjects: return Response([]) params = self.quantize_date_params(request, params) self._validate_project_ids(request, organization, params) with sentry_sdk.start_span(op="discover.endpoint", description="discover_query"): try: facets = discover.get_facets( query=request.GET.get("query"), params=params, referrer="api.organization-events-facets.top-tags", ) except (discover.InvalidSearchQuery, snuba.QueryOutsideRetentionError) as error: raise ParseError(detail=six.text_type(error)) with sentry_sdk.start_span(op="discover.endpoint", description="populate_results") as span: span.set_data("facet_count", len(facets or [])) resp = defaultdict(lambda: {"key": "", "topValues": []}) for row in facets: values = resp[row.key] values["key"] = tagstore.get_standardized_key(row.key) values["topValues"].append({ "name": tagstore.get_tag_value_label(row.key, row.value), "value": row.value, "count": row.count, }) if "project" in resp: # Replace project ids with slugs as that is what we generally expose to users # and filter out projects that the user doesn't have access too. projects = { p.id: p.slug for p in self.get_projects(request, organization) } filtered_values = [] for v in resp["project"]["topValues"]: if v["value"] in projects: name = projects[v["value"]] v.update({"name": name}) filtered_values.append(v) resp["project"]["topValues"] = filtered_values return Response(resp.values())
def get_tags(event): tag_list = event.tags if not tag_list: return () return ( (tagstore.get_tag_key_label(k), tagstore.get_tag_value_label(k, v)) for k, v in tag_list )
def get(self, request, organization): try: snuba_args = self.get_snuba_query_args(request, organization) except OrganizationEventsError as exc: return Response({'detail': exc.message}, status=400) except NoProjects: return Response({'detail': 'A valid project must be included.'}, status=400) try: key = self._validate_key(request) self._validate_project_ids(request, organization, snuba_args) except OrganizationEventsError as error: return Response({'detail': six.text_type(error)}, status=400) colname = get_snuba_column_name(key) if key == PROJECT_KEY: colname = 'project_id' top_values = raw_query( start=snuba_args['start'], end=snuba_args['end'], conditions=snuba_args['conditions'] + [[colname, 'IS NOT NULL', None]], filter_keys=snuba_args['filter_keys'], groupby=[colname], aggregations=[('count()', None, 'count')], orderby='-count', limit=TOP_VALUES_DEFAULT_LIMIT, referrer='api.organization-events-distribution', )['data'] projects = {p.id: p.slug for p in self.get_projects(request, organization)} if key == PROJECT_KEY: resp = { 'key': PROJECT_KEY, 'topValues': [ { 'value': projects[v['project_id']], 'name': projects[v['project_id']], 'count': v['count'], } for v in top_values ] } else: resp = { 'key': key, 'topValues': [ { 'value': v[colname], 'name': tagstore.get_tag_value_label(colname, v[colname]), 'count': v['count'], } for v in top_values ], } return Response(resp)
def get_attrs(self, item_list, user): from sentry import tagstore result = {} for item in item_list: result[item] = { 'name': tagstore.get_tag_value_label(item.key, item.value), } return result
def get_attrs(self, item_list, user): from sentry import tagstore result = {} for item in item_list: result[item] = { "name": tagstore.get_tag_value_label(item.key, item.value) } return result
def get(self, request, organization): if not features.has("organizations:discover-basic", organization, actor=request.user): return Response(status=404) try: params = self.get_filter_params(request, organization) except OrganizationEventsError as error: raise ParseError(detail=six.text_type(error)) except NoProjects: return Response({"detail": "A valid project must be included."}, status=400) try: self._validate_project_ids(request, organization, params) except OrganizationEventsError as error: return Response({"detail": six.text_type(error)}, status=400) try: facets = discover.get_facets( query=request.GET.get("query"), params=params, referrer="api.organization-events-facets.top-tags", ) except discover.InvalidSearchQuery as error: raise ParseError(detail=six.text_type(error)) resp = defaultdict(lambda: {"key": "", "topValues": []}) for row in facets: values = resp[row.key] values["key"] = tagstore.get_standardized_key(row.key) values["topValues"].append({ "name": tagstore.get_tag_value_label(row.key, row.value), "value": row.value, "count": row.count, }) if "project" in resp: # Replace project ids with slugs as that is what we generally expose to users # and filter out projects that the user doesn't have access too. projects = { p.id: p.slug for p in self.get_projects(request, organization) } filtered_values = [] for v in resp["project"]["topValues"]: if v["value"] in projects: name = projects[v["value"]] v.update({"name": name}) filtered_values.append(v) resp["project"]["topValues"] = filtered_values return Response(resp.values())
def serialize(self, obj, attrs, user): from sentry import tagstore return { 'key': tagstore.get_standardized_key(obj.key), 'name': tagstore.get_tag_value_label(obj.key, obj.value), 'value': obj.value, 'count': obj.times_seen, 'lastSeen': obj.last_seen, 'firstSeen': obj.first_seen, }
def get(self, request, organization): if not self.has_feature(organization, request): return Response(status=404) try: params = self.get_snuba_params(request, organization) except NoProjects: return Response([]) with sentry_sdk.start_span(op="discover.endpoint", description="discover_query"): with self.handle_query_errors(): facets = discover.get_facets( query=request.GET.get("query"), params=params, referrer="api.organization-events-facets.top-tags", ) with sentry_sdk.start_span(op="discover.endpoint", description="populate_results") as span: span.set_data("facet_count", len(facets or [])) resp = defaultdict(lambda: {"key": "", "topValues": []}) for row in facets: values = resp[row.key] values["key"] = tagstore.get_standardized_key(row.key) values["topValues"].append({ "name": tagstore.get_tag_value_label(row.key, row.value), "value": row.value, "count": row.count, }) if "project" in resp: # Replace project ids with slugs as that is what we generally expose to users # and filter out projects that the user doesn't have access too. projects = { p.id: p.slug for p in self.get_projects(request, organization) } filtered_values = [] for v in resp["project"]["topValues"]: if v["value"] in projects: name = projects[v["value"]] v.update({"name": name}) filtered_values.append(v) resp["project"]["topValues"] = filtered_values return Response(list(resp.values()))
def build_tag_fields(event_for_tags, tags: Mapping[str, str] = None): fields = [] if tags: event_tags = event_for_tags.tags if event_for_tags else [] for key, value in event_tags: std_key = tagstore.get_standardized_key(key) if std_key not in tags: continue labeled_value = tagstore.get_tag_value_label(key, value) fields.append({ "title": std_key.encode("utf-8"), "value": labeled_value.encode("utf-8"), "short": True, }) return fields
def serialize(self, obj, attrs, user): from sentry import tagstore key = tagstore.get_standardized_key(obj.key) serialized = { 'key': key, 'name': tagstore.get_tag_value_label(obj.key, obj.value), 'value': obj.value, 'count': obj.times_seen, 'lastSeen': obj.last_seen, 'firstSeen': obj.first_seen, } query = convert_user_tag_to_query(key, obj.value) if query: serialized['query'] = query return serialized
def serialize(self, obj, attrs, user): from sentry import tagstore key = tagstore.get_standardized_key(obj.key) serialized = { "key": key, "name": tagstore.get_tag_value_label(obj.key, obj.value), "value": obj.value, "count": obj.times_seen, "lastSeen": obj.last_seen, "firstSeen": obj.first_seen, } query = convert_user_tag_to_query(key, obj.value) if query: serialized["query"] = query return serialized
def build_tag_fields( event_for_tags: Any, tags: Optional[Set[str]] = None ) -> Sequence[Mapping[str, Union[str, bool]]]: fields = [] if tags: event_tags = event_for_tags.tags if event_for_tags else [] for key, value in event_tags: std_key = tagstore.get_standardized_key(key) if std_key not in tags: continue labeled_value = tagstore.get_tag_value_label(key, value) fields.append({ "title": std_key.encode("utf-8"), "value": labeled_value.encode("utf-8"), "short": True, }) return fields
def get(self, request, organization): if not self.has_feature(organization, request): return Response(status=404) try: params = self.get_snuba_params(request, organization) except NoProjects: return Response([]) aggregate_column = request.GET.get("aggregateColumn", "duration") orderby = request.GET.getlist("order", None) with sentry_sdk.start_span(op="discover.endpoint", description="discover_query"): with self.handle_query_errors(): facets = discover.get_performance_facets( query=request.GET.get("query"), params=params, referrer= "api.organization-events-facets-performance.top-tags", aggregate_column=aggregate_column, orderby=orderby, ) with sentry_sdk.start_span(op="discover.endpoint", description="populate_results") as span: span.set_data("facet_count", len(facets or [])) resp = defaultdict(lambda: {"key": "", "topValues": []}) for row in facets: values = resp[row.key] values["key"] = tagstore.get_standardized_key(row.key) values["topValues"].append({ "name": tagstore.get_tag_value_label(row.key, row.value), "value": row.value, "count": row.count, "aggregate": row.performance, }) return Response(list(resp.values()))
def data_fn(): with sentry_sdk.start_span(op="discover.endpoint", description="discover_query"): referrer = "api.organization-events-facets-performance-histogram" top_tags = query_top_tags( tag_key=tag_key, limit=tag_key_limit, filter_query=filter_query, aggregate_column=aggregate_column, params=params, orderby=self.get_orderby(request), referrer=referrer, ) if not top_tags: return {"data": []}, [] results = query_facet_performance_key_histogram( top_tags=top_tags, tag_key=tag_key, filter_query=filter_query, aggregate_column=aggregate_column, referrer=referrer, params=params, limit=tag_key_limit, num_buckets_per_key=num_buckets_per_key, ) if not results: return {"data": []}, top_tags for row in results["data"]: row["tags_value"] = tagstore.get_tag_value_label( row["tags_key"], row["tags_value"]) row["tags_key"] = tagstore.get_standardized_key( row["tags_key"]) return results, top_tags
def notify(self, notification, raise_exception=None): """ notify Send Event Notifications """ event = notification.event group = event.group project = group.project # Make sure we're configured if not self.is_configured(project): return webhook_url = self.get_option('webhook_url', project) project_name = project.get_full_name().encode('utf-8') notification_link = self.create_markdown_link( 'Click Here', self.add_notification_referrer_param(group.get_absolute_url())) try: # Sentry 9 title = event.message_short.encode('utf-8') error_message = event.error().encode('utf-8') except AttributeError: # Sentry 10 title = event.title.encode('utf-8') error_message = event.message.encode('utf-8') message_facts = [] message_facts.append({'name': 'Project', 'value': project_name}) if error_message: message_facts.append({'name': 'Error', 'value': error_message}) if group.times_seen: message_facts.append({ 'name': 'Times Seen', 'value': 'Seen %s Times' % group.times_seen }) if group.culprit and title != group.culprit: message_facts.append({ 'name': 'Culprit', 'value': group.culprit.encode('utf-8') }) message_object = { 'sections': [{ 'activityTitle': '[%s] %s' % (project_name, title), 'activityText': '%s to View this Event in Sentry' % notification_link, 'facts': message_facts }], '@type': 'MessageCard', 'summary': '[%s] %s' % (project_name, title) } if self.get_option('show_tags', project): tags = [] try: # Sentry 9 sentry_tags = event.get_tags() except AttributeError: # Sentry 10 sentry_tags = event.tags if sentry_tags: sentry_tag_tuples = ((tagstore.get_tag_key_label(tagname), tagstore.get_tag_value_label( tagname, tagvalue)) for tagname, tagvalue in sentry_tags) for tag_name, tag_value in sentry_tag_tuples: tags.append({ 'name': tag_name.encode('utf-8'), 'value': tag_value.encode('utf-8') }) section = { 'activityTitle': 'Tags on Event', 'activityText': 'The following Tags were attached to the Event', 'facts': tags } message_object['sections'].append(section) return http.safe_urlopen(webhook_url, method='POST', data=json.dumps(message_object))
def get_label(self): from sentry import tagstore return tagstore.get_tag_value_label(self.key, self.value)
def build_attachment(group, event=None, tags=None, identity=None, actions=None, rules=None): # XXX(dcramer): options are limited to 100 choices, even when nested status = group.get_status() members = get_member_assignees(group) teams = get_team_assignees(group) logo_url = absolute_uri(get_asset_url('sentry', 'images/sentry-email-avatar.png')) color = LEVEL_TO_COLOR.get( event.get_tag('level'), 'error') if event else LEVEL_TO_COLOR['error'] text = build_attachment_text(group, event) or '' if actions is None: actions = [] assignee = get_assignee(group) resolve_button = { 'name': 'resolve_dialog', 'value': 'resolve_dialog', 'type': 'button', 'text': 'Resolve...', } ignore_button = { 'name': 'status', 'value': 'ignored', 'type': 'button', 'text': 'Ignore', } has_releases = Release.objects.filter( projects=group.project, organization_id=group.project.organization_id ).exists() if not has_releases: resolve_button.update({ 'name': 'status', 'text': 'Resolve', 'value': 'resolved', }) if status == GroupStatus.RESOLVED: resolve_button.update({ 'name': 'status', 'text': 'Unresolve', 'value': 'unresolved', }) if status == GroupStatus.IGNORED: ignore_button.update({ 'text': 'Stop Ignoring', 'value': 'unresolved', }) option_groups = [] if teams: option_groups.append({ 'text': 'Teams', 'options': teams, }) if members: option_groups.append({ 'text': 'People', 'options': members, }) payload_actions = [ resolve_button, ignore_button, { 'name': 'assign', 'text': 'Select Assignee...', 'type': 'select', 'selected_options': [assignee], 'option_groups': option_groups, }, ] fields = [] if tags: event_tags = event.tags if event else group.get_latest_event().tags for key, value in event_tags: std_key = tagstore.get_standardized_key(key) if std_key not in tags: continue labeled_value = tagstore.get_tag_value_label(key, value) fields.append( { 'title': std_key.encode('utf-8'), 'value': labeled_value.encode('utf-8'), 'short': True, } ) if actions: action_texts = filter(None, [build_action_text(group, identity, a) for a in actions]) text += '\n' + '\n'.join(action_texts) color = ACTIONED_ISSUE_COLOR payload_actions = [] ts = group.last_seen if event: event_ts = event.datetime ts = max(ts, event_ts) footer = u'{}'.format(group.qualified_short_id) if rules: footer += u' via {}'.format(rules[0].label) if len(rules) > 1: footer += u' (+{} other)'.format(len(rules) - 1) return { 'fallback': u'[{}] {}'.format(group.project.slug, group.title), 'title': build_attachment_title(group, event), 'title_link': group.get_absolute_url(params={'referrer': 'slack'}), 'text': text, 'fields': fields, 'mrkdwn_in': ['text'], 'callback_id': json.dumps({'issue': group.id}), 'footer_icon': logo_url, 'footer': footer, 'ts': to_timestamp(ts), 'color': color, 'actions': payload_actions, }
def build_alert_payload(group, team_id=None, user_id=None, priority=None, event=None, tags=None, identity=None, actions=[], rules=None): priority = LEVEL_TO_PRIORITY.get(event.get_tag('level')) if not priority else priority description = build_attachment_text(group, event) or '' assignee = get_assignee(group) fields = [] if tags: event_tags = event.tags if event else group.get_latest_event().tags for key, value in event_tags: std_key = tagstore.get_standardized_key(key) if std_key not in tags: continue labeled_value = tagstore.get_tag_value_label(key, value) fields.append('%s:%s' % (std_key.encode('utf-8'), labeled_value.encode('utf-8'))) ts = group.last_seen if event: event_ts = event.datetime ts = max(ts, event_ts) footer = u'{}'.format(group.qualified_short_id) if rules: footer += u' via {}'.format(rules[0].label) if len(rules) > 1: footer += u' (+{} other)'.format(len(rules) - 1) return CreateAlertRequest( message = build_attachment_title(group, event), alias = 'sentry-%d' % group.id, description = description, responders = [ {"id": team_id, "type": "team"}, {"id": user_id, "type": "user"}, ], actions = actions, # these are custom actions on opsgenie, example: ["Restart", "AnExampleAction"] tags = fields, details = { 'Assignee': assignee or 'Not assigned to anyone yet', 'Sentry ID': str(group.id), 'Sentry Group': getattr(group, 'message_short', group.message).encode('utf-8'), 'Checksum': group.checksum, 'Project ID': group.project.slug, 'Project Name': group.project.name, 'Logger': group.logger, 'Level': group.get_level_display(), 'URL': group.get_absolute_url(params={'referrer': 'opsgenie'}), # don't foget to set system.url-prefix in config.yml 'Timestamp': str(ts), 'Trigerring Rules': footer }, entity = group.culprit, source = 'Sentry', priority = priority )
def build_group_attachment(group, event=None, tags=None, identity=None, actions=None, rules=None): # XXX(dcramer): options are limited to 100 choices, even when nested status = group.get_status() members = get_member_assignees(group) teams = get_team_assignees(group) logo_url = absolute_uri( get_asset_url('sentry', 'images/sentry-email-avatar.png')) color = LEVEL_TO_COLOR.get(event.get_tag('level'), 'error') if event else LEVEL_TO_COLOR['error'] text = build_attachment_text(group, event) or '' if actions is None: actions = [] assignee = get_assignee(group) resolve_button = { 'name': 'resolve_dialog', 'value': 'resolve_dialog', 'type': 'button', 'text': 'Resolve...', } ignore_button = { 'name': 'status', 'value': 'ignored', 'type': 'button', 'text': 'Ignore', } has_releases = Release.objects.filter( projects=group.project, organization_id=group.project.organization_id).exists() if not has_releases: resolve_button.update({ 'name': 'status', 'text': 'Resolve', 'value': 'resolved', }) if status == GroupStatus.RESOLVED: resolve_button.update({ 'name': 'status', 'text': 'Unresolve', 'value': 'unresolved', }) if status == GroupStatus.IGNORED: ignore_button.update({ 'text': 'Stop Ignoring', 'value': 'unresolved', }) option_groups = [] if teams: option_groups.append({ 'text': 'Teams', 'options': teams, }) if members: option_groups.append({ 'text': 'People', 'options': members, }) payload_actions = [ resolve_button, ignore_button, { 'name': 'assign', 'text': 'Select Assignee...', 'type': 'select', 'selected_options': [assignee], 'option_groups': option_groups, }, ] fields = [] if tags: event_tags = event.tags if event else group.get_latest_event().tags for key, value in event_tags: std_key = tagstore.get_standardized_key(key) if std_key not in tags: continue labeled_value = tagstore.get_tag_value_label(key, value) fields.append({ 'title': std_key.encode('utf-8'), 'value': labeled_value.encode('utf-8'), 'short': True, }) if actions: action_texts = filter( None, [build_action_text(group, identity, a) for a in actions]) text += '\n' + '\n'.join(action_texts) color = ACTIONED_ISSUE_COLOR payload_actions = [] ts = group.last_seen if event: event_ts = event.datetime ts = max(ts, event_ts) footer = u'{}'.format(group.qualified_short_id) if rules: footer += u' via {}'.format(rules[0].label) if len(rules) > 1: footer += u' (+{} other)'.format(len(rules) - 1) return { 'fallback': u'[{}] {}'.format(group.project.slug, group.title), 'title': build_attachment_title(group, event), 'title_link': group.get_absolute_url(params={'referrer': 'slack'}), 'text': text, 'fields': fields, 'mrkdwn_in': ['text'], 'callback_id': json.dumps({'issue': group.id}), 'footer_icon': logo_url, 'footer': footer, 'ts': to_timestamp(ts), 'color': color, 'actions': payload_actions, }
def get(self, request, organization): if not features.has( "organizations:events-v2", organization, actor=request.user): return Response(status=404) try: params = self.get_filter_params(request, organization) snuba_args = self.get_snuba_query_args(request, organization, params) except OrganizationEventsError as exc: return Response({"detail": exc.message}, status=400) except NoProjects: return Response({"detail": "A valid project must be included."}, status=400) try: key = self._validate_key(request) self._validate_project_ids(request, organization, snuba_args) except OrganizationEventsError as error: return Response({"detail": six.text_type(error)}, status=400) if key == PROJECT_KEY: colname = "project_id" conditions = snuba_args["conditions"] else: colname = get_snuba_column_name(key) conditions = snuba_args["conditions"] + [[ colname, "IS NOT NULL", None ]] top_values = raw_query( start=snuba_args["start"], end=snuba_args["end"], conditions=conditions, filter_keys=snuba_args["filter_keys"], groupby=[colname], aggregations=[("count()", None, "count")], orderby="-count", limit=TOP_VALUES_DEFAULT_LIMIT, referrer="api.organization-events-distribution", )["data"] projects = { p.id: p.slug for p in self.get_projects(request, organization) } if key == PROJECT_KEY: resp = { "key": PROJECT_KEY, "topValues": [{ "value": projects[v["project_id"]], "name": projects[v["project_id"]], "count": v["count"], } for v in top_values], } else: resp = { "key": key, "topValues": [{ "value": v[colname], "name": tagstore.get_tag_value_label(colname, v[colname]), "count": v["count"], } for v in top_values], } return Response(resp)
def get(self, request, organization): if not features.has( "organizations:events-v2", organization, actor=request.user): return Response(status=404) try: params = self.get_filter_params(request, organization) except OrganizationEventsError as error: raise ParseError(detail=six.text_type(error)) except NoProjects: return Response({"detail": "A valid project must be included."}, status=400) try: key = self._validate_key(request) self._validate_project_ids(request, organization, params) except OrganizationEventsError as error: raise ParseError(detail=six.text_type(error)) if key == PROJECT_KEY: colname = "project.id" elif key == "user": colname = "sentry:user" else: colname = key try: result = discover.query( selected_columns=[colname, "count()"], params=params, query=request.GET.get("query"), orderby="-count", limit=TOP_VALUES_DEFAULT_LIMIT, referrer="api.organization-events-distribution", ) except discover.InvalidSearchQuery as error: raise ParseError(detail=six.text_type(error)) if key == PROJECT_KEY: projects = { p.id: p.slug for p in self.get_projects(request, organization) } resp = { "key": PROJECT_KEY, "topValues": [{ "value": projects[v["project.id"]], "name": projects[v["project.id"]], "count": v["count"], } for v in result["data"]], } else: resp = { "key": key, "topValues": [{ "value": v[colname], "name": tagstore.get_tag_value_label(colname, v[colname]), "count": v["count"], } for v in result["data"]], } return Response(resp)
def build_group_attachment(group, event=None, tags=None, identity=None, actions=None, rules=None): # XXX(dcramer): options are limited to 100 choices, even when nested status = group.get_status() members = get_member_assignees(group) teams = get_team_assignees(group) logo_url = absolute_uri( get_asset_url("sentry", "images/sentry-email-avatar.png")) color = (LEVEL_TO_COLOR.get(event.get_tag("level"), "error") if event else LEVEL_TO_COLOR["error"]) text = build_attachment_text(group, event) or "" if actions is None: actions = [] assignee = get_assignee(group) resolve_button = { "name": "resolve_dialog", "value": "resolve_dialog", "type": "button", "text": "Resolve...", } ignore_button = { "name": "status", "value": "ignored", "type": "button", "text": "Ignore" } project = Project.objects.get_from_cache(id=group.project_id) cache_key = "has_releases:2:%s" % (project.id) has_releases = cache.get(cache_key) if has_releases is None: has_releases = ReleaseProject.objects.filter( project_id=project.id).exists() if has_releases: cache.set(cache_key, True, 3600) else: cache.set(cache_key, False, 60) if not has_releases: resolve_button.update({ "name": "status", "text": "Resolve", "value": "resolved" }) if status == GroupStatus.RESOLVED: resolve_button.update({ "name": "status", "text": "Unresolve", "value": "unresolved" }) if status == GroupStatus.IGNORED: ignore_button.update({"text": "Stop Ignoring", "value": "unresolved"}) option_groups = [] if teams: option_groups.append({"text": "Teams", "options": teams}) if members: option_groups.append({"text": "People", "options": members}) payload_actions = [ resolve_button, ignore_button, { "name": "assign", "text": "Select Assignee...", "type": "select", "selected_options": [assignee], "option_groups": option_groups, }, ] fields = [] if tags: event_tags = event.tags if event else group.get_latest_event().tags for key, value in event_tags: std_key = tagstore.get_standardized_key(key) if std_key not in tags: continue labeled_value = tagstore.get_tag_value_label(key, value) fields.append({ "title": std_key.encode("utf-8"), "value": labeled_value.encode("utf-8"), "short": True, }) if actions: action_texts = [ _f for _f in [build_action_text(group, identity, a) for a in actions] if _f ] text += "\n" + "\n".join(action_texts) color = ACTIONED_ISSUE_COLOR payload_actions = [] ts = group.last_seen if event: event_ts = event.datetime ts = max(ts, event_ts) footer = u"{}".format(group.qualified_short_id) if rules: footer += u" via {}".format(rules[0].label) if len(rules) > 1: footer += u" (+{} other)".format(len(rules) - 1) obj = event if event is not None else group return { "fallback": u"[{}] {}".format(project.slug, obj.title), "title": build_attachment_title(obj), "title_link": group.get_absolute_url(params={"referrer": "slack"}), "text": text, "fields": fields, "mrkdwn_in": ["text"], "callback_id": json.dumps({"issue": group.id}), "footer_icon": logo_url, "footer": footer, "ts": to_timestamp(ts), "color": color, "actions": payload_actions, }
def build_alert_payload(group, routing_key, severity=None, event=None, tags=None, identity=None, rules=None): severity = LEVEL_TO_SEVERITY.get( event.get_tag('level')) if not severity else severity description = build_attachment_text(group, event) or '' assignee = get_assignee(group) fields = [] if tags: event_tags = event.tags if event else group.get_latest_event().tags for key, value in event_tags: std_key = tagstore.get_standardized_key(key) if std_key not in tags: continue labeled_value = tagstore.get_tag_value_label(key, value) fields.append( '%s:%s' % (std_key.encode('utf-8'), labeled_value.encode('utf-8'))) ts = group.last_seen if event: event_ts = event.datetime ts = max(ts, event_ts) footer = u'{}'.format(group.qualified_short_id) if rules: footer += u' via {}'.format(rules[0].label) if len(rules) > 1: footer += u' (+{} other)'.format(len(rules) - 1) logo_url = absolute_uri( get_asset_url('sentry', 'images/sentry-email-avatar.png')) status = group.get_status() return { 'payload': { 'summary': build_attachment_title(group, event), 'timestamp': ts.strftime("%Y-%m-%dT%H:%M:%S.%fZ"), 'source': group.project.name, 'severity': severity, 'component': group.culprit, 'group': group.project.slug, 'class': group.title, 'custom_details': { 'Description': description, 'Assignee': assignee or 'Not assigned to anyone yet', 'Sentry ID': str(group.id), 'Sentry Group': getattr(group, 'message_short', group.message).encode('utf-8'), 'Checksum': group.checksum, 'Project ID': group.project.slug, 'Project Name': group.project.name, 'Logger': group.logger, 'Trigerring Rules': footer, 'Tags': fields, 'Status': GROUP_STATUS_VERBOSE.get(status, status), 'Number of times seen': group.times_seen, 'First seen': group.first_seen.strftime("%Y-%m-%dT%H:%M:%S.%fZ"), 'Number of users seen': group.count_users_seen(), } }, 'images': [{ 'src': logo_url, 'href': options.get("system.url-prefix"), 'alt': group.title, }], 'dedup_key': 'sentry-%s-%d' % (group.project.slug, group.id), 'event_action': 'trigger', 'client': 'Sentry', 'client_url': group.get_absolute_url(params={'referrer': 'pagerduty'}), 'routing_key': routing_key, }