diff --git a/packages/fx-core/src/common/telemetry.ts b/packages/fx-core/src/common/telemetry.ts index 67e3fd03f9..aede020419 100644 --- a/packages/fx-core/src/common/telemetry.ts +++ b/packages/fx-core/src/common/telemetry.ts @@ -83,6 +83,9 @@ export enum TelemetryProperty { HasAzureOpenAIEndpoint = "has-azure-openai-endpoint", HasAzureOpenAIDeploymentName = "has-azure-openai-deployment-name", HasOpenAIKey = "has-openai-key", + + TDPTraceId = "tdp-trace-id", + MOSTraceId = "mos-trace-id", } export const TelemetryConstants = { @@ -156,6 +159,7 @@ export enum TelemetryEvent { ProjectType = "project-type", DependencyApi = "dependency-api", AppStudioApi = "app-studio-api", + MOSApi = "ttk-mos-api", } export enum ProjectTypeProps { diff --git a/packages/fx-core/src/common/wrappedAxiosClient.ts b/packages/fx-core/src/common/wrappedAxiosClient.ts index 2f584923d3..17840dc838 100644 --- a/packages/fx-core/src/common/wrappedAxiosClient.ts +++ b/packages/fx-core/src/common/wrappedAxiosClient.ts @@ -47,14 +47,7 @@ export class WrappedAxiosClient { params: this.generateParameters(request.params), ...this.generateExtraProperties(fullPath, request.data), }; - - let eventName: string; - if (this.isTDPApi(fullPath)) { - eventName = TelemetryEvent.AppStudioApi; - } else { - eventName = TelemetryEvent.DependencyApi; - } - + const eventName = this.getEventName(fullPath); TOOLS?.telemetryReporter?.sendTelemetryEvent(`${eventName}-start`, properties); return request; } @@ -80,12 +73,7 @@ export class WrappedAxiosClient { ...this.generateExtraProperties(fullPath, response.data), }; - let eventName: string; - if (this.isTDPApi(fullPath)) { - eventName = TelemetryEvent.AppStudioApi; - } else { - eventName = TelemetryEvent.DependencyApi; - } + const eventName = this.getEventName(fullPath); TOOLS?.telemetryReporter?.sendTelemetryEvent(eventName, properties); return response; } @@ -122,8 +110,8 @@ export class WrappedAxiosClient { ...this.generateExtraProperties(fullPath, requestData), }; - let eventName: string; - if (this.isTDPApi(fullPath)) { + const eventName = this.getEventName(fullPath); + if (eventName === TelemetryEvent.AppStudioApi) { const correlationId = error.response?.headers[Constants.CORRELATION_ID] ?? "undefined"; // eslint-disable-next-line @typescript-eslint/restrict-template-expressions const extraData = error.response?.data ? `data: ${JSON.stringify(error.response.data)}` : ""; @@ -137,9 +125,16 @@ export class WrappedAxiosClient { TelemetryProperty.ErrorCode ] = `${TDPApiFailedError.source}.${TDPApiFailedError.name}`; properties[TelemetryProperty.ErrorMessage] = TDPApiFailedError.message; - eventName = TelemetryEvent.AppStudioApi; - } else { - eventName = TelemetryEvent.DependencyApi; + properties[TelemetryProperty.TDPTraceId] = correlationId; + } else if (eventName === TelemetryEvent.MOSApi) { + const tracingId = (error.response?.headers?.traceresponse ?? "undefined") as string; + const originalMessage = error.message; + const innerError = (error.response?.data as any).error || { code: "", message: "" }; + const finalMessage = `${originalMessage} (tracingId: ${tracingId}) ${ + innerError.code as string + }: ${innerError.message as string} `; + properties[TelemetryProperty.ErrorMessage] = finalMessage; + properties[TelemetryProperty.MOSTraceId] = tracingId; } TOOLS?.telemetryReporter?.sendTelemetryErrorEvent(eventName, properties); @@ -295,6 +290,18 @@ export class WrappedAxiosClient { return matches != null && matches.length > 0; } + private static getEventName( + baseUrl: string + ): TelemetryEvent.MOSApi | TelemetryEvent.AppStudioApi | TelemetryEvent.DependencyApi { + if (this.isTDPApi(baseUrl)) { + return TelemetryEvent.AppStudioApi; + } else if (baseUrl.includes("titles.prod.mos.microsoft.com")) { + return TelemetryEvent.MOSApi; + } else { + return TelemetryEvent.DependencyApi; + } + } + /** * Flattern query parameters to string, e.g. {a: 1, b: 2} => a:1;b:2 * @param params diff --git a/packages/fx-core/tests/common/wrappedAxiosClient.test.ts b/packages/fx-core/tests/common/wrappedAxiosClient.test.ts index 85fd4fa1d7..563d9092be 100644 --- a/packages/fx-core/tests/common/wrappedAxiosClient.test.ts +++ b/packages/fx-core/tests/common/wrappedAxiosClient.test.ts @@ -242,6 +242,27 @@ describe("Wrapped Axios Client Test", () => { chai.expect(telemetryChecker.calledOnce).to.be.true; }); + it("MOS API error response", async () => { + const mockedError = { + request: { + method: "GET", + host: "https://titles.prod.mos.microsoft.com", + path: "/users/packages", + }, + config: {}, + response: { + status: 400, + data: { + code: "BadRequest", + message: "Invalid request", + }, + }, + } as any; + const telemetryChecker = sinon.spy(mockTools.telemetryReporter, "sendTelemetryErrorEvent"); + WrappedAxiosClient.onRejected(mockedError); + chai.expect(telemetryChecker.calledOnce).to.be.true; + }); + it("Create bot API start telemetry", async () => { const mockedRequest = { method: "POST",