rsnext/packages/next/trace/trace.ts
Tim Neutkens a5bfc1eecc
Simplify trace span id generation (#32946)
Uses a simple counter for span ids, previously these required to be randomly generated but I've changed the importer script to ensure it gets prepended `0`s to make sure it gets to 16 characters which Jaeger requires.



## Bug

- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`

## Documentation / Examples

- [ ] Make sure the linting passes by running `yarn lint`
2022-01-02 21:22:01 +00:00

113 lines
2.5 KiB
TypeScript

import { SpanId } from './shared'
import { reporter } from './report'
const NUM_OF_MICROSEC_IN_SEC = BigInt('1000')
let count = 0
const getId = () => {
count++
return count
}
// eslint typescript has a bug with TS enums
/* eslint-disable no-shadow */
export enum SpanStatus {
Started,
Stopped,
}
export class Span {
name: string
id: SpanId
parentId?: SpanId
duration: number | null
attrs: { [key: string]: any }
status: SpanStatus
_start: bigint
constructor({
name,
parentId,
attrs,
startTime,
}: {
name: string
parentId?: SpanId
startTime?: bigint
attrs?: Object
}) {
this.name = name
this.parentId = parentId
this.duration = null
this.attrs = attrs ? { ...attrs } : {}
this.status = SpanStatus.Started
this.id = getId()
this._start = startTime || process.hrtime.bigint()
}
// Durations are reported as microseconds. This gives 1000x the precision
// of something like Date.now(), which reports in milliseconds.
// Additionally, ~285 years can be safely represented as microseconds as
// a float64 in both JSON and JavaScript.
stop(stopTime?: bigint) {
const end: bigint = stopTime || process.hrtime.bigint()
const duration = (end - this._start) / NUM_OF_MICROSEC_IN_SEC
this.status = SpanStatus.Stopped
if (duration > Number.MAX_SAFE_INTEGER) {
throw new Error(`Duration is too long to express as float64: ${duration}`)
}
const timestamp = this._start / NUM_OF_MICROSEC_IN_SEC
reporter.report(
this.name,
Number(duration),
Number(timestamp),
this.id,
this.parentId,
this.attrs
)
}
traceChild(name: string, attrs?: Object) {
return new Span({ name, parentId: this.id, attrs })
}
manualTraceChild(
name: string,
startTime: bigint,
stopTime: bigint,
attrs?: Object
) {
const span = new Span({ name, parentId: this.id, attrs, startTime })
span.stop(stopTime)
}
setAttribute(key: string, value: any) {
this.attrs[key] = String(value)
}
traceFn(fn: any) {
try {
return fn()
} finally {
this.stop()
}
}
async traceAsyncFn<T>(fn: () => T | Promise<T>): Promise<T> {
try {
return await fn()
} finally {
this.stop()
}
}
}
export const trace = (
name: string,
parentId?: SpanId,
attrs?: { [key: string]: string }
) => {
return new Span({ name, parentId, attrs })
}
export const flushAllTraces = () => reporter.flushAll()