Skip to content

feat(analytics): typesafe analytics.Event and analytics.record #94953

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

constantinius
Copy link
Contributor

@constantinius constantinius commented Jul 7, 2025

Closes: https://linear.app/getsentry/issue/TET-804/analytics-allow-both-old-style-attributes-as-well-as-new-style

Supersedes: #92943

Making analytics.record and analytics.Event typesafer

Deprecate stringly typed analytics.record() in favor of version that uses analytics.Event objects.
Migrating analytics.Event to dataclasses. For convenience introduce the analytics.eventclass decorator, which sets the type and applies the dataclass decorator with common parameters underneath.

Allows "old-style" definition of Events as well as to record() them until all event classes are migrated.

@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Jul 7, 2025
@constantinius constantinius changed the title feat(analytics): feat(analytics): typesafe analytics.Event and analytics.record Jul 7, 2025
Copy link

codecov bot commented Jul 7, 2025

Codecov Report

Attention: Patch coverage is 96.47059% with 3 lines in your changes missing coverage. Please review.

✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/sentry/analytics/event.py 94.28% 2 Missing ⚠️
src/sentry/analytics/base.py 92.30% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #94953      +/-   ##
==========================================
+ Coverage   87.87%   87.90%   +0.02%     
==========================================
  Files       10456    10438      -18     
  Lines      604784   604154     -630     
  Branches    23617    23498     -119     
==========================================
- Hits       531454   531064     -390     
+ Misses      72969    72725     -244     
- Partials      361      365       +4     

@constantinius constantinius marked this pull request as ready for review July 7, 2025 14:34
@constantinius constantinius requested a review from a team as a code owner July 7, 2025 14:34
@constantinius constantinius requested a review from a team July 7, 2025 14:35
cursor[bot]

This comment was marked as outdated.

Co-authored-by: Simon Hellmayr <[email protected]>
cursor[bot]

This comment was marked as outdated.

Co-authored-by: Vjeran Grozdanić <[email protected]>
cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

Copy link
Member

@shellmayr shellmayr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - and great job designing this, it will make our analytics system so much more robust! 🥳

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

Copy link
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Dataclass Construction Fails Across Styles

The from_instance method has multiple issues:

  • Old-style path: It ignores kwargs for uuid_, datetime_, and other dataclass fields, leading to incorrect event data. The direct cls() call is also fragile, potentially failing if old-style event subclasses introduce required fields without defaults.
  • New-style path: It fails to filter init=False fields when constructing the instance, which can cause a TypeError.
  • General: The codebase mixes Pydantic's @dataclass with standard library dataclasses functions, risking subtle incompatibilities.

src/sentry/analytics/event.py#L102-L118

# we can remove this.
if cls.attributes:
items = {
attr.name: kwargs.get(attr.name, getattr(instance, attr.name, None))
for attr in cls.attributes
}
self = cls()
self.data = get_data(cls.attributes, items)
return self
return cls(
**{
f.name: kwargs.get(f.name, getattr(instance, f.name, None))
for f in fields(cls)
if f.name not in ("type", "uuid_", "datetime_")
}
)

Fix in CursorFix in Web


Was this report helpful? Give feedback by reacting with 👍 or 👎

@constantinius constantinius merged commit e4f18a6 into master Jul 9, 2025
65 checks passed
@constantinius constantinius deleted the constantinius/feat/analytics/eventclass-dataclass-record branch July 9, 2025 14:39
Copy link

sentry-io bot commented Jul 10, 2025

Suspect Issues

This pull request was deployed and Sentry observed the following issues:

Did you find this useful? React with a 👍 or 👎

andrewshie-sentry pushed a commit that referenced this pull request Jul 14, 2025
…94953)

Co-authored-by: Simon Hellmayr <[email protected]>
Co-authored-by: Vjeran Grozdanić <[email protected]>
Comment on lines +11 to +12
from pydantic import Field
from pydantic.dataclasses import dataclass
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it be possible to write this without pydantic

we're permastuck on version 1 and I'm looking to factor it out because it is a liability to upgrading python -- adding new usage of it makes that a lot lot harder

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah AFAIK @constantinius wants to refactor this without pydantic when the migration of analytics events over to the typed structure is done. Do you have a timeline in mind?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not urgent -- still have to factor it out of hybrid cloud 😭

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright cool - I'll bring up that you want to get pydantic out of the codebase when he's back from vacation 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Scope: Backend Automatically applied to PRs that change backend components
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants