Skip to content

Commit cfc050b

Browse files
committed
fix(analytics): update backend analytics documentation
1 parent 7030caa commit cfc050b

File tree

1 file changed

+53
-45
lines changed

1 file changed

+53
-45
lines changed

develop-docs/development-infrastructure/analytics.mdx

Lines changed: 53 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -23,87 +23,95 @@ Conventionally, the analytics events are stored in a file named `analytics` with
2323
The Event classes look like this:
2424

2525
```python
26-
from __future__ import absolute_import, print_function
26+
import abc
2727

2828
from sentry import analytics
2929

30-
class ExampleTutorialCreatedEvent(analytics.Event):
31-
type = 'example_tutorial.created'
3230

33-
attributes = (
34-
analytics.Attribute('id'),
35-
analytics.Attribute('user_id'),
36-
)
31+
# if we have several events that have common attributes, we can define a base class,
32+
# that is not intended to be instantiated directly. To make sure it is not instantiated,
33+
# we also inherit from `abc.ABC`.
34+
@analytics.eventclass()
35+
class BaseExampleTutorialEvent(analytics.Event, abc.ABC):
36+
# these are required attributes, which are also inherited to the child classes
37+
id: int
38+
user_id: int
3739

38-
class ExampleTutorialDeletedEvent(analytics.Event):
39-
type = 'example_tutorial.deleted'
4040

41-
attributes = (
42-
analytics.Attribute('id'),
43-
analytics.Attribute('user_id'),
44-
)
41+
@analytics.eventclass('example_tutorial.created')
42+
class ExampleTutorialCreatedEvent(BaseExampleTutorialEvent):
43+
# if we don't have additional attributes, we can simply use "pass" here
44+
pass
4545

46-
analytics.register(ExampleTutorialCreatedEvent)
47-
analytics.register(ExampleTutorialDeletedEvent)
48-
```
49-
50-
Your event classes will inherit from [`analytics.Event`](https://github.com/getsentry/sentry/blob/master/src/sentry/analytics/event.py) as shown above. All events have a `type` and `attributes`.
51-
52-
- `type`: Describes what the Event is, and this name should be unique across all analytics event classes.
5346

54-
- `attributes`: Parameters what you would like to track, for example the `user_id` of the user performing the action. All `attributes` must be an `Attribute` object as shown above. Note that you cannot create an `attribute` named `'type'`.
47+
@analytics.eventclass('example_tutorial.deleted')
48+
class ExampleTutorialDeletedEvent(BaseExampleTutorialEvent):
49+
reason: str | None = None # this is an additional, optional attribute
5550

56-
Finally, register your event classes so that the analytics [event_manager](https://github.com/getsentry/sentry/blob/master/src/sentry/analytics/event_manager.py) will pick them up.
5751

58-
### If you are creating the [analytics.py](http://analytics.py) file for the first time:
59-
60-
If you are creating a new analytics file for the first time, you will need to add an import to the package's `__init__.py`.
61-
62-
If the Event classes are defined in a file named: `sentry/examples/analytics`, then the class below would be defined at `sentry/examples/__init__.py`:
52+
# we only register the concrete classes, not the base class
53+
analytics.register(ExampleTutorialCreatedEvent)
54+
analytics.register(ExampleTutorialDeletedEvent)
55+
```
6356

64-
```python
65-
from __future__ import absolute_import
57+
Your event classes will inherit from [`analytics.Event`](https://github.com/getsentry/sentry/blob/master/src/sentry/analytics/event.py) as shown above and must use the `analytics.eventclass` decorator. If the event is an abstract base class, it can be used without argument. If it is to be registered, it must be passed a unique event type string. This type string describes what the Event is, and this name should be unique across all analytics event classes.
6658

67-
from .analytics import * # NOQA
68-
```
59+
Additional attributes can be declared on the class with the appropriate typing syntax. This is similar to how you would declare attributes on a [`dataclass`](https://docs.python.org/3/library/dataclasses.html)(which are actually used underneath). If an attribute is optional, it can be declared with a default value, otherwise it is required and a value must always be provided.
6960

70-
Here, you have your usual `absolute_import` but in addition you will import every class in your [`analytics.py`](http://analytics.py) add `# NOQA` to avoid linter complaints.
61+
Finally, register your event classes so that the analytics [event_manager](https://github.com/getsentry/sentry/blob/master/src/sentry/analytics/event_manager.py) will pick them up. This is only necessary if you want to `record` your analytics event using the string type as discussed below.
7162

7263
### Step 2: Add it to the code you want to track
7364

7465
You'll be adding code in some user-facing area like an API endpoint.
7566

7667
```python
7768
from sentry import analytics
69+
from sentry.examples.analytics import ExampleTutorialCreatedEvent
7870

7971
class ExampleEndpoint(Endpoint):
72+
def post(self, request):
73+
example = Example.objects.create(...)
74+
analytics.record(
75+
ExampleTutorialCreatedEvent(
76+
id=example.id,
77+
user_id=request.user.id,
78+
)
79+
)
80+
return Response(serialize(example, request.user))
81+
```
82+
83+
Do whatever you would normally with the endpoint, then use the `analytics.record` method to gather the information you want. Note that it takes input of the form:
8084

81-
def post(self, request):
82-
example = Example.objects.create(...)
83-
analytics.record(
84-
'example_tutorial.created',
85-
id=example.id,
86-
user_id=request.user.id,
85+
```python
86+
analytics.record(
87+
<EventClass>(
88+
<attribute_name_0>=<value>,
89+
....
90+
<attribute_name_n>=<value>,
8791
)
88-
return Response(serialize(example, request.user))
92+
)
8993
```
9094

91-
Do whatever you would normally with the endpoint, then use the `analytics.record` method to gather the information you want. Note that it takes input of the form:
95+
There is an older, deprecated, way to record analytics events using the `type` passed in the `eventclass` decorator:
9296

9397
```python
9498
analytics.record(
95-
'event_type_as_string',
96-
<attribute_name_0>=<value>,
97-
....
98-
<attribute_name_n>=<value>,
99+
'event_type_as_string',
100+
<attribute_name_0>=<value>,
101+
....
102+
<attribute_name_n>=<value>,
99103
)
100104
```
101105

106+
<Alert level='warning'>
107+
This way of recording analytics events is deprecated and will be removed in a future release as it has several drawbacks. For one, it sidelines static type checking and cannot make guarantees about the passed attributes.
108+
</Alert>
109+
102110
Run the tests that touch the endpoint to ensure everything is Gucci.
103111

104112
### Step 3:
105113

106-
By default, a new event type is aggregated and sent to Amplitude as long as there is a user_id sent along with the event. If you would like to send events unaggregated, refer to [our Amplitude aggregation docs](https://github.com/getsentry/etl/blob/master/documentation/amplitude_analytics.md)
114+
By default, a new event type is aggregated and sent to Amplitude as long as there is a `user_id` sent along with the event. If you would like to send events unaggregated, refer to [our Amplitude aggregation docs](https://github.com/getsentry/etl/blob/master/documentation/amplitude_analytics.md)
107115

108116
## Route-Based Frontend Analytics
109117

0 commit comments

Comments
 (0)