-
Notifications
You must be signed in to change notification settings - Fork 536
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add correlation id in routerlicious-driver #4734
Changes from all commits
17faeba
b54f5f6
9350089
9448795
40c3d08
661e485
fc6d646
dbe8475
b4f65ab
b10ca14
0c6ca99
f6ec10e
2196f10
ad615c6
b7a3c2b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,12 +3,15 @@ | |
* Licensed under the MIT License. | ||
*/ | ||
|
||
import { OutgoingHttpHeaders } from "http"; | ||
import querystring from "querystring"; | ||
import { fromUtf8ToBase64 } from "@fluidframework/common-utils"; | ||
import { IDeltaStorageService, IDocumentDeltaStorageService } from "@fluidframework/driver-definitions"; | ||
import Axios from "axios"; | ||
import * as uuid from "uuid"; | ||
import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions"; | ||
import { readAndParse } from "@fluidframework/driver-utils"; | ||
import { ITelemetryLogger } from "@fluidframework/common-definitions"; | ||
import { ITokenProvider } from "./tokens"; | ||
import { DocumentStorageService } from "./documentStorageService"; | ||
|
||
|
@@ -44,7 +47,10 @@ export class DocumentDeltaStorageService implements IDocumentDeltaStorageService | |
* Provides access to the underlying delta storage on the server for routerlicious driver. | ||
*/ | ||
export class DeltaStorageService implements IDeltaStorageService { | ||
constructor(private readonly url: string, private readonly tokenProvider: ITokenProvider) { | ||
constructor( | ||
private readonly url: string, | ||
private readonly tokenProvider: ITokenProvider, | ||
private readonly logger: ITelemetryLogger | undefined) { | ||
} | ||
|
||
public async get( | ||
|
@@ -54,22 +60,29 @@ export class DeltaStorageService implements IDeltaStorageService { | |
to?: number): Promise<ISequencedDocumentMessage[]> { | ||
const query = querystring.stringify({ from, to }); | ||
|
||
let headers: { Authorization: string } | null = null; | ||
const headers: OutgoingHttpHeaders = { | ||
"x-correlation-id": uuid.v4(), | ||
}; | ||
|
||
const storageToken = await this.tokenProvider.fetchStorageToken( | ||
tenantId, | ||
id, | ||
); | ||
|
||
if (storageToken) { | ||
headers = { | ||
Authorization: `Basic ${fromUtf8ToBase64(`${tenantId}:${storageToken.jwt}`)}`, | ||
}; | ||
headers.Authorization = `Basic ${fromUtf8ToBase64(`${tenantId}:${storageToken.jwt}`)}`; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: Why do we need this change? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The initial value of headers was null. Now the initial value of headers is { "x-correlation-id": uuid.v4() } (on line 63). So it needs to add a key to dictionary instead of giving a value to it. |
||
} | ||
|
||
const ops = await Axios.get<ISequencedDocumentMessage[]>( | ||
`${this.url}?${query}`, { headers }); | ||
|
||
if (this.logger) { | ||
this.logger.sendTelemetryEvent({ | ||
eventName: "R11sDriverToServer", | ||
correlationId: headers["x-correlation-id"] as string, | ||
}); | ||
} | ||
|
||
return ops.data; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the value of this ID?
I can see the value if it was written to client side telemetry, then we can use it to correlate activity between client & server. But with this code, it will land only on server, so server can generate ID with the same result, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good point. We added correlation id in server side and this PR is just for the completeness for the server side to receive http requests with correlation id in the header. As for client side telemetry, I didn't go deep into that. Could you explain a little bit more how we can add to client side telemetry? Or maybe we can talk offline with Tanvir.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vladsud Correct! FRS has recently done the work to store and track correlation ids of http requests. Next, we want wrap all these calls with telemetry. Can you provide us some pointers on how ODSP driver does that? I am expecting to follow a similar pattern.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Take a look at how ITelemetryLogger / ITelemetryBaseLogger and usage in ODSP driver.
Basically it is passed to driver in Container.load() (when calling createDocumentService) and driver passes it through it's layers and uses to log data (look for this.logger in odspDocumentStorageManager.ts as an example).
We wrap pretty much every network call and write out a bunch of properties to allow us to do analyzes later.
Note that in similar case, we rely on server communicating to client its correlation ID (in http response), and client recording it in client-side logging. That way, server is pretty much agnostic of client and client behavior. Reverse would work too, I do not have strong opinion here.