|
| 1 | +from typing import TYPE_CHECKING |
| 2 | +import posthog |
| 3 | +from posthog import contexts |
| 4 | + |
| 5 | +if TYPE_CHECKING: |
| 6 | + from starlette.requests import Request |
| 7 | + |
| 8 | + |
| 9 | +async def inject_posthog_tags(request: Request): |
| 10 | + """ |
| 11 | + Inject some common tags into posthog events for this request. This is helpful for linking frontend events to backend events. |
| 12 | +
|
| 13 | + The Django implementation pulls a lot of data from the request. However, this data should already be in place from the frontend |
| 14 | + library. If it's not, something else is wrong and we shouldn't hack around it by including more data here. |
| 15 | +
|
| 16 | + Instead, let's primary just tag the distinct_id and session_id from the request headers. These are injected in all HeyAPI |
| 17 | + requests, but are *not* guaranteed to be present on all requests. |
| 18 | +
|
| 19 | + https://github.com/PostHog/posthog-python/blob/master/posthog/integrations/django.py |
| 20 | + """ |
| 21 | + |
| 22 | + # by default, there is not a context, so we must define one |
| 23 | + # `capture_exceptions=False` https://github.com/PostHog/posthog-python/issues/353 |
| 24 | + with posthog.new_context(capture_exceptions=False): |
| 25 | + # intentionally overwrite any other session or distinct id set previously |
| 26 | + # it's up to the user to add dependencies in the correct order |
| 27 | + if distinct_id := request.headers.get("X-Posthog-Distinct-Id"): |
| 28 | + contexts.identify_context(distinct_id) |
| 29 | + |
| 30 | + if session_id := request.headers.get("X-Posthog-Session-Id"): |
| 31 | + contexts.set_context_session(session_id) |
| 32 | + |
| 33 | + tags = {} |
| 34 | + |
| 35 | + if absolute_url := str(request.url): |
| 36 | + tags["$current_url"] = absolute_url |
| 37 | + |
| 38 | + if request.method: |
| 39 | + tags["$request_method"] = request.method |
| 40 | + |
| 41 | + if request.url.path: |
| 42 | + tags["$request_path"] = request.url.path |
| 43 | + |
| 44 | + # TODO adding another dependency for IP extraction seems heavy-handed, but using the default IP is mostly useless |
| 45 | + # if request_ip := fastapi_access_logger.client_ip_from_request(request): |
| 46 | + # # django uses $ip_address, but posthog web library uses $ip |
| 47 | + # tags["$ip"] = request_ip |
| 48 | + |
| 49 | + # although absolute_url contains the host, we must set it separately |
| 50 | + if request.url.hostname: |
| 51 | + tags["$host"] = request.url.hostname |
| 52 | + |
| 53 | + for k, v in tags.items(): |
| 54 | + contexts.tag(k, v) |
| 55 | + |
| 56 | + yield |
0 commit comments