@dxos/tracing 0.1.56-next.a63ce79 → 0.1.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/browser/index.mjs +292 -20
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +296 -20
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/types/src/api.d.ts +1 -0
- package/dist/types/src/api.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/metrics/base.d.ts +7 -0
- package/dist/types/src/metrics/base.d.ts.map +1 -0
- package/dist/types/src/metrics/index.d.ts +5 -0
- package/dist/types/src/metrics/index.d.ts.map +1 -0
- package/dist/types/src/metrics/time-series-counter.d.ts +15 -0
- package/dist/types/src/metrics/time-series-counter.d.ts.map +1 -0
- package/dist/types/src/metrics/time-usage-counter.d.ts +15 -0
- package/dist/types/src/metrics/time-usage-counter.d.ts.map +1 -0
- package/dist/types/src/metrics/unary-counter.d.ts +12 -0
- package/dist/types/src/metrics/unary-counter.d.ts.map +1 -0
- package/dist/types/src/symbols.d.ts +1 -0
- package/dist/types/src/symbols.d.ts.map +1 -1
- package/dist/types/src/trace-processor.d.ts +10 -1
- package/dist/types/src/trace-processor.d.ts.map +1 -1
- package/dist/types/src/trace-sender.d.ts.map +1 -1
- package/package.json +10 -9
- package/src/api.ts +14 -0
- package/src/index.ts +1 -0
- package/src/metrics/base.ts +26 -0
- package/src/metrics/index.ts +8 -0
- package/src/metrics/time-series-counter.ts +52 -0
- package/src/metrics/time-usage-counter.ts +62 -0
- package/src/metrics/unary-counter.ts +31 -0
- package/src/symbols.ts +4 -2
- package/src/trace-processor.ts +158 -2
- package/src/trace-sender.ts +28 -18
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/metrics/index.ts"],"names":[],"mappings":"AAIA,cAAc,QAAQ,CAAC;AACvB,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Metric } from '@dxos/protocols/proto/dxos/tracing';
|
|
2
|
+
import { BaseCounter } from './base';
|
|
3
|
+
export declare class TimeSeriesCounter extends BaseCounter {
|
|
4
|
+
private _currentValue;
|
|
5
|
+
private _totalValue;
|
|
6
|
+
private _buckets;
|
|
7
|
+
units?: string;
|
|
8
|
+
constructor({ units }?: {
|
|
9
|
+
units?: string;
|
|
10
|
+
});
|
|
11
|
+
inc(by?: number): void;
|
|
12
|
+
_tick(time: number): void;
|
|
13
|
+
getData(): Metric;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=time-series-counter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"time-series-counter.d.ts","sourceRoot":"","sources":["../../../../src/metrics/time-series-counter.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;AAE5D,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAIrC,qBAAa,iBAAkB,SAAQ,WAAW;IAChD,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,QAAQ,CAAgB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;gBAEH,EAAE,KAAK,EAAE,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO;IAK9C,GAAG,CAAC,EAAE,SAAI;IAKD,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAQzB,OAAO,IAAI,MAAM;CAiB3B"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Metric } from '@dxos/protocols/proto/dxos/tracing';
|
|
2
|
+
import { BaseCounter } from './base';
|
|
3
|
+
export declare class TimeUsageCounter extends BaseCounter {
|
|
4
|
+
private _currentValue;
|
|
5
|
+
private _totalValue;
|
|
6
|
+
private _buckets;
|
|
7
|
+
private _lastTickTime;
|
|
8
|
+
record(time: number): void;
|
|
9
|
+
beginRecording(): {
|
|
10
|
+
end: () => void;
|
|
11
|
+
};
|
|
12
|
+
_tick(time: number): void;
|
|
13
|
+
getData(): Metric;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=time-usage-counter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"time-usage-counter.d.ts","sourceRoot":"","sources":["../../../../src/metrics/time-usage-counter.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;AAE5D,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAIrC,qBAAa,gBAAiB,SAAQ,WAAW;IAC/C,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,QAAQ,CAAgB;IAEhC,OAAO,CAAC,aAAa,CAAqB;IAE1C,MAAM,CAAC,IAAI,EAAE,MAAM;IAKnB,cAAc,IAAI;QAAE,GAAG,EAAE,MAAM,IAAI,CAAA;KAAE;IAU5B,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAYzB,OAAO,IAAI,MAAM;CAiB3B"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Metric } from '@dxos/protocols/proto/dxos/tracing';
|
|
2
|
+
import { BaseCounter } from './base';
|
|
3
|
+
export declare class UnaryCounter extends BaseCounter {
|
|
4
|
+
value: number;
|
|
5
|
+
units?: string;
|
|
6
|
+
constructor({ units }?: {
|
|
7
|
+
units?: string;
|
|
8
|
+
});
|
|
9
|
+
inc(by?: number): void;
|
|
10
|
+
getData(): Metric;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=unary-counter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unary-counter.d.ts","sourceRoot":"","sources":["../../../../src/metrics/unary-counter.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;AAE5D,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAErC,qBAAa,YAAa,SAAQ,WAAW;IAC3C,KAAK,SAAK;IACV,KAAK,CAAC,EAAE,MAAM,CAAC;gBAEH,EAAE,KAAK,EAAE,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO;IAK9C,GAAG,CAAC,EAAE,SAAI;IAIV,OAAO,IAAI,MAAM;CASlB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export declare const symbolTracingContext: unique symbol;
|
|
2
2
|
export type TracingContext = {
|
|
3
3
|
infoProperties: Record<string, {}>;
|
|
4
|
+
metricsProperties: Record<string, {}>;
|
|
4
5
|
};
|
|
5
6
|
export declare const getTracingContext: (target: any) => TracingContext;
|
|
6
7
|
export declare const TRACE_SPAN_ATTRIBUTE = "dxos.trace-span";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"symbols.d.ts","sourceRoot":"","sources":["../../../src/symbols.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,oBAAoB,eAAiC,CAAC;AAEnE,MAAM,MAAM,cAAc,GAAG;IAC3B,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"symbols.d.ts","sourceRoot":"","sources":["../../../src/symbols.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,oBAAoB,eAAiC,CAAC;AAEnE,MAAM,MAAM,cAAc,GAAG;IAC3B,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACnC,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;CACvC,CAAC;AAEF,eAAO,MAAM,iBAAiB,WAAY,GAAG,KAAG,cAK/C,CAAC;AAEF,eAAO,MAAM,oBAAoB,oBAAoB,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Context } from '@dxos/context';
|
|
2
|
+
import { LogEntry } from '@dxos/protocols/proto/dxos/client/services';
|
|
2
3
|
import { Error as SerializedError } from '@dxos/protocols/proto/dxos/error';
|
|
3
|
-
import { Resource, Span } from '@dxos/protocols/proto/dxos/tracing';
|
|
4
|
+
import { Metric, Resource, Span } from '@dxos/protocols/proto/dxos/tracing';
|
|
4
5
|
import type { AddLinkOptions } from './api';
|
|
5
6
|
import { TraceSender } from './trace-sender';
|
|
6
7
|
export type TraceResourceConstructorParams = {
|
|
@@ -19,8 +20,10 @@ export type ResourceEntry = {
|
|
|
19
20
|
instance: WeakRef<any>;
|
|
20
21
|
};
|
|
21
22
|
export type TraceSubscription = {
|
|
23
|
+
flush: () => void;
|
|
22
24
|
dirtyResources: Set<number>;
|
|
23
25
|
dirtySpans: Set<number>;
|
|
26
|
+
newLogs: LogEntry[];
|
|
24
27
|
};
|
|
25
28
|
export declare class TraceProcessor {
|
|
26
29
|
resources: Map<number, ResourceEntry>;
|
|
@@ -28,17 +31,23 @@ export declare class TraceProcessor {
|
|
|
28
31
|
resourceIdList: number[];
|
|
29
32
|
spans: Map<number, Span>;
|
|
30
33
|
spanIdList: number[];
|
|
34
|
+
logs: LogEntry[];
|
|
31
35
|
subscriptions: Set<TraceSubscription>;
|
|
36
|
+
constructor();
|
|
32
37
|
traceResourceConstructor(params: TraceResourceConstructorParams): void;
|
|
33
38
|
getResourceInfo(instance: any): Record<string, any>;
|
|
39
|
+
getResourceMetrics(instance: any): Metric[];
|
|
34
40
|
traceSpan(params: TraceSpanParams): TracingSpan;
|
|
35
41
|
addLink(parent: any, child: any, opts: AddLinkOptions): void;
|
|
36
42
|
getResourceId(instance: any): number | null;
|
|
37
43
|
createTraceSender(): TraceSender;
|
|
44
|
+
refresh(): void;
|
|
38
45
|
private _markResourceDirty;
|
|
39
46
|
private _markSpanDirty;
|
|
40
47
|
private _clearResources;
|
|
41
48
|
private _clearSpans;
|
|
49
|
+
private _pushLog;
|
|
50
|
+
private _logProcessor;
|
|
42
51
|
}
|
|
43
52
|
export declare class TracingSpan {
|
|
44
53
|
private _traceProcessor;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trace-processor.d.ts","sourceRoot":"","sources":["../../../src/trace-processor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"trace-processor.d.ts","sourceRoot":"","sources":["../../../src/trace-processor.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trace-sender.d.ts","sourceRoot":"","sources":["../../../src/trace-sender.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"trace-sender.d.ts","sourceRoot":"","sources":["../../../src/trace-sender.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAE9C,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEtF,OAAO,EAAE,cAAc,EAAqB,MAAM,mBAAmB,CAAC;AAEtE,qBAAa,WAAY,YAAW,cAAc;IACpC,OAAO,CAAC,eAAe;gBAAf,eAAe,EAAE,cAAc;IAEnD,WAAW,CAAC,OAAO,EAAE,IAAI,GAAG,MAAM,CAAC,gBAAgB,CAAC;CA0ErD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/tracing",
|
|
3
|
-
"version": "0.1.56
|
|
3
|
+
"version": "0.1.56",
|
|
4
4
|
"description": "Async utilities.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -16,14 +16,15 @@
|
|
|
16
16
|
"src"
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@dxos/
|
|
20
|
-
"@dxos/
|
|
21
|
-
"@dxos/
|
|
22
|
-
"@dxos/
|
|
23
|
-
"@dxos/
|
|
24
|
-
"@dxos/
|
|
25
|
-
"@dxos/
|
|
26
|
-
"@dxos/
|
|
19
|
+
"@dxos/async": "0.1.56",
|
|
20
|
+
"@dxos/codec-protobuf": "0.1.56",
|
|
21
|
+
"@dxos/context": "0.1.56",
|
|
22
|
+
"@dxos/debug": "0.1.56",
|
|
23
|
+
"@dxos/invariant": "0.1.56",
|
|
24
|
+
"@dxos/log": "0.1.56",
|
|
25
|
+
"@dxos/node-std": "0.1.56",
|
|
26
|
+
"@dxos/protocols": "0.1.56",
|
|
27
|
+
"@dxos/util": "0.1.56"
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {},
|
|
29
30
|
"publishConfig": {
|
package/src/api.ts
CHANGED
|
@@ -7,6 +7,9 @@ import { Context } from '@dxos/context';
|
|
|
7
7
|
import { getTracingContext } from './symbols';
|
|
8
8
|
import { TRACE_PROCESSOR } from './trace-processor';
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Annotates a class as a tracked resource.
|
|
12
|
+
*/
|
|
10
13
|
const resource =
|
|
11
14
|
() =>
|
|
12
15
|
<T extends { new (...args: any[]): {} }>(constructor: T) => {
|
|
@@ -20,6 +23,9 @@ const resource =
|
|
|
20
23
|
return klass;
|
|
21
24
|
};
|
|
22
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Marks a property or a method to be included in the resource info section.
|
|
28
|
+
*/
|
|
23
29
|
const info = () => (target: any, propertyKey: string, descriptor?: PropertyDescriptor) => {
|
|
24
30
|
getTracingContext(target).infoProperties[propertyKey] = {};
|
|
25
31
|
};
|
|
@@ -43,6 +49,13 @@ const span = () => (target: any, propertyKey: string, descriptor: TypedPropertyD
|
|
|
43
49
|
};
|
|
44
50
|
};
|
|
45
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Attaches metrics counter to the resource.
|
|
54
|
+
*/
|
|
55
|
+
const metricsCounter = () => (target: any, propertyKey: string, descriptor?: PropertyDescriptor) => {
|
|
56
|
+
getTracingContext(target).metricsProperties[propertyKey] = {};
|
|
57
|
+
};
|
|
58
|
+
|
|
46
59
|
export type AddLinkOptions = {};
|
|
47
60
|
|
|
48
61
|
const addLink = (parent: any, child: any, opts: AddLinkOptions = {}) => {
|
|
@@ -53,6 +66,7 @@ export const trace = {
|
|
|
53
66
|
resource,
|
|
54
67
|
info,
|
|
55
68
|
span,
|
|
69
|
+
metricsCounter,
|
|
56
70
|
|
|
57
71
|
addLink,
|
|
58
72
|
};
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Metric } from '@dxos/protocols/proto/dxos/tracing';
|
|
6
|
+
|
|
7
|
+
export abstract class BaseCounter {
|
|
8
|
+
/**
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
_instance: any;
|
|
12
|
+
|
|
13
|
+
name?: string;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
_assign(instance: any, name: string) {
|
|
19
|
+
this._instance = instance;
|
|
20
|
+
this.name = name;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
abstract getData(): Metric;
|
|
24
|
+
|
|
25
|
+
_tick(time: number): void {}
|
|
26
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Metric } from '@dxos/protocols/proto/dxos/tracing';
|
|
6
|
+
|
|
7
|
+
import { BaseCounter } from './base';
|
|
8
|
+
|
|
9
|
+
const MAX_BUCKETS = 60;
|
|
10
|
+
|
|
11
|
+
export class TimeSeriesCounter extends BaseCounter {
|
|
12
|
+
private _currentValue = 0;
|
|
13
|
+
private _totalValue = 0;
|
|
14
|
+
private _buckets: number[] = [];
|
|
15
|
+
units?: string;
|
|
16
|
+
|
|
17
|
+
constructor({ units }: { units?: string } = {}) {
|
|
18
|
+
super();
|
|
19
|
+
this.units = units;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
inc(by = 1) {
|
|
23
|
+
this._currentValue += by;
|
|
24
|
+
this._totalValue += by;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
override _tick(time: number): void {
|
|
28
|
+
this._buckets.push(this._currentValue);
|
|
29
|
+
if (this._buckets.length > MAX_BUCKETS) {
|
|
30
|
+
this._buckets.shift();
|
|
31
|
+
}
|
|
32
|
+
this._currentValue = 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
override getData(): Metric {
|
|
36
|
+
return {
|
|
37
|
+
name: this.name!,
|
|
38
|
+
timeSeries: {
|
|
39
|
+
tracks: [
|
|
40
|
+
{
|
|
41
|
+
name: this.name!,
|
|
42
|
+
units: this.units,
|
|
43
|
+
points: this._buckets.map((value, index) => ({
|
|
44
|
+
value,
|
|
45
|
+
})),
|
|
46
|
+
total: this._totalValue,
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Metric } from '@dxos/protocols/proto/dxos/tracing';
|
|
6
|
+
|
|
7
|
+
import { BaseCounter } from './base';
|
|
8
|
+
|
|
9
|
+
const MAX_BUCKETS = 60;
|
|
10
|
+
|
|
11
|
+
export class TimeUsageCounter extends BaseCounter {
|
|
12
|
+
private _currentValue = 0;
|
|
13
|
+
private _totalValue = 0;
|
|
14
|
+
private _buckets: number[] = [];
|
|
15
|
+
|
|
16
|
+
private _lastTickTime = performance.now();
|
|
17
|
+
|
|
18
|
+
record(time: number) {
|
|
19
|
+
this._currentValue += time;
|
|
20
|
+
this._totalValue += time;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
beginRecording(): { end: () => void } {
|
|
24
|
+
const start = performance.now();
|
|
25
|
+
return {
|
|
26
|
+
end: () => {
|
|
27
|
+
const end = performance.now();
|
|
28
|
+
this.record(end - start);
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
override _tick(time: number): void {
|
|
34
|
+
const delta = time - this._lastTickTime;
|
|
35
|
+
this._lastTickTime = time;
|
|
36
|
+
|
|
37
|
+
const percentage = (this._currentValue / delta) * 100;
|
|
38
|
+
this._buckets.push(percentage);
|
|
39
|
+
if (this._buckets.length > MAX_BUCKETS) {
|
|
40
|
+
this._buckets.shift();
|
|
41
|
+
}
|
|
42
|
+
this._currentValue = 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
override getData(): Metric {
|
|
46
|
+
return {
|
|
47
|
+
name: this.name!,
|
|
48
|
+
timeSeries: {
|
|
49
|
+
tracks: [
|
|
50
|
+
{
|
|
51
|
+
name: this.name!,
|
|
52
|
+
units: '%',
|
|
53
|
+
points: this._buckets.map((value, index) => ({
|
|
54
|
+
value,
|
|
55
|
+
})),
|
|
56
|
+
total: this._totalValue,
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Metric } from '@dxos/protocols/proto/dxos/tracing';
|
|
6
|
+
|
|
7
|
+
import { BaseCounter } from './base';
|
|
8
|
+
|
|
9
|
+
export class UnaryCounter extends BaseCounter {
|
|
10
|
+
value = 0;
|
|
11
|
+
units?: string;
|
|
12
|
+
|
|
13
|
+
constructor({ units }: { units?: string } = {}) {
|
|
14
|
+
super();
|
|
15
|
+
this.units = units;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
inc(by = 1) {
|
|
19
|
+
this.value += by;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getData(): Metric {
|
|
23
|
+
return {
|
|
24
|
+
name: this.name!,
|
|
25
|
+
counter: {
|
|
26
|
+
value: this.value,
|
|
27
|
+
units: this.units,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
package/src/symbols.ts
CHANGED
|
@@ -2,15 +2,17 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
export const symbolTracingContext = Symbol('dxos.tracing
|
|
5
|
+
export const symbolTracingContext = Symbol('dxos.tracing.context');
|
|
6
6
|
|
|
7
7
|
export type TracingContext = {
|
|
8
8
|
infoProperties: Record<string, {}>;
|
|
9
|
+
metricsProperties: Record<string, {}>;
|
|
9
10
|
};
|
|
10
11
|
|
|
11
12
|
export const getTracingContext = (target: any): TracingContext => {
|
|
12
|
-
return (target[symbolTracingContext] ??= {
|
|
13
|
+
return ((target[symbolTracingContext] as TracingContext | undefined) ??= {
|
|
13
14
|
infoProperties: {},
|
|
15
|
+
metricsProperties: {},
|
|
14
16
|
});
|
|
15
17
|
};
|
|
16
18
|
|
package/src/trace-processor.ts
CHANGED
|
@@ -2,12 +2,16 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { unrefTimeout } from '@dxos/async';
|
|
5
6
|
import { Context } from '@dxos/context';
|
|
7
|
+
import { LogLevel, LogProcessor, getContextFromEntry, log } from '@dxos/log';
|
|
8
|
+
import { LogEntry } from '@dxos/protocols/proto/dxos/client/services';
|
|
6
9
|
import { Error as SerializedError } from '@dxos/protocols/proto/dxos/error';
|
|
7
|
-
import { Resource, Span } from '@dxos/protocols/proto/dxos/tracing';
|
|
10
|
+
import { Metric, Resource, Span } from '@dxos/protocols/proto/dxos/tracing';
|
|
8
11
|
import { getPrototypeSpecificInstanceId } from '@dxos/util';
|
|
9
12
|
|
|
10
13
|
import type { AddLinkOptions } from './api';
|
|
14
|
+
import { BaseCounter } from './metrics';
|
|
11
15
|
import { TRACE_SPAN_ATTRIBUTE, getTracingContext } from './symbols';
|
|
12
16
|
import { TraceSender } from './trace-sender';
|
|
13
17
|
|
|
@@ -28,12 +32,18 @@ export type ResourceEntry = {
|
|
|
28
32
|
};
|
|
29
33
|
|
|
30
34
|
export type TraceSubscription = {
|
|
35
|
+
flush: () => void;
|
|
36
|
+
|
|
31
37
|
dirtyResources: Set<number>;
|
|
32
38
|
dirtySpans: Set<number>;
|
|
39
|
+
newLogs: LogEntry[];
|
|
33
40
|
};
|
|
34
41
|
|
|
35
42
|
const MAX_RESOURCE_RECORDS = 500;
|
|
36
43
|
const MAX_SPAN_RECORDS = 1_000;
|
|
44
|
+
const MAX_LOG_RECORDS = 1_000;
|
|
45
|
+
|
|
46
|
+
const REFRESH_INTERVAL = 1_000;
|
|
37
47
|
|
|
38
48
|
export class TraceProcessor {
|
|
39
49
|
resources = new Map<number, ResourceEntry>();
|
|
@@ -43,10 +53,26 @@ export class TraceProcessor {
|
|
|
43
53
|
spans = new Map<number, Span>();
|
|
44
54
|
spanIdList: number[] = [];
|
|
45
55
|
|
|
56
|
+
logs: LogEntry[] = [];
|
|
57
|
+
|
|
46
58
|
subscriptions: Set<TraceSubscription> = new Set();
|
|
47
59
|
|
|
60
|
+
constructor() {
|
|
61
|
+
log.addProcessor(this._logProcessor.bind(this));
|
|
62
|
+
|
|
63
|
+
const refreshInterval = setInterval(this.refresh.bind(this), REFRESH_INTERVAL);
|
|
64
|
+
unrefTimeout(refreshInterval);
|
|
65
|
+
}
|
|
66
|
+
|
|
48
67
|
traceResourceConstructor(params: TraceResourceConstructorParams) {
|
|
49
68
|
const id = this.resources.size;
|
|
69
|
+
|
|
70
|
+
// init metrics counters.
|
|
71
|
+
const tracingContext = getTracingContext(Object.getPrototypeOf(params.instance));
|
|
72
|
+
for (const key of Object.keys(tracingContext.metricsProperties)) {
|
|
73
|
+
(params.instance[key] as BaseCounter)._assign(params.instance, key);
|
|
74
|
+
}
|
|
75
|
+
|
|
50
76
|
const entry: ResourceEntry = {
|
|
51
77
|
data: {
|
|
52
78
|
id,
|
|
@@ -54,6 +80,7 @@ export class TraceProcessor {
|
|
|
54
80
|
instanceId: getPrototypeSpecificInstanceId(params.instance),
|
|
55
81
|
info: this.getResourceInfo(params.instance),
|
|
56
82
|
links: [],
|
|
83
|
+
metrics: this.getResourceMetrics(params.instance),
|
|
57
84
|
},
|
|
58
85
|
instance: new WeakRef(params.instance),
|
|
59
86
|
};
|
|
@@ -72,7 +99,7 @@ export class TraceProcessor {
|
|
|
72
99
|
|
|
73
100
|
for (const [key, _opts] of Object.entries(tracingContext.infoProperties)) {
|
|
74
101
|
try {
|
|
75
|
-
res[key] = typeof instance[key] === 'function' ? instance[key]() : instance[key];
|
|
102
|
+
res[key] = sanitizeValue(typeof instance[key] === 'function' ? instance[key]() : instance[key]);
|
|
76
103
|
} catch (err: any) {
|
|
77
104
|
res[key] = err.message;
|
|
78
105
|
}
|
|
@@ -81,6 +108,17 @@ export class TraceProcessor {
|
|
|
81
108
|
return res;
|
|
82
109
|
}
|
|
83
110
|
|
|
111
|
+
getResourceMetrics(instance: any): Metric[] {
|
|
112
|
+
const res: Metric[] = [];
|
|
113
|
+
const tracingContext = getTracingContext(Object.getPrototypeOf(instance));
|
|
114
|
+
|
|
115
|
+
for (const [key, _opts] of Object.entries(tracingContext.metricsProperties)) {
|
|
116
|
+
res.push(instance[key].getData());
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return res;
|
|
120
|
+
}
|
|
121
|
+
|
|
84
122
|
traceSpan(params: TraceSpanParams): TracingSpan {
|
|
85
123
|
const span = new TracingSpan(this, params);
|
|
86
124
|
this._flushSpan(span);
|
|
@@ -98,6 +136,40 @@ export class TraceProcessor {
|
|
|
98
136
|
return new TraceSender(this);
|
|
99
137
|
}
|
|
100
138
|
|
|
139
|
+
refresh() {
|
|
140
|
+
for (const resource of this.resources.values()) {
|
|
141
|
+
const instance = resource.instance.deref();
|
|
142
|
+
if (!instance) {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const tracingContext = getTracingContext(Object.getPrototypeOf(instance));
|
|
147
|
+
const time = performance.now();
|
|
148
|
+
for (const key of Object.keys(tracingContext.metricsProperties)) {
|
|
149
|
+
(instance[key] as BaseCounter)._tick?.(time);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
let _changed = false;
|
|
153
|
+
|
|
154
|
+
const oldInfo = resource.data.info;
|
|
155
|
+
resource.data.info = this.getResourceInfo(instance);
|
|
156
|
+
_changed ||= !areEqualShallow(oldInfo, resource.data.info);
|
|
157
|
+
|
|
158
|
+
const oldMetrics = resource.data.metrics;
|
|
159
|
+
resource.data.metrics = this.getResourceMetrics(instance);
|
|
160
|
+
_changed ||= !areEqualShallow(oldMetrics, resource.data.metrics);
|
|
161
|
+
|
|
162
|
+
// TODO(dmaretskyi): Test if works and enable.
|
|
163
|
+
// if (changed) {
|
|
164
|
+
this._markResourceDirty(resource.data.id);
|
|
165
|
+
// }
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
for (const subscription of this.subscriptions) {
|
|
169
|
+
subscription.flush();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
101
173
|
/**
|
|
102
174
|
* @internal
|
|
103
175
|
*/
|
|
@@ -137,6 +209,52 @@ export class TraceProcessor {
|
|
|
137
209
|
this.spans.delete(id);
|
|
138
210
|
}
|
|
139
211
|
}
|
|
212
|
+
|
|
213
|
+
private _pushLog(log: LogEntry) {
|
|
214
|
+
this.logs.push(log);
|
|
215
|
+
if (this.logs.length > MAX_LOG_RECORDS) {
|
|
216
|
+
this.logs.shift();
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
for (const subscription of this.subscriptions) {
|
|
220
|
+
subscription.newLogs.push(log);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
private _logProcessor: LogProcessor = (config, entry) => {
|
|
225
|
+
switch (entry.level) {
|
|
226
|
+
case LogLevel.ERROR:
|
|
227
|
+
case LogLevel.WARN:
|
|
228
|
+
case LogLevel.TRACE: {
|
|
229
|
+
const scope = entry.meta?.S;
|
|
230
|
+
const resource = this.resourceInstanceIndex.get(scope);
|
|
231
|
+
if (!resource) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const context = getContextFromEntry(entry) ?? {};
|
|
236
|
+
|
|
237
|
+
for (const key of Object.keys(context)) {
|
|
238
|
+
context[key] = sanitizeValue(context[key]);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const entryToPush: LogEntry = {
|
|
242
|
+
level: entry.level,
|
|
243
|
+
message: entry.message,
|
|
244
|
+
context,
|
|
245
|
+
timestamp: new Date(),
|
|
246
|
+
meta: {
|
|
247
|
+
file: entry.meta?.F ?? '',
|
|
248
|
+
line: entry.meta?.L ?? 0,
|
|
249
|
+
resourceId: resource.data.id,
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
this._pushLog(entryToPush);
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
default:
|
|
256
|
+
}
|
|
257
|
+
};
|
|
140
258
|
}
|
|
141
259
|
|
|
142
260
|
export class TracingSpan {
|
|
@@ -213,3 +331,41 @@ const serializeError = (err: unknown): SerializedError => {
|
|
|
213
331
|
};
|
|
214
332
|
|
|
215
333
|
export const TRACE_PROCESSOR: TraceProcessor = ((globalThis as any).TRACE_PROCESSOR ??= new TraceProcessor());
|
|
334
|
+
|
|
335
|
+
const sanitizeValue = (value: any) => {
|
|
336
|
+
switch (typeof value) {
|
|
337
|
+
case 'string':
|
|
338
|
+
case 'number':
|
|
339
|
+
case 'boolean':
|
|
340
|
+
case 'undefined':
|
|
341
|
+
return value;
|
|
342
|
+
break;
|
|
343
|
+
case 'object':
|
|
344
|
+
case 'function':
|
|
345
|
+
if (value === null) {
|
|
346
|
+
return value;
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// TODO(dmaretskyi): Expose trait.
|
|
351
|
+
if (typeof value.truncate === 'function') {
|
|
352
|
+
return value.truncate();
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return value.toString();
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
const areEqualShallow = (a: any, b: any) => {
|
|
360
|
+
for (const key in a) {
|
|
361
|
+
if (!(key in b) || a[key] !== b[key]) {
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
for (const key in b) {
|
|
366
|
+
if (!(key in a) || a[key] !== b[key]) {
|
|
367
|
+
return false;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return true;
|
|
371
|
+
};
|