@agentuity/runtime 0.0.42 → 0.0.44
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/AGENTS.md +11 -9
- package/README.md +4 -4
- package/dist/_context.d.ts +12 -4
- package/dist/_context.d.ts.map +1 -1
- package/dist/_server.d.ts +7 -4
- package/dist/_server.d.ts.map +1 -1
- package/dist/_services.d.ts +13 -2
- package/dist/_services.d.ts.map +1 -1
- package/dist/_util.d.ts +1 -1
- package/dist/_util.d.ts.map +1 -1
- package/dist/_waituntil.d.ts +1 -3
- package/dist/_waituntil.d.ts.map +1 -1
- package/dist/agent.d.ts +41 -14
- package/dist/agent.d.ts.map +1 -1
- package/dist/app.d.ts +90 -8
- package/dist/app.d.ts.map +1 -1
- package/dist/eval.d.ts +79 -0
- package/dist/eval.d.ts.map +1 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/io/email.d.ts +77 -0
- package/dist/io/email.d.ts.map +1 -0
- package/dist/logger/console.d.ts +21 -1
- package/dist/logger/console.d.ts.map +1 -1
- package/dist/logger/index.d.ts +0 -1
- package/dist/logger/index.d.ts.map +1 -1
- package/dist/logger/user.d.ts +2 -2
- package/dist/logger/user.d.ts.map +1 -1
- package/dist/otel/config.d.ts +3 -1
- package/dist/otel/config.d.ts.map +1 -1
- package/dist/otel/console.d.ts +2 -1
- package/dist/otel/console.d.ts.map +1 -1
- package/dist/otel/exporters/index.d.ts +4 -0
- package/dist/otel/exporters/index.d.ts.map +1 -0
- package/dist/otel/exporters/jsonl-log-exporter.d.ts +36 -0
- package/dist/otel/exporters/jsonl-log-exporter.d.ts.map +1 -0
- package/dist/otel/exporters/jsonl-metric-exporter.d.ts +40 -0
- package/dist/otel/exporters/jsonl-metric-exporter.d.ts.map +1 -0
- package/dist/otel/exporters/jsonl-trace-exporter.d.ts +36 -0
- package/dist/otel/exporters/jsonl-trace-exporter.d.ts.map +1 -0
- package/dist/otel/http.d.ts.map +1 -1
- package/dist/otel/logger.d.ts +15 -11
- package/dist/otel/logger.d.ts.map +1 -1
- package/dist/otel/otel.d.ts +8 -2
- package/dist/otel/otel.d.ts.map +1 -1
- package/dist/router.d.ts +4 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/services/evalrun/composite.d.ts +21 -0
- package/dist/services/evalrun/composite.d.ts.map +1 -0
- package/dist/services/evalrun/http.d.ts +24 -0
- package/dist/services/evalrun/http.d.ts.map +1 -0
- package/dist/services/evalrun/index.d.ts +5 -0
- package/dist/services/evalrun/index.d.ts.map +1 -0
- package/dist/services/evalrun/json.d.ts +21 -0
- package/dist/services/evalrun/json.d.ts.map +1 -0
- package/dist/services/evalrun/local.d.ts +19 -0
- package/dist/services/evalrun/local.d.ts.map +1 -0
- package/dist/services/local/_db.d.ts +4 -0
- package/dist/services/local/_db.d.ts.map +1 -0
- package/dist/services/local/_router.d.ts +3 -0
- package/dist/services/local/_router.d.ts.map +1 -0
- package/dist/services/local/_util.d.ts +18 -0
- package/dist/services/local/_util.d.ts.map +1 -0
- package/dist/services/local/index.d.ts +8 -0
- package/dist/services/local/index.d.ts.map +1 -0
- package/dist/services/local/keyvalue.d.ts +10 -0
- package/dist/services/local/keyvalue.d.ts.map +1 -0
- package/dist/services/local/objectstore.d.ts +11 -0
- package/dist/services/local/objectstore.d.ts.map +1 -0
- package/dist/services/local/stream.d.ts +10 -0
- package/dist/services/local/stream.d.ts.map +1 -0
- package/dist/services/local/vector.d.ts +13 -0
- package/dist/services/local/vector.d.ts.map +1 -0
- package/dist/services/session/composite.d.ts +21 -0
- package/dist/services/session/composite.d.ts.map +1 -0
- package/dist/services/session/http.d.ts +23 -0
- package/dist/services/session/http.d.ts.map +1 -0
- package/dist/services/session/index.d.ts +5 -0
- package/dist/services/session/index.d.ts.map +1 -0
- package/dist/services/session/json.d.ts +22 -0
- package/dist/services/session/json.d.ts.map +1 -0
- package/dist/services/session/local.d.ts +19 -0
- package/dist/services/session/local.d.ts.map +1 -0
- package/dist/session.d.ts +70 -0
- package/dist/session.d.ts.map +1 -0
- package/package.json +10 -6
- package/src/_config.ts +1 -1
- package/src/_context.ts +19 -16
- package/src/_server.ts +284 -42
- package/src/_services.ts +147 -34
- package/src/_util.ts +2 -3
- package/src/_waituntil.ts +5 -153
- package/src/agent.ts +667 -65
- package/src/app.ts +159 -13
- package/src/eval.ts +95 -0
- package/src/index.ts +6 -1
- package/src/io/email.ts +173 -0
- package/src/logger/console.ts +222 -15
- package/src/logger/index.ts +0 -1
- package/src/logger/user.ts +8 -4
- package/src/otel/config.ts +7 -44
- package/src/otel/console.ts +9 -4
- package/src/otel/exporters/README.md +217 -0
- package/src/otel/exporters/index.ts +3 -0
- package/src/otel/exporters/jsonl-log-exporter.ts +113 -0
- package/src/otel/exporters/jsonl-metric-exporter.ts +120 -0
- package/src/otel/exporters/jsonl-trace-exporter.ts +121 -0
- package/src/otel/http.ts +3 -1
- package/src/otel/logger.ts +106 -41
- package/src/otel/otel.ts +43 -22
- package/src/router.ts +44 -4
- package/src/services/evalrun/composite.ts +34 -0
- package/src/services/evalrun/http.ts +112 -0
- package/src/services/evalrun/index.ts +4 -0
- package/src/services/evalrun/json.ts +46 -0
- package/src/services/evalrun/local.ts +28 -0
- package/src/services/local/README.md +1576 -0
- package/src/services/local/_db.ts +182 -0
- package/src/services/local/_router.ts +86 -0
- package/src/services/local/_util.ts +49 -0
- package/src/services/local/index.ts +7 -0
- package/src/services/local/keyvalue.ts +118 -0
- package/src/services/local/objectstore.ts +152 -0
- package/src/services/local/stream.ts +296 -0
- package/src/services/local/vector.ts +264 -0
- package/src/services/session/composite.ts +33 -0
- package/src/services/session/http.ts +64 -0
- package/src/services/session/index.ts +4 -0
- package/src/services/session/json.ts +42 -0
- package/src/services/session/local.ts +28 -0
- package/src/session.ts +284 -0
- package/dist/_unauthenticated.d.ts +0 -26
- package/dist/_unauthenticated.d.ts.map +0 -1
- package/src/_unauthenticated.ts +0 -126
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { type ExportResult, ExportResultCode } from '@opentelemetry/core';
|
|
2
|
+
import type { LogRecordExporter, ReadableLogRecord } from '@opentelemetry/sdk-logs';
|
|
3
|
+
import { existsSync, appendFileSync, mkdirSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { randomUUID } from 'node:crypto';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* JSONL implementation of the LogRecordExporter interface
|
|
9
|
+
* Writes logs to a timestamped JSONL file
|
|
10
|
+
*/
|
|
11
|
+
export class JSONLLogExporter implements LogRecordExporter {
|
|
12
|
+
private currentFile: string | null = null;
|
|
13
|
+
private readonly basePath: string;
|
|
14
|
+
private readonly filePrefix: string;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Creates a new JSONL log record exporter
|
|
18
|
+
* @param basePath - Directory to store the JSONL files
|
|
19
|
+
*/
|
|
20
|
+
constructor(basePath: string) {
|
|
21
|
+
this.basePath = basePath;
|
|
22
|
+
this.filePrefix = 'otel-log';
|
|
23
|
+
this.ensureDirectory();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private ensureDirectory(): void {
|
|
27
|
+
if (!existsSync(this.basePath)) {
|
|
28
|
+
mkdirSync(this.basePath, { recursive: true });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private getOrCreateFile(): string {
|
|
33
|
+
// If current file exists, use it
|
|
34
|
+
if (this.currentFile && existsSync(this.currentFile)) {
|
|
35
|
+
return this.currentFile;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
this.currentFile = join(
|
|
39
|
+
this.basePath,
|
|
40
|
+
`${this.filePrefix}-${Date.now()}.${randomUUID()}.jsonl`
|
|
41
|
+
);
|
|
42
|
+
return this.currentFile;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Exports log records to a JSONL file
|
|
47
|
+
*
|
|
48
|
+
* @param logs - The log records to export
|
|
49
|
+
* @param resultCallback - Callback function to report the export result
|
|
50
|
+
*/
|
|
51
|
+
export(logs: ReadableLogRecord[], resultCallback: (result: ExportResult) => void): void {
|
|
52
|
+
try {
|
|
53
|
+
if (logs.length === 0) {
|
|
54
|
+
resultCallback({ code: ExportResultCode.SUCCESS });
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const file = this.getOrCreateFile();
|
|
58
|
+
const lines: string[] = [];
|
|
59
|
+
for (const log of logs) {
|
|
60
|
+
const record = {
|
|
61
|
+
timestamp: log.hrTime,
|
|
62
|
+
observedTimestamp: log.hrTimeObserved,
|
|
63
|
+
severityNumber: log.severityNumber,
|
|
64
|
+
severityText: log.severityText,
|
|
65
|
+
body: log.body,
|
|
66
|
+
attributes: log.attributes,
|
|
67
|
+
resource: log.resource.attributes,
|
|
68
|
+
instrumentationScope: log.instrumentationScope,
|
|
69
|
+
spanContext: log.spanContext,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
lines.push(JSON.stringify(record));
|
|
73
|
+
}
|
|
74
|
+
const payload = `${lines.join('\n')}\n`;
|
|
75
|
+
try {
|
|
76
|
+
appendFileSync(file, payload, 'utf-8');
|
|
77
|
+
} catch (err) {
|
|
78
|
+
// File may have been deleted, reset and retry once
|
|
79
|
+
const code = (err as NodeJS.ErrnoException).code;
|
|
80
|
+
if (code === 'ENOENT') {
|
|
81
|
+
this.currentFile = null;
|
|
82
|
+
const newFile = this.getOrCreateFile();
|
|
83
|
+
appendFileSync(newFile, payload, 'utf-8');
|
|
84
|
+
} else {
|
|
85
|
+
throw err;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
resultCallback({ code: ExportResultCode.SUCCESS });
|
|
90
|
+
} catch (error) {
|
|
91
|
+
resultCallback({
|
|
92
|
+
code: ExportResultCode.FAILED,
|
|
93
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Shuts down the exporter
|
|
100
|
+
*
|
|
101
|
+
* @returns A promise that resolves when shutdown is complete
|
|
102
|
+
*/
|
|
103
|
+
async shutdown(): Promise<void> {
|
|
104
|
+
this.currentFile = null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Forces a flush of any pending data
|
|
109
|
+
*/
|
|
110
|
+
async forceFlush(): Promise<void> {
|
|
111
|
+
// No-op for file-based exporter as writes are synchronous
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { type ExportResult, ExportResultCode } from '@opentelemetry/core';
|
|
2
|
+
import {
|
|
3
|
+
type PushMetricExporter,
|
|
4
|
+
type ResourceMetrics,
|
|
5
|
+
AggregationTemporality,
|
|
6
|
+
InstrumentType,
|
|
7
|
+
} from '@opentelemetry/sdk-metrics';
|
|
8
|
+
import { existsSync, appendFileSync, mkdirSync } from 'node:fs';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { randomUUID } from 'node:crypto';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* JSONL implementation of the PushMetricExporter interface
|
|
14
|
+
* Writes metrics to a timestamped JSONL file
|
|
15
|
+
*/
|
|
16
|
+
export class JSONLMetricExporter implements PushMetricExporter {
|
|
17
|
+
private currentFile: string | null = null;
|
|
18
|
+
private readonly basePath: string;
|
|
19
|
+
private readonly filePrefix: string;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Creates a new JSONL metric exporter
|
|
23
|
+
* @param basePath - Directory to store the JSONL files
|
|
24
|
+
*/
|
|
25
|
+
constructor(basePath: string) {
|
|
26
|
+
this.basePath = basePath;
|
|
27
|
+
this.filePrefix = 'otel-metric';
|
|
28
|
+
this.ensureDirectory();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
private ensureDirectory(): void {
|
|
32
|
+
if (!existsSync(this.basePath)) {
|
|
33
|
+
mkdirSync(this.basePath, { recursive: true });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private getOrCreateFile(): string {
|
|
38
|
+
// If current file exists, use it
|
|
39
|
+
if (this.currentFile && existsSync(this.currentFile)) {
|
|
40
|
+
return this.currentFile;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
this.currentFile = join(
|
|
44
|
+
this.basePath,
|
|
45
|
+
`${this.filePrefix}-${Date.now()}.${randomUUID()}.jsonl`
|
|
46
|
+
);
|
|
47
|
+
return this.currentFile;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Exports metrics to a JSONL file
|
|
52
|
+
*
|
|
53
|
+
* @param metrics - The resource metrics to export
|
|
54
|
+
* @param resultCallback - Callback function to report the export result
|
|
55
|
+
*/
|
|
56
|
+
export(metrics: ResourceMetrics, resultCallback: (result: ExportResult) => void): void {
|
|
57
|
+
try {
|
|
58
|
+
const file = this.getOrCreateFile();
|
|
59
|
+
|
|
60
|
+
const record = {
|
|
61
|
+
resource: metrics.resource.attributes,
|
|
62
|
+
scopeMetrics: metrics.scopeMetrics.map((sm) => ({
|
|
63
|
+
scope: sm.scope,
|
|
64
|
+
metrics: sm.metrics.map((m) => ({
|
|
65
|
+
descriptor: m.descriptor,
|
|
66
|
+
dataPointType: m.dataPointType,
|
|
67
|
+
dataPoints: m.dataPoints,
|
|
68
|
+
aggregationTemporality: m.aggregationTemporality,
|
|
69
|
+
})),
|
|
70
|
+
})),
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const line = JSON.stringify(record) + '\n';
|
|
74
|
+
try {
|
|
75
|
+
appendFileSync(file, line, 'utf-8');
|
|
76
|
+
} catch (err) {
|
|
77
|
+
// File may have been deleted, reset and retry once
|
|
78
|
+
const code = (err as NodeJS.ErrnoException).code;
|
|
79
|
+
if (code === 'ENOENT') {
|
|
80
|
+
this.currentFile = null;
|
|
81
|
+
const newFile = this.getOrCreateFile();
|
|
82
|
+
appendFileSync(newFile, line, 'utf-8');
|
|
83
|
+
} else {
|
|
84
|
+
throw err;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
resultCallback({ code: ExportResultCode.SUCCESS });
|
|
89
|
+
} catch (error) {
|
|
90
|
+
resultCallback({
|
|
91
|
+
code: ExportResultCode.FAILED,
|
|
92
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Shuts down the exporter
|
|
99
|
+
*
|
|
100
|
+
* @returns A promise that resolves when shutdown is complete
|
|
101
|
+
*/
|
|
102
|
+
async shutdown(): Promise<void> {
|
|
103
|
+
this.currentFile = null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Forces a flush of any pending data
|
|
108
|
+
*/
|
|
109
|
+
async forceFlush(): Promise<void> {
|
|
110
|
+
// No-op for file-based exporter as writes are synchronous
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Selects the aggregation temporality for the given instrument type
|
|
115
|
+
*/
|
|
116
|
+
selectAggregationTemporality?(_instrumentType: InstrumentType): AggregationTemporality {
|
|
117
|
+
// Default to cumulative temporality
|
|
118
|
+
return AggregationTemporality.CUMULATIVE;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { type ExportResult, ExportResultCode } from '@opentelemetry/core';
|
|
2
|
+
import type { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base';
|
|
3
|
+
import { existsSync, appendFileSync, mkdirSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { randomUUID } from 'node:crypto';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* JSONL implementation of the SpanExporter interface
|
|
9
|
+
* Writes traces to a timestamped JSONL file
|
|
10
|
+
*/
|
|
11
|
+
export class JSONLTraceExporter implements SpanExporter {
|
|
12
|
+
private currentFile: string | null = null;
|
|
13
|
+
private readonly basePath: string;
|
|
14
|
+
private readonly filePrefix: string;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Creates a new JSONL trace exporter
|
|
18
|
+
* @param basePath - Directory to store the JSONL files
|
|
19
|
+
*/
|
|
20
|
+
constructor(basePath: string) {
|
|
21
|
+
this.basePath = basePath;
|
|
22
|
+
this.filePrefix = 'otel-trace';
|
|
23
|
+
this.ensureDirectory();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private ensureDirectory(): void {
|
|
27
|
+
if (!existsSync(this.basePath)) {
|
|
28
|
+
mkdirSync(this.basePath, { recursive: true });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private getOrCreateFile(): string {
|
|
33
|
+
// If current file exists, use it
|
|
34
|
+
if (this.currentFile && existsSync(this.currentFile)) {
|
|
35
|
+
return this.currentFile;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
this.currentFile = join(
|
|
39
|
+
this.basePath,
|
|
40
|
+
`${this.filePrefix}-${Date.now()}.${randomUUID()}.jsonl`
|
|
41
|
+
);
|
|
42
|
+
return this.currentFile;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Exports spans to a JSONL file
|
|
47
|
+
*
|
|
48
|
+
* @param spans - The spans to export
|
|
49
|
+
* @param resultCallback - Callback function to report the export result
|
|
50
|
+
*/
|
|
51
|
+
export(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): void {
|
|
52
|
+
try {
|
|
53
|
+
if (spans.length === 0) {
|
|
54
|
+
resultCallback({ code: ExportResultCode.SUCCESS });
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const file = this.getOrCreateFile();
|
|
58
|
+
const lines: string[] = [];
|
|
59
|
+
for (const span of spans) {
|
|
60
|
+
const record = {
|
|
61
|
+
traceId: span.spanContext().traceId,
|
|
62
|
+
spanId: span.spanContext().spanId,
|
|
63
|
+
traceState: span.spanContext().traceState?.serialize(),
|
|
64
|
+
name: span.name,
|
|
65
|
+
kind: span.kind,
|
|
66
|
+
startTime: span.startTime,
|
|
67
|
+
endTime: span.endTime,
|
|
68
|
+
attributes: span.attributes,
|
|
69
|
+
status: span.status,
|
|
70
|
+
events: span.events,
|
|
71
|
+
links: span.links,
|
|
72
|
+
resource: span.resource.attributes,
|
|
73
|
+
droppedAttributesCount: span.droppedAttributesCount,
|
|
74
|
+
droppedEventsCount: span.droppedEventsCount,
|
|
75
|
+
droppedLinksCount: span.droppedLinksCount,
|
|
76
|
+
duration: span.duration,
|
|
77
|
+
ended: span.ended,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
lines.push(JSON.stringify(record));
|
|
81
|
+
}
|
|
82
|
+
const payload = `${lines.join('\n')}\n`;
|
|
83
|
+
try {
|
|
84
|
+
appendFileSync(file, payload, 'utf-8');
|
|
85
|
+
} catch (err) {
|
|
86
|
+
// File may have been deleted, reset and retry once
|
|
87
|
+
const code = (err as NodeJS.ErrnoException).code;
|
|
88
|
+
if (code === 'ENOENT') {
|
|
89
|
+
this.currentFile = null;
|
|
90
|
+
const newFile = this.getOrCreateFile();
|
|
91
|
+
appendFileSync(newFile, payload, 'utf-8');
|
|
92
|
+
} else {
|
|
93
|
+
throw err;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
resultCallback({ code: ExportResultCode.SUCCESS });
|
|
98
|
+
} catch (error) {
|
|
99
|
+
resultCallback({
|
|
100
|
+
code: ExportResultCode.FAILED,
|
|
101
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Shuts down the exporter
|
|
108
|
+
*
|
|
109
|
+
* @returns A promise that resolves when shutdown is complete
|
|
110
|
+
*/
|
|
111
|
+
async shutdown(): Promise<void> {
|
|
112
|
+
this.currentFile = null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Forces a flush of any pending data
|
|
117
|
+
*/
|
|
118
|
+
async forceFlush(): Promise<void> {
|
|
119
|
+
// No-op for file-based exporter as writes are synchronous
|
|
120
|
+
}
|
|
121
|
+
}
|
package/src/otel/http.ts
CHANGED
|
@@ -12,7 +12,9 @@ export function injectTraceContextToHeaders(
|
|
|
12
12
|
let _headers: Record<string, string>;
|
|
13
13
|
if (headers instanceof Headers) {
|
|
14
14
|
_headers = {};
|
|
15
|
-
headers.forEach((v, k) =>
|
|
15
|
+
headers.forEach((v, k) => {
|
|
16
|
+
_headers[k] = v;
|
|
17
|
+
});
|
|
16
18
|
} else {
|
|
17
19
|
_headers = { ...headers };
|
|
18
20
|
}
|
package/src/otel/logger.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { format } from 'node:util';
|
|
2
|
-
import { safeStringify } from '@agentuity/core';
|
|
2
|
+
import { safeStringify, type LogLevel } from '@agentuity/core';
|
|
3
3
|
import * as LogsAPI from '@opentelemetry/api-logs';
|
|
4
4
|
import type { Logger } from '../logger';
|
|
5
5
|
import ConsoleLogger from '../logger/console';
|
|
@@ -11,22 +11,21 @@ import { getAgentContext } from '../_context';
|
|
|
11
11
|
export const __originalConsole = Object.create(console); // save the original console before we patch it
|
|
12
12
|
|
|
13
13
|
export class OtelLogger implements Logger {
|
|
14
|
-
private readonly
|
|
14
|
+
private readonly delegate: LogsAPI.Logger;
|
|
15
15
|
private readonly context: Record<string, unknown> | undefined;
|
|
16
16
|
private readonly logger: ConsoleLogger | undefined;
|
|
17
|
+
private readonly logLevel: LogLevel;
|
|
17
18
|
|
|
18
19
|
constructor(
|
|
19
20
|
useConsole: boolean,
|
|
20
|
-
|
|
21
|
-
context?: Record<string, unknown> | undefined
|
|
21
|
+
delegate: LogsAPI.Logger,
|
|
22
|
+
context?: Record<string, unknown> | undefined,
|
|
23
|
+
logLevel?: LogLevel
|
|
22
24
|
) {
|
|
23
|
-
this.
|
|
25
|
+
this.delegate = delegate;
|
|
24
26
|
this.context = context;
|
|
25
|
-
this.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
addDelegate(delegate: LogsAPI.Logger) {
|
|
29
|
-
this.delegates.push(delegate);
|
|
27
|
+
this.logLevel = logLevel ?? 'info';
|
|
28
|
+
this.logger = useConsole ? new ConsoleLogger(context, false, this.logLevel) : undefined;
|
|
30
29
|
}
|
|
31
30
|
|
|
32
31
|
private formatMessage(message: unknown) {
|
|
@@ -62,25 +61,65 @@ export class OtelLogger implements Logger {
|
|
|
62
61
|
return this.context;
|
|
63
62
|
}
|
|
64
63
|
|
|
65
|
-
private
|
|
64
|
+
private emit(severityNumber: LogsAPI.SeverityNumber, severityText: string, body: string) {
|
|
66
65
|
const attributes = this.getAttributes();
|
|
67
66
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
});
|
|
67
|
+
try {
|
|
68
|
+
this.delegate.emit({
|
|
69
|
+
severityNumber,
|
|
70
|
+
severityText,
|
|
71
|
+
body,
|
|
72
|
+
attributes: attributes as LogsAPI.LogRecord['attributes'],
|
|
73
|
+
});
|
|
74
|
+
} catch (error) {
|
|
75
|
+
// Log error to console if available, but don't fail the entire operation
|
|
76
|
+
this.logger?.error('Failed to emit log to OTLP instance:', error);
|
|
77
|
+
}
|
|
81
78
|
}
|
|
82
79
|
|
|
83
|
-
|
|
80
|
+
private shouldLog(level: LogsAPI.SeverityNumber): boolean {
|
|
81
|
+
switch (this.logLevel) {
|
|
82
|
+
case 'trace':
|
|
83
|
+
return true;
|
|
84
|
+
case 'debug':
|
|
85
|
+
return (
|
|
86
|
+
level === LogsAPI.SeverityNumber.DEBUG ||
|
|
87
|
+
level == LogsAPI.SeverityNumber.INFO ||
|
|
88
|
+
level == LogsAPI.SeverityNumber.WARN ||
|
|
89
|
+
level == LogsAPI.SeverityNumber.ERROR
|
|
90
|
+
);
|
|
91
|
+
case 'info':
|
|
92
|
+
return (
|
|
93
|
+
level == LogsAPI.SeverityNumber.INFO ||
|
|
94
|
+
level == LogsAPI.SeverityNumber.WARN ||
|
|
95
|
+
level == LogsAPI.SeverityNumber.ERROR
|
|
96
|
+
);
|
|
97
|
+
case 'warn':
|
|
98
|
+
return level == LogsAPI.SeverityNumber.WARN || level == LogsAPI.SeverityNumber.ERROR;
|
|
99
|
+
case 'error':
|
|
100
|
+
return level == LogsAPI.SeverityNumber.ERROR;
|
|
101
|
+
}
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
trace(message: unknown, ...args: unknown[]) {
|
|
106
|
+
if (!this.shouldLog(LogsAPI.SeverityNumber.TRACE)) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
this.logger?.trace(message, ...args);
|
|
110
|
+
let body: string;
|
|
111
|
+
try {
|
|
112
|
+
body = format(this.formatMessage(message), ...args);
|
|
113
|
+
} catch {
|
|
114
|
+
// Fallback if format causes recursion
|
|
115
|
+
body = `${this.formatMessage(message)} ${args.map((arg) => String(arg)).join(' ')}`;
|
|
116
|
+
}
|
|
117
|
+
this.emit(LogsAPI.SeverityNumber.TRACE, 'TRACE', body);
|
|
118
|
+
}
|
|
119
|
+
debug(message: unknown, ...args: unknown[]) {
|
|
120
|
+
if (!this.shouldLog(LogsAPI.SeverityNumber.DEBUG)) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
84
123
|
this.logger?.debug(message, ...args);
|
|
85
124
|
let body: string;
|
|
86
125
|
try {
|
|
@@ -89,9 +128,12 @@ export class OtelLogger implements Logger {
|
|
|
89
128
|
// Fallback if format causes recursion
|
|
90
129
|
body = `${this.formatMessage(message)} ${args.map((arg) => String(arg)).join(' ')}`;
|
|
91
130
|
}
|
|
92
|
-
this.
|
|
131
|
+
this.emit(LogsAPI.SeverityNumber.DEBUG, 'DEBUG', body);
|
|
93
132
|
}
|
|
94
|
-
info(message:
|
|
133
|
+
info(message: unknown, ...args: unknown[]) {
|
|
134
|
+
if (!this.shouldLog(LogsAPI.SeverityNumber.INFO)) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
95
137
|
this.logger?.info(message, ...args);
|
|
96
138
|
let body: string;
|
|
97
139
|
try {
|
|
@@ -100,9 +142,12 @@ export class OtelLogger implements Logger {
|
|
|
100
142
|
// Fallback if format causes recursion
|
|
101
143
|
body = `${this.formatMessage(message)} ${args.map((arg) => String(arg)).join(' ')}`;
|
|
102
144
|
}
|
|
103
|
-
this.
|
|
145
|
+
this.emit(LogsAPI.SeverityNumber.INFO, 'INFO', body);
|
|
104
146
|
}
|
|
105
|
-
warn(message:
|
|
147
|
+
warn(message: unknown, ...args: unknown[]) {
|
|
148
|
+
if (!this.shouldLog(LogsAPI.SeverityNumber.WARN)) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
106
151
|
this.logger?.warn(message, ...args);
|
|
107
152
|
let body: string;
|
|
108
153
|
try {
|
|
@@ -111,9 +156,12 @@ export class OtelLogger implements Logger {
|
|
|
111
156
|
// Fallback if format causes recursion
|
|
112
157
|
body = `${this.formatMessage(message)} ${args.map((arg) => String(arg)).join(' ')}`;
|
|
113
158
|
}
|
|
114
|
-
this.
|
|
159
|
+
this.emit(LogsAPI.SeverityNumber.WARN, 'WARN', body);
|
|
115
160
|
}
|
|
116
|
-
error(message:
|
|
161
|
+
error(message: unknown, ...args: unknown[]) {
|
|
162
|
+
if (!this.shouldLog(LogsAPI.SeverityNumber.ERROR)) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
117
165
|
this.logger?.error(message, ...args);
|
|
118
166
|
let body: string;
|
|
119
167
|
try {
|
|
@@ -122,13 +170,22 @@ export class OtelLogger implements Logger {
|
|
|
122
170
|
// Fallback if format causes recursion
|
|
123
171
|
body = `${this.formatMessage(message)} ${args.map((arg) => String(arg)).join(' ')}`;
|
|
124
172
|
}
|
|
125
|
-
this.
|
|
173
|
+
this.emit(LogsAPI.SeverityNumber.ERROR, 'ERROR', body);
|
|
174
|
+
}
|
|
175
|
+
fatal(message: unknown, ...args: unknown[]): never {
|
|
176
|
+
this.error(message, ...args);
|
|
177
|
+
process.exit(1);
|
|
126
178
|
}
|
|
127
|
-
child(opts: Record<string, unknown>) {
|
|
128
|
-
return new OtelLogger(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
179
|
+
child(opts: Record<string, unknown>): Logger {
|
|
180
|
+
return new OtelLogger(
|
|
181
|
+
!!this.logger,
|
|
182
|
+
this.delegate,
|
|
183
|
+
{
|
|
184
|
+
...(this.context ?? {}),
|
|
185
|
+
...opts,
|
|
186
|
+
},
|
|
187
|
+
this.logLevel
|
|
188
|
+
);
|
|
132
189
|
}
|
|
133
190
|
}
|
|
134
191
|
|
|
@@ -139,11 +196,15 @@ export class OtelLogger implements Logger {
|
|
|
139
196
|
* @param context - Additional context to include with log records
|
|
140
197
|
* @returns A logger instance
|
|
141
198
|
*/
|
|
142
|
-
export function createLogger(
|
|
199
|
+
export function createLogger(
|
|
200
|
+
useConsole: boolean,
|
|
201
|
+
context?: Record<string, unknown>,
|
|
202
|
+
logLevel?: LogLevel
|
|
203
|
+
): Logger {
|
|
143
204
|
const delegate = LogsAPI.logs.getLogger('default', undefined, {
|
|
144
205
|
scopeAttributes: context as LogsAPI.LoggerOptions['scopeAttributes'],
|
|
145
206
|
});
|
|
146
|
-
return new OtelLogger(useConsole,
|
|
207
|
+
return new OtelLogger(useConsole, delegate, context, logLevel);
|
|
147
208
|
}
|
|
148
209
|
|
|
149
210
|
/**
|
|
@@ -151,12 +212,16 @@ export function createLogger(useConsole: boolean, context?: Record<string, unkno
|
|
|
151
212
|
*
|
|
152
213
|
* @param attributes - Attributes to include with all console log records
|
|
153
214
|
*/
|
|
154
|
-
export function patchConsole(
|
|
215
|
+
export function patchConsole(
|
|
216
|
+
enabled: boolean,
|
|
217
|
+
attributes: Record<string, unknown>,
|
|
218
|
+
logLevel: LogLevel
|
|
219
|
+
) {
|
|
155
220
|
if (!enabled) {
|
|
156
221
|
return;
|
|
157
222
|
}
|
|
158
223
|
const _patch = { ...__originalConsole };
|
|
159
|
-
const delegate = createLogger(true, attributes);
|
|
224
|
+
const delegate = createLogger(true, attributes, logLevel);
|
|
160
225
|
|
|
161
226
|
// Patch individual console methods instead of reassigning the whole object
|
|
162
227
|
_patch.log = (...args: unknown[]) => {
|