From c2a7febfaa1f2ab5fdc4b9d64c63d564bb5efe05 Mon Sep 17 00:00:00 2001 From: Peter Marton Date: Tue, 17 Sep 2019 16:43:04 -0700 Subject: [PATCH] fix(basic-tracer): performance.now() is relative from start time (#206) * fix(basic-tracer): performance.now() is relative from start time * refactor(time): tuples * refactor(span): change name of toHrTime * fix(span): duration default * fix(hrtime): conver to tuple * fix(basic-tracer): nanosecond accuracy * feat(core): move time utils to core * feat(core): add millis and nanos converter * test(basic-tracer): fix span time tests --- .../opentelemetry-basic-tracer/package.json | 2 +- .../opentelemetry-basic-tracer/src/Span.ts | 39 ++++-- .../src/export/ReadableSpan.ts | 6 +- .../test/Span.test.ts | 53 ++++++- packages/opentelemetry-core/package.json | 2 + .../opentelemetry-core/src/common/time.ts | 99 ++++++++++++++ packages/opentelemetry-core/src/index.ts | 1 + .../opentelemetry-core/src/trace/NoopSpan.ts | 2 +- .../test/common/time.test.ts | 129 ++++++++++++++++++ .../test/functionals/http-enable.test.ts | 39 +++--- .../test/utils/assertSpan.ts | 4 +- .../opentelemetry-types/src/common/Time.ts | 25 ++++ packages/opentelemetry-types/src/index.ts | 1 + .../src/trace/TimedEvent.ts | 3 +- .../opentelemetry-types/src/trace/span.ts | 5 +- 15 files changed, 366 insertions(+), 44 deletions(-) create mode 100644 packages/opentelemetry-core/src/common/time.ts create mode 100644 packages/opentelemetry-core/test/common/time.test.ts create mode 100644 packages/opentelemetry-types/src/common/Time.ts diff --git a/packages/opentelemetry-basic-tracer/package.json b/packages/opentelemetry-basic-tracer/package.json index 3289aee07..cb6300821 100644 --- a/packages/opentelemetry-basic-tracer/package.json +++ b/packages/opentelemetry-basic-tracer/package.json @@ -6,7 +6,7 @@ "types": "build/src/index.d.ts", "repository": "open-telemetry/opentelemetry-js", "scripts": { - "test": "nyc ts-mocha -p tsconfig.json 'test/**/*.ts'", + "test": "nyc ts-mocha -p tsconfig.json test/**/**/*.ts", "tdd": "yarn test -- --watch-extensions ts --watch", "codecov": "nyc report --reporter=json && codecov -f coverage/*.json -p ../../", "clean": "rimraf build/*", diff --git a/packages/opentelemetry-basic-tracer/src/Span.ts b/packages/opentelemetry-basic-tracer/src/Span.ts index 8e71c3bf2..d87ce23c9 100644 --- a/packages/opentelemetry-basic-tracer/src/Span.ts +++ b/packages/opentelemetry-basic-tracer/src/Span.ts @@ -15,7 +15,7 @@ */ import * as types from '@opentelemetry/types'; -import { performance } from 'perf_hooks'; +import { hrTime, hrTimeDuration, timeInputToHrTime } from '@opentelemetry/core'; import { ReadableSpan } from './export/ReadableSpan'; import { BasicTracer } from './BasicTracer'; import { SpanProcessor } from './SpanProcessor'; @@ -33,13 +33,14 @@ export class Span implements types.Span, ReadableSpan { readonly attributes: types.Attributes = {}; readonly links: types.Link[] = []; readonly events: types.TimedEvent[] = []; - readonly startTime: number; + readonly startTime: types.HrTime; name: string; status: types.Status = { code: types.CanonicalCode.OK, }; - endTime = 0; + endTime: types.HrTime = [0, 0]; private _ended = false; + private _duration: types.HrTime = [-1, -1]; private readonly _logger: types.Logger; private readonly _spanProcessor: SpanProcessor; @@ -50,14 +51,14 @@ export class Span implements types.Span, ReadableSpan { spanContext: types.SpanContext, kind: types.SpanKind, parentSpanId?: string, - startTime?: number + startTime: types.TimeInput = hrTime() ) { this._tracer = parentTracer; this.name = spanName; this.spanContext = spanContext; this.parentSpanId = parentSpanId; this.kind = kind; - this.startTime = startTime || performance.now(); + this.startTime = timeInputToHrTime(startTime); this._logger = parentTracer.logger; this._spanProcessor = parentTracer.activeSpanProcessor; this._spanProcessor.onStart(this); @@ -86,7 +87,11 @@ export class Span implements types.Span, ReadableSpan { addEvent(name: string, attributes?: types.Attributes): this { if (this._isSpanEnded()) return this; - this.events.push({ name, attributes, time: performance.now() }); + this.events.push({ + name, + attributes, + time: hrTime(), + }); return this; } @@ -108,13 +113,13 @@ export class Span implements types.Span, ReadableSpan { return this; } - end(endTime?: number): void { + end(endTime: types.TimeInput = hrTime()): void { if (this._isSpanEnded()) { this._logger.error('You can only call end() on a span once.'); return; } this._ended = true; - this.endTime = endTime || performance.now(); + this.endTime = timeInputToHrTime(endTime); this._spanProcessor.onEnd(this); } @@ -126,6 +131,24 @@ export class Span implements types.Span, ReadableSpan { return this; } + get duration(): types.HrTime { + if (this._duration[0] !== -1) { + return this._duration; + } + + this._duration = hrTimeDuration(this.startTime, this.endTime); + + if (this._duration[0] < 0) { + this._logger.warn( + 'Inconsistent start and end time, startTime > endTime', + this.startTime, + this.endTime + ); + } + + return this._duration; + } + private _isSpanEnded(): boolean { if (this._ended) { this._logger.warn( diff --git a/packages/opentelemetry-basic-tracer/src/export/ReadableSpan.ts b/packages/opentelemetry-basic-tracer/src/export/ReadableSpan.ts index e8169cbee..a0f84b062 100644 --- a/packages/opentelemetry-basic-tracer/src/export/ReadableSpan.ts +++ b/packages/opentelemetry-basic-tracer/src/export/ReadableSpan.ts @@ -18,6 +18,7 @@ import { SpanKind, Status, Attributes, + HrTime, Link, SpanContext, TimedEvent, @@ -28,10 +29,11 @@ export interface ReadableSpan { readonly kind: SpanKind; readonly spanContext: SpanContext; readonly parentSpanId?: string; - readonly startTime: number; - readonly endTime: number; + readonly startTime: HrTime; + readonly endTime: HrTime; readonly status: Status; readonly attributes: Attributes; readonly links: Link[]; readonly events: TimedEvent[]; + readonly duration: HrTime; } diff --git a/packages/opentelemetry-basic-tracer/test/Span.test.ts b/packages/opentelemetry-basic-tracer/test/Span.test.ts index d2e415b0e..6fbe76f0f 100644 --- a/packages/opentelemetry-basic-tracer/test/Span.test.ts +++ b/packages/opentelemetry-basic-tracer/test/Span.test.ts @@ -15,6 +15,7 @@ */ import * as assert from 'assert'; +import { performance } from 'perf_hooks'; import { Span } from '../src/Span'; import { SpanKind, @@ -23,7 +24,11 @@ import { SpanContext, } from '@opentelemetry/types'; import { BasicTracer } from '../src'; -import { NoopLogger } from '@opentelemetry/core'; +import { + hrTimeToNanoseconds, + hrTimeToMilliseconds, + NoopLogger, +} from '@opentelemetry/core'; describe('Span', () => { const tracer = new BasicTracer({ @@ -43,6 +48,39 @@ describe('Span', () => { span.end(); }); + it('should have valid startTime', () => { + const span = new Span(tracer, name, spanContext, SpanKind.SERVER); + assert.ok(hrTimeToMilliseconds(span.startTime) > performance.timeOrigin); + }); + + it('should have valid endTime', () => { + const span = new Span(tracer, name, spanContext, SpanKind.SERVER); + span.end(); + assert.ok( + hrTimeToNanoseconds(span.endTime) > hrTimeToNanoseconds(span.startTime), + 'end time must be bigger than start time' + ); + + assert.ok( + hrTimeToMilliseconds(span.endTime) > performance.timeOrigin, + 'end time must be bigger than time origin' + ); + }); + + it('should have a duration', () => { + const span = new Span(tracer, name, spanContext, SpanKind.SERVER); + span.end(); + assert.ok(hrTimeToNanoseconds(span.duration) >= 0); + }); + + it('should have valid event.time', () => { + const span = new Span(tracer, name, spanContext, SpanKind.SERVER); + span.addEvent('my-event'); + assert.ok( + hrTimeToMilliseconds(span.events[0].time) > performance.timeOrigin + ); + }); + it('should get the span context of span', () => { const span = new Span(tracer, name, spanContext, SpanKind.CLIENT); const context = span.context(); @@ -189,7 +227,7 @@ describe('Span', () => { const [event] = readableSpan.events; assert.deepStrictEqual(event.name, 'sent'); assert.ok(!event.attributes); - assert.ok(event.time > 0); + assert.ok(event.time[0] > 0); span.addEvent('rev', { attr1: 'value', attr2: 123, attr3: true }); readableSpan = span.toReadableSpan(); @@ -197,14 +235,14 @@ describe('Span', () => { const [event1, event2] = readableSpan.events; assert.deepStrictEqual(event1.name, 'sent'); assert.ok(!event1.attributes); - assert.ok(event1.time > 0); + assert.ok(event1.time[0] > 0); assert.deepStrictEqual(event2.name, 'rev'); assert.deepStrictEqual(event2.attributes, { attr1: 'value', attr2: 123, attr3: true, }); - assert.ok(event2.time > 0); + assert.ok(event2.time[0] > 0); span.end(); // shouldn't add new event @@ -238,9 +276,10 @@ describe('Span', () => { it('should only end a span once', () => { const span = new Span(tracer, name, spanContext, SpanKind.SERVER); - span.end(1234); - span.end(4567); - assert.strictEqual(span.endTime, 1234); + const endTime = Date.now(); + span.end(endTime); + span.end(endTime + 10); + assert.deepStrictEqual(span.endTime, [endTime, 0]); }); it('should update name', () => { diff --git a/packages/opentelemetry-core/package.json b/packages/opentelemetry-core/package.json index 1fb7089a0..771b604ba 100644 --- a/packages/opentelemetry-core/package.json +++ b/packages/opentelemetry-core/package.json @@ -46,6 +46,7 @@ "devDependencies": { "@types/mocha": "^5.2.5", "@types/node": "^12.6.8", + "@types/sinon": "^7.0.13", "@types/webpack-env": "1.13.9", "codecov": "^3.1.0", "gts": "^1.0.0", @@ -56,6 +57,7 @@ "karma-webpack": "^4.0.2", "mocha": "^6.1.0", "nyc": "^14.1.1", + "sinon": "^7.3.2", "tslint-microsoft-contrib": "^6.2.0", "tslint-consistent-codestyle":"^1.15.1", "ts-loader": "^6.0.4", diff --git a/packages/opentelemetry-core/src/common/time.ts b/packages/opentelemetry-core/src/common/time.ts new file mode 100644 index 000000000..ed46a1fc7 --- /dev/null +++ b/packages/opentelemetry-core/src/common/time.ts @@ -0,0 +1,99 @@ +/** + * Copyright 2019, OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as types from '@opentelemetry/types'; +import { performance } from 'perf_hooks'; + +const NANOSECOND_DIGITS = 9; +const SECOND_TO_NANOSECONDS = Math.pow(10, NANOSECOND_DIGITS); + +// Converts a number to HrTime +function numberToHrtime(time: number): types.HrTime { + // Decimals only. + const seconds = Math.trunc(time); + // Round sub-nanosecond accuracy to nanosecond. + const nanos = + Number((time - seconds).toFixed(NANOSECOND_DIGITS)) * SECOND_TO_NANOSECONDS; + return [seconds, nanos]; +} + +// Returns an hrtime calculated via performance component. +export function hrTime(performanceNow?: number): types.HrTime { + const timeOrigin = numberToHrtime(performance.timeOrigin); + const now = numberToHrtime(performanceNow || performance.now()); + + let seconds = timeOrigin[0] + now[0]; + let nanos = timeOrigin[1] + now[1]; + + // Nanoseconds + if (nanos > SECOND_TO_NANOSECONDS) { + nanos -= SECOND_TO_NANOSECONDS; + seconds += 1; + } + + return [seconds, nanos]; +} + +// Converts a TimeInput to an HrTime, defaults to _hrtime(). +export function timeInputToHrTime(time: types.TimeInput): types.HrTime { + // process.hrtime + if (Array.isArray(time)) { + return time; + } else if (typeof time === 'number') { + // Must be a performance.now() if it's smaller than process start time. + if (time < performance.timeOrigin) { + return hrTime(time); + } + // epoch milliseconds or performance.timeOrigin + else { + return numberToHrtime(time); + } + } else if (time instanceof Date) { + return [time.getTime(), 0]; + } else { + throw TypeError('Invalid input type'); + } +} + +// Returns a duration of two hrTime. +export function hrTimeDuration( + startTime: types.HrTime, + endTime: types.HrTime +): types.HrTime { + let seconds = endTime[0] - startTime[0]; + let nanos = endTime[1] - startTime[1]; + + // overflow + if (nanos < 0) { + seconds -= 1; + // negate + nanos += SECOND_TO_NANOSECONDS; + } + + return [seconds, nanos]; +} + +// Convert hrTime to nanoseconds. +export function hrTimeToNanoseconds(hrTime: types.HrTime): number { + const nanos = hrTime[0] * SECOND_TO_NANOSECONDS + hrTime[1]; + return nanos; +} + +// Convert hrTime to milliseconds. +export function hrTimeToMilliseconds(hrTime: types.HrTime): number { + const nanos = Math.round(hrTime[0] * 1000 + hrTime[1] / 1e6); + return nanos; +} diff --git a/packages/opentelemetry-core/src/index.ts b/packages/opentelemetry-core/src/index.ts index 3db49f5e4..a515efed4 100644 --- a/packages/opentelemetry-core/src/index.ts +++ b/packages/opentelemetry-core/src/index.ts @@ -16,6 +16,7 @@ export * from './common/ConsoleLogger'; export * from './common/NoopLogger'; +export * from './common/time'; export * from './common/types'; export * from './context/propagation/B3Format'; export * from './context/propagation/BinaryTraceContext'; diff --git a/packages/opentelemetry-core/src/trace/NoopSpan.ts b/packages/opentelemetry-core/src/trace/NoopSpan.ts index 78ff9073f..cd4b7e465 100644 --- a/packages/opentelemetry-core/src/trace/NoopSpan.ts +++ b/packages/opentelemetry-core/src/trace/NoopSpan.ts @@ -64,7 +64,7 @@ export class NoopSpan implements types.Span { } // By default does nothing - end(endTime?: number): void {} + end(endTime?: types.TimeInput): void {} // isRecordingEvents always returns false for noopSpan. isRecordingEvents(): boolean { diff --git a/packages/opentelemetry-core/test/common/time.test.ts b/packages/opentelemetry-core/test/common/time.test.ts new file mode 100644 index 000000000..ad1a88df5 --- /dev/null +++ b/packages/opentelemetry-core/test/common/time.test.ts @@ -0,0 +1,129 @@ +/** + * Copyright 2019, OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as assert from 'assert'; +import { performance } from 'perf_hooks'; +import * as sinon from 'sinon'; +import * as types from '@opentelemetry/types'; +import { + hrTime, + timeInputToHrTime, + hrTimeDuration, + hrTimeToNanoseconds, + hrTimeToMilliseconds, +} from '../../src/common/time'; + +describe('time', () => { + let sandbox: sinon.SinonSandbox; + + beforeEach(() => { + sandbox = sinon.createSandbox(); + }); + + afterEach(() => { + sandbox.restore(); + }); + + describe('#hrTime', () => { + it('should return hrtime now', () => { + sandbox.stub(performance, 'timeOrigin').value(11.5); + sandbox.stub(performance, 'now').callsFake(() => 11.3); + + const output = hrTime(); + assert.deepStrictEqual(output, [22, 800000000]); + }); + + it('should convert performance now', () => { + sandbox.stub(performance, 'timeOrigin').value(11.5); + const performanceNow = 11.3; + + const output = hrTime(performanceNow); + assert.deepStrictEqual(output, [22, 800000000]); + }); + + it('should handle nanosecond overflow', () => { + sandbox.stub(performance, 'timeOrigin').value(11.5); + const performanceNow = 11.6; + + const output = hrTime(performanceNow); + assert.deepStrictEqual(output, [23, 100000000]); + }); + }); + + describe('#timeInputToHrTime', () => { + it('should convert Date hrTime', () => { + const timeInput = new Date(); + const output = timeInputToHrTime(timeInput); + assert.deepStrictEqual(output, [timeInput.getTime(), 0]); + }); + + it('should convert epoch milliseconds hrTime', () => { + const timeInput = Date.now(); + const output = timeInputToHrTime(timeInput); + assert.deepStrictEqual(output, [timeInput, 0]); + }); + + it('should convert performance.now() hrTime', () => { + sandbox.stub(performance, 'timeOrigin').value(111.5); + + const timeInput = 11.9; + const output = timeInputToHrTime(timeInput); + + assert.deepStrictEqual(output, [123, 400000000]); + }); + + it('should not convert hrtime hrTime', () => { + sandbox.stub(performance, 'timeOrigin').value(111.5); + + const timeInput: [number, number] = [3138971, 245466222]; + const output = timeInputToHrTime(timeInput); + + assert.deepStrictEqual(timeInput, output); + }); + }); + + describe('#hrTimeDuration', () => { + it('should return duration', () => { + const startTime: types.HrTime = [22, 400000000]; + const endTime: types.HrTime = [32, 800000000]; + + const output = hrTimeDuration(startTime, endTime); + assert.deepStrictEqual(output, [10, 400000000]); + }); + + it('should handle nanosecond overflow', () => { + const startTime: types.HrTime = [22, 400000000]; + const endTime: types.HrTime = [32, 200000000]; + + const output = hrTimeDuration(startTime, endTime); + assert.deepStrictEqual(output, [9, 800000000]); + }); + }); + + describe('#hrTimeToNanoseconds', () => { + it('should return nanoseconds', () => { + const output = hrTimeToNanoseconds([1, 200000000]); + assert.deepStrictEqual(output, 1200000000); + }); + }); + + describe('#hrTimeToMilliseconds', () => { + it('should return milliseconds', () => { + const output = hrTimeToMilliseconds([1, 200000000]); + assert.deepStrictEqual(output, 1200); + }); + }); +}); diff --git a/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts b/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts index 608caffbd..c99e836a3 100644 --- a/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts +++ b/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts @@ -107,26 +107,24 @@ describe('HttpPlugin', () => { plugin.disable(); }); - it('should generate valid spans (client side and server side)', done => { - httpRequest - .get(`http://${hostname}:${serverPort}${pathname}`) - .then(result => { - const spans = memoryExporter.getFinishedSpans(); - const [incomingSpan, outgoingSpan] = spans; - const validations = { - hostname, - httpStatusCode: result.statusCode!, - httpMethod: result.method!, - pathname, - resHeaders: result.resHeaders, - reqHeaders: result.reqHeaders, - }; + it('should generate valid spans (client side and server side)', async () => { + const result = await httpRequest.get( + `http://${hostname}:${serverPort}${pathname}` + ); + const spans = audit.processSpans(); + const [incomingSpan, outgoingSpan] = spans; + const validations = { + hostname, + httpStatusCode: result.statusCode!, + httpMethod: result.method!, + pathname, + resHeaders: result.resHeaders, + reqHeaders: result.reqHeaders, + }; - assert.strictEqual(spans.length, 2); - assertSpan(incomingSpan, SpanKind.SERVER, validations); - assertSpan(outgoingSpan, SpanKind.CLIENT, validations); - done(); - }); + assert.strictEqual(spans.length, 2); + assertSpan(incomingSpan, SpanKind.SERVER, validations); + assertSpan(outgoingSpan, SpanKind.CLIENT, validations); }); const httpErrorCodes = [400, 401, 403, 404, 429, 501, 503, 504, 500]; @@ -246,7 +244,8 @@ describe('HttpPlugin', () => { reqSpan.spanContext.spanId ); done(); - }); + }) + .catch(done); }); }); } diff --git a/packages/opentelemetry-plugin-http/test/utils/assertSpan.ts b/packages/opentelemetry-plugin-http/test/utils/assertSpan.ts index 83770e4a2..87731e2b3 100644 --- a/packages/opentelemetry-plugin-http/test/utils/assertSpan.ts +++ b/packages/opentelemetry-plugin-http/test/utils/assertSpan.ts @@ -15,6 +15,7 @@ */ import { SpanKind } from '@opentelemetry/types'; +import { hrTimeToNanoseconds } from '@opentelemetry/core'; import * as assert from 'assert'; import * as http from 'http'; import { AttributeNames } from '../../src/enums/AttributeNames'; @@ -75,8 +76,7 @@ export const assertSpan = ( Utils.parseResponseStatus(validations.httpStatusCode) ); - assert.ok(span.startTime < span.endTime); - assert.ok(span.endTime > 0); + assert.ok(hrTimeToNanoseconds(span.duration), 'must have positive duration'); if (validations.reqHeaders) { const userAgent = validations.reqHeaders['user-agent']; diff --git a/packages/opentelemetry-types/src/common/Time.ts b/packages/opentelemetry-types/src/common/Time.ts new file mode 100644 index 000000000..14c9e124c --- /dev/null +++ b/packages/opentelemetry-types/src/common/Time.ts @@ -0,0 +1,25 @@ +/** + * Copyright 2019, OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** High resolution HrTime: [seconds: number, nanoseconds: number] */ +export type HrTime = [number, number]; + +/** + * Defines TimeInput. + * + * hrtime, expoch milliseconds, performance.now() or Date + */ +export type TimeInput = HrTime | number | Date; diff --git a/packages/opentelemetry-types/src/index.ts b/packages/opentelemetry-types/src/index.ts index 063d69d10..f57e16c97 100644 --- a/packages/opentelemetry-types/src/index.ts +++ b/packages/opentelemetry-types/src/index.ts @@ -15,6 +15,7 @@ */ export * from './common/Logger'; +export * from './common/Time'; export * from './context/propagation/BinaryFormat'; export * from './context/propagation/HttpTextFormat'; export * from './distributed_context/DistributedContext'; diff --git a/packages/opentelemetry-types/src/trace/TimedEvent.ts b/packages/opentelemetry-types/src/trace/TimedEvent.ts index 46d792f48..3218bfa60 100644 --- a/packages/opentelemetry-types/src/trace/TimedEvent.ts +++ b/packages/opentelemetry-types/src/trace/TimedEvent.ts @@ -15,11 +15,12 @@ */ import { Event } from './Event'; +import { HrTime } from '../common/Time'; /** * Represents a timed event. * A timed event is an event with a timestamp. */ export interface TimedEvent extends Event { - time: number; + time: HrTime; } diff --git a/packages/opentelemetry-types/src/trace/span.ts b/packages/opentelemetry-types/src/trace/span.ts index 229a5b34d..279159498 100644 --- a/packages/opentelemetry-types/src/trace/span.ts +++ b/packages/opentelemetry-types/src/trace/span.ts @@ -17,6 +17,7 @@ import { Attributes } from './attributes'; import { SpanContext } from './span_context'; import { Status } from './status'; +import { TimeInput } from '../common/Time'; /** * An interface that represents a span. A span represents a single operation @@ -99,11 +100,11 @@ export interface Span { * Do not return `this`. The Span generally should not be used after it * is ended so chaining is not desired in this context. * - * @param [endTime] the timestamp to set as Span's end time. If not provided, + * @param [endTime] the time to set as Span's end time. If not provided, * use the current time as the span's end time. * TODO (Add timestamp format): https://github.com/open-telemetry/opentelemetry-js/issues/19 */ - end(endTime?: number): void; + end(endTime?: TimeInput): void; /** * Returns the flag whether this span will be recorded.