@reactionary/core 0.10.34 → 0.10.35
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/index.js +1 -0
- package/metrics/protocol.js +84 -0
- package/package.json +1 -1
- package/src/index.d.ts +1 -0
- package/src/metrics/protocol.d.ts +20 -0
package/index.js
CHANGED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import {
|
|
2
|
+
metrics,
|
|
3
|
+
SpanStatusCode,
|
|
4
|
+
trace
|
|
5
|
+
} from "@opentelemetry/api";
|
|
6
|
+
const METER_NAME = "@reactionary";
|
|
7
|
+
const METER_VERSION = "0.0.1";
|
|
8
|
+
let globalProtocolMetrics = null;
|
|
9
|
+
function getReactionaryProtocolMeter() {
|
|
10
|
+
if (!globalProtocolMetrics) {
|
|
11
|
+
const meter = metrics.getMeter(METER_NAME, METER_VERSION);
|
|
12
|
+
globalProtocolMetrics = {
|
|
13
|
+
requests: meter.createCounter("reactionary_protocol_requests", {
|
|
14
|
+
description: "Counts the number of protocol invocations (UCP, ACP, MCP) served by Reactionary protocol servers"
|
|
15
|
+
}),
|
|
16
|
+
requestDuration: meter.createHistogram(
|
|
17
|
+
"reactionary_protocol_request_duration",
|
|
18
|
+
{
|
|
19
|
+
description: "Records the duration of protocol invocations (UCP, ACP, MCP) served by Reactionary protocol servers",
|
|
20
|
+
unit: "ms"
|
|
21
|
+
}
|
|
22
|
+
),
|
|
23
|
+
requestsInProgress: meter.createUpDownCounter(
|
|
24
|
+
"reactionary_protocol_requests_in_progress",
|
|
25
|
+
{
|
|
26
|
+
description: "Tracks the number of in-progress protocol invocations (UCP, ACP, MCP)"
|
|
27
|
+
}
|
|
28
|
+
)
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return globalProtocolMetrics;
|
|
32
|
+
}
|
|
33
|
+
async function traceProtocolInvocation(invocation, fn, getResultAttributes) {
|
|
34
|
+
const meter = getReactionaryProtocolMeter();
|
|
35
|
+
const tracer = trace.getTracer(METER_NAME, METER_VERSION);
|
|
36
|
+
const baseAttributes = {
|
|
37
|
+
"labels.protocol": invocation.protocol,
|
|
38
|
+
"labels.operation": invocation.operation,
|
|
39
|
+
...invocation.attributes
|
|
40
|
+
};
|
|
41
|
+
const startTime = performance.now();
|
|
42
|
+
meter.requestsInProgress.add(1, baseAttributes);
|
|
43
|
+
return tracer.startActiveSpan(
|
|
44
|
+
`${invocation.protocol.toUpperCase()} ${invocation.operation}`,
|
|
45
|
+
{ attributes: baseAttributes },
|
|
46
|
+
async (span) => {
|
|
47
|
+
let resultAttributes = { "labels.status": "success" };
|
|
48
|
+
try {
|
|
49
|
+
const result = await fn(span);
|
|
50
|
+
if (getResultAttributes) {
|
|
51
|
+
resultAttributes = { ...resultAttributes, ...getResultAttributes(result) };
|
|
52
|
+
}
|
|
53
|
+
if (resultAttributes["labels.status"] === "error") {
|
|
54
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
55
|
+
}
|
|
56
|
+
span.setAttributes(resultAttributes);
|
|
57
|
+
return result;
|
|
58
|
+
} catch (err) {
|
|
59
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
60
|
+
resultAttributes = { "labels.status": "exception" };
|
|
61
|
+
span.recordException(err instanceof Error ? err : { message });
|
|
62
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message });
|
|
63
|
+
throw err;
|
|
64
|
+
} finally {
|
|
65
|
+
const finalAttributes = { ...baseAttributes, ...resultAttributes };
|
|
66
|
+
meter.requestsInProgress.add(-1, baseAttributes);
|
|
67
|
+
meter.requests.add(1, finalAttributes);
|
|
68
|
+
meter.requestDuration.record(performance.now() - startTime, finalAttributes);
|
|
69
|
+
span.end();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
function getHttpProtocolResultAttributes(response) {
|
|
75
|
+
return {
|
|
76
|
+
"labels.status": response.status >= 500 ? "error" : "success",
|
|
77
|
+
"http.response.status_code": response.status
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export {
|
|
81
|
+
getHttpProtocolResultAttributes,
|
|
82
|
+
getReactionaryProtocolMeter,
|
|
83
|
+
traceProtocolInvocation
|
|
84
|
+
};
|
package/package.json
CHANGED
package/src/index.d.ts
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type Attributes, type Counter, type Histogram, type Span, type UpDownCounter } from '@opentelemetry/api';
|
|
2
|
+
export interface ReactionaryProtocolMetrics {
|
|
3
|
+
requests: Counter;
|
|
4
|
+
requestDuration: Histogram;
|
|
5
|
+
requestsInProgress: UpDownCounter;
|
|
6
|
+
}
|
|
7
|
+
export declare function getReactionaryProtocolMeter(): ReactionaryProtocolMetrics;
|
|
8
|
+
export interface ReactionaryProtocolInvocation {
|
|
9
|
+
protocol: 'ucp' | 'acp' | 'mcp';
|
|
10
|
+
operation: string;
|
|
11
|
+
attributes?: Attributes;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Wraps a single protocol invocation (an inbound UCP/ACP HTTP request or an
|
|
15
|
+
* MCP tool call) in an OpenTelemetry span and records request count,
|
|
16
|
+
* duration, and in-progress metrics. `getResultAttributes` may add result
|
|
17
|
+
* attributes such as the HTTP status code and override `labels.status`.
|
|
18
|
+
*/
|
|
19
|
+
export declare function traceProtocolInvocation<T>(invocation: ReactionaryProtocolInvocation, fn: (span: Span) => Promise<T>, getResultAttributes?: (result: T) => Attributes): Promise<T>;
|
|
20
|
+
export declare function getHttpProtocolResultAttributes(response: Response): Attributes;
|