Skip to content

Commit 9e91cc8

Browse files
authored
fix(spanner): record fractional latency metrics (#8168)
1 parent ffcac54 commit 9e91cc8

2 files changed

Lines changed: 45 additions & 9 deletions

File tree

handwritten/spanner/src/metrics/metrics-tracer.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ import {Spanner} from '..';
3131
* by MetricsTracer to monitor and report metrics for each individual gRPC call attempt.
3232
*/
3333
class MetricAttemptTracer {
34-
private _startTime: Date;
34+
private _startTime: number;
3535
public status: string;
3636

3737
constructor() {
38-
this._startTime = new Date(Date.now());
38+
this._startTime = performance.now();
3939
this.status = Status[Status.UNKNOWN];
4040
}
4141

@@ -67,12 +67,12 @@ class MetricAttemptTracer {
6767
*/
6868
class MetricOperationTracer {
6969
private _attemptCount: number;
70-
private _startTime: Date;
70+
private _startTime: number;
7171
private _currentAttempt: MetricAttemptTracer | null;
7272

7373
constructor() {
7474
this._attemptCount = 0;
75-
this._startTime = new Date(Date.now());
75+
this._startTime = performance.now();
7676
this._currentAttempt = null;
7777
}
7878

@@ -173,13 +173,13 @@ export class MetricsTracer {
173173
}
174174

175175
/**
176-
* Returns the difference in milliseconds between two Date objects.
176+
* Returns the difference in milliseconds between two times.
177177
* @param start The start time.
178178
* @param end The end time.
179179
* @returns The time difference in milliseconds.
180180
*/
181-
private _getMillisecondTimeDifference(start: Date, end: Date): number {
182-
return end.valueOf() - start.valueOf();
181+
private _getMillisecondTimeDifference(start: number, end: number): number {
182+
return end - start;
183183
}
184184

185185
/**
@@ -235,7 +235,7 @@ export class MetricsTracer {
235235
if (!this.enabled) return;
236236
this.currentOperation!.currentAttempt!.status = Status[statusCode];
237237
const attemptAttributes = this._createAttemptOtelAttributes();
238-
const endTime = new Date(Date.now());
238+
const endTime = performance.now();
239239
const attemptLatencyMilliseconds = this._getMillisecondTimeDifference(
240240
this.currentOperation!.currentAttempt!.startTime,
241241
endTime,
@@ -265,7 +265,7 @@ export class MetricsTracer {
265265
*/
266266
public recordOperationCompletion() {
267267
if (!this.enabled || !this.currentOperation) return;
268-
const endTime = new Date(Date.now());
268+
const endTime = performance.now();
269269
const operationAttributes = this._createOperationOtelAttributes();
270270
const operationLatencyMilliseconds = this._getMillisecondTimeDifference(
271271
this.currentOperation!.startTime,

handwritten/spanner/test/metrics/metrics-tracer.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,21 @@ describe('MetricsTracer', () => {
113113
);
114114
});
115115

116+
it('should record fractional latency with sub-millisecond precision', () => {
117+
const nowStub = sandbox.stub(performance, 'now');
118+
nowStub.onCall(0).returns(100.0); // op start
119+
nowStub.onCall(1).returns(200.5); // attempt start
120+
nowStub.onCall(2).returns(202.75); // attempt end
121+
122+
tracer.recordOperationStart();
123+
tracer.recordAttemptStart();
124+
tracer.recordAttemptCompletion(Status.OK);
125+
126+
assert.strictEqual(fakeAttemptLatency.record.calledOnce, true);
127+
const [[latency]] = fakeAttemptLatency.record.args;
128+
assert.strictEqual(latency, 2.25); // 202.75 - 200.5
129+
});
130+
116131
it('should do nothing if disabled', () => {
117132
tracer.enabled = false;
118133
tracer.recordAttemptStart();
@@ -142,6 +157,27 @@ describe('MetricsTracer', () => {
142157
assert.strictEqual(opAttrs[Constants.METRIC_LABEL_KEY_STATUS], 'OK');
143158
});
144159

160+
it('should record fractional operation latency with sub-millisecond precision', () => {
161+
const nowStub = sandbox.stub(performance, 'now');
162+
nowStub.onCall(0).returns(100.5); // op start
163+
nowStub.onCall(1).returns(105.0); // attempt start
164+
nowStub.onCall(2).returns(108.0); // attempt end
165+
nowStub.onCall(3).returns(110.25); // op end
166+
167+
sandbox.stub(MetricsTracerFactory, 'getInstance').returns({
168+
clearCurrentTracer: sinon.spy(),
169+
} as any);
170+
171+
tracer.recordOperationStart();
172+
tracer.recordAttemptStart();
173+
tracer.recordAttemptCompletion(Status.OK);
174+
tracer.recordOperationCompletion();
175+
176+
assert.strictEqual(fakeOperationLatency.record.calledOnce, true);
177+
const [[latency]] = fakeOperationLatency.record.args;
178+
assert.strictEqual(latency, 9.75); // 110.25 - 100.5
179+
});
180+
145181
it('should do nothing if disabled', () => {
146182
tracer.enabled = false;
147183
tracer.recordOperationCompletion();

0 commit comments

Comments
 (0)