From 5d5174d6c9250a6643ab4c33206f9ea323d82b5a Mon Sep 17 00:00:00 2001 From: William Mak Date: Wed, 18 May 2022 16:56:09 -0400 Subject: [PATCH 1/7] feat(discover): Add docs for organization_events - This adds a new doc sections for Visibility called `Discover and Performance` --- .../api/endpoints/organization_events.py | 75 +++++++++++++++- src/sentry/apidocs/build.py | 11 +++ src/sentry/apidocs/parameters.py | 89 +++++++++++++++++++ 3 files changed, 173 insertions(+), 2 deletions(-) diff --git a/src/sentry/api/endpoints/organization_events.py b/src/sentry/api/endpoints/organization_events.py index cfb1f9dc426e07..7897c490ce6fe1 100644 --- a/src/sentry/api/endpoints/organization_events.py +++ b/src/sentry/api/endpoints/organization_events.py @@ -1,13 +1,19 @@ import logging +from typing import Any, Dict, List import sentry_sdk +from drf_spectacular.utils import OpenApiExample, OpenApiResponse, extend_schema from rest_framework.exceptions import ParseError from rest_framework.request import Request from rest_framework.response import Response +from typing_extensions import TypedDict from sentry import features from sentry.api.bases import NoProjects, OrganizationEventsV2EndpointBase from sentry.api.paginator import GenericOffsetPaginator +from sentry.apidocs import constants as api_constants +from sentry.apidocs.parameters import GLOBAL_PARAMS, VISIBILITY_PARAMS +from sentry.apidocs.utils import inline_sentry_response_serializer from sentry.search.events.fields import is_function from sentry.snuba import discover, metrics_enhanced_performance @@ -122,10 +128,75 @@ def data_fn(offset, limit): ) -class OrganizationEventsEndpoint(OrganizationEventsV2EndpointBase): - private = True +class EventsResponse(TypedDict): + data: List[Dict[str, Any]] + meta: Dict[str, str] + +@extend_schema(tags=["Visibility"]) +class OrganizationEventsEndpoint(OrganizationEventsV2EndpointBase): + public = {"GET"} + + @extend_schema( + operation_id="Query Discover Events in Table Format", + parameters=[ + VISIBILITY_PARAMS.QUERY, + VISIBILITY_PARAMS.FIELD, + VISIBILITY_PARAMS.SORT, + VISIBILITY_PARAMS.PER_PAGE, + GLOBAL_PARAMS.STATS_PERIOD, + GLOBAL_PARAMS.START, + GLOBAL_PARAMS.END, + GLOBAL_PARAMS.PROJECT, + GLOBAL_PARAMS.ENVIRONMENT, + ], + responses={ + 200: inline_sentry_response_serializer( + "OrganizationEventsResponseDict", EventsResponse + ), + 400: OpenApiResponse(description="Invalid Query"), + 404: api_constants.RESPONSE_NOTFOUND, + }, + examples=[ + OpenApiExample( + "Success", + value=[ + { + "data": [ + { + "count_if(transaction.duration,greater,300)": 5, + "count()": 10, + "equation[0]": 50, + "transaction": "foo", + }, + { + "count_if(transaction.duration,greater,300)": 3, + "count()": 20, + "equation[0]": 15, + "transaction": "bar", + }, + { + "count_if(transaction.duration,greater,300)": 8, + "count()": 40, + "equation[0]": 20, + "transaction": "baz", + }, + ], + "meta": { + "count_if(transaction.duration,greater,300)": "integer", + "count()": "integer", + "equation[0]": "integer", + "transaction": "string", + }, + } + ], + ) + ], + ) def get(self, request: Request, organization) -> Response: + """ + Retrieves discover (aka. events) data for a given organization + """ if not self.has_feature(organization, request): return Response(status=404) diff --git a/src/sentry/apidocs/build.py b/src/sentry/apidocs/build.py index b740deedd8190d..576bd216c7638b 100644 --- a/src/sentry/apidocs/build.py +++ b/src/sentry/apidocs/build.py @@ -79,4 +79,15 @@ def get_old_json_paths(filename: str) -> json.JSONData: "url": "https://github.com/getsentry/sentry-docs/issues/new/?title=API%20Documentation%20Error:%20/api/integration-platform/&template=api_error_template.md", }, }, + { + # Using Visibility here since that's the common *internal* name for d&d & performance + "name": "Visibility", + "x-sidebar-name": "Discover & Performance", + "description": "Discover and Performance allow you to slice and dice your Events", + "x-display-description": True, + "externalDocs": { + "description": "Found an error? Let us know.", + "url": "https://github.com/getsentry/sentry-docs/issues/new/?title=API%20Documentation%20Error:%20/api/integration-platform/&template=api_error_template.md", + }, + }, ] diff --git a/src/sentry/apidocs/parameters.py b/src/sentry/apidocs/parameters.py index 75e4cdfa503c68..d910ae5a1bd016 100644 --- a/src/sentry/apidocs/parameters.py +++ b/src/sentry/apidocs/parameters.py @@ -1,3 +1,4 @@ +from drf_spectacular.types import OpenApiTypes from drf_spectacular.utils import OpenApiParameter from rest_framework import serializers @@ -17,6 +18,50 @@ class GLOBAL_PARAMS: type=str, location="path", ) + STATS_PERIOD = OpenApiParameter( + name="statsPeriod", + location="query", + required=False, + type=str, + description="""The period of time for the query, will override the start & end parameters, a number followed by one of: +- `d` for days +- `h` for hours +- `m` for minutes +- `s` for seconds +- `w` for weeks + +For example `24h`, to mean query data starting from 24 hours ago to now.""", + ) + START = OpenApiParameter( + name="start", + location="query", + required=False, + type=OpenApiTypes.DATETIME, + description="The start of the period of time for the query, expected in ISO-8601 format. For example 2000-05-27T16:20:11.0000", + ) + END = OpenApiParameter( + name="end", + location="query", + required=False, + type=OpenApiTypes.DATETIME, + description="The end of the period of time for the query, expected in ISO-8601 format. For example 2000-05-27T16:20:11.0000", + ) + PROJECT = OpenApiParameter( + name="project", + location="query", + required=False, + many=True, + type=int, + description="The ids of projects to filter by. `-1` means all available projects, if parameter omitted means 'My Projects'", + ) + ENVIRONMENT = OpenApiParameter( + name="environment", + location="query", + required=False, + many=True, + type=str, + description="The name of environments to filter by.", + ) class SCIM_PARAMS: @@ -46,6 +91,50 @@ class ISSUE_ALERT_PARAMS: ) +class VISIBILITY_PARAMS: + QUERY = OpenApiParameter( + name="query", + location="query", + required=False, + type=str, + description="""The search query for your filter, read more about query syntax [here](https://docs.sentry.io/product/sentry-basics/search/) + +example: `query=(transaction:foo AND release:abc) OR (transaction:[bar,baz] AND release:def)` +""", + ) + FIELD = OpenApiParameter( + name="field", + location="query", + required=True, + type=str, + many=True, + description="""The fields, functions or equations to request for the query. At most 20 fields can be passed per request. +- can be a field, see possible events fields in the [properties table](https://docs.sentry.io/product/sentry-basics/search/searchable-properties/#properties-table) + - example: `field=transaction` +- can be a function, see possible fields in the [properties table](https://docs.sentry.io/product/sentry-basics/search/searchable-properties/#properties-table) + - example: `field=count_if(transaction.duration,greater,300)` +- an equation when prefixed with `equation|`, read more about [equations here](https://docs.sentry.io/product/discover-queries/query-builder/query-equations/) + - example: `field=equation|count_if(transaction.duration,greater,300) / count() * 100` + - The key of this field in the `data` response will be in the format `equation[{number}]` where number is the + equation's position in the field list +""", + ) + SORT = OpenApiParameter( + name="sort", + location="query", + required=False, + type=int, + description="What to order the results of the query by. Must be something in the field list, excluding equations.", + ) + PER_PAGE = OpenApiParameter( + name="per_page", + location="query", + required=False, + type=int, + description="The number of rows to return in the result", + ) + + class CURSOR_QUERY_PARAM(serializers.Serializer): # type: ignore cursor = serializers.CharField( help_text="A pointer to the last object fetched and its' sort order; used to retrieve the next or previous results.", From 36ba73b59d2a934e1b12101bb436ec0fffa2f38f Mon Sep 17 00:00:00 2001 From: William Mak Date: Thu, 19 May 2022 15:09:41 -0400 Subject: [PATCH 2/7] ref: updating params, but realized i want to do the typing changes first --- .../api/endpoints/organization_events.py | 24 +++++----- src/sentry/apidocs/parameters.py | 4 +- src/sentry/snuba/discover.py | 44 ++++++++++++++----- 3 files changed, 45 insertions(+), 27 deletions(-) diff --git a/src/sentry/api/endpoints/organization_events.py b/src/sentry/api/endpoints/organization_events.py index 7897c490ce6fe1..b8f228c6c758ed 100644 --- a/src/sentry/api/endpoints/organization_events.py +++ b/src/sentry/api/endpoints/organization_events.py @@ -1,12 +1,10 @@ import logging -from typing import Any, Dict, List import sentry_sdk from drf_spectacular.utils import OpenApiExample, OpenApiResponse, extend_schema from rest_framework.exceptions import ParseError from rest_framework.request import Request from rest_framework.response import Response -from typing_extensions import TypedDict from sentry import features from sentry.api.bases import NoProjects, OrganizationEventsV2EndpointBase @@ -50,6 +48,8 @@ class OrganizationEventsV2Endpoint(OrganizationEventsV2EndpointBase): + """Deprecated in favour of OrganizationEventsEndpoint""" + def get(self, request: Request, organization) -> Response: if not self.has_feature(organization, request): return Response(status=404) @@ -128,11 +128,6 @@ def data_fn(offset, limit): ) -class EventsResponse(TypedDict): - data: List[Dict[str, Any]] - meta: Dict[str, str] - - @extend_schema(tags=["Visibility"]) class OrganizationEventsEndpoint(OrganizationEventsV2EndpointBase): public = {"GET"} @@ -152,7 +147,7 @@ class OrganizationEventsEndpoint(OrganizationEventsV2EndpointBase): ], responses={ 200: inline_sentry_response_serializer( - "OrganizationEventsResponseDict", EventsResponse + "OrganizationEventsResponseDict", discover.EventsResponse ), 400: OpenApiResponse(description="Invalid Query"), 404: api_constants.RESPONSE_NOTFOUND, @@ -166,26 +161,26 @@ class OrganizationEventsEndpoint(OrganizationEventsV2EndpointBase): { "count_if(transaction.duration,greater,300)": 5, "count()": 10, - "equation[0]": 50, + "equation|count_if(transaction.duration,greater,300) / count() * 100": 50, "transaction": "foo", }, { "count_if(transaction.duration,greater,300)": 3, "count()": 20, - "equation[0]": 15, + "equation|count_if(transaction.duration,greater,300) / count() * 100": 15, "transaction": "bar", }, { "count_if(transaction.duration,greater,300)": 8, "count()": 40, - "equation[0]": 20, + "equation|count_if(transaction.duration,greater,300) / count() * 100": 20, "transaction": "baz", }, ], "meta": { "count_if(transaction.duration,greater,300)": "integer", "count()": "integer", - "equation[0]": "integer", + "equation|count_if(transaction.duration,greater,300) / count() * 100": "integer", "transaction": "string", }, } @@ -196,6 +191,11 @@ class OrganizationEventsEndpoint(OrganizationEventsV2EndpointBase): def get(self, request: Request, organization) -> Response: """ Retrieves discover (aka. events) data for a given organization + + This endpoint is intended to get a table of results, and is not for doing a full export of data sent to Sentry + Fields determine what will be returned back in the response of the endpoint both in the `data` and `meta` key. + - The `data` key will contain a list of results row by row for what matched the query made + - The `meta` key will contain general """ if not self.has_feature(organization, request): return Response(status=404) diff --git a/src/sentry/apidocs/parameters.py b/src/sentry/apidocs/parameters.py index d910ae5a1bd016..a588011575a95c 100644 --- a/src/sentry/apidocs/parameters.py +++ b/src/sentry/apidocs/parameters.py @@ -115,8 +115,6 @@ class VISIBILITY_PARAMS: - example: `field=count_if(transaction.duration,greater,300)` - an equation when prefixed with `equation|`, read more about [equations here](https://docs.sentry.io/product/discover-queries/query-builder/query-equations/) - example: `field=equation|count_if(transaction.duration,greater,300) / count() * 100` - - The key of this field in the `data` response will be in the format `equation[{number}]` where number is the - equation's position in the field list """, ) SORT = OpenApiParameter( @@ -131,7 +129,7 @@ class VISIBILITY_PARAMS: location="query", required=False, type=int, - description="The number of rows to return in the result", + description="Limit the number of rows to return in the result, maximum allowed is 100", ) diff --git a/src/sentry/snuba/discover.py b/src/sentry/snuba/discover.py index c78bb49c891225..fb8d93ff00ebc8 100644 --- a/src/sentry/snuba/discover.py +++ b/src/sentry/snuba/discover.py @@ -3,12 +3,13 @@ from collections import namedtuple from copy import deepcopy from datetime import timedelta -from typing import Dict, Optional, Sequence +from typing import Any, Dict, List, Optional, Sequence import sentry_sdk from dateutil.parser import parse as parse_datetime from snuba_sdk.conditions import Condition, Op from snuba_sdk.function import Function +from typing_extensions import TypedDict from sentry.discover.arithmetic import categorize_columns from sentry.models import Group @@ -66,6 +67,18 @@ PaginationResult = namedtuple("PaginationResult", ["next", "previous", "oldest", "latest"]) FacetResult = namedtuple("FacetResult", ["key", "value", "count"]) + +class EventsResponse(TypedDict): + data: List[Dict[str, Any]] + meta: Dict[str, str] + + +class EventsMeta(TypedDict): + fields: Dict[str, str] + # One of; "Discover", "metricsEnhanced", or "metrics" + dataset: str + + resolve_discover_column = resolve_column(Dataset.Discover) OTHER_KEY = "Other" @@ -127,14 +140,16 @@ def zerofill(data, start, end, rollup, orderby): return rv -def transform_results(results, function_alias_map, translated_columns, snuba_filter): +def transform_results( + results, function_alias_map, translated_columns, snuba_filter +) -> EventsResponse: results = transform_data(results, translated_columns, snuba_filter) results["meta"] = transform_meta(results, function_alias_map) return results -def transform_meta(results, function_alias_map): - meta = { +def transform_meta(results: EventsResponse, function_alias_map) -> Dict[str, str]: + meta: Dict[str, str] = { value["name"]: get_json_meta_type( value["name"], value.get("type"), function_alias_map.get(value["name"]) ) @@ -148,14 +163,15 @@ def transform_meta(results, function_alias_map): return meta -def transform_data(result, translated_columns, snuba_filter): +def transform_data(result, translated_columns, snuba_filter) -> EventsResponse: """ Transform internal names back to the public schema ones. When getting timeseries results via rollup, this function will zerofill the output results. """ - for col in result["meta"]: + final_result: EventsResponse = {"data": result["data"], "meta": result["meta"]} + for col in final_result["meta"]: # Translate back column names that were converted to snuba format col["name"] = translated_columns.get(col["name"], col["name"]) @@ -173,19 +189,23 @@ def get_row(row): return transformed - result["data"] = [get_row(row) for row in result["data"]] + final_result["data"] = [get_row(row) for row in final_result["data"]] if snuba_filter and snuba_filter.rollup and snuba_filter.rollup > 0: rollup = snuba_filter.rollup with sentry_sdk.start_span( op="discover.discover", description="transform_results.zerofill" ) as span: - span.set_data("result_count", len(result.get("data", []))) - result["data"] = zerofill( - result["data"], snuba_filter.start, snuba_filter.end, rollup, snuba_filter.orderby + span.set_data("result_count", len(final_result.get("data", []))) + final_result["data"] = zerofill( + final_result["data"], + snuba_filter.start, + snuba_filter.end, + rollup, + snuba_filter.orderby, ) - return result + return final_result def query( @@ -205,7 +225,7 @@ def query( conditions=None, functions_acl=None, transform_alias_to_input_format=False, -): +) -> EventsResponse: """ High-level API for doing arbitrary user queries against events. From 34929aa23089b547d476b5a68a2c9ca35e088135 Mon Sep 17 00:00:00 2001 From: William Mak Date: Tue, 24 May 2022 14:45:19 -0400 Subject: [PATCH 3/7] Merge branch 'master' into wmak/feat/org-events-docs --- .../api/endpoints/organization_events.py | 20 +++++++++++-------- src/sentry/apidocs/build.py | 7 ++++--- src/sentry/apidocs/parameters.py | 13 +++++++----- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/sentry/api/endpoints/organization_events.py b/src/sentry/api/endpoints/organization_events.py index cec8a18ee50ba5..0d0166cf37ad59 100644 --- a/src/sentry/api/endpoints/organization_events.py +++ b/src/sentry/api/endpoints/organization_events.py @@ -130,7 +130,7 @@ def data_fn(offset, limit): ) -@extend_schema(tags=["Visibility"]) +@extend_schema(tags=["Discover"]) class OrganizationEventsEndpoint(OrganizationEventsV2EndpointBase): public = {"GET"} @@ -180,10 +180,12 @@ class OrganizationEventsEndpoint(OrganizationEventsV2EndpointBase): }, ], "meta": { - "count_if(transaction.duration,greater,300)": "integer", - "count()": "integer", - "equation|count_if(transaction.duration,greater,300) / count() * 100": "integer", - "transaction": "string", + "fields": { + "count_if(transaction.duration,greater,300)": "integer", + "count()": "integer", + "equation|count_if(transaction.duration,greater,300) / count() * 100": "number", + "transaction": "string", + }, }, } ], @@ -192,12 +194,14 @@ class OrganizationEventsEndpoint(OrganizationEventsV2EndpointBase): ) def get(self, request: Request, organization) -> Response: """ - Retrieves discover (aka. events) data for a given organization + Retrieves discover (aka. events) data for a given organization. + + Note: This endpoint is intended to get a table of results, and is not for doing a full export of data sent to + Sentry. - This endpoint is intended to get a table of results, and is not for doing a full export of data sent to Sentry Fields determine what will be returned back in the response of the endpoint both in the `data` and `meta` key. - The `data` key will contain a list of results row by row for what matched the query made - - The `meta` key will contain general + - The `meta` key will contain information about the response, including the unit or type of the fields requested """ if not self.has_feature(organization, request): return Response(status=404) diff --git a/src/sentry/apidocs/build.py b/src/sentry/apidocs/build.py index 576bd216c7638b..debe53a946c559 100644 --- a/src/sentry/apidocs/build.py +++ b/src/sentry/apidocs/build.py @@ -80,10 +80,11 @@ def get_old_json_paths(filename: str) -> json.JSONData: }, }, { - # Using Visibility here since that's the common *internal* name for d&d & performance - "name": "Visibility", + # Not using visibility here since users won't be aware what that is, this "name" is only used in the URL so not + # a big deal that its missing Performance + "name": "Discover", "x-sidebar-name": "Discover & Performance", - "description": "Discover and Performance allow you to slice and dice your Events", + "description": "Discover and Performance allow you to slice and dice your Error and Transaction events", "x-display-description": True, "externalDocs": { "description": "Found an error? Let us know.", diff --git a/src/sentry/apidocs/parameters.py b/src/sentry/apidocs/parameters.py index a588011575a95c..da0e06ffb51ccc 100644 --- a/src/sentry/apidocs/parameters.py +++ b/src/sentry/apidocs/parameters.py @@ -37,14 +37,14 @@ class GLOBAL_PARAMS: location="query", required=False, type=OpenApiTypes.DATETIME, - description="The start of the period of time for the query, expected in ISO-8601 format. For example 2000-05-27T16:20:11.0000", + description="The start of the period of time for the query, expected in ISO-8601 format. For example 2001-12-34T12:34:56.7890", ) END = OpenApiParameter( name="end", location="query", required=False, type=OpenApiTypes.DATETIME, - description="The end of the period of time for the query, expected in ISO-8601 format. For example 2000-05-27T16:20:11.0000", + description="The end of the period of time for the query, expected in ISO-8601 format. For example 2001-12-34T12:34:56.7890", ) PROJECT = OpenApiParameter( name="project", @@ -108,10 +108,13 @@ class VISIBILITY_PARAMS: required=True, type=str, many=True, - description="""The fields, functions or equations to request for the query. At most 20 fields can be passed per request. -- can be a field, see possible events fields in the [properties table](https://docs.sentry.io/product/sentry-basics/search/searchable-properties/#properties-table) + description="""The fields, functions or equations to request for the query. At most 20 fields can be passed per request. Each field can be one of the following types: +- a built-in key field, see possible fields in the [properties table](/product/sentry-basics/search/searchable-properties/#properties-table), under any field that is an event property - example: `field=transaction` -- can be a function, see possible fields in the [properties table](https://docs.sentry.io/product/sentry-basics/search/searchable-properties/#properties-table) +- a tag, tags should use the `tag[]` formatting to avoid ambiguity with any fields + - example: `field=tag[isEnterprise]` +- a function which will be in the format of `function_name(parameters,...)`, see possible functions in the [query builder documentation](/product/discover-queries/query-builder/#stacking-functions) + - when a function is included, discover will group by any tags or fields - example: `field=count_if(transaction.duration,greater,300)` - an equation when prefixed with `equation|`, read more about [equations here](https://docs.sentry.io/product/discover-queries/query-builder/query-equations/) - example: `field=equation|count_if(transaction.duration,greater,300) / count() * 100` From 1716b4f31739c2950f051197e0a9c2bc3f574313 Mon Sep 17 00:00:00 2001 From: William Mak Date: Tue, 24 May 2022 14:55:47 -0400 Subject: [PATCH 4/7] ref: --- .../api/endpoints/organization_events.py | 60 +++++++++---------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/src/sentry/api/endpoints/organization_events.py b/src/sentry/api/endpoints/organization_events.py index 0d0166cf37ad59..4da9521709bac1 100644 --- a/src/sentry/api/endpoints/organization_events.py +++ b/src/sentry/api/endpoints/organization_events.py @@ -157,38 +157,36 @@ class OrganizationEventsEndpoint(OrganizationEventsV2EndpointBase): examples=[ OpenApiExample( "Success", - value=[ - { - "data": [ - { - "count_if(transaction.duration,greater,300)": 5, - "count()": 10, - "equation|count_if(transaction.duration,greater,300) / count() * 100": 50, - "transaction": "foo", - }, - { - "count_if(transaction.duration,greater,300)": 3, - "count()": 20, - "equation|count_if(transaction.duration,greater,300) / count() * 100": 15, - "transaction": "bar", - }, - { - "count_if(transaction.duration,greater,300)": 8, - "count()": 40, - "equation|count_if(transaction.duration,greater,300) / count() * 100": 20, - "transaction": "baz", - }, - ], - "meta": { - "fields": { - "count_if(transaction.duration,greater,300)": "integer", - "count()": "integer", - "equation|count_if(transaction.duration,greater,300) / count() * 100": "number", - "transaction": "string", - }, + value={ + "data": [ + { + "count_if(transaction.duration,greater,300)": 5, + "count()": 10, + "equation|count_if(transaction.duration,greater,300) / count() * 100": 50, + "transaction": "foo", }, - } - ], + { + "count_if(transaction.duration,greater,300)": 3, + "count()": 20, + "equation|count_if(transaction.duration,greater,300) / count() * 100": 15, + "transaction": "bar", + }, + { + "count_if(transaction.duration,greater,300)": 8, + "count()": 40, + "equation|count_if(transaction.duration,greater,300) / count() * 100": 20, + "transaction": "baz", + }, + ], + "meta": { + "fields": { + "count_if(transaction.duration,greater,300)": "integer", + "count()": "integer", + "equation|count_if(transaction.duration,greater,300) / count() * 100": "number", + "transaction": "string", + }, + }, + }, ) ], ) From 55d33a3e977dbf1a9d5fc3e9069c6eff0d89d6b1 Mon Sep 17 00:00:00 2001 From: William Mak Date: Mon, 30 May 2022 19:26:09 -0400 Subject: [PATCH 5/7] fix: typing issue --- src/sentry/snuba/discover.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/sentry/snuba/discover.py b/src/sentry/snuba/discover.py index 5706e096391549..b3d4b8c5fa46f2 100644 --- a/src/sentry/snuba/discover.py +++ b/src/sentry/snuba/discover.py @@ -68,15 +68,13 @@ FacetResult = namedtuple("FacetResult", ["key", "value", "count"]) -class EventsResponse(TypedDict): - data: List[Dict[str, Any]] - meta: Dict[str, str] - - class EventsMeta(TypedDict): fields: Dict[str, str] - # One of; "Discover", "metricsEnhanced", or "metrics" - dataset: str + + +class EventsResponse(TypedDict): + data: List[Dict[str, Any]] + meta: EventsMeta resolve_discover_column = resolve_column(Dataset.Discover) From 1d43cb4c23ddfb1b51ff2f80e2fef48d3a9d8e35 Mon Sep 17 00:00:00 2001 From: William Mak Date: Wed, 1 Jun 2022 12:26:19 -0400 Subject: [PATCH 6/7] ref: sort isn't an integer --- src/sentry/apidocs/parameters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sentry/apidocs/parameters.py b/src/sentry/apidocs/parameters.py index da0e06ffb51ccc..21299db30ae55b 100644 --- a/src/sentry/apidocs/parameters.py +++ b/src/sentry/apidocs/parameters.py @@ -124,7 +124,7 @@ class VISIBILITY_PARAMS: name="sort", location="query", required=False, - type=int, + type=str, description="What to order the results of the query by. Must be something in the field list, excluding equations.", ) PER_PAGE = OpenApiParameter( From a15876c30bc9618d23a356f080da0af89869a6d5 Mon Sep 17 00:00:00 2001 From: William Mak Date: Thu, 2 Jun 2022 13:28:59 -0400 Subject: [PATCH 7/7] Apply suggestions from code review Co-authored-by: edwardgou-sentry <83961295+edwardgou-sentry@users.noreply.github.com> Co-authored-by: Ash Anand <0Calories@users.noreply.github.com> --- .../api/endpoints/organization_events.py | 10 ++++---- src/sentry/apidocs/parameters.py | 24 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/sentry/api/endpoints/organization_events.py b/src/sentry/api/endpoints/organization_events.py index 8cebc215c0afe1..ea4b921b6aab46 100644 --- a/src/sentry/api/endpoints/organization_events.py +++ b/src/sentry/api/endpoints/organization_events.py @@ -195,14 +195,14 @@ class OrganizationEventsEndpoint(OrganizationEventsV2EndpointBase): ) def get(self, request: Request, organization) -> Response: """ - Retrieves discover (aka. events) data for a given organization. + Retrieves discover (also known as events) data for a given organization. - Note: This endpoint is intended to get a table of results, and is not for doing a full export of data sent to + **Note**: This endpoint is intended to get a table of results, and is not for doing a full export of data sent to Sentry. - Fields determine what will be returned back in the response of the endpoint both in the `data` and `meta` key. - - The `data` key will contain a list of results row by row for what matched the query made - - The `meta` key will contain information about the response, including the unit or type of the fields requested + The `field` query parameter determines what fields will be selected in the `data` and `meta` keys of the endpoint response. + - The `data` key contains a list of results row by row that match the `query` made + - The `meta` key contains information about the response, including the unit or type of the fields requested """ if not self.has_feature(organization, request): return Response(status=404) diff --git a/src/sentry/apidocs/parameters.py b/src/sentry/apidocs/parameters.py index 21299db30ae55b..d0618cf83b7f3b 100644 --- a/src/sentry/apidocs/parameters.py +++ b/src/sentry/apidocs/parameters.py @@ -37,14 +37,14 @@ class GLOBAL_PARAMS: location="query", required=False, type=OpenApiTypes.DATETIME, - description="The start of the period of time for the query, expected in ISO-8601 format. For example 2001-12-34T12:34:56.7890", + description="The start of the period of time for the query, expected in ISO-8601 format. For example `2001-12-14T12:34:56.7890`", ) END = OpenApiParameter( name="end", location="query", required=False, type=OpenApiTypes.DATETIME, - description="The end of the period of time for the query, expected in ISO-8601 format. For example 2001-12-34T12:34:56.7890", + description="The end of the period of time for the query, expected in ISO-8601 format. For example `2001-12-14T12:34:56.7890`", ) PROJECT = OpenApiParameter( name="project", @@ -52,7 +52,7 @@ class GLOBAL_PARAMS: required=False, many=True, type=int, - description="The ids of projects to filter by. `-1` means all available projects, if parameter omitted means 'My Projects'", + description="The ids of projects to filter by. `-1` means all available projects. If this parameter is omitted, the request will default to using 'My Projects'", ) ENVIRONMENT = OpenApiParameter( name="environment", @@ -97,7 +97,7 @@ class VISIBILITY_PARAMS: location="query", required=False, type=str, - description="""The search query for your filter, read more about query syntax [here](https://docs.sentry.io/product/sentry-basics/search/) + description="""The search filter for your query, read more about query syntax [here](https://docs.sentry.io/product/sentry-basics/search/) example: `query=(transaction:foo AND release:abc) OR (transaction:[bar,baz] AND release:def)` """, @@ -108,15 +108,15 @@ class VISIBILITY_PARAMS: required=True, type=str, many=True, - description="""The fields, functions or equations to request for the query. At most 20 fields can be passed per request. Each field can be one of the following types: -- a built-in key field, see possible fields in the [properties table](/product/sentry-basics/search/searchable-properties/#properties-table), under any field that is an event property + description="""The fields, functions, or equations to request for the query. At most 20 fields can be selected per request. Each field can be one of the following types: +- A built-in key field. See possible fields in the [properties table](/product/sentry-basics/search/searchable-properties/#properties-table), under any field that is an event property - example: `field=transaction` -- a tag, tags should use the `tag[]` formatting to avoid ambiguity with any fields +- A tag. Tags should use the `tag[]` formatting to avoid ambiguity with any fields - example: `field=tag[isEnterprise]` -- a function which will be in the format of `function_name(parameters,...)`, see possible functions in the [query builder documentation](/product/discover-queries/query-builder/#stacking-functions) - - when a function is included, discover will group by any tags or fields +- A function which will be in the format of `function_name(parameters,...)`. See possible functions in the [query builder documentation](/product/discover-queries/query-builder/#stacking-functions) + - when a function is included, Discover will group by any tags or fields - example: `field=count_if(transaction.duration,greater,300)` -- an equation when prefixed with `equation|`, read more about [equations here](https://docs.sentry.io/product/discover-queries/query-builder/query-equations/) +- An equation when prefixed with `equation|`. Read more about [equations here](https://docs.sentry.io/product/discover-queries/query-builder/query-equations/) - example: `field=equation|count_if(transaction.duration,greater,300) / count() * 100` """, ) @@ -125,14 +125,14 @@ class VISIBILITY_PARAMS: location="query", required=False, type=str, - description="What to order the results of the query by. Must be something in the field list, excluding equations.", + description="What to order the results of the query by. Must be something in the `field` list, excluding equations.", ) PER_PAGE = OpenApiParameter( name="per_page", location="query", required=False, type=int, - description="Limit the number of rows to return in the result, maximum allowed is 100", + description="Limit the number of rows to return in the result. Default and maximum allowed is 100.", )