Skip to content

Commit

Permalink
Merge ed3fdb7 into dc67f4e
Browse files Browse the repository at this point in the history
  • Loading branch information
dyladan committed Aug 3, 2022
2 parents dc67f4e + ed3fdb7 commit 9b98061
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 6 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ All notable changes to this project will be documented in this file.

### :bug: (Bug Fix)

* fix(sdk-trace-base): make span start times resistant to hrtime clock drift
[#3129](https://github.com/open-telemetry/opentelemetry-js/issues/3129)

### :books: (Refine Doc)

### :house: (Internal)
Expand Down
12 changes: 12 additions & 0 deletions packages/opentelemetry-core/src/common/time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,18 @@ export function hrTimeDuration(
return [seconds, nanos];
}

/**
* Add an HrTime duration to an HrTime
*/
export function addHrTime(time: api.HrTime, duration: api.HrTime): api.HrTime {
const out: api.HrTime = [time[0] + duration[0], time[1] + duration[1]];
if (out[1] >= 1e9) {
out[1] -= 1e9;
out[0] += 1;
}
return out;
}

/**
* Convert hrTime to timestamp, for example "2019-05-14T17:00:00.000123456Z"
* @param time
Expand Down
18 changes: 18 additions & 0 deletions packages/opentelemetry-core/test/common/time.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
hrTimeToMicroseconds,
hrTimeToTimeStamp,
isTimeInput,
addHrTime,
} from '../../src/common/time';

describe('time', () => {
Expand Down Expand Up @@ -151,6 +152,23 @@ describe('time', () => {
});
});

describe('#addHrTime', () => {
it('should add two HrTimes', () => {
const startTime: api.HrTime = [22, 400000000];
const endTime: api.HrTime = [32, 200000000];

const output = addHrTime(startTime, endTime);
assert.deepStrictEqual(output, [54, 600000000]);
});
it('should overflow nanoseconds', () => {
const startTime: api.HrTime = [22, 600000000];
const endTime: api.HrTime = [32, 700000000];

const output = addHrTime(startTime, endTime);
assert.deepStrictEqual(output, [55, 300000000]);
});
});

describe('#hrTimeToTimeStamp', () => {
it('should return timestamp', () => {
const time: api.HrTime = [1573513121, 123456];
Expand Down
22 changes: 16 additions & 6 deletions packages/opentelemetry-sdk-trace-base/src/Span.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
isTimeInput,
timeInputToHrTime,
sanitizeAttributes,
addHrTime,
} from '@opentelemetry/core';
import { Resource } from '@opentelemetry/resources';
import { SemanticAttributes } from '@opentelemetry/semantic-conventions';
Expand Down Expand Up @@ -59,6 +60,7 @@ export class Span implements api.Span, ReadableSpan {
private readonly _spanProcessor: SpanProcessor;
private readonly _spanLimits: SpanLimits;
private readonly _attributeValueLengthLimit: number;
private readonly _hrStartTime: api.HrTime;

/** Constructs a new Span instance. */
constructor(
Expand All @@ -69,14 +71,15 @@ export class Span implements api.Span, ReadableSpan {
kind: api.SpanKind,
parentSpanId?: string,
links: api.Link[] = [],
startTime: api.TimeInput = hrTime()
startTime?: api.TimeInput
) {
this.name = spanName;
this._spanContext = spanContext;
this.parentSpanId = parentSpanId;
this.kind = kind;
this.links = links;
this.startTime = timeInputToHrTime(startTime);
this._hrStartTime = hrTime();
this.startTime = timeInputToHrTime(startTime ?? Date.now());
this.resource = parentTracer.resource;
this.instrumentationLibrary = parentTracer.instrumentationLibrary;
this._spanLimits = parentTracer.getSpanLimits();
Expand All @@ -103,7 +106,7 @@ export class Span implements api.Span, ReadableSpan {

if (
Object.keys(this.attributes).length >=
this._spanLimits.attributeCountLimit! &&
this._spanLimits.attributeCountLimit! &&
!Object.prototype.hasOwnProperty.call(this.attributes, key)
) {
return this;
Expand Down Expand Up @@ -171,15 +174,22 @@ export class Span implements api.Span, ReadableSpan {
return this;
}

end(endTime: api.TimeInput = hrTime()): void {
end(endTime?: api.TimeInput): void {
if (this._isSpanEnded()) {
api.diag.error('You can only call end() on a span once.');
return;
}
this._ended = true;
this.endTime = timeInputToHrTime(endTime);

this._duration = hrTimeDuration(this.startTime, this.endTime);

if (endTime != null) {
this.endTime = timeInputToHrTime(endTime);
this._duration = hrTimeDuration(this._hrStartTime, this.endTime);
} else {
this._duration = hrTimeDuration(this._hrStartTime, hrTime());
this.endTime = addHrTime(this.startTime, this._duration);
}

if (this._duration[0] < 0) {
api.diag.warn(
'Inconsistent start and end time, startTime > endTime',
Expand Down

0 comments on commit 9b98061

Please sign in to comment.