Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/sentry/api/endpoints/organization_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
)
from sentry.snuba.metrics.extraction import MetricSpecType
from sentry.snuba.ourlogs import OurLogs
from sentry.snuba.profile_functions import ProfileFunctions
from sentry.snuba.referrer import Referrer, is_valid_referrer
from sentry.snuba.spans_rpc import Spans
from sentry.snuba.trace_metrics import TraceMetrics
Expand Down Expand Up @@ -532,6 +533,13 @@ def get_rpc_config():
auto_fields=True,
disable_aggregate_extrapolation=disable_aggregate_extrapolation,
)
elif scoped_dataset == ProfileFunctions:
# profile_functions uses aggregate conditions
return SearchResolverConfig(
use_aggregate_conditions=use_aggregate_conditions,
auto_fields=True,
disable_aggregate_extrapolation=disable_aggregate_extrapolation,
)
elif scoped_dataset == uptime_results.UptimeResults:
return SearchResolverConfig(
use_aggregate_conditions=use_aggregate_conditions,
Expand Down Expand Up @@ -600,7 +608,7 @@ def data_fn(offset, limit):

paginator, cursor_cls = paginator_factory(dataset)

max_per_page = 9999 if dataset in (OurLogs, TraceMetrics) else None
max_per_page = 9999 if dataset in (OurLogs, TraceMetrics, ProfileFunctions) else None

def _handle_results(results):
# Apply error upsampling for regular Events API
Expand Down
2 changes: 2 additions & 0 deletions src/sentry/api/endpoints/organization_events_stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
)
from sentry.snuba.metrics.extraction import MetricSpecType
from sentry.snuba.ourlogs import OurLogs
from sentry.snuba.profile_functions import ProfileFunctions
from sentry.snuba.query_sources import QuerySource
from sentry.snuba.referrer import Referrer, is_valid_referrer
from sentry.snuba.spans_rpc import Spans
Expand Down Expand Up @@ -192,6 +193,7 @@ def get(self, request: Request, organization: Organization) -> Response:
spans_metrics,
Spans,
OurLogs,
ProfileFunctions,
TraceMetrics,
errors,
transactions,
Expand Down
5 changes: 4 additions & 1 deletion src/sentry/replays/lib/eap/snuba_transpiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,12 @@
"uptime_result": TraceItemType.TRACE_ITEM_TYPE_UPTIME_RESULT,
"replay": TraceItemType.TRACE_ITEM_TYPE_REPLAY,
"metric": TraceItemType.TRACE_ITEM_TYPE_METRIC,
"profile_functions": TraceItemType.TRACE_ITEM_TYPE_PROFILE_FUNCTION,
}

TRACE_ITEM_TYPES = TLiteral["span", "error", "log", "uptime_result", "replay", "metric"] # noqa
TRACE_ITEM_TYPES = TLiteral[
"span", "error", "log", "uptime_result", "replay", "metric", "profile_functions" # noqa
]


class RequestMeta(TypedDict):
Expand Down
1 change: 1 addition & 0 deletions src/sentry/search/eap/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
SupportedTraceItemType.SPANS: TraceItemType.TRACE_ITEM_TYPE_SPAN,
SupportedTraceItemType.UPTIME_RESULTS: TraceItemType.TRACE_ITEM_TYPE_UPTIME_RESULT,
SupportedTraceItemType.TRACEMETRICS: TraceItemType.TRACE_ITEM_TYPE_METRIC,
SupportedTraceItemType.PROFILE_FUNCTIONS: TraceItemType.TRACE_ITEM_TYPE_PROFILE_FUNCTION,
}

