Fix exception when loading PostHog

PostHog was expecting the matrix client object to be initialised at
the point it ran its setup, which wasn't the case. Check to see if it's
there on login and add an onLoginStatusChanged hook that to re-check.

Also make a few methods private that didn't need to be public.

Also fix a few instances where the OpenTelemetry group call tried to
report metrics using a tracer which didn't exist anymore, if the user
disabled analytics and then joined the same call again.
This commit is contained in:
David Baker 2023-04-05 13:06:55 +01:00
parent 7b88c4330e
commit 0dcaa90650
3 changed files with 24 additions and 5 deletions

View file

@ -342,6 +342,8 @@ export const ClientProvider: FC<Props> = ({ children }) => {
useEffect(() => { useEffect(() => {
window.matrixclient = client; window.matrixclient = client;
window.isPasswordlessUser = isPasswordlessUser; window.isPasswordlessUser = isPasswordlessUser;
PosthogAnalytics.instance.onLoginStatusChanged();
}, [client, isPasswordlessUser]); }, [client, isPasswordlessUser]);
if (error) { if (error) {

View file

@ -227,7 +227,7 @@ export class PosthogAnalytics {
.join(""); .join("");
} }
public async identifyUser(analyticsIdGenerator: () => string) { private async identifyUser(analyticsIdGenerator: () => string) {
if (this.anonymity == Anonymity.Pseudonymous && this.enabled) { if (this.anonymity == Anonymity.Pseudonymous && this.enabled) {
// Check the user's account_data for an analytics ID to use. Storing the ID in account_data allows // Check the user's account_data for an analytics ID to use. Storing the ID in account_data allows
// different devices to send the same ID. // different devices to send the same ID.
@ -319,7 +319,12 @@ export class PosthogAnalytics {
this.setAnonymity(Anonymity.Disabled); this.setAnonymity(Anonymity.Disabled);
} }
public updateSuperProperties() { public onLoginStatusChanged(): void {
const optInAnalytics = getSetting("opt-in-analytics", false);
this.updateAnonymityAndIdentifyUser(optInAnalytics);
}
private updateSuperProperties() {
// Update super properties in posthog with our platform (app version, platform). // Update super properties in posthog with our platform (app version, platform).
// These properties will be subsequently passed in every event. // These properties will be subsequently passed in every event.
// //
@ -339,7 +344,7 @@ export class PosthogAnalytics {
return this.eventSignup.getSignupEndTime() > new Date(0); return this.eventSignup.getSignupEndTime() > new Date(0);
} }
public async updateAnonymityAndIdentifyUser( private async updateAnonymityAndIdentifyUser(
pseudonymousOptIn: boolean pseudonymousOptIn: boolean
): Promise<void> { ): Promise<void> {
// Update this.anonymity based on the user's analytics opt-in settings // Update this.anonymity based on the user's analytics opt-in settings
@ -348,6 +353,10 @@ export class PosthogAnalytics {
: Anonymity.Disabled; : Anonymity.Disabled;
this.setAnonymity(anonymity); this.setAnonymity(anonymity);
// We may not yet have a Matrix client at this point, if not, bail. This should get
// triggered again by onLoginStatusChanged once we do have a client.
if (!window.matrixclient) return;
if (anonymity === Anonymity.Pseudonymous) { if (anonymity === Anonymity.Pseudonymous) {
this.setRegistrationType( this.setRegistrationType(
window.matrixclient.isGuest() || window.isPasswordlessUser window.matrixclient.isGuest() || window.isPasswordlessUser
@ -385,7 +394,7 @@ export class PosthogAnalytics {
this.capture(eventName, properties, options); this.capture(eventName, properties, options);
} }
public startListeningToSettingsChanges(): void { private startListeningToSettingsChanges(): void {
// Listen to account data changes from sync so we can observe changes to relevant flags and update. // Listen to account data changes from sync so we can observe changes to relevant flags and update.
// This is called - // This is called -
// * On page load, when the account data is first received by sync // * On page load, when the account data is first received by sync

View file

@ -124,6 +124,8 @@ export class OTelGroupCallMembership {
} }
public onJoinCall() { public onJoinCall() {
if (!ElementCallOpenTelemetry.instance) return;
// Create the main span that tracks the time we intend to be in the call // Create the main span that tracks the time we intend to be in the call
this.callMembershipSpan = this.callMembershipSpan =
ElementCallOpenTelemetry.instance.tracer.startSpan( ElementCallOpenTelemetry.instance.tracer.startSpan(
@ -174,7 +176,7 @@ export class OTelGroupCallMembership {
for (const [userId, userCalls] of calls.entries()) { for (const [userId, userCalls] of calls.entries()) {
for (const [deviceId, call] of userCalls.entries()) { for (const [deviceId, call] of userCalls.entries()) {
if (!this.callsByCallId.has(call.callId)) { if (!this.callsByCallId.has(call.callId)) {
const span = ElementCallOpenTelemetry.instance.tracer.startSpan( const span = ElementCallOpenTelemetry.instance?.tracer.startSpan(
`matrix.call`, `matrix.call`,
undefined, undefined,
this.groupCallContext this.groupCallContext
@ -321,6 +323,8 @@ export class OTelGroupCallMembership {
public onConnectionStatsReport( public onConnectionStatsReport(
statsReport: GroupCallStatsReport<ConnectionStatsReport> statsReport: GroupCallStatsReport<ConnectionStatsReport>
) { ) {
if (!ElementCallOpenTelemetry.instance) return;
const type = OTelStatsReportType.ConnectionReport; const type = OTelStatsReportType.ConnectionReport;
const data = const data =
ObjectFlattener.flattenConnectionStatsReportObject(statsReport); ObjectFlattener.flattenConnectionStatsReportObject(statsReport);
@ -330,6 +334,8 @@ export class OTelGroupCallMembership {
public onByteSentStatsReport( public onByteSentStatsReport(
statsReport: GroupCallStatsReport<ByteSentStatsReport> statsReport: GroupCallStatsReport<ByteSentStatsReport>
) { ) {
if (!ElementCallOpenTelemetry.instance) return;
const type = OTelStatsReportType.ByteSentReport; const type = OTelStatsReportType.ByteSentReport;
const data = ObjectFlattener.flattenByteSentStatsReportObject(statsReport); const data = ObjectFlattener.flattenByteSentStatsReportObject(statsReport);
this.buildStatsEventSpan({ type, data }); this.buildStatsEventSpan({ type, data });
@ -338,6 +344,8 @@ export class OTelGroupCallMembership {
public onSummaryStatsReport( public onSummaryStatsReport(
statsReport: GroupCallStatsReport<SummaryStatsReport> statsReport: GroupCallStatsReport<SummaryStatsReport>
) { ) {
if (!ElementCallOpenTelemetry.instance) return;
const type = OTelStatsReportType.SummaryReport; const type = OTelStatsReportType.SummaryReport;
const data = ObjectFlattener.flattenSummaryStatsReportObject(statsReport); const data = ObjectFlattener.flattenSummaryStatsReportObject(statsReport);
this.buildStatsEventSpan({ type, data }); this.buildStatsEventSpan({ type, data });