Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion common/api-review/telemetry-angular.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { FirebaseApp } from '@firebase/app';

// @public
export class FirebaseErrorHandler implements ErrorHandler {
constructor(app: FirebaseApp, telemetryOptions?: TelemetryOptions | undefined);
constructor(app: FirebaseApp, telemetryOptions?: TelemetryOptions);
// (undocumented)
handleError(error: unknown): void;
}
Expand Down
4 changes: 2 additions & 2 deletions docs-devsite/telemetry_angular.firebaseerrorhandler.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@ Constructs a new instance of the `FirebaseErrorHandler` class
<b>Signature:</b>

```typescript
constructor(app: FirebaseApp, telemetryOptions?: TelemetryOptions | undefined);
constructor(app: FirebaseApp, telemetryOptions?: TelemetryOptions);
```

#### Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| app | [FirebaseApp](./app.firebaseapp.md#firebaseapp_interface) | |
| telemetryOptions | [TelemetryOptions](./telemetry_.telemetryoptions.md#telemetryoptions_interface) \| undefined | |
| telemetryOptions | [TelemetryOptions](./telemetry_.telemetryoptions.md#telemetryoptions_interface) | |

## FirebaseErrorHandler.handleError()

Expand Down
1 change: 1 addition & 0 deletions packages/telemetry/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@
"@angular/platform-browser": "19.2.15",
"@angular/router": "19.2.15",
"@firebase/app": "0.14.6",
"@firebase/util": "1.13.0",
"@opentelemetry/sdk-trace-web": "2.1.0",
"@rollup/plugin-json": "6.1.0",
"@rollup/plugin-replace": "6.0.2",
Expand Down
19 changes: 2 additions & 17 deletions packages/telemetry/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { Provider } from '@firebase/component';
import { AnyValueMap, SeverityNumber } from '@opentelemetry/api-logs';
import { trace } from '@opentelemetry/api';
import { TelemetryService } from './service';
import { getAppVersion, getSessionId } from './helpers';
import { flush, getAppVersion, getSessionId } from './helpers';
import { TelemetryInternal } from './types';

declare module '@firebase/component' {
Expand Down Expand Up @@ -132,19 +132,4 @@ export function captureError(
}
}

/**
* Flushes all enqueued telemetry data immediately, instead of waiting for default batching.
*
* @public
*
* @param telemetry - The {@link Telemetry} instance.
* @returns a promise which is resolved when all flushes are complete
*/
export function flush(telemetry: Telemetry): Promise<void> {
// Cast to TelemetryInternal to access internal loggerProvider
return (telemetry as TelemetryInternal).loggerProvider
.forceFlush()
.catch(err => {
console.error('Error flushing logs from Firebase Telemetry:', err);
});
}
export { flush };
48 changes: 46 additions & 2 deletions packages/telemetry/src/helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
import { expect } from 'chai';
import { LoggerProvider } from '@opentelemetry/sdk-logs';
import { Logger, LogRecord } from '@opentelemetry/api-logs';
import { startNewSession } from './helpers';
import { isNode } from '@firebase/util';
import { registerListeners, startNewSession } from './helpers';
import {
LOG_ENTRY_ATTRIBUTE_KEYS,
TELEMETRY_SESSION_ID_KEY
Expand All @@ -34,6 +35,7 @@ describe('helpers', () => {
let originalCrypto: Crypto | undefined;
let storage: Record<string, string> = {};
let emittedLogs: LogRecord[] = [];
let flushed = false;

const fakeLoggerProvider = {
getLogger: (): Logger => {
Expand All @@ -43,7 +45,10 @@ describe('helpers', () => {
}
};
},
forceFlush: () => Promise.resolve(),
forceFlush: () => {
flushed = true;
return Promise.resolve();
},
shutdown: () => Promise.resolve()
} as unknown as LoggerProvider;

Expand All @@ -61,6 +66,7 @@ describe('helpers', () => {

beforeEach(() => {
emittedLogs = [];
flushed = false;
storage = {};
// @ts-ignore
originalSessionStorage = global.sessionStorage;
Expand Down Expand Up @@ -96,6 +102,12 @@ describe('helpers', () => {
value: originalCrypto,
writable: true
});
if (!isNode()) {
Object.defineProperty(document, 'visibilityState', {
value: 'visible',
writable: true
});
}
delete AUTO_CONSTANTS.appVersion;
});

Expand Down Expand Up @@ -136,4 +148,36 @@ describe('helpers', () => {
});
});
});

describe('registerListeners', () => {
if (isNode()) {
it('should do nothing in node', () => {
registerListeners(fakeTelemetry);
});
} else {
it('should flush logs when the visibility changes to hidden', () => {
registerListeners(fakeTelemetry);

expect(flushed).to.be.false;

Object.defineProperty(document, 'visibilityState', {
value: 'hidden',
writable: true
});
window.dispatchEvent(new Event('visibilitychange'));

expect(flushed).to.be.true;
});

it('should flush logs when the pagehide event fires', () => {
registerListeners(fakeTelemetry);

expect(flushed).to.be.false;

window.dispatchEvent(new Event('pagehide'));

expect(flushed).to.be.true;
});
}
});
});
34 changes: 34 additions & 0 deletions packages/telemetry/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,37 @@ export function startNewSession(telemetry: Telemetry): void {
}
}
}

/**
* Registers event listeners to flush logs when the page is hidden. In some cases multiple listeners
* may trigger at the same time, but flushing only occurs once per batch.
*/
export function registerListeners(telemetry: Telemetry): void {
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
window.addEventListener('visibilitychange', async () => {
if (document.visibilityState === 'hidden') {
await flush(telemetry);
}
});
window.addEventListener('pagehide', async () => {
await flush(telemetry);
});
}
}

/**
* Flushes all enqueued telemetry data immediately, instead of waiting for default batching.
*
* @public
*
* @param telemetry - The {@link Telemetry} instance.
* @returns a promise which is resolved when all flushes are complete
*/
export function flush(telemetry: Telemetry): Promise<void> {
// Cast to TelemetryInternal to access internal loggerProvider
return (telemetry as TelemetryInternal).loggerProvider
.forceFlush()
.catch(err => {
console.error('Error flushing logs from Firebase Telemetry:', err);
});
}
5 changes: 4 additions & 1 deletion packages/telemetry/src/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ import { createLoggerProvider } from './logging/logger-provider';
import { AppCheckProvider } from './logging/appcheck-provider';
import { InstallationIdProvider } from './logging/installation-id-provider';
import { TELEMETRY_TYPE } from './constants';
import { getSessionId, registerListeners, startNewSession } from './helpers';

// We only import types from this package elsewhere in the `telemetry` package, so this
// explicit import is needed here to prevent this module from being tree-shaken out.
import '@firebase/installations';
import { getSessionId, startNewSession } from './helpers';

export function registerTelemetry(): void {
_registerComponent(
Expand Down Expand Up @@ -65,6 +65,9 @@ export function registerTelemetry(): void {
startNewSession(telemetryService);
}

// Register relevant event listeners
registerListeners(telemetryService);

return telemetryService;
},
ComponentType.PUBLIC
Expand Down
Loading