OPERATOR_MAP = {
Expand Down
5 changes: 5 additions & 0 deletions src/sentry/search/eap/profile_functions/aggregates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from sentry.search.eap.ourlogs.aggregates import LOG_AGGREGATE_DEFINITIONS

# For now, profile functions uses the same aggregates as logs
# This can be extended in the future with trace metrics specific aggregates
PROFILE_FUNCTIONS_AGGREGATE_DEFINITIONS = LOG_AGGREGATE_DEFINITIONS
198 changes: 198 additions & 0 deletions src/sentry/search/eap/profile_functions/attributes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
from typing import Literal

from sentry.search.eap import constants
from sentry.search.eap.columns import (
ResolvedAttribute,
VirtualColumnDefinition,
project_context_constructor,
project_term_resolver,
)
from sentry.search.eap.common_columns import COMMON_COLUMNS
from sentry.utils.validators import is_event_id_or_list

PROFILE_FUNCTIONS_ATTRIBUTE_DEFINITIONS = {
column.public_alias: column
for column in COMMON_COLUMNS
+ [
ResolvedAttribute(
public_alias="id",
internal_name="sentry.item_id",
search_type="string",
validator=is_event_id_or_list,
),
ResolvedAttribute(
public_alias=constants.TRACE_ALIAS,
internal_name="sentry.trace_id",
search_type="string",
validator=is_event_id_or_list,
),
ResolvedAttribute(
public_alias="environment",
internal_name="environment",
search_type="string",
),
ResolvedAttribute(
public_alias="release",
internal_name="release",
search_type="string",
),
ResolvedAttribute(
public_alias="transaction",
internal_name="transaction_name",
search_type="string",
),
ResolvedAttribute(
public_alias="function",
internal_name="name",
search_type="string",
),
ResolvedAttribute(
public_alias="_fingerprint",
internal_name="fingerprint",
search_type="integer",
),
ResolvedAttribute(
public_alias="stack_fingerprint",
internal_name="stack_fingerprint",
search_type="integer",
),
ResolvedAttribute(
public_alias="parent_fingerprint",
internal_name="parent_fingerprint",
search_type="integer",
),
# will contain profile_id for tnx profiles and profiler_id for continuous profiles
ResolvedAttribute(
public_alias="profile_id",
internal_name="profile_id",
search_type="string",
),
# enum ("transaction" | "continuous")
ResolvedAttribute(
public_alias="profiling_type",
internal_name="profiling_type",
search_type="string",
),
ResolvedAttribute(
public_alias="function",
internal_name="name",
search_type="string",
),
ResolvedAttribute(
public_alias="package",
internal_name="package",
search_type="string",
),
ResolvedAttribute(
public_alias="is_application",
internal_name="is_application",
search_type="string",
),
ResolvedAttribute(
public_alias="platform.name",
internal_name="platform",
search_type="string",
),
ResolvedAttribute(
public_alias="function.self_duration",
internal_name="self_time_ns",
search_type="integer",
),
ResolvedAttribute(
public_alias="depth",
internal_name="depth",
search_type="integer",
),
ResolvedAttribute(
public_alias="function.total_duration",
internal_name="total_time_ns",
search_type="integer",
),
ResolvedAttribute(
public_alias="thread_id",
internal_name="thread_id",
search_type="string",
),
# only for continuous profiles
ResolvedAttribute(
public_alias="start_timestamp",
internal_name="start_timestamp",
search_type="number",
),
# only for continuous profiles
ResolvedAttribute(
public_alias="end_timestamp",
internal_name="end_timestamp",
search_type="number",
),
]
}


# Ensure that required fields are defined at runtime
for field in {constants.TIMESTAMP_ALIAS, constants.TRACE_ALIAS}:
assert (
field in PROFILE_FUNCTIONS_ATTRIBUTE_DEFINITIONS
), f"{field} must be defined for profile functions"

PROFILE_FUNCTIONS_VIRTUAL_CONTEXTS = {
key: VirtualColumnDefinition(
constructor=project_context_constructor(key),
term_resolver=project_term_resolver,
filter_column="project.id",
)
for key in constants.PROJECT_FIELDS
}

PROFILE_FUNCTIONS_INTERNAL_TO_PUBLIC_ALIAS_MAPPINGS: dict[
Literal["string", "number"], dict[str, str]
] = {
"string": {
definition.internal_name: definition.public_alias
for definition in PROFILE_FUNCTIONS_ATTRIBUTE_DEFINITIONS.values()
if not definition.secondary_alias and definition.search_type == "string"
}
| {
# sentry.service is the project id as a string, but map to project for convenience
"sentry.service": "project",
},
"number": {
definition.internal_name: definition.public_alias
for definition in PROFILE_FUNCTIONS_ATTRIBUTE_DEFINITIONS.values()
if not definition.secondary_alias and definition.search_type != "string"
},
}

PROFILE_FUNCTIONS_PRIVATE_ATTRIBUTES: set[str] = {
definition.internal_name
for definition in PROFILE_FUNCTIONS_ATTRIBUTE_DEFINITIONS.values()
if definition.private
}

# For dynamic internal attributes (eg. meta information for attributes) we match by the beginning of the key.
PROFILE_FUNCTIONS_PRIVATE_ATTRIBUTE_PREFIXES: set[str] = {constants.META_PREFIX}

PROFILE_FUNCTIONS_REPLACEMENT_ATTRIBUTES: set[str] = {
definition.replacement
for definition in PROFILE_FUNCTIONS_ATTRIBUTE_DEFINITIONS.values()
if definition.replacement
}

PROFILE_FUNCTIONS_REPLACEMENT_MAP: dict[str, str] = {
definition.public_alias: definition.replacement
for definition in PROFILE_FUNCTIONS_ATTRIBUTE_DEFINITIONS.values()
if definition.replacement
}
PROFILE_FUNCTIONS_INTERNAL_TO_SECONDARY_ALIASES_MAPPING: dict[str, set[str]] = {}

for definition in PROFILE_FUNCTIONS_ATTRIBUTE_DEFINITIONS.values():
if not definition.secondary_alias:
continue

secondary_aliases = PROFILE_FUNCTIONS_INTERNAL_TO_SECONDARY_ALIASES_MAPPING.get(
definition.internal_name, set()
)
secondary_aliases.add(definition.public_alias)
PROFILE_FUNCTIONS_INTERNAL_TO_SECONDARY_ALIASES_MAPPING[definition.internal_name] = (
secondary_aliases
)
20 changes: 20 additions & 0 deletions src/sentry/search/eap/profile_functions/definitions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from sentry_protos.snuba.v1.request_common_pb2 import TraceItemType

from sentry.search.eap.columns import ColumnDefinitions
from sentry.search.eap.profile_functions.aggregates import PROFILE_FUNCTIONS_AGGREGATE_DEFINITIONS
from sentry.search.eap.profile_functions.attributes import (
PROFILE_FUNCTIONS_ATTRIBUTE_DEFINITIONS,
PROFILE_FUNCTIONS_VIRTUAL_CONTEXTS,
)

PROFILE_FUNCTIONS_DEFINITIONS = ColumnDefinitions(
aggregates=PROFILE_FUNCTIONS_AGGREGATE_DEFINITIONS,
conditional_aggregates={},
formulas={},
columns=PROFILE_FUNCTIONS_ATTRIBUTE_DEFINITIONS,
contexts=PROFILE_FUNCTIONS_VIRTUAL_CONTEXTS,
trace_item_type=TraceItemType.TRACE_ITEM_TYPE_PROFILE_FUNCTION,
filter_aliases={},
column_to_alias=None,
alias_to_column=None,
)
1 change: 1 addition & 0 deletions src/sentry/search/eap/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class SupportedTraceItemType(str, Enum):
SPANS = "spans"
UPTIME_RESULTS = "uptime_results"
TRACEMETRICS = "tracemetrics"
PROFILE_FUNCTIONS = "profile_functions"


class AttributeSourceType(str, Enum):
Expand Down
18 changes: 18 additions & 0 deletions src/sentry/search/eap/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@
OURLOG_ATTRIBUTE_DEFINITIONS,
)
from sentry.search.eap.ourlogs.definitions import OURLOG_DEFINITIONS
from sentry.search.eap.profile_functions.attributes import (
PROFILE_FUNCTIONS_ATTRIBUTE_DEFINITIONS,
PROFILE_FUNCTIONS_INTERNAL_TO_PUBLIC_ALIAS_MAPPINGS,
PROFILE_FUNCTIONS_INTERNAL_TO_SECONDARY_ALIASES_MAPPING,
PROFILE_FUNCTIONS_PRIVATE_ATTRIBUTE_PREFIXES,
PROFILE_FUNCTIONS_PRIVATE_ATTRIBUTES,
PROFILE_FUNCTIONS_REPLACEMENT_ATTRIBUTES,
PROFILE_FUNCTIONS_REPLACEMENT_MAP,
)
from sentry.search.eap.profile_functions.definitions import PROFILE_FUNCTIONS_DEFINITIONS
from sentry.search.eap.spans.attributes import (
SPAN_ATTRIBUTE_DEFINITIONS,
SPAN_INTERNAL_TO_SECONDARY_ALIASES_MAPPING,
Expand Down Expand Up @@ -58,50 +68,58 @@ def add_start_end_conditions(
SupportedTraceItemType.SPANS: SPANS_INTERNAL_TO_PUBLIC_ALIAS_MAPPINGS,
SupportedTraceItemType.LOGS: LOGS_INTERNAL_TO_PUBLIC_ALIAS_MAPPINGS,
SupportedTraceItemType.TRACEMETRICS: TRACE_METRICS_INTERNAL_TO_PUBLIC_ALIAS_MAPPINGS,
SupportedTraceItemType.PROFILE_FUNCTIONS: PROFILE_FUNCTIONS_INTERNAL_TO_PUBLIC_ALIAS_MAPPINGS,
}

PUBLIC_ALIAS_TO_INTERNAL_MAPPING: dict[SupportedTraceItemType, dict[str, ResolvedAttribute]] = {
SupportedTraceItemType.SPANS: SPAN_ATTRIBUTE_DEFINITIONS,
SupportedTraceItemType.LOGS: OURLOG_ATTRIBUTE_DEFINITIONS,
SupportedTraceItemType.TRACEMETRICS: TRACE_METRICS_ATTRIBUTE_DEFINITIONS,
SupportedTraceItemType.PROFILE_FUNCTIONS: PROFILE_FUNCTIONS_ATTRIBUTE_DEFINITIONS,
}


PRIVATE_ATTRIBUTES: dict[SupportedTraceItemType, set[str]] = {
SupportedTraceItemType.SPANS: SPANS_PRIVATE_ATTRIBUTES,
SupportedTraceItemType.LOGS: LOGS_PRIVATE_ATTRIBUTES,
SupportedTraceItemType.TRACEMETRICS: TRACE_METRICS_PRIVATE_ATTRIBUTES,
SupportedTraceItemType.PROFILE_FUNCTIONS: PROFILE_FUNCTIONS_PRIVATE_ATTRIBUTES,
}

PRIVATE_ATTRIBUTE_PREFIXES: dict[SupportedTraceItemType, set[str]] = {
SupportedTraceItemType.SPANS: SPANS_PRIVATE_ATTRIBUTE_PREFIXES,
SupportedTraceItemType.LOGS: LOGS_PRIVATE_ATTRIBUTE_PREFIXES,
SupportedTraceItemType.TRACEMETRICS: TRACE_METRICS_PRIVATE_ATTRIBUTE_PREFIXES,
SupportedTraceItemType.PROFILE_FUNCTIONS: PROFILE_FUNCTIONS_PRIVATE_ATTRIBUTE_PREFIXES,
}

SENTRY_CONVENTIONS_REPLACEMENT_ATTRIBUTES: dict[SupportedTraceItemType, set[str]] = {
SupportedTraceItemType.SPANS: SPANS_REPLACEMENT_ATTRIBUTES,
SupportedTraceItemType.LOGS: LOGS_REPLACEMENT_ATTRIBUTES,
SupportedTraceItemType.TRACEMETRICS: TRACE_METRICS_REPLACEMENT_ATTRIBUTES,
SupportedTraceItemType.PROFILE_FUNCTIONS: PROFILE_FUNCTIONS_REPLACEMENT_ATTRIBUTES,
}

SENTRY_CONVENTIONS_REPLACEMENT_MAPPINGS: dict[SupportedTraceItemType, dict[str, str]] = {
SupportedTraceItemType.SPANS: SPANS_REPLACEMENT_MAP,
SupportedTraceItemType.LOGS: LOGS_REPLACEMENT_MAP,
SupportedTraceItemType.TRACEMETRICS: TRACE_METRICS_REPLACEMENT_MAP,
SupportedTraceItemType.PROFILE_FUNCTIONS: PROFILE_FUNCTIONS_REPLACEMENT_MAP,
}


INTERNAL_TO_SECONDARY_ALIASES: dict[SupportedTraceItemType, dict[str, set[str]]] = {
SupportedTraceItemType.SPANS: SPAN_INTERNAL_TO_SECONDARY_ALIASES_MAPPING,
SupportedTraceItemType.LOGS: LOGS_INTERNAL_TO_SECONDARY_ALIASES_MAPPING,
SupportedTraceItemType.TRACEMETRICS: TRACE_METRICS_INTERNAL_TO_SECONDARY_ALIASES_MAPPING,
SupportedTraceItemType.PROFILE_FUNCTIONS: PROFILE_FUNCTIONS_INTERNAL_TO_SECONDARY_ALIASES_MAPPING,
}

TRACE_ITEM_TYPE_DEFINITIONS: dict[SupportedTraceItemType, ColumnDefinitions] = {
SupportedTraceItemType.SPANS: SPAN_DEFINITIONS,
SupportedTraceItemType.LOGS: OURLOG_DEFINITIONS,
SupportedTraceItemType.TRACEMETRICS: TRACE_METRICS_DEFINITIONS,
SupportedTraceItemType.PROFILE_FUNCTIONS: PROFILE_FUNCTIONS_DEFINITIONS,
}


Expand Down
Loading
Loading