def get(self, request, sentry_app): """ :qparam float since :qparam float until :qparam resolution - optional """ views = tsdb.get_range(model=tsdb.models.sentry_app_viewed, keys=[sentry_app.id], **self._parse_args(request))[sentry_app.id] component_interactions = tsdb.get_range( model=tsdb.models.sentry_app_component_interacted, keys=[ get_component_interaction_key(sentry_app, component.type) for component in sentry_app.components.all() ], **self._parse_args(request), ) return Response({ "views": views, "componentInteractions": {k.split(":")[1]: v for k, v in component_interactions.items()}, })
def get_attrs(self, item_list, user): attrs = super(StreamGroupSerializer, self).get_attrs(item_list, user) if self.stats_period: # we need to compute stats at 1d (1h resolution), and 14d group_ids = [g.id for g in item_list] segments, interval = self.STATS_PERIOD_CHOICES[self.stats_period] now = timezone.now() query_params = { 'start': now - ((segments - 1) * interval), 'end': now, 'rollup': int(interval.total_seconds()), } try: stats = tsdb.get_range( model=tsdb.models.group, keys=group_ids, environment_id=self.environment_id_func(), **query_params) except Environment.DoesNotExist: stats = { key: tsdb.make_series(0, **query_params) for key in group_ids } for item in item_list: attrs[item].update({ 'stats': stats[item.id], }) return attrs
def get(self, request, project, key_id): try: key = ProjectKey.objects.get( project=project, public_key=key_id, roles=ProjectKey.roles.store, ) except ProjectKey.DoesNotExist: raise ResourceDoesNotExist stat_args = self._parse_args(request) stats = OrderedDict() for model, name in ( (tsdb.models.key_total_received, 'total'), (tsdb.models.key_total_blacklisted, 'filtered'), (tsdb.models.key_total_rejected, 'dropped'), ): result = tsdb.get_range(model=model, keys=[key.id], **stat_args)[key.id] for ts, count in result: stats.setdefault(int(ts), {})[name] = count return Response( [ { 'ts': ts, 'total': data['total'], 'dropped': data['dropped'], 'filtered': data['filtered'], 'accepted': data['total'] - data['dropped'] - data['filtered'], } for ts, data in six.iteritems(stats) ] )
def get(self, request, project, key_id): try: key = ProjectKey.objects.get( project=project, public_key=key_id, roles=F('roles').bitor(ProjectKey.roles.store), ) except ProjectKey.DoesNotExist: raise ResourceDoesNotExist stat_args = self._parse_args(request) stats = OrderedDict() for model, name in ( (tsdb.models.key_total_received, 'total'), (tsdb.models.key_total_blacklisted, 'filtered'), (tsdb.models.key_total_rejected, 'dropped'), ): result = tsdb.get_range(model=model, keys=[key.id], **stat_args)[key.id] for ts, count in result: stats.setdefault(int(ts), {})[name] = count return Response([{ 'ts': ts, 'total': data['total'], 'dropped': data['dropped'], 'filtered': data['filtered'], 'accepted': data['total'] - data['dropped'] - data['filtered'], } for ts, data in six.iteritems(stats)])
def get(self, request, project, hook_id): try: hook = ServiceHook.objects.get( project_id=project.id, guid=hook_id, ) except ServiceHook.DoesNotExist: raise ResourceDoesNotExist stat_args = self._parse_args(request) stats = OrderedDict() for model, name in ( (tsdb.models.servicehook_fired, 'total'), ): result = tsdb.get_range(model=model, keys=[hook.id], **stat_args)[hook.id] for ts, count in result: stats.setdefault(int(ts), {})[name] = count return self.respond([ { 'ts': ts, 'total': data['total'], } for ts, data in six.iteritems(stats) ])
def get(self, request, team): """ Retrieve Event Counts for a Team ```````````````````````````````` .. caution:: This endpoint may change in the future without notice. Return a set of points representing a normalized timestamp and the number of events seen in the period. Query ranges are limited to Sentry's configured time-series resolutions. :pparam string organization_slug: the slug of the organization. :pparam string team_slug: the slug of the team. :qparam string stat: the name of the stat to query (``"received"``, ``"rejected"``) :qparam timestamp since: a timestamp to set the start of the query in seconds since UNIX epoch. :qparam timestamp until: a timestamp to set the end of the query in seconds since UNIX epoch. :qparam string resolution: an explicit resolution to search for (eg: ``10s``). This should not be used unless you are familiar with Sentry's internals as it's restricted to pre-defined values. :auth: required """ try: environment_id = self._get_environment_id_from_request( request, team.organization_id, ) except Environment.DoesNotExist: raise ResourceDoesNotExist projects = Project.objects.get_for_user( team=team, user=request.user, ) if not projects: return Response([]) data = list( tsdb.get_range( model=tsdb.models.project, keys=[p.id for p in projects], **self._parse_args(request, environment_id) ).values() ) summarized = [] for n in range(len(data[0])): total = sum(d[n][1] for d in data) summarized.append((data[0][n][0], total)) return Response(summarized)
def get(self, request, project): """ Retrieve Event Counts for a Project ``````````````````````````````````` .. caution:: This endpoint may change in the future without notice. Return a set of points representing a normalized timestamp and the number of events seen in the period. Query ranges are limited to Sentry's configured time-series resolutions. :pparam string organization_slug: the slug of the organization. :pparam string project_slug: the slug of the project. :qparam string stat: the name of the stat to query (``"received"``, ``"rejected"``, ``"blacklisted"``, ``generated``) :qparam timestamp since: a timestamp to set the start of the query in seconds since UNIX epoch. :qparam timestamp until: a timestamp to set the end of the query in seconds since UNIX epoch. :qparam string resolution: an explicit resolution to search for (eg: ``10s``). This should not be used unless you are familiar with Sentry's internals as it's restricted to pre-defined values. :auth: required """ stat = request.GET.get('stat', 'received') query_kwargs = {} if stat == 'received': stat_model = tsdb.models.project_total_received elif stat == 'rejected': stat_model = tsdb.models.project_total_rejected elif stat == 'blacklisted': stat_model = tsdb.models.project_total_blacklisted elif stat == 'generated': stat_model = tsdb.models.project try: query_kwargs['environment_id'] = self._get_environment_id_from_request( request, project.organization_id, ) except Environment.DoesNotExist: raise ResourceDoesNotExist elif stat == 'forwarded': stat_model = tsdb.models.project_total_forwarded else: try: stat_model = FILTER_STAT_KEYS_TO_VALUES[stat] except KeyError: raise ValueError('Invalid stat: %s' % stat) data = tsdb.get_range( model=stat_model, keys=[project.id], **self._parse_args(request, **query_kwargs) )[project.id] return Response(data)
def get(self, request): key = request.GET["key"] data = tsdb.get_range(model=tsdb.models.internal, keys=[key], **self._parse_args(request))[key] return Response(data)
def get(self, request): key = request.GET['key'] data = tsdb.get_range( model=tsdb.models.internal, keys=[key], **self._parse_args(request) )[key] return Response(data)
def get(self, request, group): data = tsdb.get_range( model=tsdb.models.group, keys=[group.id], **self._parse_args(request) )[group.id] return Response(data)
def get(self, request, project): """ Retrieve Event Counts for a Project ``````````````````````````````````` .. caution:: This endpoint may change in the future without notice. Return a set of points representing a normalized timestamp and the number of events seen in the period. Query ranges are limited to Sentry's configured time-series resolutions. :pparam string organization_slug: the slug of the organization. :pparam string project_slug: the slug of the project. :qparam string stat: the name of the stat to query (``"received"``, ``"rejected"``, ``"blacklisted"``, ``generated``) :qparam timestamp since: a timestamp to set the start of the query in seconds since UNIX epoch. :qparam timestamp until: a timestamp to set the end of the query in seconds since UNIX epoch. :qparam string resolution: an explicit resolution to search for (one of ``10s``, ``1h``, and ``1d``) :auth: required """ stat = request.GET.get('stat', 'received') query_kwargs = {} if stat == 'received': stat_model = tsdb.models.project_total_received elif stat == 'rejected': stat_model = tsdb.models.project_total_rejected elif stat == 'blacklisted': stat_model = tsdb.models.project_total_blacklisted elif stat == 'generated': stat_model = tsdb.models.project try: query_kwargs[ 'environment_id'] = self._get_environment_id_from_request( request, project.organization_id, ) except Environment.DoesNotExist: raise ResourceDoesNotExist elif stat == 'forwarded': stat_model = tsdb.models.project_total_forwarded else: try: stat_model = FILTER_STAT_KEYS_TO_VALUES[stat] except KeyError: raise ValueError('Invalid stat: %s' % stat) data = tsdb.get_range(model=stat_model, keys=[project.id], **self._parse_args(request, **query_kwargs))[project.id] return Response(data)
def get(self, request, team): """ Retrieve Event Counts for a Team ```````````````````````````````` .. caution:: This endpoint may change in the future without notice. Return a set of points representing a normalized timestamp and the number of events seen in the period. Query ranges are limited to Sentry's configured time-series resolutions. :pparam string organization_slug: the slug of the organization. :pparam string team_slug: the slug of the team. :qparam string stat: the name of the stat to query (``"received"``, ``"rejected"``) :qparam timestamp since: a timestamp to set the start of the query in seconds since UNIX epoch. :qparam timestamp until: a timestamp to set the end of the query in seconds since UNIX epoch. :qparam string resolution: an explicit resolution to search for (eg: ``10s``). This should not be used unless you are familiar with Sentry's internals as it's restricted to pre-defined values. :auth: required """ try: environment_id = self._get_environment_id_from_request( request, team.organization_id, ) except Environment.DoesNotExist: raise ResourceDoesNotExist projects = Project.objects.get_for_user( team=team, user=request.user, ) if not projects: return Response([]) data = list( tsdb.get_range(model=tsdb.models.project, keys=[p.id for p in projects], **self._parse_args(request, environment_id)).values()) summarized = [] for n in range(len(data[0])): total = sum(d[n][1] for d in data) summarized.append((data[0][n][0], total)) return Response(summarized)
def with_event_counts(project_list): end = timezone.now() start = end - datetime.timedelta(days=1) tsdb_results = tsdb.get_range( model=tsdb.models.project, keys=[p.id for p in project_list], start=start, end=end ) for project in project_list: yield project, sum(t[1] for t in tsdb_results[project.id])
def get_attrs(self, item_list, user): project_ids = [i.id for i in item_list] if user.is_authenticated() and item_list: bookmarks = set( ProjectBookmark.objects.filter( user=user, project_id__in=project_ids, ).values_list('project_id', flat=True)) user_options = { (u.project_id, u.key): u.value for u in UserOption.objects.filter( Q(user=user, project__in=item_list, key='mail:alert') | Q(user=user, key='subscribe_by_default', project__isnull=True)) } default_subscribe = (user_options.get('subscribe_by_default', '1') == '1') else: bookmarks = set() user_options = {} default_subscribe = False if self.stats_period: # we need to compute stats at 1d (1h resolution), and 14d project_ids = [o.id for o in item_list] segments, interval = STATS_PERIOD_CHOICES[self.stats_period] now = timezone.now() stats = tsdb.get_range( model=tsdb.models.project, keys=project_ids, end=now, start=now - ((segments - 1) * interval), rollup=int(interval.total_seconds()), environment_id=self.environment_id, ) else: stats = None result = self.get_access_by_project(item_list, user) for item in item_list: result[item].update({ 'is_bookmarked': item.id in bookmarks, 'is_subscribed': bool( user_options.get( (item.id, 'mail:alert'), default_subscribe, )), }) if stats: result[item]['stats'] = stats[item.id] return result
def attach_metadata(self, objects, request=None): from sentry.templatetags.sentry_plugins import handle_before_events attach_foreignkey(objects, Group.project, ['team']) GroupMeta.objects.populate_cache(objects) if request and objects: handle_before_events(request, objects) if request and request.user.is_authenticated() and objects: bookmarks = set( GroupBookmark.objects.filter( user=request.user, group__in=objects, ).values_list('group_id', flat=True)) seen_groups = dict( GroupSeen.objects.filter( user=request.user, group__in=objects, ).values_list('group_id', 'last_seen')) else: bookmarks = set() seen_groups = {} if objects: end = timezone.now() start = end - timedelta(days=1) historical_data = tsdb.get_range( model=tsdb.models.group, keys=[g.id for g in objects], start=start, end=end, ) else: historical_data = {} user_tagkeys = GroupTagKey.objects.filter( group_id__in=[o.id for o in objects], key='sentry:user', ) user_counts = {} for user_tagkey in user_tagkeys: user_counts[user_tagkey.group_id] = user_tagkey.values_seen for g in objects: g.is_bookmarked = g.pk in bookmarks g.historical_data = [x[1] for x in historical_data.get(g.id, [])] active_date = g.active_at or g.first_seen g.has_seen = seen_groups.get(g.id, active_date) > active_date g.annotations = [{ 'label': 'users', 'count': user_counts.get(g.id, 0), }]
def get_attrs(self, item_list, user): project_ids = [i.id for i in item_list] if user.is_authenticated() and item_list: bookmarks = set( ProjectBookmark.objects.filter( user=user, project_id__in=project_ids, ).values_list('project_id', flat=True) ) user_options = { (u.project_id, u.key): u.value for u in UserOption.objects.filter( Q(user=user, project__in=item_list, key='mail:alert') | Q(user=user, key='subscribe_by_default', project__isnull=True) ) } default_subscribe = (user_options.get( 'subscribe_by_default', '1') == '1') else: bookmarks = set() user_options = {} default_subscribe = False if self.stats_period: # we need to compute stats at 1d (1h resolution), and 14d project_ids = [o.id for o in item_list] segments, interval = STATS_PERIOD_CHOICES[self.stats_period] now = timezone.now() stats = tsdb.get_range( model=tsdb.models.project_total_received, keys=project_ids, end=now, start=now - ((segments - 1) * interval), rollup=int(interval.total_seconds()), ) else: stats = None result = {} for item in item_list: result[item] = { 'is_bookmarked': item.id in bookmarks, 'is_subscribed': bool(user_options.get( (item.id, 'mail:alert'), default_subscribe, )), } if stats: result[item]['stats'] = stats[item.id] return result
def with_event_counts(project_list): end = timezone.now() start = end - datetime.timedelta(days=1) tsdb_results = tsdb.get_range( model=tsdb.models.project, keys=[p.id for p in project_list], start=start, end=end, ) for project in project_list: yield project, sum(t[1] for t in tsdb_results[project.id])
def get(self, request, group): try: environment_id = self._get_environment_id_from_request( request, group.project.organization_id) except Environment.DoesNotExist: raise ResourceDoesNotExist data = tsdb.get_range(model=tsdb.models.group, keys=[group.id], **self._parse_args(request, environment_id))[group.id] return Response(data)
def get(self, request, project): """ Retrieve Event Counts for a Project ``````````````````````````````````` .. caution:: This endpoint may change in the future without notice. Return a set of points representing a normalized timestamp and the number of events seen in the period. Query ranges are limited to Sentry's configured time-series resolutions. :pparam string organization_slug: the slug of the organization. :pparam string project_slug: the slug of the project. :qparam string stat: the name of the stat to query (``"received"``, ``"rejected"``, ``"blacklisted"``, ``generated``) :qparam timestamp since: a timestamp to set the start of the query in seconds since UNIX epoch. :qparam timestamp until: a timestamp to set the end of the query in seconds since UNIX epoch. :qparam string resolution: an explicit resolution to search for (eg: ``10s``). This should not be used unless you are familiar with Sentry's internals as it's restricted to pre-defined values. :auth: required """ stat = request.GET.get('stat', 'received') if stat == 'received': stat_model = tsdb.models.project_total_received elif stat == 'rejected': stat_model = tsdb.models.project_total_rejected elif stat == 'blacklisted': stat_model = tsdb.models.project_total_blacklisted elif stat == 'generated': stat_model = tsdb.models.project elif stat == 'forwarded': stat_model = tsdb.models.project_total_forwarded else: try: stat_model = FILTER_STAT_KEYS_TO_VALUES[stat] except KeyError: raise ValueError('Invalid stat: %s' % stat) data = tsdb.get_range(model=stat_model, keys=[project.id], **self._parse_args(request))[project.id] return Response(data)
def query_tsdb(self, group_ids, query_params, **kwargs): try: environment = self.environment_func() except Environment.DoesNotExist: stats = {key: tsdb.make_series(0, **query_params) for key in group_ids} else: stats = tsdb.get_range( model=tsdb.models.group, keys=group_ids, environment_ids=environment and [environment.id], **query_params, ) return stats
def query_tsdb(self, group_ids, query_params): try: environment = self.environment_func() except Environment.DoesNotExist: stats = {key: tsdb.make_series(0, **query_params) for key in group_ids} else: stats = tsdb.get_range( model=tsdb.models.group, keys=group_ids, environment_ids=environment and [environment.id], **query_params ) return stats
def get(self, request, group): try: environment_id = self._get_environment_id_from_request( request, group.project.organization_id, ) except Environment.DoesNotExist: raise ResourceDoesNotExist data = tsdb.get_range( model=tsdb.models.group, keys=[group.id], **self._parse_args( request, environment_id, ) )[group.id] return Response(data)
def get(self, request, project, key_id): try: key = ProjectKey.objects.get( project=project, public_key=key_id, roles=F('roles').bitor(ProjectKey.roles.store), ) except ProjectKey.DoesNotExist: raise ResourceDoesNotExist try: stat_args = self._parse_args(request) except ValueError: return Response({'detail': 'Invalid request data'}, status=400) stats = OrderedDict() for model, name in ( (tsdb.models.key_total_received, 'total'), (tsdb.models.key_total_blacklisted, 'filtered'), (tsdb.models.key_total_rejected, 'dropped'), ): # XXX (alex, 08/05/19) key stats were being stored under either key_id or str(key_id) # so merge both of those back into one stats result. result = tsdb.get_range(model=model, keys=[key.id, six.text_type(key.id)], **stat_args) for key_id, points in six.iteritems(result): for ts, count in points: bucket = stats.setdefault(int(ts), {}) bucket.setdefault(name, 0) bucket[name] += count return Response([{ 'ts': ts, 'total': data['total'], 'dropped': data['dropped'], 'filtered': data['filtered'], 'accepted': data['total'] - data['dropped'] - data['filtered'], } for ts, data in six.iteritems(stats)])
def get(self, request: Request, project, key_id) -> Response: try: key = ProjectKey.objects.get(project=project, public_key=key_id, roles=F("roles").bitor( ProjectKey.roles.store)) except ProjectKey.DoesNotExist: raise ResourceDoesNotExist try: stat_args = self._parse_args(request) except ValueError: return Response({"detail": "Invalid request data"}, status=400) stats = OrderedDict() for model, name in ( (tsdb.models.key_total_received, "total"), (tsdb.models.key_total_blacklisted, "filtered"), (tsdb.models.key_total_rejected, "dropped"), ): # XXX (alex, 08/05/19) key stats were being stored under either key_id or str(key_id) # so merge both of those back into one stats result. result = tsdb.get_range(model=model, keys=[key.id, str(key.id)], **stat_args) for key_id, points in result.items(): for ts, count in points: bucket = stats.setdefault(int(ts), {}) bucket.setdefault(name, 0) bucket[name] += count return Response([{ "ts": ts, "total": data["total"], "dropped": data["dropped"], "filtered": data["filtered"], "accepted": data["total"] - data["dropped"] - data["filtered"], } for ts, data in stats.items()])
def get(self, request, project, key_id): try: key = ProjectKey.objects.get( project=project, public_key=key_id, roles=F('roles').bitor(ProjectKey.roles.store), ) except ProjectKey.DoesNotExist: raise ResourceDoesNotExist stat_args = self._parse_args(request) stats = OrderedDict() for model, name in ( (tsdb.models.key_total_received, 'total'), (tsdb.models.key_total_blacklisted, 'filtered'), (tsdb.models.key_total_rejected, 'dropped'), ): # XXX (alex, 08/05/19) key stats were being stored under either key_id or str(key_id) # so merge both of those back into one stats result. result = tsdb.get_range(model=model, keys=[key.id, six.text_type(key.id)], **stat_args) for key_id, points in six.iteritems(result): for ts, count in points: bucket = stats.setdefault(int(ts), {}) bucket.setdefault(name, 0) bucket[name] += count return Response( [ { 'ts': ts, 'total': data['total'], 'dropped': data['dropped'], 'filtered': data['filtered'], 'accepted': data['total'] - data['dropped'] - data['filtered'], } for ts, data in six.iteritems(stats) ] )
def get_attrs(self, item_list, user): attrs = super(StreamGroupSerializer, self).get_attrs(item_list, user) if self.stats_period: # we need to compute stats at 1d (1h resolution), and 14d group_ids = [g.id for g in item_list] segments, interval = self.STATS_PERIOD_CHOICES[self.stats_period] now = timezone.now() stats = tsdb.get_range( model=tsdb.models.group, keys=group_ids, end=now, start=now - ((segments - 1) * interval), rollup=int(interval.total_seconds()), ) for item in item_list: attrs[item].update({ 'stats': stats[item.id], }) return attrs
def get_attrs(self, item_list, user): attrs = super(StreamGroupSerializer, self).get_attrs(item_list, user) if self.stats_period: # we need to compute stats at 1d (1h resolution), and 14d group_ids = [g.id for g in item_list] segments, interval = self.STATS_PERIOD_CHOICES[self.stats_period] now = timezone.now() stats = tsdb.get_range( model=tsdb.models.group, keys=group_ids, end=now, start=now - ((segments - 1) * interval), rollup=int(interval.total_seconds()), ) for item in item_list: attrs[item].update({ 'stats': stats[item.id], }) return attrs
def get_attrs(self, item_list, user): project_ids = [i.id for i in item_list] if user.is_authenticated() and item_list: bookmarks = set( ProjectBookmark.objects.filter( user=user, project_id__in=project_ids).values_list("project_id", flat=True)) user_options = { (u.project_id, u.key): u.value for u in UserOption.objects.filter( Q(user=user, project__in=item_list, key="mail:alert") | Q(user=user, key="subscribe_by_default", project__isnull=True)) } default_subscribe = user_options.get("subscribe_by_default", "1") == "1" else: bookmarks = set() user_options = {} default_subscribe = False if self.stats_period: # we need to compute stats at 1d (1h resolution), and 14d project_ids = [o.id for o in item_list] segments, interval = STATS_PERIOD_CHOICES[self.stats_period] now = timezone.now() stats = tsdb.get_range( model=tsdb.models.project, keys=project_ids, end=now, start=now - ((segments - 1) * interval), rollup=int(interval.total_seconds()), environment_ids=self.environment_id and [self.environment_id], ) else: stats = None avatars = { a.project_id: a for a in ProjectAvatar.objects.filter(project__in=item_list) } project_ids = [i.id for i in item_list] platforms = ProjectPlatform.objects.filter( project_id__in=project_ids).values_list("project_id", "platform") platforms_by_project = defaultdict(list) for project_id, platform in platforms: platforms_by_project[project_id].append(platform) result = self.get_access_by_project(item_list, user) for item in item_list: result[item].update({ "is_bookmarked": item.id in bookmarks, "is_subscribed": bool( user_options.get((item.id, "mail:alert"), default_subscribe)), "avatar": avatars.get(item.id), "platforms": platforms_by_project[item.id], }) if stats: result[item]["stats"] = stats[item.id] return result
def get(self, request, group): """ Retrieve an Issue ````````````````` Return details on an individual issue. This returns the basic stats for the issue (title, last seen, first seen), some overall numbers (number of comments, user reports) as well as the summarized event data. :pparam string issue_id: the ID of the issue to retrieve. :auth: required """ # TODO(dcramer): handle unauthenticated/public response data = serialize(group, request.user) # TODO: these probably should be another endpoint activity = self._get_activity(request, group, num=100) seen_by = self._get_seen_by(request, group) # find first seen release if group.first_release is None: try: first_release = GroupTagValue.objects.filter( group=group, key__in=('sentry:release', 'release'), ).order_by('first_seen')[0] except IndexError: first_release = None else: first_release = first_release.value else: first_release = group.first_release.version if first_release is not None: # find last seen release try: last_release = GroupTagValue.objects.filter( group=group, key__in=('sentry:release', 'release'), ).order_by('-last_seen')[0] except IndexError: last_release = None else: last_release = last_release.value else: last_release = None action_list = self._get_actions(request, group) now = timezone.now() hourly_stats = tsdb.rollup( tsdb.get_range( model=tsdb.models.group, keys=[group.id], end=now, start=now - timedelta(days=1), ), 3600)[group.id] daily_stats = tsdb.rollup( tsdb.get_range( model=tsdb.models.group, keys=[group.id], end=now, start=now - timedelta(days=30), ), 3600 * 24)[group.id] if first_release: first_release = self._get_release_info(request, group, first_release) if last_release: last_release = self._get_release_info(request, group, last_release) tags = list(GroupTagKey.objects.filter(group=group, )[:100]) participants = list( User.objects.filter( groupsubscription__is_active=True, groupsubscription__group=group, )) data.update({ 'firstRelease': first_release, 'lastRelease': last_release, 'activity': serialize(activity, request.user), 'seenBy': seen_by, 'participants': serialize(participants, request.user), 'pluginActions': action_list, 'pluginIssues': self._get_available_issue_plugins(request, group), 'pluginContexts': self._get_context_plugins(request, group), 'userReportCount': UserReport.objects.filter(group=group).count(), 'tags': sorted(serialize(tags, request.user), key=lambda x: x['name']), 'stats': { '24h': hourly_stats, '30d': daily_stats, } }) return Response(data)
def get(self, request, group): """ Retrieve an Issue ````````````````` Return details on an individual issue. This returns the basic stats for the issue (title, last seen, first seen), some overall numbers (number of comments, user reports) as well as the summarized event data. :pparam string issue_id: the ID of the issue to retrieve. :auth: required """ # TODO(dcramer): handle unauthenticated/public response data = serialize(group, request.user) # TODO: these probably should be another endpoint activity = self._get_activity(request, group, num=100) seen_by = self._get_seen_by(request, group) first_release = group.get_first_release() if first_release is not None: last_release = group.get_last_release() else: last_release = None action_list = self._get_actions(request, group) now = timezone.now() hourly_stats = tsdb.rollup( tsdb.get_range( model=tsdb.models.group, keys=[group.id], end=now, start=now - timedelta(days=1), ), 3600)[group.id] daily_stats = tsdb.rollup( tsdb.get_range( model=tsdb.models.group, keys=[group.id], end=now, start=now - timedelta(days=30), ), 3600 * 24)[group.id] if first_release: first_release = self._get_release_info(request, group, first_release) if last_release: last_release = self._get_release_info(request, group, last_release) try: environment_id = self._get_environment_id_from_request( request, group.project.organization_id) except Environment.DoesNotExist: tags = [] else: tags = tagstore.get_group_tag_keys(group.project_id, group.id, environment_id, limit=100) participants = list( User.objects.filter( groupsubscription__is_active=True, groupsubscription__group=group, )) data.update({ 'firstRelease': first_release, 'lastRelease': last_release, 'activity': serialize(activity, request.user), 'seenBy': seen_by, 'participants': serialize(participants, request.user), 'pluginActions': action_list, 'pluginIssues': self._get_available_issue_plugins(request, group), 'pluginContexts': self._get_context_plugins(request, group), 'userReportCount': UserReport.objects.filter(group=group).count(), 'tags': sorted(serialize(tags, request.user), key=lambda x: x['name']), 'stats': { '24h': hourly_stats, '30d': daily_stats, } }) return Response(data)
def get(self, request, organization): """ Retrieve Event Counts for an Organization ````````````````````````````````````````` .. caution:: This endpoint may change in the future without notice. Return a set of points representing a normalized timestamp and the number of events seen in the period. :pparam string organization_slug: the slug of the organization for which the stats should be retrieved. :qparam string stat: the name of the stat to query (``"received"``, ``"rejected"``, ``"blacklisted"``) :qparam timestamp since: a timestamp to set the start of the query in seconds since UNIX epoch. :qparam timestamp until: a timestamp to set the end of the query in seconds since UNIX epoch. :qparam string resolution: an explicit resolution to search for (one of ``10s``, ``1h``, and ``1d``) :auth: required """ group = request.GET.get("group", "organization") if group == "organization": keys = [organization.id] elif group == "project": team_list = Team.objects.get_for_user(organization=organization, user=request.user) project_ids = request.GET.getlist("projectID") if not project_ids: project_list = [] for team in team_list: project_list.extend( Project.objects.get_for_user(team=team, user=request.user)) else: project_list = Project.objects.filter(teams__in=team_list, id__in=project_ids) keys = list({p.id for p in project_list}) else: raise ValueError("Invalid group: %s" % group) if "id" in request.GET: id_filter_set = frozenset(map(int, request.GET.getlist("id"))) keys = [k for k in keys if k in id_filter_set] if not keys: return Response([]) stat_model = None stat = request.GET.get("stat", "received") query_kwargs = {} if stat == "received": if group == "project": stat_model = tsdb.models.project_total_received else: stat_model = tsdb.models.organization_total_received elif stat == "rejected": if group == "project": stat_model = tsdb.models.project_total_rejected else: stat_model = tsdb.models.organization_total_rejected elif stat == "blacklisted": if group == "project": stat_model = tsdb.models.project_total_blacklisted else: stat_model = tsdb.models.organization_total_blacklisted elif stat == "generated": if group == "project": stat_model = tsdb.models.project try: query_kwargs[ "environment_id"] = self._get_environment_id_from_request( request, organization.id) except Environment.DoesNotExist: raise ResourceDoesNotExist if stat_model is None: raise ValueError("Invalid group: %s, stat: %s" % (group, stat)) data = tsdb.get_range(model=stat_model, keys=keys, **self._parse_args(request, **query_kwargs)) if group == "organization": data = data[organization.id] return Response(data)
def attach_metadata(self, objects, request=None): from sentry.templatetags.sentry_plugins import handle_before_events attach_foreignkey(objects, Group.project, ['team']) GroupMeta.objects.populate_cache(objects) if request and objects: handle_before_events(request, objects) if request and request.user.is_authenticated() and objects: bookmarks = set( GroupBookmark.objects.filter( user=request.user, group__in=objects, ).values_list('group_id', flat=True)) seen_groups = dict( GroupSeen.objects.filter( user=request.user, group__in=objects, ).values_list('group_id', 'last_seen')) else: bookmarks = set() seen_groups = {} if objects: end = timezone.now() start = end - timedelta(days=1) historical_data = tsdb.get_range( model=tsdb.models.group, keys=[g.id for g in objects], start=start, end=end, ) else: historical_data = {} project_list = set(o.project for o in objects) tag_keys = set(['sentry:user']) project_annotations = {} for project in project_list: enabled_annotations = ProjectOption.objects.get_value( project, 'annotations', ['sentry:user']) project_annotations[project] = enabled_annotations tag_keys.update(enabled_annotations) annotation_counts = defaultdict(dict) annotation_results = GroupTagKey.objects.filter( group__in=objects, key__in=tag_keys, ).values_list('key', 'group', 'values_seen') for key, group_id, values_seen in annotation_results: annotation_counts[key][group_id] = values_seen for g in objects: g.is_bookmarked = g.pk in bookmarks g.historical_data = [x[1] for x in historical_data.get(g.id, [])] active_date = g.active_at or g.first_seen g.has_seen = seen_groups.get(g.id, active_date) > active_date g.annotations = [] for key in sorted(tag_keys): if key in project_annotations[project]: label = TAG_LABELS.get(key, key.replace('_', ' ')).lower() + 's' try: value = annotation_counts[key].get(g.id, 0) except KeyError: value = 0 g.annotations.append({ 'label': label, 'count': value, })
def attach_metadata(self, objects, request=None): from sentry.templatetags.sentry_plugins import handle_before_events attach_foreignkey(objects, Group.project, ['team']) GroupMeta.objects.populate_cache(objects) if request and objects: handle_before_events(request, objects) if request and request.user.is_authenticated() and objects: bookmarks = set(GroupBookmark.objects.filter( user=request.user, group__in=objects, ).values_list('group_id', flat=True)) seen_groups = dict(GroupSeen.objects.filter( user=request.user, group__in=objects, ).values_list('group_id', 'last_seen')) else: bookmarks = set() seen_groups = {} if objects: end = timezone.now() start = end - timedelta(days=1) historical_data = tsdb.get_range( model=tsdb.models.group, keys=[g.id for g in objects], start=start, end=end, ) else: historical_data = {} project_list = set(o.project for o in objects) tag_keys = set(['sentry:user']) project_annotations = {} for project in project_list: enabled_annotations = ProjectOption.objects.get_value( project, 'annotations', ['sentry:user']) project_annotations[project] = enabled_annotations tag_keys.update(enabled_annotations) annotation_counts = defaultdict(dict) annotation_results = GroupTagKey.objects.filter( group__in=objects, key__in=tag_keys, ).values_list('key', 'group', 'values_seen') for key, group_id, values_seen in annotation_results: annotation_counts[key][group_id] = values_seen for g in objects: g.is_bookmarked = g.pk in bookmarks g.historical_data = [x[1] for x in historical_data.get(g.id, [])] active_date = g.active_at or g.first_seen g.has_seen = seen_groups.get(g.id, active_date) > active_date g.annotations = [] for key in sorted(tag_keys): if key in project_annotations[project]: label = TAG_LABELS.get(key, key.replace('_', ' ')).lower() + 's' try: value = annotation_counts[key].get(g.id, 0) except KeyError: value = 0 g.annotations.append({ 'label': label, 'count': value, })
def get_attrs(self, item_list, user): project_ids = [i.id for i in item_list] if user.is_authenticated() and item_list: bookmarks = set( ProjectBookmark.objects.filter( user=user, project_id__in=project_ids, ).values_list('project_id', flat=True) ) user_options = { (u.project_id, u.key): u.value for u in UserOption.objects.filter( Q(user=user, project__in=item_list, key='mail:alert') | Q(user=user, key='subscribe_by_default', project__isnull=True) ) } default_subscribe = (user_options.get( 'subscribe_by_default', '1') == '1') else: bookmarks = set() user_options = {} default_subscribe = False if self.stats_period: # we need to compute stats at 1d (1h resolution), and 14d project_ids = [o.id for o in item_list] segments, interval = STATS_PERIOD_CHOICES[self.stats_period] now = timezone.now() stats = tsdb.get_range( model=tsdb.models.project, keys=project_ids, end=now, start=now - ((segments - 1) * interval), rollup=int(interval.total_seconds()), environment_id=self.environment_id, ) else: stats = None avatars = {a.project_id: a for a in ProjectAvatar.objects.filter(project__in=item_list)} project_ids = [i.id for i in item_list] platforms = ProjectPlatform.objects.filter( project_id__in=project_ids, ).values_list('project_id', 'platform') platforms_by_project = defaultdict(list) for project_id, platform in platforms: platforms_by_project[project_id].append(platform) result = self.get_access_by_project(item_list, user) for item in item_list: result[item].update({ 'is_bookmarked': item.id in bookmarks, 'is_subscribed': bool(user_options.get( (item.id, 'mail:alert'), default_subscribe, )), 'avatar': avatars.get(item.id), 'platforms': platforms_by_project[item.id] }) if stats: result[item]['stats'] = stats[item.id] return result
def get(self, request, organization): """ Retrieve Event Counts for an Organization ````````````````````````````````````````` .. caution:: This endpoint may change in the future without notice. Return a set of points representing a normalized timestamp and the number of events seen in the period. :pparam string organization_slug: the slug of the organization for which the stats should be retrieved. :qparam string stat: the name of the stat to query (``"received"``, ``"rejected"``, ``"blacklisted"``) :qparam timestamp since: a timestamp to set the start of the query in seconds since UNIX epoch. :qparam timestamp until: a timestamp to set the end of the query in seconds since UNIX epoch. :qparam string resolution: an explicit resolution to search for (eg: ``10s``). This should not be used unless you are familiar with Sentry's internals as it's restricted to pre-defined values. :auth: required """ group = request.GET.get('group', 'organization') if group == 'organization': keys = [organization.id] elif group == 'project': team_list = Team.objects.get_for_user( organization=organization, user=request.user, ) project_list = [] for team in team_list: project_list.extend( Project.objects.get_for_user( team=team, user=request.user, )) keys = list({p.id for p in project_list}) else: raise ValueError('Invalid group: %s' % group) if 'id' in request.GET: id_filter_set = frozenset(map(int, request.GET.getlist('id'))) keys = [k for k in keys if k in id_filter_set] if not keys: return Response([]) stat_model = None stat = request.GET.get('stat', 'received') query_kwargs = {} if stat == 'received': if group == 'project': stat_model = tsdb.models.project_total_received else: stat_model = tsdb.models.organization_total_received elif stat == 'rejected': if group == 'project': stat_model = tsdb.models.project_total_rejected else: stat_model = tsdb.models.organization_total_rejected elif stat == 'blacklisted': if group == 'project': stat_model = tsdb.models.project_total_blacklisted else: stat_model = tsdb.models.organization_total_blacklisted elif stat == 'generated': if group == 'project': stat_model = tsdb.models.project try: query_kwargs[ 'environment_id'] = self._get_environment_id_from_request( request, organization.id, ) except Environment.DoesNotExist: raise ResourceDoesNotExist if stat_model is None: raise ValueError('Invalid group: %s, stat: %s' % (group, stat)) data = tsdb.get_range(model=stat_model, keys=keys, **self._parse_args(request, **query_kwargs)) if group == 'organization': data = data[organization.id] return Response(data)
def get(self, request, group): """ Retrieve an Issue ````````````````` Return details on an individual issue. This returns the basic stats for the issue (title, last seen, first seen), some overall numbers (number of comments, user reports) as well as the summarized event data. :pparam string issue_id: the ID of the issue to retrieve. :auth: required """ # TODO(dcramer): handle unauthenticated/public response data = serialize(group, request.user) # TODO: these probably should be another endpoint activity = self._get_activity(request, group, num=100) seen_by = self._get_seen_by(request, group) first_release = group.get_first_release() if first_release is not None: last_release = group.get_last_release() else: last_release = None action_list = self._get_actions(request, group) now = timezone.now() hourly_stats = tsdb.rollup( tsdb.get_range( model=tsdb.models.group, keys=[group.id], end=now, start=now - timedelta(days=1), ), 3600 )[group.id] daily_stats = tsdb.rollup( tsdb.get_range( model=tsdb.models.group, keys=[group.id], end=now, start=now - timedelta(days=30), ), 3600 * 24 )[group.id] if first_release: first_release = self._get_release_info(request, group, first_release) if last_release: last_release = self._get_release_info(request, group, last_release) tags = tagstore.get_group_tag_keys(group.id, limit=100) participants = list( User.objects.filter( groupsubscription__is_active=True, groupsubscription__group=group, ) ) data.update( { 'firstRelease': first_release, 'lastRelease': last_release, 'activity': serialize(activity, request.user), 'seenBy': seen_by, 'participants': serialize(participants, request.user), 'pluginActions': action_list, 'pluginIssues': self._get_available_issue_plugins(request, group), 'pluginContexts': self._get_context_plugins(request, group), 'userReportCount': UserReport.objects.filter(group=group).count(), 'tags': sorted(serialize(tags, request.user), key=lambda x: x['name']), 'stats': { '24h': hourly_stats, '30d': daily_stats, } } ) return Response(data)
def get(self, request, organization): """ Retrieve Event Counts for an Organization ````````````````````````````````````````` .. caution:: This endpoint may change in the future without notice. Return a set of points representing a normalized timestamp and the number of events seen in the period. :pparam string organization_slug: the slug of the organization for which the stats should be retrieved. :qparam string stat: the name of the stat to query (``"received"``, ``"rejected"``, ``"blacklisted"``) :qparam timestamp since: a timestamp to set the start of the query in seconds since UNIX epoch. :qparam timestamp until: a timestamp to set the end of the query in seconds since UNIX epoch. :qparam string resolution: an explicit resolution to search for (eg: ``10s``). This should not be used unless you are familiar with Sentry's internals as it's restricted to pre-defined values. :auth: required """ group = request.GET.get('group', 'organization') if group == 'organization': keys = [organization.id] elif group == 'project': team_list = Team.objects.get_for_user( organization=organization, user=request.user, ) project_list = [] for team in team_list: project_list.extend(Project.objects.get_for_user( team=team, user=request.user, )) keys = [p.id for p in project_list] else: raise ValueError('Invalid group: %s' % group) if 'id' in request.GET: id_filter_set = frozenset(map(int, request.GET.getlist('id'))) keys = [k for k in keys if k in id_filter_set] if not keys: return Response([]) stat_model = None stat = request.GET.get('stat', 'received') query_kwargs = {} if stat == 'received': if group == 'project': stat_model = tsdb.models.project_total_received else: stat_model = tsdb.models.organization_total_received elif stat == 'rejected': if group == 'project': stat_model = tsdb.models.project_total_rejected else: stat_model = tsdb.models.organization_total_rejected elif stat == 'blacklisted': if group == 'project': stat_model = tsdb.models.project_total_blacklisted else: stat_model = tsdb.models.organization_total_blacklisted elif stat == 'generated': if group == 'project': stat_model = tsdb.models.project try: query_kwargs['environment_id'] = self._get_environment_id_from_request( request, organization.id, ) except Environment.DoesNotExist: raise ResourceDoesNotExist if stat_model is None: raise ValueError('Invalid group: %s, stat: %s' % (group, stat)) data = tsdb.get_range(model=stat_model, keys=keys, **self._parse_args(request, **query_kwargs)) if group == 'organization': data = data[organization.id] return Response(data)
def get_attrs(self, item_list, user): def measure_span(op_tag): span = sentry_sdk.start_span( op="serialize.get_attrs.project.{}".format(op_tag)) span.set_data("Object Count", len(item_list)) return span with measure_span("preamble"): project_ids = [i.id for i in item_list] if user.is_authenticated() and item_list: bookmarks = set( ProjectBookmark.objects.filter( user=user, project_id__in=project_ids).values_list("project_id", flat=True)) user_options = { (u.project_id, u.key): u.value for u in UserOption.objects.filter( Q(user=user, project__in=item_list, key="mail:alert") | Q(user=user, key="subscribe_by_default", project__isnull=True)) } default_subscribe = user_options.get("subscribe_by_default", "1") == "1" else: bookmarks = set() user_options = {} default_subscribe = False if self.stats_period: # we need to compute stats at 1d (1h resolution), and 14d project_ids = [o.id for o in item_list] segments, interval = STATS_PERIOD_CHOICES[self.stats_period] now = timezone.now() stats = tsdb.get_range( model=tsdb.models.project, keys=project_ids, end=now, start=now - ((segments - 1) * interval), rollup=int(interval.total_seconds()), environment_ids=self.environment_id and [self.environment_id], ) else: stats = None avatars = { a.project_id: a for a in ProjectAvatar.objects.filter(project__in=item_list) } project_ids = [i.id for i in item_list] platforms = ProjectPlatform.objects.filter( project_id__in=project_ids).values_list( "project_id", "platform") platforms_by_project = defaultdict(list) for project_id, platform in platforms: platforms_by_project[project_id].append(platform) with measure_span("access"): result = self.get_access_by_project(item_list, user) with measure_span("features"): features_by_project = self._get_features_for_projects( item_list, user) for project, serialized in result.items(): serialized["features"] = features_by_project[project] with measure_span("other"): for project, serialized in result.items(): serialized.update({ "is_bookmarked": project.id in bookmarks, "is_subscribed": bool( user_options.get((project.id, "mail:alert"), default_subscribe)), "avatar": avatars.get(project.id), "platforms": platforms_by_project[project.id], }) if stats: serialized["stats"] = stats[project.id] return result