@hazeljs/observability 0.7.8 → 0.8.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/README.md +9 -11
- package/dist/decorators/trace.decorator.d.ts +8 -0
- package/dist/decorators/trace.decorator.d.ts.map +1 -0
- package/dist/decorators/trace.decorator.js +57 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/opentelemetry.provider.d.ts +28 -0
- package/dist/opentelemetry.provider.d.ts.map +1 -0
- package/dist/opentelemetry.provider.js +73 -0
- package/dist/types.d.ts +37 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -93,14 +93,15 @@ class AIService {
|
|
|
93
93
|
The observability package follows the A2A (Agent-to-Agent) and OTel specifications to ensure your traces are compatible with the broader ecosystem.
|
|
94
94
|
|
|
95
95
|
<MermaidDiagram chart={`graph TD
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
96
|
+
A["@Trace() Decorator"] --> B["Observability Service"]
|
|
97
|
+
B --> C["OpenTelemetry Provider"]
|
|
98
|
+
C --> D["OTLP Exporter"]
|
|
99
|
+
D --> E["Observability Platform<br/>(Jaeger, Honeycomb, Datadog)"]
|
|
100
|
+
|
|
101
101
|
style A fill:#3b82f6,color:#fff
|
|
102
102
|
style B fill:#6366f1,color:#fff
|
|
103
103
|
style C fill:#10b981,color:#fff
|
|
104
|
+
|
|
104
105
|
`} />
|
|
105
106
|
|
|
106
107
|
## API Reference
|
|
@@ -109,11 +110,7 @@ The observability package follows the A2A (Agent-to-Agent) and OTel specificatio
|
|
|
109
110
|
|
|
110
111
|
```typescript
|
|
111
112
|
class OpenTelemetryProvider {
|
|
112
|
-
constructor(config: {
|
|
113
|
-
serviceName: string;
|
|
114
|
-
endpoint?: string;
|
|
115
|
-
headers?: Record<string, string>;
|
|
116
|
-
});
|
|
113
|
+
constructor(config: { serviceName: string; endpoint?: string; headers?: Record<string, string> });
|
|
117
114
|
initialize(): void;
|
|
118
115
|
shutdown(): Promise<void>;
|
|
119
116
|
}
|
|
@@ -126,6 +123,7 @@ class OpenTelemetryProvider {
|
|
|
126
123
|
```
|
|
127
124
|
|
|
128
125
|
**TraceOptions:**
|
|
126
|
+
|
|
129
127
|
- `attributes`: Static attributes to add to the span.
|
|
130
128
|
- `captureArgs`: Whether to capture method arguments (default: `false`).
|
|
131
129
|
- `captureResult`: Whether to capture method return value (default: `false`).
|
|
@@ -152,4 +150,4 @@ Apache 2.0 © [HazelJS](https://hazeljs.ai)
|
|
|
152
150
|
|
|
153
151
|
- [Documentation](https://hazeljs.ai/docs/packages/observability)
|
|
154
152
|
- [GitHub](https://github.com/hazel-js/hazeljs)
|
|
155
|
-
- [Discord](https://discord.
|
|
153
|
+
- [Discord](https://discord.gg/PxNBPzvQk7)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tracing Decorator (@Trace)
|
|
3
|
+
* Automatically wraps a class method inside an OpenTelemetry Span for detailed observability.
|
|
4
|
+
*
|
|
5
|
+
* @param spanName Custom name for the span. Defaults to the method name.
|
|
6
|
+
*/
|
|
7
|
+
export declare function Trace(spanName?: string): MethodDecorator;
|
|
8
|
+
//# sourceMappingURL=trace.decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace.decorator.d.ts","sourceRoot":"","sources":["../../src/decorators/trace.decorator.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,eAAe,CAoDxD"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Trace = Trace;
|
|
4
|
+
const api_1 = require("@opentelemetry/api");
|
|
5
|
+
/**
|
|
6
|
+
* Tracing Decorator (@Trace)
|
|
7
|
+
* Automatically wraps a class method inside an OpenTelemetry Span for detailed observability.
|
|
8
|
+
*
|
|
9
|
+
* @param spanName Custom name for the span. Defaults to the method name.
|
|
10
|
+
*/
|
|
11
|
+
function Trace(spanName) {
|
|
12
|
+
return (target, propertyKey, descriptor) => {
|
|
13
|
+
const originalMethod = descriptor.value;
|
|
14
|
+
if (typeof originalMethod !== 'function')
|
|
15
|
+
return descriptor;
|
|
16
|
+
const methodName = String(propertyKey);
|
|
17
|
+
const resolvedSpanName = spanName || methodName;
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
19
|
+
descriptor.value = function (...args) {
|
|
20
|
+
const tracer = api_1.trace.getTracer('hazeljs');
|
|
21
|
+
return tracer.startActiveSpan(resolvedSpanName, (span) => {
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
23
|
+
const handleError = (error) => {
|
|
24
|
+
span.recordException(error);
|
|
25
|
+
span.setStatus({
|
|
26
|
+
code: api_1.SpanStatusCode.ERROR,
|
|
27
|
+
message: error instanceof Error ? error.message : String(error),
|
|
28
|
+
});
|
|
29
|
+
span.end();
|
|
30
|
+
throw error;
|
|
31
|
+
};
|
|
32
|
+
try {
|
|
33
|
+
span.setAttribute('code.function', methodName);
|
|
34
|
+
// Execute original logic
|
|
35
|
+
const result = originalMethod.apply(this, args);
|
|
36
|
+
if (result instanceof Promise) {
|
|
37
|
+
return result
|
|
38
|
+
.then((res) => {
|
|
39
|
+
span.setStatus({ code: api_1.SpanStatusCode.OK });
|
|
40
|
+
span.end();
|
|
41
|
+
return res;
|
|
42
|
+
})
|
|
43
|
+
.catch(handleError);
|
|
44
|
+
}
|
|
45
|
+
span.setStatus({ code: api_1.SpanStatusCode.OK });
|
|
46
|
+
span.end();
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
return handleError(error);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
54
|
+
};
|
|
55
|
+
return descriptor;
|
|
56
|
+
};
|
|
57
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./types"), exports);
|
|
18
|
+
__exportStar(require("./opentelemetry.provider"), exports);
|
|
19
|
+
__exportStar(require("./decorators/trace.decorator"), exports);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Tracer } from '@opentelemetry/api';
|
|
2
|
+
import { ObservabilityProvider, ObservabilityConfig } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* OpenTelemetry implementation of the ObservabilityProvider
|
|
5
|
+
*/
|
|
6
|
+
export declare class OpenTelemetryProvider implements ObservabilityProvider {
|
|
7
|
+
private config;
|
|
8
|
+
private provider;
|
|
9
|
+
private exporter?;
|
|
10
|
+
constructor(config: ObservabilityConfig);
|
|
11
|
+
/**
|
|
12
|
+
* Start tracking observability metrics
|
|
13
|
+
*/
|
|
14
|
+
start(): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Stop operations gracefully, ensuring spans flush
|
|
17
|
+
*/
|
|
18
|
+
stop(): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Retrieves a named tracer
|
|
21
|
+
*/
|
|
22
|
+
getTracer(name: string): Tracer;
|
|
23
|
+
/**
|
|
24
|
+
* Tracking LLM cost allows the agent runtime to dynamically emit span metrics or print usage statistics
|
|
25
|
+
*/
|
|
26
|
+
trackCost(model: string, promptTokens: number, completionTokens: number): void;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=opentelemetry.provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opentelemetry.provider.d.ts","sourceRoot":"","sources":["../src/opentelemetry.provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAS,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAKnD,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAErE;;GAEG;AACH,qBAAa,qBAAsB,YAAW,qBAAqB;IACjE,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,QAAQ,CAAC,CAAoB;gBAEzB,MAAM,EAAE,mBAAmB;IAqBvC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAO5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAY3B;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI/B;;OAEG;IACH,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,IAAI;CAS/E"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OpenTelemetryProvider = void 0;
|
|
4
|
+
/* eslint-disable no-console */
|
|
5
|
+
const api_1 = require("@opentelemetry/api");
|
|
6
|
+
const sdk_trace_node_1 = require("@opentelemetry/sdk-trace-node");
|
|
7
|
+
const exporter_trace_otlp_http_1 = require("@opentelemetry/exporter-trace-otlp-http");
|
|
8
|
+
const resources_1 = require("@opentelemetry/resources");
|
|
9
|
+
const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
|
|
10
|
+
/**
|
|
11
|
+
* OpenTelemetry implementation of the ObservabilityProvider
|
|
12
|
+
*/
|
|
13
|
+
class OpenTelemetryProvider {
|
|
14
|
+
constructor(config) {
|
|
15
|
+
this.config = config;
|
|
16
|
+
const resource = (0, resources_1.resourceFromAttributes)({
|
|
17
|
+
[semantic_conventions_1.SemanticResourceAttributes.SERVICE_NAME]: config.serviceName,
|
|
18
|
+
});
|
|
19
|
+
const spanProcessors = [];
|
|
20
|
+
if (config.otlpEndpoint) {
|
|
21
|
+
this.exporter = new exporter_trace_otlp_http_1.OTLPTraceExporter({
|
|
22
|
+
url: config.otlpEndpoint,
|
|
23
|
+
});
|
|
24
|
+
spanProcessors.push(new sdk_trace_node_1.BatchSpanProcessor(this.exporter));
|
|
25
|
+
}
|
|
26
|
+
this.provider = new sdk_trace_node_1.NodeTracerProvider({
|
|
27
|
+
resource,
|
|
28
|
+
...(spanProcessors.length > 0 ? { spanProcessors } : {}),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Start tracking observability metrics
|
|
33
|
+
*/
|
|
34
|
+
async start() {
|
|
35
|
+
// Register provider globally so trace decorators can pick it up
|
|
36
|
+
this.provider.register();
|
|
37
|
+
console.log(`[Observability] Started tracing service ${this.config.serviceName}`);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Stop operations gracefully, ensuring spans flush
|
|
41
|
+
*/
|
|
42
|
+
async stop() {
|
|
43
|
+
try {
|
|
44
|
+
await this.provider.shutdown();
|
|
45
|
+
if (this.exporter) {
|
|
46
|
+
await this.exporter.shutdown();
|
|
47
|
+
}
|
|
48
|
+
console.log(`[Observability] Stopped tracing service ${this.config.serviceName}`);
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
console.error('[Observability] Failed to shutdown opentelemetry gracefully', e);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Retrieves a named tracer
|
|
56
|
+
*/
|
|
57
|
+
getTracer(name) {
|
|
58
|
+
return api_1.trace.getTracer(name);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Tracking LLM cost allows the agent runtime to dynamically emit span metrics or print usage statistics
|
|
62
|
+
*/
|
|
63
|
+
trackCost(model, promptTokens, completionTokens) {
|
|
64
|
+
const activeSpan = api_1.trace.getActiveSpan();
|
|
65
|
+
if (activeSpan) {
|
|
66
|
+
activeSpan.setAttribute('llm.model', model);
|
|
67
|
+
activeSpan.setAttribute('llm.usage.prompt_tokens', promptTokens);
|
|
68
|
+
activeSpan.setAttribute('llm.usage.completion_tokens', completionTokens);
|
|
69
|
+
activeSpan.setAttribute('llm.usage.total_tokens', promptTokens + completionTokens);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
exports.OpenTelemetryProvider = OpenTelemetryProvider;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Tracer } from '@opentelemetry/api';
|
|
2
|
+
/**
|
|
3
|
+
* Interface for tracking and reporting observability metrics
|
|
4
|
+
*/
|
|
5
|
+
export interface ObservabilityProvider {
|
|
6
|
+
/**
|
|
7
|
+
* Initializes the tracing provider setup (e.g., OpenTelemetry NodeSDK)
|
|
8
|
+
*/
|
|
9
|
+
start(): Promise<void>;
|
|
10
|
+
/**
|
|
11
|
+
* Stops and flushes the tracing provider setup
|
|
12
|
+
*/
|
|
13
|
+
stop(): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Retrieves the tracer
|
|
16
|
+
*/
|
|
17
|
+
getTracer(name: string): Tracer;
|
|
18
|
+
/**
|
|
19
|
+
* Tracks LLM cost metrics
|
|
20
|
+
* @param model Model name (e.g., 'gpt-4o')
|
|
21
|
+
* @param promptTokens Number of tokens in the prompt
|
|
22
|
+
* @param completionTokens Number of tokens in the completion
|
|
23
|
+
*/
|
|
24
|
+
trackCost(model: string, promptTokens: number, completionTokens: number): void;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Represents the configuration properties to setup tracing
|
|
28
|
+
*/
|
|
29
|
+
export interface ObservabilityConfig {
|
|
30
|
+
/** The service name to appear in tracing tools (e.g. 'agent-runtime') */
|
|
31
|
+
serviceName: string;
|
|
32
|
+
/** Otlp GRPC/HTTP exporter endpoint (e.g., Datadog, Jaeger, Zipkin) */
|
|
33
|
+
otlpEndpoint?: string;
|
|
34
|
+
/** Whether to log prompts directly to the spans (false by default for privacy) */
|
|
35
|
+
logPrompts?: boolean;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;OAEG;IACH,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtB;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAEhC;;;;;OAKG;IACH,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CAChF;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,yEAAyE;IACzE,WAAW,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kFAAkF;IAClF,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB"}
|
package/dist/types.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hazeljs/observability",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Unified observability, OpenTelemetry tracing, and LLM cost tracking for HazelJS agents and flows",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -48,5 +48,5 @@
|
|
|
48
48
|
"url": "https://github.com/hazeljs/hazel-js/issues"
|
|
49
49
|
},
|
|
50
50
|
"homepage": "https://hazeljs.ai",
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "e0ed98ca074dd4f7472816d3c32ef576900dcca6"
|
|
52
52
|
}
|