forked from Azure/azure-sdk-for-js
-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added Diagnostic type definitions for @azure/cosmos (Azure#25103)
### Packages impacted by this PR @azure/cosmos ### Issues associated with this PR [Azure#21177](Azure#21177) ### Describe the problem that is addressed by this PR This PR is the first in series, for adding Diagnostics in @azure/comsos package. Here is the [design doc](https://gist.github.com/v1k1/8950942027c9ca1bf631bb6d135c7451). Here is the [complete reference PR](Azure#25043), but to make review easy, I have broken the PR into 3 parts. (The reference PR is not to be merged; it is simply to showcase how all things will tie together) 1. Type Definitions. 2. Adding Diagnostics to point lookup and exception APIs 3. Adding diagnostics to bulk/batch and query APIs ### What are the possible designs available to address the problem? If there are more than one possible design, why was the one in this PR chosen? ### Are there test cases added in this PR? _(If not, why?)_ No, this PR contains only type definitions. ### Provide a list of related PRs _(if any)_ Azure#25043 ### Command used to generate this PR:**_(Applicable only to SDK release request PRs)_ ### Checklists - [ ] Added impacted package name to the issue description - [ ] Does this PR needs any fixes in the SDK Generator?** _(If so, create an Issue in the [Autorest/typescript](https://github.com/Azure/autorest.typescript) repository and link it here)_ - [ ] Added a changelog (if necessary)
- Loading branch information
Showing
5 changed files
with
365 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT license. | ||
|
||
import { v4 } from "uuid"; | ||
import { Location } from "./documents"; | ||
import { CosmosDiagnosticContext } from "./CosmosDiagnosticsContext"; | ||
|
||
/** | ||
* This is a Cosmos Diagnostic type that holds diagnostic information during client operations. ie. Item.read(). | ||
* The `clientSideRequestStatistics` member contains diagnostic information on operations happening in client process. ie.e | ||
* - metadata lookups. | ||
* - retries | ||
* - endpoints contacted. | ||
* - request, response payload stats. | ||
* Here all the server requests, apart from the final intended resource are considered as metadata calls. | ||
* i.e. for item.read(id), if the client makes server call to discover endpoints it would be considered | ||
* as metadata call. | ||
*/ | ||
export class CosmosDiagnostics { | ||
/** | ||
* @internal | ||
*/ | ||
constructor( | ||
public readonly id: string, | ||
clientSideRequestStatistics: ClientSideRequestStatistics, | ||
private readonly cosmosDiagnosticContext: CosmosDiagnosticContext | ||
) { | ||
this.clientSideRequestStatistics = clientSideRequestStatistics; | ||
} | ||
|
||
public readonly clientSideRequestStatistics: ClientSideRequestStatistics; | ||
|
||
public get getContactedRegionNames(): Set<string> { | ||
const locations = this.cosmosDiagnosticContext.locationEndpointsContacted.values(); | ||
return new Set([...locations].map((location) => location.name)); | ||
} | ||
} | ||
|
||
/** | ||
* This type contains diagnostic information regarding all metadata request to server during an CosmosDB client operation. | ||
*/ | ||
export type MetadataLookUpDiagnostics = { | ||
metadataLookups: MetadataLookUpDiagnostic[]; | ||
}; | ||
|
||
/** | ||
* This type captures diagnostic information regarding retries attempt during an CosmosDB client operation. | ||
*/ | ||
export type RetryDiagnostics = { | ||
failedAttempts: FailedRequestAttemptDiagnostic[]; | ||
}; | ||
|
||
/** | ||
* This type contains diagnostic information regarding a single metadata request to server. | ||
*/ | ||
export interface MetadataLookUpDiagnostic { | ||
id: string; | ||
startTimeUTCInMs: number; | ||
endTimeUTCInMs: number; | ||
metaDataType: MetadataLookUpType; | ||
activityId: string; | ||
} | ||
|
||
/** | ||
* This type captures diagnostic information regarding a failed request to server api. | ||
*/ | ||
export interface FailedRequestAttemptDiagnostic { | ||
id: string; | ||
attemptNumber: number; | ||
startTimeUTCInMs: number; | ||
endTimeUTCInMs: number; | ||
statusCode: string; | ||
} | ||
|
||
/** | ||
* This is enum for Type of Metadata lookups possible. | ||
*/ | ||
export enum MetadataLookUpType { | ||
PartitionKeyRangeLookUp = "PARTITION_KEY_RANGE_LOOK_UP", | ||
ServerAddressLookUp = "SERVER_ADDRESS_LOOK_UP", | ||
DatabaseAccountLookUp = "DATABASE_ACCOUNT_LOOK_UP", | ||
} | ||
|
||
/** | ||
* This is a collection type for all client side diagnostic information. | ||
*/ | ||
export type ClientSideRequestStatistics = { | ||
/** | ||
* This is the UTC timestamp for start of client operation. | ||
*/ | ||
requestStartTimeUTCInMs: number; | ||
/** | ||
* This is the UTC timestamp for end of client operation. | ||
*/ | ||
requestEndTimeUTCInMs: number; | ||
/** | ||
* This is the activityId for request, made to server for fetching the requested resource. (As opposed to other potential meta data requests) | ||
*/ | ||
activityId: string; | ||
/** | ||
* This is the list of Location Endpoints contacted during the client operation. | ||
*/ | ||
locationEndpointsContacted: Location[]; | ||
/** | ||
* This field captures diagnostic information for retries happened during client operation. | ||
*/ | ||
retryDiagnostics: RetryDiagnostics; | ||
/** | ||
* This field captures diagnostic information for meta data lookups happened during client operation. | ||
*/ | ||
metadataDiagnostics: MetadataLookUpDiagnostics; | ||
/** | ||
* This is the payload length, in bytes made to server for the client operation requested. (This doesn't include payloads for meta data requests) | ||
*/ | ||
requestPayloadLength: number; | ||
/** | ||
* This is the payload length, in bytes made to recieved from server for the client operation requested. (This doesn't include payloads for meta data responses) | ||
*/ | ||
responsePayloadLength: number; | ||
}; | ||
|
||
/** | ||
* @hidden | ||
* Utility function to create an Empty CosmosDiagnostic object. | ||
* @returns | ||
*/ | ||
export function getEmptyCosmosDiagnostics(): CosmosDiagnostics { | ||
return new CosmosDiagnostics( | ||
v4(), | ||
{ | ||
activityId: "", | ||
requestEndTimeUTCInMs: 0, | ||
requestStartTimeUTCInMs: 0, | ||
locationEndpointsContacted: [], | ||
retryDiagnostics: { | ||
failedAttempts: [], | ||
}, | ||
metadataDiagnostics: { | ||
metadataLookups: [], | ||
}, | ||
requestPayloadLength: 0, | ||
responsePayloadLength: 0, | ||
}, | ||
new CosmosDiagnosticContext() | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT license. | ||
|
||
import { v4 } from "uuid"; | ||
import { Constants } from "./common"; | ||
import { Location } from "./documents"; | ||
import { CosmosHeaders } from "./queryExecutionContext"; | ||
import { | ||
CosmosDiagnostics, | ||
FailedRequestAttemptDiagnostic, | ||
MetadataLookUpDiagnostic, | ||
MetadataLookUpType, | ||
} from "./CosmosDiagnostics"; | ||
|
||
/** | ||
* @hidden | ||
* Internal class to hold CosmosDiagnostic information all through the lifecycle of a request. | ||
* This object gathers diagnostic information throughout Client operation which may span across multiple | ||
* Server call, retries etc. | ||
* Functions - recordFailedAttempt, recordMetaDataQuery, recordEndpointContactEvent are used to ingest | ||
* data into the context. At the end of operation, getDiagnostics() is used to | ||
* get final CosmosDiagnostic object. | ||
*/ | ||
export class CosmosDiagnosticContext { | ||
private requestStartTimeUTCinMs: number; | ||
private requestEndTimeUTCinMs: number; | ||
private retryStartTimeUTCinMs: number; | ||
private headers: CosmosHeaders = {}; | ||
private retryAttempNumber: number; | ||
private failedAttempts: FailedRequestAttemptDiagnostic[] = []; | ||
private metadataLookups: MetadataLookUpDiagnostic[] = []; | ||
private requestPayloadLength: number; | ||
private responsePayloadLength: number; | ||
|
||
public locationEndpointsContacted: Map<string, Location> = new Map(); | ||
|
||
public constructor() { | ||
this.requestStartTimeUTCinMs = getCurrentTimestampInMs(); | ||
this.retryStartTimeUTCinMs = this.requestStartTimeUTCinMs; | ||
} | ||
|
||
public recordRequestPayload(payload: string): void { | ||
this.requestPayloadLength = payload.length; | ||
} | ||
|
||
public recordResponseStats(payload: string, headers: CosmosHeaders): void { | ||
this.responsePayloadLength = typeof payload === "string" ? payload.length : 0; | ||
this.headers = { ...this.headers, ...headers }; | ||
} | ||
|
||
public recordFailedAttempt(statusCode: string): void { | ||
const attempt: FailedRequestAttemptDiagnostic = { | ||
id: v4(), | ||
attemptNumber: this.retryAttempNumber, | ||
startTimeUTCInMs: this.retryStartTimeUTCinMs, | ||
endTimeUTCInMs: getCurrentTimestampInMs(), | ||
statusCode, | ||
}; | ||
this.retryStartTimeUTCinMs = getCurrentTimestampInMs(); | ||
this.retryAttempNumber++; | ||
this.failedAttempts.push(attempt); | ||
} | ||
|
||
public recordMetaDataLookup( | ||
diagnostics: CosmosDiagnostics, | ||
metaDataType: MetadataLookUpType | ||
): void { | ||
const metaDataRequest = { | ||
startTimeUTCInMs: diagnostics.clientSideRequestStatistics.requestStartTimeUTCInMs, | ||
endTimeUTCInMs: diagnostics.clientSideRequestStatistics.requestEndTimeUTCInMs, | ||
activityId: diagnostics.clientSideRequestStatistics.activityId, | ||
metaDataType, | ||
id: v4(), | ||
}; | ||
this.metadataLookups.push(metaDataRequest); | ||
} | ||
|
||
// public recordSerializationEvent() {} | ||
|
||
// public recordResponse() {} | ||
|
||
public mergeDiagnostics(diagnostics: CosmosDiagnostics): void { | ||
diagnostics.clientSideRequestStatistics.locationEndpointsContacted.forEach((endpoint) => | ||
this.locationEndpointsContacted.set(endpoint.databaseAccountEndpoint, endpoint) | ||
); | ||
diagnostics.clientSideRequestStatistics.metadataDiagnostics.metadataLookups.forEach((lookup) => | ||
this.metadataLookups.push(lookup) | ||
); | ||
diagnostics.clientSideRequestStatistics.retryDiagnostics.failedAttempts.forEach((lookup) => | ||
this.failedAttempts.push(lookup) | ||
); | ||
} | ||
|
||
public recordEndpointContactEvent(location: Location): void { | ||
this.locationEndpointsContacted.set(location.databaseAccountEndpoint, location); | ||
} | ||
|
||
public getDiagnostics(): CosmosDiagnostics { | ||
this.recordSessionEnd(); | ||
return new CosmosDiagnostics( | ||
v4(), | ||
{ | ||
activityId: this.getActivityId(), | ||
requestStartTimeUTCInMs: this.requestStartTimeUTCinMs, | ||
requestEndTimeUTCInMs: this.requestEndTimeUTCinMs, | ||
locationEndpointsContacted: [...this.locationEndpointsContacted.values()], | ||
metadataDiagnostics: { | ||
metadataLookups: [...this.metadataLookups], | ||
}, | ||
retryDiagnostics: { | ||
failedAttempts: [...this.failedAttempts], | ||
}, | ||
requestPayloadLength: this.requestPayloadLength, | ||
responsePayloadLength: this.responsePayloadLength, | ||
}, | ||
this | ||
); | ||
} | ||
|
||
private recordSessionEnd() { | ||
this.requestEndTimeUTCinMs = getCurrentTimestampInMs(); | ||
} | ||
|
||
private getActivityId(): string { | ||
return this.headers[Constants.HttpHeaders.ActivityId] as string; | ||
} | ||
} | ||
|
||
/** | ||
* @hidden | ||
* Utility function to get currentTime in UTC milliseconds. | ||
* @returns | ||
*/ | ||
export function getCurrentTimestampInMs(): number { | ||
return Date.now(); | ||
} |
Oops, something went wrong.