@uipath/common 1.198.0-preview.95 → 1.198.0
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/index.browser.js +236 -8
- package/dist/index.d.ts +1 -1
- package/dist/index.js +402 -157
- package/dist/telemetry/index.d.ts +2 -2
- package/dist/telemetry/index.js +118 -9
- package/dist/telemetry/node-appinsights-telemetry-provider.d.ts +45 -2
- package/dist/telemetry/node.d.ts +3 -1
- package/dist/telemetry/pii-redactor.d.ts +16 -0
- package/dist/telemetry/session-id.d.ts +19 -0
- package/dist/telemetry/telemetry-provider.d.ts +7 -1
- package/dist/telemetry/telemetry-service.d.ts +105 -1
- package/dist/telemetry/trace-context.d.ts +49 -0
- package/dist/telemetry/tracked-fetch.d.ts +33 -0
- package/dist/trackedAction.d.ts +15 -0
- package/package.json +2 -2
|
@@ -4,8 +4,8 @@ export { ConsoleTelemetryProvider } from "./console-telemetry-provider.js";
|
|
|
4
4
|
export type { IContextStorage } from "./context-storage.js";
|
|
5
5
|
export { buildEnvironmentProperties, type NormalizedEnvironment, normalizeBaseUrl, normalizeEnvironment, } from "./environment-info.js";
|
|
6
6
|
export { type CiProvider, detectExecutionContext, EXECUTION_CONTEXT_VALUES, type ExecutionContext, type ExecutionContextDetection, type ExecutionContextDetectionOptions, getExecutionContextTelemetryProperties, setExecutionContextAuthSignal, } from "./execution-context.js";
|
|
7
|
-
export { redactProperties, redactProperty } from "./pii-redactor.js";
|
|
7
|
+
export { redactError, redactProperties, redactProperty, redactValue, } from "./pii-redactor.js";
|
|
8
8
|
export { getConfiguredTelemetrySessionId, getTelemetrySessionId, resolveTelemetrySessionId, TELEMETRY_SESSION_ID_ENV, TELEMETRY_SESSION_ID_PROPERTY, } from "./session-id.js";
|
|
9
9
|
export type { ITelemetryProvider } from "./telemetry-provider.js";
|
|
10
10
|
export type { ITelemetryService, TelemetryContext, TelemetryProperties, } from "./telemetry-service.js";
|
|
11
|
-
export { TelemetryService } from "./telemetry-service.js";
|
|
11
|
+
export { TELEMETRY_OPERATION_ID_PROPERTY, TELEMETRY_PARENT_ID_PROPERTY, TELEMETRY_SPAN_ID_PROPERTY, TelemetryService, } from "./telemetry-service.js";
|
package/dist/telemetry/index.js
CHANGED
|
@@ -508,8 +508,17 @@ function redactValueDetectors(value) {
|
|
|
508
508
|
}
|
|
509
509
|
return out;
|
|
510
510
|
}
|
|
511
|
+
function redactValue(value) {
|
|
512
|
+
return redactValueDetectors(value);
|
|
513
|
+
}
|
|
514
|
+
function redactError(error) {
|
|
515
|
+
const safe = new Error(redactValueDetectors(error.message ?? ""));
|
|
516
|
+
safe.name = error.name;
|
|
517
|
+
safe.stack = typeof error.stack === "string" ? redactValueDetectors(error.stack) : undefined;
|
|
518
|
+
return safe;
|
|
519
|
+
}
|
|
511
520
|
function nameTokens(name) {
|
|
512
|
-
return name.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").split(/[\
|
|
521
|
+
return name.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").split(/[\s._-]+/).map((t) => t.toLowerCase()).filter(Boolean);
|
|
513
522
|
}
|
|
514
523
|
function isSensitiveName(name) {
|
|
515
524
|
const tokens = nameTokens(name);
|
|
@@ -552,11 +561,36 @@ function redactProperties(properties) {
|
|
|
552
561
|
}
|
|
553
562
|
return out;
|
|
554
563
|
}
|
|
564
|
+
// src/telemetry/trace-context.ts
|
|
565
|
+
var TELEMETRY_TRACEPARENT_ENV = "TRACEPARENT";
|
|
566
|
+
var TRACEPARENT_PATTERN = /^00-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/;
|
|
567
|
+
function getProcessEnv() {
|
|
568
|
+
return globalThis.process?.env;
|
|
569
|
+
}
|
|
570
|
+
function parseInboundTraceparent(value) {
|
|
571
|
+
if (!value) {
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
const match = TRACEPARENT_PATTERN.exec(value.trim().toLowerCase());
|
|
575
|
+
if (!match) {
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
const [, traceId, parentSpanId] = match;
|
|
579
|
+
if (/^0+$/.test(traceId) || /^0+$/.test(parentSpanId)) {
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
return { traceId, parentSpanId };
|
|
583
|
+
}
|
|
584
|
+
function getInboundTraceContext() {
|
|
585
|
+
return parseInboundTraceparent(getProcessEnv()?.[TELEMETRY_TRACEPARENT_ENV]);
|
|
586
|
+
}
|
|
587
|
+
|
|
555
588
|
// src/telemetry/session-id.ts
|
|
556
589
|
var TELEMETRY_SESSION_ID_ENV = "UIPATH_SESSION_ID";
|
|
557
590
|
var TELEMETRY_SESSION_ID_PROPERTY = "session_id";
|
|
558
591
|
var telemetrySessionIdSlot = singleton("TelemetrySessionId");
|
|
559
|
-
|
|
592
|
+
var telemetryOperationIdSlot = singleton("TelemetryOperationId");
|
|
593
|
+
function getProcessEnv2() {
|
|
560
594
|
return globalThis.process?.env;
|
|
561
595
|
}
|
|
562
596
|
function normalizeSessionId(value) {
|
|
@@ -567,7 +601,7 @@ function normalizeSessionId(value) {
|
|
|
567
601
|
return trimmed || undefined;
|
|
568
602
|
}
|
|
569
603
|
function getConfiguredTelemetrySessionId() {
|
|
570
|
-
return normalizeSessionId(
|
|
604
|
+
return normalizeSessionId(getProcessEnv2()?.[TELEMETRY_SESSION_ID_ENV]);
|
|
571
605
|
}
|
|
572
606
|
function getTelemetrySessionId() {
|
|
573
607
|
const envSessionId = getConfiguredTelemetrySessionId();
|
|
@@ -585,6 +619,16 @@ function getTelemetrySessionId() {
|
|
|
585
619
|
function resolveTelemetrySessionId(existingSessionId) {
|
|
586
620
|
return getConfiguredTelemetrySessionId() ?? normalizeSessionId(existingSessionId);
|
|
587
621
|
}
|
|
622
|
+
function getTelemetryOperationId() {
|
|
623
|
+
const existing = telemetryOperationIdSlot.get();
|
|
624
|
+
if (existing) {
|
|
625
|
+
return existing;
|
|
626
|
+
}
|
|
627
|
+
const inboundTraceId = getInboundTraceContext()?.traceId;
|
|
628
|
+
const generated = inboundTraceId ?? crypto.randomUUID().replaceAll("-", "");
|
|
629
|
+
telemetryOperationIdSlot.set(generated);
|
|
630
|
+
return generated;
|
|
631
|
+
}
|
|
588
632
|
// src/telemetry/global-telemetry-properties.ts
|
|
589
633
|
var telemetryPropsSlot = singleton("TelemetryDefaultProps");
|
|
590
634
|
function getGlobalTelemetryProperties() {
|
|
@@ -592,6 +636,10 @@ function getGlobalTelemetryProperties() {
|
|
|
592
636
|
}
|
|
593
637
|
|
|
594
638
|
// src/telemetry/telemetry-service.ts
|
|
639
|
+
var TELEMETRY_OPERATION_ID_PROPERTY = "uip.trace.operation_id";
|
|
640
|
+
var TELEMETRY_PARENT_ID_PROPERTY = "uip.trace.parent_id";
|
|
641
|
+
var TELEMETRY_SPAN_ID_PROPERTY = "uip.trace.span_id";
|
|
642
|
+
|
|
595
643
|
class TelemetryService {
|
|
596
644
|
telemetryProvider;
|
|
597
645
|
contextStorage;
|
|
@@ -618,11 +666,15 @@ class TelemetryService {
|
|
|
618
666
|
trackException(error, properties) {
|
|
619
667
|
const context = this.getCurrentContext();
|
|
620
668
|
const enrichedProperties = this.enrichPropertiesWithContext(properties, context);
|
|
621
|
-
this.telemetryProvider.trackException(error, enrichedProperties);
|
|
669
|
+
this.telemetryProvider.trackException(redactError(error), enrichedProperties);
|
|
622
670
|
}
|
|
623
671
|
async trackRequest(name, fn, properties) {
|
|
672
|
+
const parentContext = this.getCurrentContext();
|
|
673
|
+
const operationId = parentContext?.operationId ?? this.operationId ?? getTelemetryOperationId();
|
|
674
|
+
const parentId = parentContext ? parentContext.id : this.inboundParentIdFor(operationId);
|
|
624
675
|
const context = {
|
|
625
|
-
operationId
|
|
676
|
+
operationId,
|
|
677
|
+
...parentId !== undefined ? { parentId } : {},
|
|
626
678
|
id: this.generateId()
|
|
627
679
|
};
|
|
628
680
|
const startTime = performance.now();
|
|
@@ -640,6 +692,45 @@ class TelemetryService {
|
|
|
640
692
|
throw error;
|
|
641
693
|
}
|
|
642
694
|
}
|
|
695
|
+
trackRequestResult(name, durationMs, success, properties, context) {
|
|
696
|
+
const requestContext = context ?? {
|
|
697
|
+
operationId: this.operationId ?? getTelemetryOperationId(),
|
|
698
|
+
id: this.generateId()
|
|
699
|
+
};
|
|
700
|
+
const enrichedProperties = this.enrichPropertiesWithContext(properties, requestContext);
|
|
701
|
+
this.telemetryProvider.trackRequest(name, durationMs, success, enrichedProperties);
|
|
702
|
+
}
|
|
703
|
+
createRequestContext() {
|
|
704
|
+
const operationId = this.operationId ?? getTelemetryOperationId();
|
|
705
|
+
const parentId = this.inboundParentIdFor(operationId);
|
|
706
|
+
return {
|
|
707
|
+
operationId,
|
|
708
|
+
...parentId !== undefined ? { parentId } : {},
|
|
709
|
+
id: this.generateId()
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
inboundParentIdFor(operationId) {
|
|
713
|
+
const inbound = getInboundTraceContext();
|
|
714
|
+
return inbound && inbound.traceId === operationId ? inbound.parentSpanId : undefined;
|
|
715
|
+
}
|
|
716
|
+
runWithContext(context, fn) {
|
|
717
|
+
return this.contextStorage.run(context, fn);
|
|
718
|
+
}
|
|
719
|
+
createDependencyContext() {
|
|
720
|
+
const parentContext = this.getCurrentContext();
|
|
721
|
+
if (!parentContext) {
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
return {
|
|
725
|
+
operationId: parentContext.operationId,
|
|
726
|
+
parentId: parentContext.id,
|
|
727
|
+
id: this.generateId()
|
|
728
|
+
};
|
|
729
|
+
}
|
|
730
|
+
trackDependencyResult(name, type, durationMs, success, properties, context, resultCode) {
|
|
731
|
+
const enrichedProperties = this.enrichPropertiesWithContext(properties, context);
|
|
732
|
+
this.telemetryProvider.trackDependency(redactValue(name), type, durationMs, success, enrichedProperties, resultCode);
|
|
733
|
+
}
|
|
643
734
|
async trackDependencyOperation(name, type, fn, properties) {
|
|
644
735
|
const parentContext = this.getCurrentContext();
|
|
645
736
|
if (!parentContext) {
|
|
@@ -676,8 +767,12 @@ class TelemetryService {
|
|
|
676
767
|
...getExecutionContextTelemetryProperties(),
|
|
677
768
|
...globalProperties,
|
|
678
769
|
...this.defaultProperties,
|
|
679
|
-
...properties,
|
|
680
|
-
...context
|
|
770
|
+
...redactProperties(properties ?? {}),
|
|
771
|
+
...context ? {
|
|
772
|
+
[TELEMETRY_OPERATION_ID_PROPERTY]: context.operationId,
|
|
773
|
+
...context.parentId !== undefined ? { [TELEMETRY_PARENT_ID_PROPERTY]: context.parentId } : {},
|
|
774
|
+
[TELEMETRY_SPAN_ID_PROPERTY]: context.id
|
|
775
|
+
} : {}
|
|
681
776
|
};
|
|
682
777
|
if (sessionId === undefined) {
|
|
683
778
|
delete enriched[TELEMETRY_SESSION_ID_PROPERTY];
|
|
@@ -687,14 +782,25 @@ class TelemetryService {
|
|
|
687
782
|
return enriched;
|
|
688
783
|
}
|
|
689
784
|
generateId() {
|
|
690
|
-
|
|
785
|
+
const bytes = new Uint8Array(8);
|
|
786
|
+
let hex = "";
|
|
787
|
+
do {
|
|
788
|
+
crypto.getRandomValues(bytes);
|
|
789
|
+
hex = "";
|
|
790
|
+
for (const byte of bytes) {
|
|
791
|
+
hex += byte.toString(16).padStart(2, "0");
|
|
792
|
+
}
|
|
793
|
+
} while (/^0+$/.test(hex));
|
|
794
|
+
return hex;
|
|
691
795
|
}
|
|
692
796
|
}
|
|
693
797
|
export {
|
|
694
798
|
setExecutionContextAuthSignal,
|
|
695
799
|
resolveTelemetrySessionId,
|
|
800
|
+
redactValue,
|
|
696
801
|
redactProperty,
|
|
697
802
|
redactProperties,
|
|
803
|
+
redactError,
|
|
698
804
|
normalizeSkillName,
|
|
699
805
|
normalizeEnvironment,
|
|
700
806
|
normalizeBaseUrl,
|
|
@@ -706,11 +812,14 @@ export {
|
|
|
706
812
|
buildEnvironmentProperties,
|
|
707
813
|
buildCommandTelemetryAttribution,
|
|
708
814
|
TelemetryService,
|
|
815
|
+
TELEMETRY_SPAN_ID_PROPERTY,
|
|
709
816
|
TELEMETRY_SESSION_ID_PROPERTY,
|
|
710
817
|
TELEMETRY_SESSION_ID_ENV,
|
|
818
|
+
TELEMETRY_PARENT_ID_PROPERTY,
|
|
819
|
+
TELEMETRY_OPERATION_ID_PROPERTY,
|
|
711
820
|
EXECUTION_CONTEXT_VALUES,
|
|
712
821
|
ConsoleTelemetryProvider,
|
|
713
822
|
BrowserContextStorage
|
|
714
823
|
};
|
|
715
824
|
|
|
716
|
-
//# debugId=
|
|
825
|
+
//# debugId=B104F80E6DBFBC9064756E2164756E21
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ITelemetryProvider } from "./telemetry-provider.js";
|
|
2
|
-
import type
|
|
2
|
+
import { type TelemetryProperties } from "./telemetry-service.js";
|
|
3
3
|
export { getGlobalTelemetryProperties, setGlobalTelemetryProperties, } from "./global-telemetry-properties.js";
|
|
4
4
|
/**
|
|
5
5
|
* Node.js Application Insights telemetry provider.
|
|
@@ -31,10 +31,53 @@ export declare class NodeAppInsightsTelemetryProvider implements ITelemetryProvi
|
|
|
31
31
|
* Per-call properties take precedence over global defaults.
|
|
32
32
|
*/
|
|
33
33
|
private mergeProperties;
|
|
34
|
+
/**
|
|
35
|
+
* Read the trace context off the internal `uip.trace.*` routing keys and
|
|
36
|
+
* strip them, so nothing correlation-related ever ships as a custom
|
|
37
|
+
* dimension. `merged` is a fresh per-call object, so mutating it in place is
|
|
38
|
+
* safe; the same reference is what the client call emits as `properties`.
|
|
39
|
+
*
|
|
40
|
+
* `operationId` falls back to the per-invocation id when no context is set
|
|
41
|
+
* (events outside a `trackRequest` scope), so every item in one run still
|
|
42
|
+
* groups under the same `operation_Id`. `parentId`/`spanId` are only present
|
|
43
|
+
* inside a scope.
|
|
44
|
+
*/
|
|
45
|
+
private consumeCorrelation;
|
|
46
|
+
/**
|
|
47
|
+
* Promote a `session_id` custom dimension onto the native `ai.session.id`
|
|
48
|
+
* context tag and strip it from the dimension bag. Session belongs in the
|
|
49
|
+
* native session tag — the App Insights Sessions blade reads it there — so
|
|
50
|
+
* shipping it as a custom dimension too is redundant and drifts (the raw
|
|
51
|
+
* tag vs. a redactor-hashed dimension). Only the AppInsights provider does
|
|
52
|
+
* this; fallback providers (logger/console) keep `session_id` as a
|
|
53
|
+
* dimension, since they have no native session field.
|
|
54
|
+
*
|
|
55
|
+
* `merged` is a fresh per-call object, so deleting in place is safe.
|
|
56
|
+
*/
|
|
57
|
+
private promoteSessionTag;
|
|
58
|
+
/**
|
|
59
|
+
* Native correlation tags for a LEAF item (event/exception). It has no item
|
|
60
|
+
* id of its own, so it nests under the current operation: `operation_Id` is
|
|
61
|
+
* the trace id, and `operation_ParentId` is the enclosing request/
|
|
62
|
+
* dependency's id (the context's `spanId`), present only inside a scope.
|
|
63
|
+
*
|
|
64
|
+
* Cross-service join: `makeTrackedFetch` stamps a W3C `traceparent`
|
|
65
|
+
* (`00-<operation_Id>-<span>-01`) on every outbound call made inside a
|
|
66
|
+
* request scope, so the API side can line its telemetry up with this trace.
|
|
67
|
+
* These native tags are the CLI-side half of that join.
|
|
68
|
+
*/
|
|
69
|
+
private leafTagOverrides;
|
|
70
|
+
/**
|
|
71
|
+
* Native correlation for an OPERATION item (request/dependency). It carries
|
|
72
|
+
* its own item `id` (the context's `spanId`) so child items can point their
|
|
73
|
+
* `operation_ParentId` at it, and its own `operation_ParentId` is the
|
|
74
|
+
* context's `parentId` (absent for a top-level request → a trace root).
|
|
75
|
+
*/
|
|
76
|
+
private operationCorrelation;
|
|
34
77
|
trackEvent(eventName: string, properties?: TelemetryProperties): Promise<void>;
|
|
35
78
|
trackException(error: Error, properties?: TelemetryProperties): Promise<void>;
|
|
36
79
|
trackRequest(name: string, duration: number, success: boolean, properties?: TelemetryProperties): Promise<void>;
|
|
37
|
-
trackDependency(name: string, type: string, duration: number, success: boolean, properties?: TelemetryProperties): Promise<void>;
|
|
80
|
+
trackDependency(name: string, type: string, duration: number, success: boolean, properties?: TelemetryProperties, resultCode?: string): Promise<void>;
|
|
38
81
|
flush(): Promise<void>;
|
|
39
82
|
/**
|
|
40
83
|
* Dispose the Application Insights SDK so its internal channels,
|
package/dist/telemetry/node.d.ts
CHANGED
|
@@ -7,4 +7,6 @@ export { NodeContextStorage } from "./node-context-storage.js";
|
|
|
7
7
|
export { getConfiguredTelemetrySessionId, getTelemetrySessionId, resolveTelemetrySessionId, TELEMETRY_SESSION_ID_ENV, TELEMETRY_SESSION_ID_PROPERTY, } from "./session-id.js";
|
|
8
8
|
export type { ITelemetryProvider } from "./telemetry-provider.js";
|
|
9
9
|
export type { ITelemetryService, TelemetryContext, TelemetryProperties, } from "./telemetry-service.js";
|
|
10
|
-
export { TelemetryService } from "./telemetry-service.js";
|
|
10
|
+
export { TELEMETRY_OPERATION_ID_PROPERTY, TELEMETRY_PARENT_ID_PROPERTY, TELEMETRY_SPAN_ID_PROPERTY, TelemetryService, } from "./telemetry-service.js";
|
|
11
|
+
export { getInboundTraceContext, type InboundTraceContext, parseInboundTraceparent, TELEMETRY_TRACEPARENT_ENV, } from "./trace-context.js";
|
|
12
|
+
export { makeTrackedFetch } from "./tracked-fetch.js";
|
|
@@ -15,6 +15,22 @@
|
|
|
15
15
|
* The goal is defense in depth: even if a new sensitive option slips through
|
|
16
16
|
* without being added to the denylist, value detectors catch common shapes.
|
|
17
17
|
*/
|
|
18
|
+
/**
|
|
19
|
+
* Run the value detectors over a free-form string (no name-based check). Use for
|
|
20
|
+
* strings that aren't property values but can still carry PII — a telemetry
|
|
21
|
+
* event/dependency name (`GET /odata/Users/alice@corp.com`) or an exception
|
|
22
|
+
* message. Emails/UUIDs are hashed, URLs reduced to origin, tokens/JWTs and
|
|
23
|
+
* user-home paths redacted, over-long strings truncated.
|
|
24
|
+
*/
|
|
25
|
+
export declare function redactValue(value: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Return a sanitized copy of an Error whose `message` and `stack` have been run
|
|
28
|
+
* through the value detectors, so telemetry never ships a raw exception string
|
|
29
|
+
* (they routinely embed the offending token, URL, path, or id). The original
|
|
30
|
+
* frames are preserved — only their sensitive substrings are rewritten — and
|
|
31
|
+
* the `name` is kept so App Insights still groups by exception type.
|
|
32
|
+
*/
|
|
33
|
+
export declare function redactError(error: Error): Error;
|
|
18
34
|
type TelemetryValue = string | number | boolean;
|
|
19
35
|
/**
|
|
20
36
|
* Redact a single telemetry property.
|
|
@@ -10,3 +10,22 @@ export declare function getConfiguredTelemetrySessionId(): string | undefined;
|
|
|
10
10
|
*/
|
|
11
11
|
export declare function getTelemetrySessionId(): string;
|
|
12
12
|
export declare function resolveTelemetrySessionId(existingSessionId: unknown): string | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Resolve the per-invocation operation id used for App Insights' native
|
|
15
|
+
* `operation_Id` tag.
|
|
16
|
+
*
|
|
17
|
+
* One CLI process is one invocation, so this is generated once per process and
|
|
18
|
+
* shared across bundled copies of @uipath/common (the singleton slot lives on
|
|
19
|
+
* globalThis). It does not take a grouping override the way the session id does:
|
|
20
|
+
* a coding-agent host sets UIPATH_SESSION_ID to group several CLI runs, but each
|
|
21
|
+
* run still needs its own operation id so consumers can tell the runs apart. The
|
|
22
|
+
* one env input it honors is an inbound TRACEPARENT — when the caller passes
|
|
23
|
+
* trace context, this run adopts that trace id so it lines up with the caller's
|
|
24
|
+
* transaction and with the API telemetry it triggers.
|
|
25
|
+
*
|
|
26
|
+
* The value is a 32-hex string (a UUID with dashes stripped). That is the shape
|
|
27
|
+
* App Insights expects for `operation_Id`, and — unlike the UUID-shaped session
|
|
28
|
+
* id — it is left untouched by the PII redactor, so the emitted value matches
|
|
29
|
+
* raw on every path.
|
|
30
|
+
*/
|
|
31
|
+
export declare function getTelemetryOperationId(): string;
|
|
@@ -18,8 +18,14 @@ export interface ITelemetryProvider {
|
|
|
18
18
|
trackRequest(name: string, duration: number, success: boolean, properties?: TelemetryProperties): Promise<void>;
|
|
19
19
|
/**
|
|
20
20
|
* Track a completed dependency operation with measured duration.
|
|
21
|
+
*
|
|
22
|
+
* `resultCode` is the backend-native status of the call (e.g. the HTTP
|
|
23
|
+
* status code for an outbound request). When omitted the provider derives a
|
|
24
|
+
* coarse code from `success`. Passing the real code keeps the App Insights
|
|
25
|
+
* `dependencies.resultCode` column accurate instead of collapsing every
|
|
26
|
+
* outcome to 200/500.
|
|
21
27
|
*/
|
|
22
|
-
trackDependency(name: string, type: string, duration: number, success: boolean, properties?: TelemetryProperties): Promise<void>;
|
|
28
|
+
trackDependency(name: string, type: string, duration: number, success: boolean, properties?: TelemetryProperties, resultCode?: string): Promise<void>;
|
|
23
29
|
/**
|
|
24
30
|
* Get the current session ID, if available.
|
|
25
31
|
*/
|
|
@@ -6,6 +6,39 @@ import type { ITelemetryProvider } from "./telemetry-provider.js";
|
|
|
6
6
|
export interface TelemetryProperties {
|
|
7
7
|
[key: string]: string | number | boolean | undefined;
|
|
8
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* Internal property key that carries an active trace context's operation id
|
|
11
|
+
* (mirrors {@link TelemetryContext.operationId}). The AppInsights provider reads
|
|
12
|
+
* it to set the native `operation_Id` tag, falling back to the per-invocation id
|
|
13
|
+
* when no context is present — i.e. for events emitted outside a `trackRequest`
|
|
14
|
+
* scope. The provider consumes and strips it, so it never ships as a dimension.
|
|
15
|
+
*
|
|
16
|
+
* The key lives in the `uip.trace.*` namespace (not the plain `operationId`)
|
|
17
|
+
* so it can never be shadowed by a command argument of the same name.
|
|
18
|
+
* `extractCommandParams` in `trackedAction.ts` now namespaces args under
|
|
19
|
+
* `uip.cmd.arg.*`, but the dedicated trace namespace keeps this control key
|
|
20
|
+
* unambiguous and consistent with the rest of the owner-namespaced schema. The
|
|
21
|
+
* provider consumes and strips it, so the dotted key never ships as a dimension.
|
|
22
|
+
*/
|
|
23
|
+
export declare const TELEMETRY_OPERATION_ID_PROPERTY = "uip.trace.operation_id";
|
|
24
|
+
/**
|
|
25
|
+
* Internal routing key carrying an active trace context's parent id (mirrors
|
|
26
|
+
* {@link TelemetryContext.parentId}). The AppInsights provider reads it to set
|
|
27
|
+
* the native `ai.operation.parentId` tag on request/dependency items, so the
|
|
28
|
+
* parent/child tree links in the App Insights UI. Present only inside a nested
|
|
29
|
+
* scope (a top-level `trackRequest` has no parent). Consumed and stripped by
|
|
30
|
+
* the provider — never ships as a dimension.
|
|
31
|
+
*/
|
|
32
|
+
export declare const TELEMETRY_PARENT_ID_PROPERTY = "uip.trace.parent_id";
|
|
33
|
+
/**
|
|
34
|
+
* Internal routing key carrying an active trace context's own id (mirrors
|
|
35
|
+
* {@link TelemetryContext.id}). The AppInsights provider uses it as the request/
|
|
36
|
+
* dependency envelope's native item `id`, so child items whose parent id equals
|
|
37
|
+
* it link up; for leaf items (events/exceptions) the provider maps it onto
|
|
38
|
+
* `ai.operation.parentId` so the leaf nests under the current operation.
|
|
39
|
+
* Consumed and stripped by the provider — never ships as a dimension.
|
|
40
|
+
*/
|
|
41
|
+
export declare const TELEMETRY_SPAN_ID_PROPERTY = "uip.trace.span_id";
|
|
9
42
|
/**
|
|
10
43
|
* Telemetry correlation context for tracking parent-child relationships
|
|
11
44
|
*/
|
|
@@ -97,6 +130,55 @@ export interface ITelemetryService {
|
|
|
97
130
|
* All nested trackDependencyOperation calls will be automatically correlated to this request.
|
|
98
131
|
*/
|
|
99
132
|
trackRequest<T>(name: string, fn: () => Promise<T>, properties?: TelemetryProperties): Promise<T>;
|
|
133
|
+
/**
|
|
134
|
+
* Track a request from already-measured data — no wrapping function.
|
|
135
|
+
*
|
|
136
|
+
* Use when the caller measured duration and success itself and just needs
|
|
137
|
+
* the request emitted (e.g. `trackedAction`, which times the whole command
|
|
138
|
+
* imperatively). The request becomes a top-level operation: it groups under
|
|
139
|
+
* the per-invocation `operation_Id` and carries its own span id, so it lands
|
|
140
|
+
* in the native App Insights `requests` table with `duration`/`success` as
|
|
141
|
+
* first-class columns instead of stringified custom dimensions.
|
|
142
|
+
*
|
|
143
|
+
* @param name The request name (e.g. the command path `uip.solution.pack`)
|
|
144
|
+
* @param durationMs Measured wall-clock duration in milliseconds
|
|
145
|
+
* @param success Whether the operation succeeded
|
|
146
|
+
* @param properties Base properties to include in telemetry
|
|
147
|
+
*/
|
|
148
|
+
trackRequestResult(name: string, durationMs: number, success: boolean, properties?: TelemetryProperties, context?: TelemetryContext): void;
|
|
149
|
+
/**
|
|
150
|
+
* Build a root request context (a trace root: a per-invocation operation
|
|
151
|
+
* id, its own span id, no parent) without storing or emitting anything.
|
|
152
|
+
*
|
|
153
|
+
* For imperative callers that time the work themselves (e.g. `trackedAction`)
|
|
154
|
+
* but still need child dependencies to nest: create the context once, run the
|
|
155
|
+
* work inside {@link runWithContext} so dependencies find it, then pass the
|
|
156
|
+
* same context to {@link trackRequestResult} so the request envelope reuses
|
|
157
|
+
* this span id and the children's parent id points at it.
|
|
158
|
+
*/
|
|
159
|
+
createRequestContext(): TelemetryContext;
|
|
160
|
+
/**
|
|
161
|
+
* Run `fn` with `context` active in the async context storage, so any
|
|
162
|
+
* telemetry emitted inside (dependencies, events, exceptions) correlates to
|
|
163
|
+
* it. Returns the function's result.
|
|
164
|
+
*/
|
|
165
|
+
runWithContext<T>(context: TelemetryContext, fn: () => Promise<T>): Promise<T>;
|
|
166
|
+
/**
|
|
167
|
+
* Build a dependency context (child of the currently active context) without
|
|
168
|
+
* emitting anything, or `undefined` when there is no active request scope.
|
|
169
|
+
*
|
|
170
|
+
* For imperative callers (e.g. the outbound-fetch wrapper) that need the
|
|
171
|
+
* span id up front — to stamp a `traceparent` header before the call — and
|
|
172
|
+
* report success/duration afterwards via {@link trackDependencyResult}.
|
|
173
|
+
*/
|
|
174
|
+
createDependencyContext(): TelemetryContext | undefined;
|
|
175
|
+
/**
|
|
176
|
+
* Track a dependency from already-measured data using an explicit context —
|
|
177
|
+
* no wrapping function. Use when success can't be inferred from "the callback
|
|
178
|
+
* didn't throw": an outbound HTTP call returning 4xx/5xx resolves normally,
|
|
179
|
+
* so the caller passes `success = response.ok`.
|
|
180
|
+
*/
|
|
181
|
+
trackDependencyResult(name: string, type: string, durationMs: number, success: boolean, properties: TelemetryProperties | undefined, context: TelemetryContext, resultCode?: string): void;
|
|
100
182
|
/**
|
|
101
183
|
* Track a dependency operation (child operation in the dependency tree).
|
|
102
184
|
* Use this for operations that are part of a larger request.
|
|
@@ -140,6 +222,21 @@ export declare class TelemetryService implements ITelemetryService {
|
|
|
140
222
|
trackEvent(name: string, properties?: TelemetryProperties): void;
|
|
141
223
|
trackException(error: Error, properties?: TelemetryProperties): void;
|
|
142
224
|
trackRequest<T>(name: string, fn: () => Promise<T>, properties?: TelemetryProperties): Promise<T>;
|
|
225
|
+
trackRequestResult(name: string, durationMs: number, success: boolean, properties?: TelemetryProperties, context?: TelemetryContext): void;
|
|
226
|
+
createRequestContext(): TelemetryContext;
|
|
227
|
+
/**
|
|
228
|
+
* The caller's span id to parent a root request under, or `undefined`.
|
|
229
|
+
*
|
|
230
|
+
* Only returns a parent when this run actually adopted the inbound trace id
|
|
231
|
+
* as its `operationId` (the run's `getTelemetryOperationId()` picked up the
|
|
232
|
+
* `TRACEPARENT` trace id). If a caller pinned a different `operationId` via
|
|
233
|
+
* `setOperationId`, the inbound parent would reference a span in a different
|
|
234
|
+
* trace, so it's dropped — correlation must stay internally consistent.
|
|
235
|
+
*/
|
|
236
|
+
private inboundParentIdFor;
|
|
237
|
+
runWithContext<T>(context: TelemetryContext, fn: () => Promise<T>): Promise<T>;
|
|
238
|
+
createDependencyContext(): TelemetryContext | undefined;
|
|
239
|
+
trackDependencyResult(name: string, type: string, durationMs: number, success: boolean, properties: TelemetryProperties | undefined, context: TelemetryContext, resultCode?: string): void;
|
|
143
240
|
trackDependencyOperation<T>(name: string, type: string, fn: () => Promise<T>, properties?: TelemetryProperties): Promise<T>;
|
|
144
241
|
/**
|
|
145
242
|
* Gets the current telemetry context from the context storage.
|
|
@@ -160,7 +257,14 @@ export declare class TelemetryService implements ITelemetryService {
|
|
|
160
257
|
*/
|
|
161
258
|
private enrichPropertiesWithContext;
|
|
162
259
|
/**
|
|
163
|
-
* Generate a
|
|
260
|
+
* Generate a span id for telemetry correlation.
|
|
261
|
+
*
|
|
262
|
+
* 16 hex chars (8 random bytes) — the W3C trace-context `span-id` width.
|
|
263
|
+
* The trace id (`operationId`) stays 32 hex (a UUID with dashes stripped,
|
|
264
|
+
* the W3C `trace-id` width). Keeping the two at their standard widths means
|
|
265
|
+
* the ids can be emitted verbatim as a `traceparent`
|
|
266
|
+
* (`00-<32hex traceId>-<16hex spanId>-01`) once the CLI propagates trace
|
|
267
|
+
* context to the APIs, without a downstream parser rejecting a mis-sized id.
|
|
164
268
|
*/
|
|
165
269
|
private generateId;
|
|
166
270
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inbound W3C Trace Context ingestion.
|
|
3
|
+
*
|
|
4
|
+
* The CLI normally starts its own trace: one process = one `operation_Id`, and
|
|
5
|
+
* the command's request is a trace root with no parent. But when the CLI is run
|
|
6
|
+
* as one step of a larger distributed operation — a robot, agent, or
|
|
7
|
+
* orchestrator shelling out to `uip ...` — that caller wants the CLI's whole
|
|
8
|
+
* telemetry subtree nested under its own span in the App Insights end-to-end
|
|
9
|
+
* transaction view.
|
|
10
|
+
*
|
|
11
|
+
* A process has no inbound HTTP headers, so the caller passes the standard W3C
|
|
12
|
+
* `traceparent` value in the `TRACEPARENT` environment variable (the same
|
|
13
|
+
* convention OpenTelemetry CLI tools use). When present and valid, this run
|
|
14
|
+
* adopts the caller's trace id as its `operation_Id` and points the command
|
|
15
|
+
* request's `operation_ParentId` at the caller's span id. The outbound-fetch
|
|
16
|
+
* wrapper then inherits the adopted trace id, so the full chain
|
|
17
|
+
* (caller → CLI → API) reads as one transaction.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Environment variable carrying the inbound W3C `traceparent`
|
|
21
|
+
* (`00-<trace-id>-<parent-id>-<flags>`). Set by a caller that wants this CLI
|
|
22
|
+
* run to join its distributed trace.
|
|
23
|
+
*/
|
|
24
|
+
export declare const TELEMETRY_TRACEPARENT_ENV = "TRACEPARENT";
|
|
25
|
+
/**
|
|
26
|
+
* The parts of an inbound `traceparent` the CLI adopts: the trace id (becomes
|
|
27
|
+
* this run's `operation_Id`) and the caller's span id (becomes the command
|
|
28
|
+
* request's parent).
|
|
29
|
+
*/
|
|
30
|
+
export interface InboundTraceContext {
|
|
31
|
+
/** 32-hex W3C trace-id. */
|
|
32
|
+
traceId: string;
|
|
33
|
+
/** 16-hex W3C parent span-id — the caller's span this run nests under. */
|
|
34
|
+
parentSpanId: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Parse a `traceparent` string into the trace/parent ids the CLI adopts, or
|
|
38
|
+
* `undefined` when the value is absent or malformed.
|
|
39
|
+
*
|
|
40
|
+
* Rejects: the wrong version, wrong id widths, and the W3C-forbidden all-zero
|
|
41
|
+
* trace-id / parent-id (which signal "no valid id"). A malformed value falls
|
|
42
|
+
* back to the default root-trace behaviour rather than corrupting correlation.
|
|
43
|
+
*/
|
|
44
|
+
export declare function parseInboundTraceparent(value: string | undefined): InboundTraceContext | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Read and parse the inbound trace context from the `TRACEPARENT` environment
|
|
47
|
+
* variable, or `undefined` when unset/invalid.
|
|
48
|
+
*/
|
|
49
|
+
export declare function getInboundTraceContext(): InboundTraceContext | undefined;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A `fetch`-shaped function. Generic so the wrapper types cleanly against both
|
|
3
|
+
* the global `fetch` (CLI host) and `node-fetch` (codedapp-tool's uploads),
|
|
4
|
+
* each keeping its own input/init/response types.
|
|
5
|
+
*/
|
|
6
|
+
type FetchLike = (input: any, init?: any) => Promise<{
|
|
7
|
+
ok: boolean;
|
|
8
|
+
status: number;
|
|
9
|
+
}>;
|
|
10
|
+
/**
|
|
11
|
+
* Wraps a `fetch` implementation so every outbound call is reported as an App
|
|
12
|
+
* Insights dependency, nested under the command's request.
|
|
13
|
+
*
|
|
14
|
+
* This is the single enforcement point for "every outbound network call is a
|
|
15
|
+
* dependency": installed over `globalThis.fetch` at CLI startup, it covers all
|
|
16
|
+
* SDKs and auth without touching their call sites, because they all funnel
|
|
17
|
+
* through the global `fetch`. codedapp-tool wraps its own `node-fetch` the same
|
|
18
|
+
* way (see its lint allowlist entry).
|
|
19
|
+
*
|
|
20
|
+
* Behaviour:
|
|
21
|
+
* - Outside a request scope (no active telemetry context) the call passes
|
|
22
|
+
* through untracked and unmodified — nothing to correlate to.
|
|
23
|
+
* - Inside a scope it stamps a W3C `traceparent` header so the server side can
|
|
24
|
+
* join the same trace, times the call, and emits a dependency whose success
|
|
25
|
+
* reflects `response.ok` (an HTTP 4xx/5xx resolves normally but is not a
|
|
26
|
+
* successful dependency).
|
|
27
|
+
*
|
|
28
|
+
* Security: the dependency name is `METHOD /path` only — never the query string
|
|
29
|
+
* (which can carry tokens/PII) and never request headers. The host is recorded
|
|
30
|
+
* as a plain, non-sensitive dimension.
|
|
31
|
+
*/
|
|
32
|
+
export declare function makeTrackedFetch<F extends FetchLike>(realFetch: F): F;
|
|
33
|
+
export {};
|
package/dist/trackedAction.d.ts
CHANGED
|
@@ -5,6 +5,21 @@ export interface CommandContext {
|
|
|
5
5
|
/** AbortSignal wired to SIGINT/SIGTERM. Pass to `pollUntil({ signal })` for graceful cancellation. */
|
|
6
6
|
pollSignal?: AbortSignal;
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* Namespace prefix for a command's own invocation arguments in telemetry.
|
|
10
|
+
*
|
|
11
|
+
* Command args and options are user-supplied and carry arbitrary names, so they
|
|
12
|
+
* are the one part of the property bag whose keys we don't control. Emitting
|
|
13
|
+
* them bare at the root of the event lets an arg named like a reserved
|
|
14
|
+
* dimension (`operationId`, `duration`, `success`, …) shadow that dimension —
|
|
15
|
+
* e.g. `uip oms organizations operation get <operationId>` overwriting the
|
|
16
|
+
* correlation tag. Prefixing every extracted arg with a dedicated namespace
|
|
17
|
+
* (mirrors OpenTelemetry attribute-namespacing) walls them off: a user arg can
|
|
18
|
+
* only ever land under `uip.cmd.arg.*`, never at the root where system and
|
|
19
|
+
* control keys live. System dimensions stay bare — they're a closed, controlled
|
|
20
|
+
* set, like OTel's semantic-convention keys.
|
|
21
|
+
*/
|
|
22
|
+
export declare const TELEMETRY_COMMAND_ARG_PREFIX = "uip.cmd.arg.";
|
|
8
23
|
/**
|
|
9
24
|
* Default CommandContext for tool packages that sets process.exitCode
|
|
10
25
|
* instead of calling process.exit().
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uipath/common",
|
|
3
3
|
"license": "MIT",
|
|
4
|
-
"version": "1.198.0
|
|
4
|
+
"version": "1.198.0",
|
|
5
5
|
"description": "Common infrastructure needed by uip tools.",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -67,5 +67,5 @@
|
|
|
67
67
|
"mihaigirleanu",
|
|
68
68
|
"vlad-uipath"
|
|
69
69
|
],
|
|
70
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "1fadf03d7a8dd102742571dff569fdac11808afb"
|
|
71
71
|
}
|