Skip to content

Commit 9b8098c

Browse files
authored
feat(insights): add receiver and signals for has_insights_xx spans (#72946)
A continuation of #72904. This PR adds a signal and receiver for the `has_insights_xx_span` event, which will trigger when the user first receives a span of a specific insight module type. The following PR will implement the logic that triggers the signal for each module.
1 parent c662a4b commit 9b8098c

File tree

5 files changed

+68
-0
lines changed

5 files changed

+68
-0
lines changed

src/sentry/analytics/events/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from .first_custom_metric_sent import * # noqa: F401,F403
2323
from .first_event_sent import * # noqa: F401,F403
2424
from .first_feedback_sent import * # noqa: F401,F403
25+
from .first_insight_span_sent import * # noqa: F401,F403
2526
from .first_new_feedback_sent import * # noqa: F401,F403
2627
from .first_profile_sent import * # noqa: F401,F403
2728
from .first_release_tag_sent import * # noqa: F401,F403
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from sentry import analytics
2+
3+
4+
class FirstInsightSpanSentEvent(analytics.Event):
5+
type = "first_insight_span.sent"
6+
7+
attributes = (
8+
analytics.Attribute("organization_id"),
9+
analytics.Attribute("user_id"),
10+
analytics.Attribute("project_id"),
11+
analytics.Attribute("module"),
12+
analytics.Attribute("platform", required=False),
13+
)
14+
15+
16+
analytics.register(FirstInsightSpanSentEvent)

src/sentry/constants.py

+13
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from collections import namedtuple
99
from collections.abc import Sequence
1010
from datetime import timedelta
11+
from enum import Enum
1112
from typing import cast
1213

1314
import sentry_relay.consts
@@ -599,6 +600,18 @@ def from_str(cls, string: str) -> int:
599600
raise ValueError(f"Not an ExportQueryType str: {string!r}")
600601

601602

603+
class InsightModules(Enum):
604+
HTTP = "http"
605+
DB = "db"
606+
ASSETS = "assets" # previously named resources
607+
APP_START = "app_start"
608+
SCREEN_LOAD = "screen_load"
609+
VITAL = "vital"
610+
CACHE = "cache"
611+
QUEUE = "queue"
612+
LLM_MONITORING = "llm_monitoring"
613+
614+
602615
StatsPeriod = namedtuple("StatsPeriod", ("segments", "interval"))
603616

604617
LEGACY_RATE_LIMIT_OPTIONS = frozenset(("sentry:project-rate-limit", "sentry:account-rate-limit"))

src/sentry/receivers/onboarding.py

+37
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from django.utils import timezone as django_timezone
88

99
from sentry import analytics, features
10+
from sentry.constants import InsightModules
1011
from sentry.models.organization import Organization
1112
from sentry.models.organizationonboardingtask import (
1213
OnboardingTask,
@@ -29,6 +30,7 @@
2930
first_event_received,
3031
first_event_with_minified_stack_trace_received,
3132
first_feedback_received,
33+
first_insight_span_received,
3234
first_new_feedback_received,
3335
first_profile_received,
3436
first_replay_received,
@@ -332,6 +334,41 @@ def record_first_custom_metric(project, **kwargs):
332334
)
333335

334336

337+
@first_insight_span_received.connect(weak=False)
338+
def record_first_insight_span(project, module, **kwargs):
339+
flag = None
340+
if module == InsightModules.HTTP:
341+
flag = Project.flags.has_insights_http
342+
elif module == InsightModules.DB:
343+
flag = Project.flags.has_insights_db
344+
elif module == InsightModules.ASSETS:
345+
flag = Project.flags.has_insights_assets
346+
elif module == InsightModules.APP_START:
347+
flag = Project.flags.has_insights_app_start
348+
elif module == InsightModules.SCREEN_LOAD:
349+
flag = Project.flags.has_insights_screen_load
350+
elif module == InsightModules.VITAL:
351+
flag = Project.flags.has_insights_vitals
352+
elif module == InsightModules.CACHE:
353+
flag = Project.flags.has_insights_caches
354+
elif module == InsightModules.QUEUE:
355+
flag = Project.flags.has_insights_queues
356+
elif module == InsightModules.LLM_MONITORING:
357+
flag = Project.flags.has_insights_llm_monitoring
358+
359+
if flag is not None:
360+
project.update(flags=F("flags").bitor(flag))
361+
362+
analytics.record(
363+
"first_insight_span.sent",
364+
user_id=project.organization.default_owner_id,
365+
organization_id=project.organization_id,
366+
project_id=project.id,
367+
platform=project.platform,
368+
module=module,
369+
)
370+
371+
335372
@member_invited.connect(weak=False)
336373
def record_member_invited(member, user, **kwargs):
337374
OrganizationOnboardingTask.objects.record(

src/sentry/signals.py

+1
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ def _log_robust_failure(self, receiver: object, err: Exception) -> None:
117117
cron_monitor_created = BetterSignal() # ["project", "user", "from_upsert"]
118118
first_cron_checkin_received = BetterSignal() # ["project", "monitor_id"]
119119
first_custom_metric_received = BetterSignal() # ["project"]
120+
first_insight_span_received = BetterSignal() # ["project", "module"]
120121
member_invited = BetterSignal() # ["member", "user"]
121122
member_joined = BetterSignal() # ["organization_member_id", "organization_id", "user_id"]
122123
issue_tracker_used = BetterSignal() # ["plugin", "project", "user"]

0 commit comments

Comments
 (0)