diff --git a/src/ClientContext.tsx b/src/ClientContext.tsx index 46dfe5a5..08593a4b 100644 --- a/src/ClientContext.tsx +++ b/src/ClientContext.tsx @@ -342,6 +342,9 @@ export const ClientProvider: FC = ({ children }) => { useEffect(() => { window.matrixclient = client; window.isPasswordlessUser = isPasswordlessUser; + + if (PosthogAnalytics.hasInstance()) + PosthogAnalytics.instance.onLoginStatusChanged(); }, [client, isPasswordlessUser]); if (error) { diff --git a/src/analytics/PosthogAnalytics.ts b/src/analytics/PosthogAnalytics.ts index e2e8fdae..ed8ada35 100644 --- a/src/analytics/PosthogAnalytics.ts +++ b/src/analytics/PosthogAnalytics.ts @@ -102,6 +102,10 @@ export class PosthogAnalytics { private platformSuperProperties = {}; private registrationType: RegistrationType = RegistrationType.Guest; + public static hasInstance(): boolean { + return Boolean(this.internalInstance); + } + public static get instance(): PosthogAnalytics { if (!this.internalInstance) { this.internalInstance = new PosthogAnalytics(posthog); @@ -227,7 +231,7 @@ export class PosthogAnalytics { .join(""); } - public async identifyUser(analyticsIdGenerator: () => string) { + private async identifyUser(analyticsIdGenerator: () => string) { 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 // different devices to send the same ID. @@ -319,7 +323,12 @@ export class PosthogAnalytics { 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). // These properties will be subsequently passed in every event. // @@ -339,7 +348,7 @@ export class PosthogAnalytics { return this.eventSignup.getSignupEndTime() > new Date(0); } - public async updateAnonymityAndIdentifyUser( + private async updateAnonymityAndIdentifyUser( pseudonymousOptIn: boolean ): Promise { // Update this.anonymity based on the user's analytics opt-in settings @@ -348,6 +357,10 @@ export class PosthogAnalytics { : Anonymity.Disabled; 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) { this.setRegistrationType( window.matrixclient.isGuest() || window.isPasswordlessUser @@ -385,7 +398,7 @@ export class PosthogAnalytics { 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. // This is called - // * On page load, when the account data is first received by sync diff --git a/src/otel/OTelGroupCallMembership.ts b/src/otel/OTelGroupCallMembership.ts index 8aa24c74..c8fce617 100644 --- a/src/otel/OTelGroupCallMembership.ts +++ b/src/otel/OTelGroupCallMembership.ts @@ -124,6 +124,8 @@ export class OTelGroupCallMembership { } public onJoinCall() { + if (!ElementCallOpenTelemetry.instance) return; + // Create the main span that tracks the time we intend to be in the call this.callMembershipSpan = ElementCallOpenTelemetry.instance.tracer.startSpan( @@ -174,21 +176,23 @@ export class OTelGroupCallMembership { for (const [userId, userCalls] of calls.entries()) { for (const [deviceId, call] of userCalls.entries()) { if (!this.callsByCallId.has(call.callId)) { - const span = ElementCallOpenTelemetry.instance.tracer.startSpan( - `matrix.call`, - undefined, - this.groupCallContext - ); - // XXX: anonymity - span.setAttribute("matrix.call.target.userId", userId); - span.setAttribute("matrix.call.target.deviceId", deviceId); - const displayName = - this.groupCall.room.getMember(userId)?.name ?? "unknown"; - span.setAttribute("matrix.call.target.displayName", displayName); - this.callsByCallId.set( - call.callId, - new OTelCall(userId, deviceId, call, span) - ); + if (ElementCallOpenTelemetry.instance) { + const span = ElementCallOpenTelemetry.instance.tracer.startSpan( + `matrix.call`, + undefined, + this.groupCallContext + ); + // XXX: anonymity + span.setAttribute("matrix.call.target.userId", userId); + span.setAttribute("matrix.call.target.deviceId", deviceId); + const displayName = + this.groupCall.room.getMember(userId)?.name ?? "unknown"; + span.setAttribute("matrix.call.target.displayName", displayName); + this.callsByCallId.set( + call.callId, + new OTelCall(userId, deviceId, call, span) + ); + } } } } @@ -321,6 +325,8 @@ export class OTelGroupCallMembership { public onConnectionStatsReport( statsReport: GroupCallStatsReport ) { + if (!ElementCallOpenTelemetry.instance) return; + const type = OTelStatsReportType.ConnectionReport; const data = ObjectFlattener.flattenConnectionStatsReportObject(statsReport); @@ -330,6 +336,8 @@ export class OTelGroupCallMembership { public onByteSentStatsReport( statsReport: GroupCallStatsReport ) { + if (!ElementCallOpenTelemetry.instance) return; + const type = OTelStatsReportType.ByteSentReport; const data = ObjectFlattener.flattenByteSentStatsReportObject(statsReport); this.buildStatsEventSpan({ type, data }); @@ -338,6 +346,8 @@ export class OTelGroupCallMembership { public onSummaryStatsReport( statsReport: GroupCallStatsReport ) { + if (!ElementCallOpenTelemetry.instance) return; + const type = OTelStatsReportType.SummaryReport; const data = ObjectFlattener.flattenSummaryStatsReportObject(statsReport); this.buildStatsEventSpan({ type, data });