From b8973235145706b85a310a34cd4a734ee7e80b54 Mon Sep 17 00:00:00 2001 From: abrook Date: Tue, 26 Aug 2025 10:44:21 -0400 Subject: [PATCH 1/2] Add support for exporting captured errors --- packages/app/src/constants.ts | 2 + packages/telemetry/package.json | 9 +- packages/telemetry/src/api.test.ts | 126 +++++++++++++++++++++++ packages/telemetry/src/api.ts | 54 ++++++++++ packages/telemetry/src/helpers.ts | 45 ++++++++ packages/telemetry/src/index.node.ts | 18 +--- packages/telemetry/src/index.test.ts | 31 ------ packages/telemetry/src/index.ts | 18 +--- packages/telemetry/src/public-types.ts | 4 + packages/telemetry/src/service.ts | 3 +- packages/telemetry/src/types/index.ts | 20 ---- yarn.lock | 136 ++++++++++++++++++++++++- 12 files changed, 380 insertions(+), 86 deletions(-) create mode 100644 packages/telemetry/src/api.test.ts create mode 100644 packages/telemetry/src/helpers.ts delete mode 100644 packages/telemetry/src/index.test.ts delete mode 100644 packages/telemetry/src/types/index.ts diff --git a/packages/app/src/constants.ts b/packages/app/src/constants.ts index 21ded00529a..3aa37b72754 100644 --- a/packages/app/src/constants.ts +++ b/packages/app/src/constants.ts @@ -41,6 +41,7 @@ import { name as storageCompatName } from '../../../packages/storage-compat/pack import { name as firestoreName } from '../../../packages/firestore/package.json'; import { name as aiName } from '../../../packages/ai/package.json'; import { name as firestoreCompatName } from '../../../packages/firestore-compat/package.json'; +import { name as telemetryName } from '../../../packages/telemetry/package.json'; import { name as packageName } from '../../../packages/firebase/package.json'; /** @@ -74,6 +75,7 @@ export const PLATFORM_LOG_STRING = { [remoteConfigCompatName]: 'fire-rc-compat', [storageName]: 'fire-gcs', [storageCompatName]: 'fire-gcs-compat', + [telemetryName]: 'fire-telemetry', [firestoreName]: 'fire-fst', [firestoreCompatName]: 'fire-fst-compat', [aiName]: 'fire-vertex', diff --git a/packages/telemetry/package.json b/packages/telemetry/package.json index ff90cc211fd..87c9f2b1c11 100644 --- a/packages/telemetry/package.json +++ b/packages/telemetry/package.json @@ -42,8 +42,13 @@ "@firebase/app-types": "0.x" }, "dependencies": { - "tslib": "^2.1.0", - "@firebase/component": "0.7.0" + "@firebase/component": "0.7.0", + "@opentelemetry/api-logs": "0.203.0", + "@opentelemetry/exporter-logs-otlp-http": "0.203.0", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/sdk-logs": "0.203.0", + "@opentelemetry/semantic-conventions": "1.36.0", + "tslib": "^2.1.0" }, "license": "Apache-2.0", "devDependencies": { diff --git a/packages/telemetry/src/api.test.ts b/packages/telemetry/src/api.test.ts new file mode 100644 index 00000000000..206c0f693d8 --- /dev/null +++ b/packages/telemetry/src/api.test.ts @@ -0,0 +1,126 @@ +/** + * @license + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect } from 'chai'; +import { LoggerProvider } from '@opentelemetry/sdk-logs'; +import { Telemetry } from './public-types'; +import { Logger, LogRecord, SeverityNumber } from '@opentelemetry/api-logs'; +import { captureError, flush } from './api'; + +const emittedLogs: LogRecord[] = []; + +const fakeLoggerProvider = { + getLogger: (): Logger => { + return { + emit: (logRecord: LogRecord) => { + emittedLogs.push(logRecord); + } + }; + }, + forceFlush: () => { + emittedLogs.length = 0; + return Promise.resolve(); + }, + shutdown: () => Promise.resolve() +} as unknown as LoggerProvider; + +const fakeTelemetry: Telemetry = { + app: { + name: 'DEFAULT', + automaticDataCollectionEnabled: true, + options: { + projectId: 'my-project', + appId: 'my-appid' + } + }, + loggerProvider: fakeLoggerProvider +}; + +describe('Top level API', () => { + beforeEach(() => { + // Clear the logs before each test. + emittedLogs.length = 0; + }); + + describe('captureError()', () => { + it('should capture an Error object correctly', () => { + const error = new Error('This is a test error'); + error.stack = '...stack trace...'; + error.name = 'TestError'; + + captureError(fakeTelemetry, error); + + expect(emittedLogs.length).to.equal(1); + const log = emittedLogs[0]; + expect(log.severityNumber).to.equal(SeverityNumber.ERROR); + expect(log.body).to.equal('This is a test error'); + expect(log.attributes).to.deep.equal({ + 'error.type': 'TestError', + 'error.stack': '...stack trace...' + }); + }); + + it('should handle an Error object with no stack trace', () => { + const error = new Error('error with no stack'); + error.stack = undefined; + + captureError(fakeTelemetry, error); + + expect(emittedLogs.length).to.equal(1); + const log = emittedLogs[0]; + expect(log.severityNumber).to.equal(SeverityNumber.ERROR); + expect(log.body).to.equal('error with no stack'); + expect(log.attributes).to.deep.equal({ + 'error.type': 'Error', + 'error.stack': 'No stack trace available' + }); + }); + + it('should capture a string error correctly', () => { + captureError(fakeTelemetry, 'a string error'); + + expect(emittedLogs.length).to.equal(1); + const log = emittedLogs[0]; + expect(log.severityNumber).to.equal(SeverityNumber.ERROR); + expect(log.body).to.equal('a string error'); + expect(log.attributes).to.be.undefined; + }); + + it('should capture an unknown error type correctly', () => { + captureError(fakeTelemetry, 12345); + + expect(emittedLogs.length).to.equal(1); + const log = emittedLogs[0]; + expect(log.severityNumber).to.equal(SeverityNumber.ERROR); + expect(log.body).to.equal('Unknown error type: number'); + expect(log.attributes).to.be.undefined; + }); + }); + + describe('flush()', () => { + it('should flush logs correctly', async () => { + captureError(fakeTelemetry, 'error1'); + captureError(fakeTelemetry, 'error2'); + + expect(emittedLogs.length).to.equal(2); + + await flush(fakeTelemetry); + + expect(emittedLogs.length).to.equal(0); + }); + }); +}); diff --git a/packages/telemetry/src/api.ts b/packages/telemetry/src/api.ts index 950d47ada33..853923104f4 100644 --- a/packages/telemetry/src/api.ts +++ b/packages/telemetry/src/api.ts @@ -19,6 +19,14 @@ import { _getProvider, FirebaseApp, getApp } from '@firebase/app'; import { TELEMETRY_TYPE } from './constants'; import { Telemetry } from './public-types'; import { Provider } from '@firebase/component'; +import { SeverityNumber } from '@opentelemetry/api-logs'; +import { TelemetryService } from './service'; + +declare module '@firebase/component' { + interface NameServiceMapping { + [TELEMETRY_TYPE]: TelemetryService; + } +} /** * Returns the default {@link Telemetry} instance that is associated with the provided @@ -44,3 +52,49 @@ export function getTelemetry(app: FirebaseApp = getApp()): Telemetry { return telemetryProvider.getImmediate(); } + +/** + * Enqueues an error to be uploaded to the Firebase Telemetry API. + * + * @public + * + * @param telemetry - The {@link Telemetry} instance. + * @param error - the caught exception, typically an {@link Error} + */ +export function captureError(telemetry: Telemetry, error: unknown): void { + const logger = telemetry.loggerProvider.getLogger('error-logger'); + if (error instanceof Error) { + logger.emit({ + severityNumber: SeverityNumber.ERROR, + body: error.message, + attributes: { + 'error.type': error.name || 'Error', + 'error.stack': error.stack || 'No stack trace available' + } + }); + } else if (typeof error === 'string') { + logger.emit({ + severityNumber: SeverityNumber.ERROR, + body: error + }); + } else { + logger.emit({ + severityNumber: SeverityNumber.ERROR, + body: `Unknown error type: ${typeof error}` + }); + } +} + +/** + * Flushes all enqueued telemetry data immediately. + * + * @public + * + * @param telemetry - The {@link Telemetry} instance. + * @returns a promise which is resolved when all flushes are complete + */ +export function flush(telemetry: Telemetry): Promise { + return telemetry.loggerProvider.forceFlush().catch(err => { + console.error('Error flushing logs from Firebase Telemetry:', err); + }); +} diff --git a/packages/telemetry/src/helpers.ts b/packages/telemetry/src/helpers.ts new file mode 100644 index 00000000000..bfc7ab6260b --- /dev/null +++ b/packages/telemetry/src/helpers.ts @@ -0,0 +1,45 @@ +/** + * @license + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + LoggerProvider, + BatchLogRecordProcessor +} from '@opentelemetry/sdk-logs'; +import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions'; +import { resourceFromAttributes } from '@opentelemetry/resources'; +import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http'; + +/** + * Create default logger provider. + * + * @internal + */ +export function createLoggerProvider(): LoggerProvider { + const resource = resourceFromAttributes({ + [ATTR_SERVICE_NAME]: 'firebase_telemetry_service' + }); + + const otlpEndpoint = process.env.OTEL_ENDPOINT; + + const logExporter = new OTLPLogExporter({ + url: `${otlpEndpoint}/api/v1/logs` + }); + return new LoggerProvider({ + resource, + processors: [new BatchLogRecordProcessor(logExporter)] + }); +} diff --git a/packages/telemetry/src/index.node.ts b/packages/telemetry/src/index.node.ts index 8c14e0f3359..e3394749726 100644 --- a/packages/telemetry/src/index.node.ts +++ b/packages/telemetry/src/index.node.ts @@ -16,23 +16,11 @@ */ import { _registerComponent, registerVersion } from '@firebase/app'; -import { TestType } from './types/index'; import { Component, ComponentType } from '@firebase/component'; import { TELEMETRY_TYPE } from './constants'; import { name, version } from '../package.json'; import { TelemetryService } from './service'; - -export function testFxn(): number { - const _thing: TestType = {}; - console.log('hi'); - return 42; -} - -declare module '@firebase/component' { - interface NameServiceMapping { - [TELEMETRY_TYPE]: TelemetryService; - } -} +import { createLoggerProvider } from './helpers'; export function registerTelemetry(): void { _registerComponent( @@ -41,7 +29,9 @@ export function registerTelemetry(): void { container => { // getImmediate for FirebaseApp will always succeed const app = container.getProvider('app').getImmediate(); - return new TelemetryService(app); + const loggerProvider = createLoggerProvider(); + + return new TelemetryService(app, loggerProvider); }, ComponentType.PUBLIC ) diff --git a/packages/telemetry/src/index.test.ts b/packages/telemetry/src/index.test.ts deleted file mode 100644 index 4b314ac8835..00000000000 --- a/packages/telemetry/src/index.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @license - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { expect } from 'chai'; -import { testFxn } from './index'; - -describe('Simple test', () => { - it('Should skip this test'); - it('Should test this function', () => { - expect(testFxn()).to.equal(42); - }); - it('Should test this async thing', async () => { - // Do some async assertions, you can use `await` syntax if it helps - const val = await Promise.resolve(42); - expect(val).to.equal(42); - }); -}); diff --git a/packages/telemetry/src/index.ts b/packages/telemetry/src/index.ts index 352b0853aef..566d65dc9d0 100644 --- a/packages/telemetry/src/index.ts +++ b/packages/telemetry/src/index.ts @@ -16,23 +16,11 @@ */ import { _registerComponent, registerVersion } from '@firebase/app'; -import { TestType } from './types/index'; import { Component, ComponentType } from '@firebase/component'; import { TELEMETRY_TYPE } from './constants'; import { name, version } from '../package.json'; import { TelemetryService } from './service'; - -export function testFxn(): number { - const _thing: TestType = {}; - console.log('hi'); - return 42; -} - -declare module '@firebase/component' { - interface NameServiceMapping { - [TELEMETRY_TYPE]: TelemetryService; - } -} +import { createLoggerProvider } from './helpers'; export function registerTelemetry(): void { _registerComponent( @@ -41,7 +29,9 @@ export function registerTelemetry(): void { (container, {}) => { // getImmediate for FirebaseApp will always succeed const app = container.getProvider('app').getImmediate(); - return new TelemetryService(app); + const loggerProvider = createLoggerProvider(); + + return new TelemetryService(app, loggerProvider); }, ComponentType.PUBLIC ) diff --git a/packages/telemetry/src/public-types.ts b/packages/telemetry/src/public-types.ts index 5bcc1830929..3ebe4196d98 100644 --- a/packages/telemetry/src/public-types.ts +++ b/packages/telemetry/src/public-types.ts @@ -16,6 +16,7 @@ */ import { FirebaseApp } from '@firebase/app'; +import { LoggerProvider } from '@opentelemetry/sdk-logs'; /** * An instance of the Firebase Telemetry SDK. @@ -29,4 +30,7 @@ export interface Telemetry { * The {@link @firebase/app#FirebaseApp} this {@link Telemetry} instance is associated with. */ app: FirebaseApp; + + /** The {@link LoggerProvider} this {@link Telemetry} instance uses. */ + loggerProvider: LoggerProvider; } diff --git a/packages/telemetry/src/service.ts b/packages/telemetry/src/service.ts index 1c314b2af9d..e09e861d3dc 100644 --- a/packages/telemetry/src/service.ts +++ b/packages/telemetry/src/service.ts @@ -17,9 +17,10 @@ import { _FirebaseService, FirebaseApp } from '@firebase/app'; import { Telemetry } from './public-types'; +import { LoggerProvider } from '@opentelemetry/sdk-logs'; export class TelemetryService implements Telemetry, _FirebaseService { - constructor(public app: FirebaseApp) {} + constructor(public app: FirebaseApp, public loggerProvider: LoggerProvider) {} _delete(): Promise { return Promise.resolve(); diff --git a/packages/telemetry/src/types/index.ts b/packages/telemetry/src/types/index.ts deleted file mode 100644 index 8626d54ad64..00000000000 --- a/packages/telemetry/src/types/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @license - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export interface TestType { - prop?: string; -} diff --git a/yarn.lock b/yarn.lock index 540d7bc7171..49b8eed4ed5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2508,11 +2508,96 @@ dependencies: "@octokit/openapi-types" "^12.11.0" -"@opentelemetry/api@~1.9.0": +"@opentelemetry/api-logs@0.203.0": + version "0.203.0" + resolved "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.203.0.tgz#3309a76c51a848ea820cd7f00ee62daf36b06380" + integrity sha512-9B9RU0H7Ya1Dx/Rkyc4stuBZSGVQF27WigitInx2QQoj6KUpEFYPKoWjdFTunJYxmXmh17HeBvbMa1EhGyPmqQ== + dependencies: + "@opentelemetry/api" "^1.3.0" + +"@opentelemetry/api@^1.3.0", "@opentelemetry/api@~1.9.0": version "1.9.0" resolved "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz#d03eba68273dc0f7509e2a3d5cba21eae10379fe" integrity sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg== +"@opentelemetry/core@2.0.1": + version "2.0.1" + resolved "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz#44e1149d5666a4743cde943ef89841db3ce0f8bc" + integrity sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw== + dependencies: + "@opentelemetry/semantic-conventions" "^1.29.0" + +"@opentelemetry/exporter-logs-otlp-http@0.203.0": + version "0.203.0" + resolved "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.203.0.tgz#cdecb5c5b39561aa8520c8bb78347c6e11c91a81" + integrity sha512-s0hys1ljqlMTbXx2XiplmMJg9wG570Z5lH7wMvrZX6lcODI56sG4HL03jklF63tBeyNwK2RV1/ntXGo3HgG4Qw== + dependencies: + "@opentelemetry/api-logs" "0.203.0" + "@opentelemetry/core" "2.0.1" + "@opentelemetry/otlp-exporter-base" "0.203.0" + "@opentelemetry/otlp-transformer" "0.203.0" + "@opentelemetry/sdk-logs" "0.203.0" + +"@opentelemetry/otlp-exporter-base@0.203.0": + version "0.203.0" + resolved "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.203.0.tgz#8a9c2916b5a87467fd85950c054cecf9a97aec26" + integrity sha512-Wbxf7k+87KyvxFr5D7uOiSq/vHXWommvdnNE7vECO3tAhsA2GfOlpWINCMWUEPdHZ7tCXxw6Epp3vgx3jU7llQ== + dependencies: + "@opentelemetry/core" "2.0.1" + "@opentelemetry/otlp-transformer" "0.203.0" + +"@opentelemetry/otlp-transformer@0.203.0": + version "0.203.0" + resolved "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.203.0.tgz#e93220ed56aae573640c85e158221094d1f2905b" + integrity sha512-Y8I6GgoCna0qDQ2W6GCRtaF24SnvqvA8OfeTi7fqigD23u8Jpb4R5KFv/pRvrlGagcCLICMIyh9wiejp4TXu/A== + dependencies: + "@opentelemetry/api-logs" "0.203.0" + "@opentelemetry/core" "2.0.1" + "@opentelemetry/resources" "2.0.1" + "@opentelemetry/sdk-logs" "0.203.0" + "@opentelemetry/sdk-metrics" "2.0.1" + "@opentelemetry/sdk-trace-base" "2.0.1" + protobufjs "^7.3.0" + +"@opentelemetry/resources@2.0.1": + version "2.0.1" + resolved "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz#0365d134291c0ed18d96444a1e21d0e6a481c840" + integrity sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw== + dependencies: + "@opentelemetry/core" "2.0.1" + "@opentelemetry/semantic-conventions" "^1.29.0" + +"@opentelemetry/sdk-logs@0.203.0": + version "0.203.0" + resolved "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.203.0.tgz#01bc7c0549929d2864af2ab0ba23fd5ce02b5b0a" + integrity sha512-vM2+rPq0Vi3nYA5akQD2f3QwossDnTDLvKbea6u/A2NZ3XDkPxMfo/PNrDoXhDUD/0pPo2CdH5ce/thn9K0kLw== + dependencies: + "@opentelemetry/api-logs" "0.203.0" + "@opentelemetry/core" "2.0.1" + "@opentelemetry/resources" "2.0.1" + +"@opentelemetry/sdk-metrics@2.0.1": + version "2.0.1" + resolved "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz#efb6e9349e8a9038ac622e172692bfcdcad8010b" + integrity sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g== + dependencies: + "@opentelemetry/core" "2.0.1" + "@opentelemetry/resources" "2.0.1" + +"@opentelemetry/sdk-trace-base@2.0.1": + version "2.0.1" + resolved "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz#25808bb6a3d08a501ad840249e4d43d3493eb6e5" + integrity sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ== + dependencies: + "@opentelemetry/core" "2.0.1" + "@opentelemetry/resources" "2.0.1" + "@opentelemetry/semantic-conventions" "^1.29.0" + +"@opentelemetry/semantic-conventions@1.36.0", "@opentelemetry/semantic-conventions@^1.29.0": + version "1.36.0" + resolved "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.36.0.tgz#149449bd4df4d0464220915ad4164121e0d75d4d" + integrity sha512-TtxJSRD8Ohxp6bKkhrm27JRHAxPczQA7idtcTOMYI+wQRRrfgqxHv1cFbCApcSnNjtXkmzFozn6jQtFrOmbjPQ== + "@opentelemetry/semantic-conventions@~1.28.0": version "1.28.0" resolved "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz#337fb2bca0453d0726696e745f50064411f646d6" @@ -13232,6 +13317,24 @@ protobufjs@7.4.0, protobufjs@^7.2.5, protobufjs@^7.3.2: "@types/node" ">=13.7.0" long "^5.0.0" +protobufjs@^7.3.0: + version "7.5.4" + resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz#885d31fe9c4b37f25d1bb600da30b1c5b37d286a" + integrity sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" + protocols@^1.4.0: version "1.4.8" resolved "https://registry.npmjs.org/protocols/-/protocols-1.4.8.tgz#48eea2d8f58d9644a4a32caae5d5db290a075ce8" @@ -15139,7 +15242,7 @@ string-argv@~0.3.1: resolved "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== -"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -15157,6 +15260,15 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" @@ -15220,7 +15332,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -15241,6 +15353,13 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^7.0.1: version "7.1.0" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -16913,7 +17032,7 @@ workerpool@6.2.0: resolved "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b" integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -16947,6 +17066,15 @@ wrap-ansi@^6.0.1, wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" From 1e3eb234b39732589a49d06e7f3ad7d895b7434b Mon Sep 17 00:00:00 2001 From: abrook Date: Tue, 26 Aug 2025 11:05:26 -0400 Subject: [PATCH 2/2] Clarify flush() usage --- packages/telemetry/src/api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/telemetry/src/api.ts b/packages/telemetry/src/api.ts index 853923104f4..3f771e2a4b9 100644 --- a/packages/telemetry/src/api.ts +++ b/packages/telemetry/src/api.ts @@ -86,7 +86,7 @@ export function captureError(telemetry: Telemetry, error: unknown): void { } /** - * Flushes all enqueued telemetry data immediately. + * Flushes all enqueued telemetry data immediately, instead of waiting for default batching. * * @public *