@mastra/loggers 1.3.4-alpha.0 → 1.3.5-alpha.1
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 +16 -0
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/reference-file-based-agents-logger.md +0 -2
- package/dist/file/index.cjs +56 -49
- package/dist/file/index.cjs.map +1 -1
- package/dist/file/index.d.ts +2 -1
- package/dist/file/index.d.ts.map +1 -1
- package/dist/file/index.js +57 -50
- package/dist/file/index.js.map +1 -1
- package/dist/http/index.cjs +91 -19
- package/dist/http/index.cjs.map +1 -1
- package/dist/http/index.d.ts +9 -0
- package/dist/http/index.d.ts.map +1 -1
- package/dist/http/index.js +91 -19
- package/dist/http/index.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -69,6 +69,22 @@ const upstashTransport = new UpstashTransport({
|
|
|
69
69
|
|
|
70
70
|
`HttpTransport` sends batches of structured log records to an HTTP endpoint and supports request headers, batching, retry, and flush configuration. Use it for application-specific collectors and hosted logging gateways.
|
|
71
71
|
|
|
72
|
+
Logs wait in an in-memory buffer until they are sent. `maxBufferSize` caps that buffer so an unreachable endpoint can't exhaust memory. It defaults to 10,000 records and is never lower than `batchSize`. When the buffer is full, the oldest records are dropped first; `getDroppedLogCount()` returns how many were dropped. `batchSize` and `maxBufferSize` must be positive integers, otherwise the constructor throws.
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import { HttpTransport } from '@mastra/loggers/http';
|
|
76
|
+
|
|
77
|
+
const httpTransport = new HttpTransport({
|
|
78
|
+
url: 'https://logs.example.com/ingest',
|
|
79
|
+
headers: { Authorization: `Bearer ${process.env.LOG_TOKEN}` },
|
|
80
|
+
batchSize: 100,
|
|
81
|
+
flushInterval: 10_000,
|
|
82
|
+
maxBufferSize: 5_000,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const droppedLogs = httpTransport.getDroppedLogCount();
|
|
86
|
+
```
|
|
87
|
+
|
|
72
88
|
- [`PinoLogger` reference](https://mastra.ai/reference/logging/pino-logger)
|
|
73
89
|
|
|
74
90
|
## Changelog
|
package/dist/docs/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: mastra-loggers
|
|
|
3
3
|
description: Documentation for @mastra/loggers. Use when working with @mastra/loggers APIs, configuration, or implementation.
|
|
4
4
|
metadata:
|
|
5
5
|
package: "@mastra/loggers"
|
|
6
|
-
version: "1.3.
|
|
6
|
+
version: "1.3.5-alpha.1"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
## When to use
|
|
@@ -4,8 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
# Logger
|
|
6
6
|
|
|
7
|
-
> **Beta:** Breaking changes may occur without a major version bump until the API is stable.
|
|
8
|
-
|
|
9
7
|
Mastra sets the project's [logger](https://mastra.ai/docs/observability/logging) from a `logger.ts` file directly under `src/mastra/`. The file default-exports a logger, which replaces the built-in `ConsoleLogger` used across agents, workflows, and other components.
|
|
10
8
|
|
|
11
9
|
Use this page for the file-based convention. For log levels, transports, and provider details, see [logging](https://mastra.ai/docs/observability/logging).
|
package/dist/file/index.cjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
let _mastra_core_logger = require("@mastra/core/logger");
|
|
3
3
|
let fs = require("fs");
|
|
4
|
+
let readline = require("readline");
|
|
4
5
|
//#region src/file/index.ts
|
|
5
6
|
var FileTransport = class extends _mastra_core_logger.LoggerTransport {
|
|
6
7
|
path;
|
|
@@ -43,39 +44,7 @@ var FileTransport = class extends _mastra_core_logger.LoggerTransport {
|
|
|
43
44
|
}
|
|
44
45
|
async listLogs(params) {
|
|
45
46
|
try {
|
|
46
|
-
|
|
47
|
-
const page = pageInput === 0 ? 1 : pageInput ?? 1;
|
|
48
|
-
const perPage = perPageInput ?? 100;
|
|
49
|
-
const returnPaginationResults = returnPaginationResultsInput ?? true;
|
|
50
|
-
let filteredLogs = (0, fs.readFileSync)(this.path, "utf8").split("\n").filter(Boolean).flatMap((line) => {
|
|
51
|
-
try {
|
|
52
|
-
return [JSON.parse(line)];
|
|
53
|
-
} catch {
|
|
54
|
-
return [];
|
|
55
|
-
}
|
|
56
|
-
}).filter((record) => record !== null && typeof record === "object");
|
|
57
|
-
if (filters) filteredLogs = filteredLogs.filter((log) => Object.entries(filters || {}).every(([key, value]) => log[key] === value));
|
|
58
|
-
if (logLevel) filteredLogs = filteredLogs.filter((log) => log.level === logLevel);
|
|
59
|
-
if (fromDate) filteredLogs = filteredLogs.filter((log) => new Date(log.time).getTime() >= fromDate.getTime());
|
|
60
|
-
if (toDate) filteredLogs = filteredLogs.filter((log) => new Date(log.time).getTime() <= toDate.getTime());
|
|
61
|
-
if (!returnPaginationResults) return {
|
|
62
|
-
logs: filteredLogs,
|
|
63
|
-
total: filteredLogs.length,
|
|
64
|
-
page,
|
|
65
|
-
perPage: filteredLogs.length,
|
|
66
|
-
hasMore: false
|
|
67
|
-
};
|
|
68
|
-
const total = filteredLogs.length;
|
|
69
|
-
const resolvedPerPage = perPage || 100;
|
|
70
|
-
const start = (page - 1) * resolvedPerPage;
|
|
71
|
-
const end = start + resolvedPerPage;
|
|
72
|
-
return {
|
|
73
|
-
logs: filteredLogs.slice(start, end),
|
|
74
|
-
total,
|
|
75
|
-
page,
|
|
76
|
-
perPage: resolvedPerPage,
|
|
77
|
-
hasMore: end < total
|
|
78
|
-
};
|
|
47
|
+
return await this.#queryLogs(params || {});
|
|
79
48
|
} catch (error) {
|
|
80
49
|
console.error("Error getting logs from file:", error);
|
|
81
50
|
return {
|
|
@@ -87,27 +56,17 @@ var FileTransport = class extends _mastra_core_logger.LoggerTransport {
|
|
|
87
56
|
};
|
|
88
57
|
}
|
|
89
58
|
}
|
|
90
|
-
async listLogsByRunId({ runId, fromDate, toDate, logLevel, filters, page
|
|
59
|
+
async listLogsByRunId({ runId, fromDate, toDate, logLevel, filters, page, perPage }) {
|
|
91
60
|
try {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const logs = (await this.listLogs({
|
|
61
|
+
return await this.#queryLogs({
|
|
62
|
+
runId,
|
|
95
63
|
fromDate,
|
|
96
64
|
toDate,
|
|
97
65
|
logLevel,
|
|
98
|
-
filters
|
|
99
|
-
}))?.logs?.filter((log) => log?.runId === runId) || [];
|
|
100
|
-
const total = logs.length;
|
|
101
|
-
const resolvedPerPage = perPage || 100;
|
|
102
|
-
const start = (page - 1) * resolvedPerPage;
|
|
103
|
-
const end = start + resolvedPerPage;
|
|
104
|
-
return {
|
|
105
|
-
logs: logs.slice(start, end),
|
|
106
|
-
total,
|
|
66
|
+
filters,
|
|
107
67
|
page,
|
|
108
|
-
perPage
|
|
109
|
-
|
|
110
|
-
};
|
|
68
|
+
perPage
|
|
69
|
+
});
|
|
111
70
|
} catch (error) {
|
|
112
71
|
console.error("Error getting logs by runId from file:", error);
|
|
113
72
|
return {
|
|
@@ -119,6 +78,54 @@ var FileTransport = class extends _mastra_core_logger.LoggerTransport {
|
|
|
119
78
|
};
|
|
120
79
|
}
|
|
121
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Streams the log file line by line, counting every matching record but
|
|
83
|
+
* retaining only the requested page (or all matches when pagination is off).
|
|
84
|
+
*/
|
|
85
|
+
async #queryLogs({ runId, fromDate, toDate, logLevel, filters, returnPaginationResults = true, page: pageInput, perPage: perPageInput }) {
|
|
86
|
+
const page = pageInput === 0 ? 1 : pageInput ?? 1;
|
|
87
|
+
const perPage = (perPageInput ?? 100) || 100;
|
|
88
|
+
const start = (page - 1) * perPage;
|
|
89
|
+
const end = start + perPage;
|
|
90
|
+
const filterEntries = Object.entries(filters ?? {});
|
|
91
|
+
const logs = [];
|
|
92
|
+
let total = 0;
|
|
93
|
+
const lines = (0, readline.createInterface)({
|
|
94
|
+
input: (0, fs.createReadStream)(this.path, "utf8"),
|
|
95
|
+
crlfDelay: Infinity
|
|
96
|
+
});
|
|
97
|
+
for await (const line of lines) {
|
|
98
|
+
if (!line.trim()) continue;
|
|
99
|
+
let log;
|
|
100
|
+
try {
|
|
101
|
+
log = JSON.parse(line);
|
|
102
|
+
} catch {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (log === null || typeof log !== "object") continue;
|
|
106
|
+
if (runId !== void 0 && log.runId !== runId) continue;
|
|
107
|
+
if (!filterEntries.every(([key, value]) => log[key] === value)) continue;
|
|
108
|
+
if (logLevel && log.level !== logLevel) continue;
|
|
109
|
+
if (fromDate && !(new Date(log.time).getTime() >= fromDate.getTime())) continue;
|
|
110
|
+
if (toDate && !(new Date(log.time).getTime() <= toDate.getTime())) continue;
|
|
111
|
+
if (!returnPaginationResults || total >= start && total < end) logs.push(log);
|
|
112
|
+
total++;
|
|
113
|
+
}
|
|
114
|
+
if (!returnPaginationResults) return {
|
|
115
|
+
logs,
|
|
116
|
+
total,
|
|
117
|
+
page,
|
|
118
|
+
perPage: total,
|
|
119
|
+
hasMore: false
|
|
120
|
+
};
|
|
121
|
+
return {
|
|
122
|
+
logs,
|
|
123
|
+
total,
|
|
124
|
+
page,
|
|
125
|
+
perPage,
|
|
126
|
+
hasMore: end < total
|
|
127
|
+
};
|
|
128
|
+
}
|
|
122
129
|
};
|
|
123
130
|
//#endregion
|
|
124
131
|
exports.FileTransport = FileTransport;
|
package/dist/file/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["LoggerTransport"],"sources":["../../src/file/index.ts"],"sourcesContent":["import type { WriteStream } from 'node:fs';\nimport { createWriteStream, existsSync
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["LoggerTransport","#queryLogs"],"sources":["../../src/file/index.ts"],"sourcesContent":["import type { WriteStream } from 'node:fs';\nimport { createReadStream, createWriteStream, existsSync } from 'node:fs';\nimport { createInterface } from 'node:readline';\nimport { LoggerTransport } from '@mastra/core/logger';\nimport type { BaseLogMessage, LogLevel } from '@mastra/core/logger';\n\nexport class FileTransport extends LoggerTransport {\n path: string;\n fileStream: WriteStream;\n constructor({ path }: { path: string }) {\n super({ objectMode: true });\n this.path = path;\n\n if (!existsSync(this.path)) {\n console.info(this.path);\n throw new Error('File path does not exist');\n }\n\n this.fileStream = createWriteStream(this.path, { flags: 'a' });\n }\n\n _transform(chunk: any, _encoding: string, callback: (error: Error | null, chunk: any) => void) {\n try {\n this.fileStream.write(chunk);\n } catch (error) {\n console.error('Error parsing log entry:', error);\n }\n callback(null, chunk);\n }\n\n _flush(callback: Function) {\n // End the file stream when transform stream ends\n this.fileStream.end(() => {\n callback();\n });\n }\n\n _write(chunk: any, encoding?: string, callback?: (error?: Error | null) => void): boolean {\n if (typeof callback === 'function') {\n this._transform(chunk, encoding || 'utf8', callback);\n return true;\n }\n\n this._transform(chunk, encoding || 'utf8', (error: Error | null) => {\n if (error) console.error('Transform error in write:', error);\n });\n return true;\n }\n\n // Clean up resources\n _destroy(error: Error, callback: Function) {\n if (this.fileStream) {\n this.fileStream.destroy(error);\n }\n callback(error);\n }\n\n async listLogs(params?: {\n fromDate?: Date;\n toDate?: Date;\n logLevel?: LogLevel;\n filters?: Record<string, any>;\n returnPaginationResults?: boolean; // default true\n page?: number;\n perPage?: number;\n }): Promise<{\n logs: BaseLogMessage[];\n total: number;\n page: number;\n perPage: number;\n hasMore: boolean;\n }> {\n try {\n return await this.#queryLogs(params || {});\n } catch (error) {\n console.error('Error getting logs from file:', error);\n return { logs: [], total: 0, page: 0, perPage: 0, hasMore: false };\n }\n }\n\n async listLogsByRunId({\n runId,\n fromDate,\n toDate,\n logLevel,\n filters,\n page,\n perPage,\n }: {\n runId: string;\n fromDate?: Date;\n toDate?: Date;\n logLevel?: LogLevel;\n filters?: Record<string, any>;\n page?: number;\n perPage?: number;\n }): Promise<{\n logs: BaseLogMessage[];\n total: number;\n page: number;\n perPage: number;\n hasMore: boolean;\n }> {\n try {\n return await this.#queryLogs({ runId, fromDate, toDate, logLevel, filters, page, perPage });\n } catch (error) {\n console.error('Error getting logs by runId from file:', error);\n return { logs: [], total: 0, page: 0, perPage: 0, hasMore: false };\n }\n }\n\n /**\n * Streams the log file line by line, counting every matching record but\n * retaining only the requested page (or all matches when pagination is off).\n */\n async #queryLogs({\n runId,\n fromDate,\n toDate,\n logLevel,\n filters,\n returnPaginationResults = true,\n page: pageInput,\n perPage: perPageInput,\n }: {\n runId?: string;\n fromDate?: Date;\n toDate?: Date;\n logLevel?: LogLevel;\n filters?: Record<string, any>;\n returnPaginationResults?: boolean;\n page?: number;\n perPage?: number;\n }) {\n const page = pageInput === 0 ? 1 : (pageInput ?? 1);\n const perPage = (perPageInput ?? 100) || 100;\n const start = (page - 1) * perPage;\n const end = start + perPage;\n const filterEntries = Object.entries(filters ?? {});\n\n const logs: BaseLogMessage[] = [];\n let total = 0;\n\n const lines = createInterface({ input: createReadStream(this.path, 'utf8'), crlfDelay: Infinity });\n for await (const line of lines) {\n if (!line.trim()) continue;\n\n let log: any;\n try {\n log = JSON.parse(line);\n } catch {\n continue;\n }\n\n if (log === null || typeof log !== 'object') continue;\n if (runId !== undefined && log.runId !== runId) continue;\n if (!filterEntries.every(([key, value]) => log[key] === value)) continue;\n if (logLevel && log.level !== logLevel) continue;\n if (fromDate && !(new Date(log.time).getTime() >= fromDate.getTime())) continue;\n if (toDate && !(new Date(log.time).getTime() <= toDate.getTime())) continue;\n\n if (!returnPaginationResults || (total >= start && total < end)) {\n logs.push(log);\n }\n total++;\n }\n\n if (!returnPaginationResults) {\n return { logs, total, page, perPage: total, hasMore: false };\n }\n\n return { logs, total, page, perPage, hasMore: end < total };\n }\n}\n"],"mappings":"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"}
|
package/dist/file/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { WriteStream } from 'node:fs';
|
|
|
2
2
|
import { LoggerTransport } from '@mastra/core/logger';
|
|
3
3
|
import type { BaseLogMessage, LogLevel } from '@mastra/core/logger';
|
|
4
4
|
export declare class FileTransport extends LoggerTransport {
|
|
5
|
+
#private;
|
|
5
6
|
path: string;
|
|
6
7
|
fileStream: WriteStream;
|
|
7
8
|
constructor({ path }: {
|
|
@@ -26,7 +27,7 @@ export declare class FileTransport extends LoggerTransport {
|
|
|
26
27
|
perPage: number;
|
|
27
28
|
hasMore: boolean;
|
|
28
29
|
}>;
|
|
29
|
-
listLogsByRunId({ runId, fromDate, toDate, logLevel, filters, page
|
|
30
|
+
listLogsByRunId({ runId, fromDate, toDate, logLevel, filters, page, perPage, }: {
|
|
30
31
|
runId: string;
|
|
31
32
|
fromDate?: Date;
|
|
32
33
|
toDate?: Date;
|
package/dist/file/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/file/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/file/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAG3C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpE,qBAAa,aAAc,SAAQ,eAAe;;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,WAAW,CAAC;IACxB,YAAY,EAAE,IAAI,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,EAUrC;IAED,UAAU,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,QAO5F;IAED,MAAM,CAAC,QAAQ,EAAE,QAAQ,QAKxB;IAED,MAAM,CAAC,KAAK,EAAE,GAAG,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,KAAK,IAAI,GAAG,OAAO,CAUxF;IAGD,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,QAKxC;IAEK,QAAQ,CAAC,MAAM,CAAC,EAAE;QACtB,QAAQ,CAAC,EAAE,IAAI,CAAC;QAChB,MAAM,CAAC,EAAE,IAAI,CAAC;QACd,QAAQ,CAAC,EAAE,QAAQ,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC9B,uBAAuB,CAAC,EAAE,OAAO,CAAC;QAClC,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC;QACV,IAAI,EAAE,cAAc,EAAE,CAAC;QACvB,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC,CAOD;IAEK,eAAe,CAAC,EACpB,KAAK,EACL,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,OAAO,EACP,IAAI,EACJ,OAAO,GACR,EAAE;QACD,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,IAAI,CAAC;QAChB,MAAM,CAAC,EAAE,IAAI,CAAC;QACd,QAAQ,CAAC,EAAE,QAAQ,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC;QACV,IAAI,EAAE,cAAc,EAAE,CAAC;QACvB,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC,CAOD;CAgEF"}
|
package/dist/file/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { LoggerTransport } from "@mastra/core/logger";
|
|
2
|
-
import { createWriteStream, existsSync
|
|
2
|
+
import { createReadStream, createWriteStream, existsSync } from "fs";
|
|
3
|
+
import { createInterface } from "readline";
|
|
3
4
|
//#region src/file/index.ts
|
|
4
5
|
var FileTransport = class extends LoggerTransport {
|
|
5
6
|
path;
|
|
@@ -42,39 +43,7 @@ var FileTransport = class extends LoggerTransport {
|
|
|
42
43
|
}
|
|
43
44
|
async listLogs(params) {
|
|
44
45
|
try {
|
|
45
|
-
|
|
46
|
-
const page = pageInput === 0 ? 1 : pageInput ?? 1;
|
|
47
|
-
const perPage = perPageInput ?? 100;
|
|
48
|
-
const returnPaginationResults = returnPaginationResultsInput ?? true;
|
|
49
|
-
let filteredLogs = readFileSync(this.path, "utf8").split("\n").filter(Boolean).flatMap((line) => {
|
|
50
|
-
try {
|
|
51
|
-
return [JSON.parse(line)];
|
|
52
|
-
} catch {
|
|
53
|
-
return [];
|
|
54
|
-
}
|
|
55
|
-
}).filter((record) => record !== null && typeof record === "object");
|
|
56
|
-
if (filters) filteredLogs = filteredLogs.filter((log) => Object.entries(filters || {}).every(([key, value]) => log[key] === value));
|
|
57
|
-
if (logLevel) filteredLogs = filteredLogs.filter((log) => log.level === logLevel);
|
|
58
|
-
if (fromDate) filteredLogs = filteredLogs.filter((log) => new Date(log.time).getTime() >= fromDate.getTime());
|
|
59
|
-
if (toDate) filteredLogs = filteredLogs.filter((log) => new Date(log.time).getTime() <= toDate.getTime());
|
|
60
|
-
if (!returnPaginationResults) return {
|
|
61
|
-
logs: filteredLogs,
|
|
62
|
-
total: filteredLogs.length,
|
|
63
|
-
page,
|
|
64
|
-
perPage: filteredLogs.length,
|
|
65
|
-
hasMore: false
|
|
66
|
-
};
|
|
67
|
-
const total = filteredLogs.length;
|
|
68
|
-
const resolvedPerPage = perPage || 100;
|
|
69
|
-
const start = (page - 1) * resolvedPerPage;
|
|
70
|
-
const end = start + resolvedPerPage;
|
|
71
|
-
return {
|
|
72
|
-
logs: filteredLogs.slice(start, end),
|
|
73
|
-
total,
|
|
74
|
-
page,
|
|
75
|
-
perPage: resolvedPerPage,
|
|
76
|
-
hasMore: end < total
|
|
77
|
-
};
|
|
46
|
+
return await this.#queryLogs(params || {});
|
|
78
47
|
} catch (error) {
|
|
79
48
|
console.error("Error getting logs from file:", error);
|
|
80
49
|
return {
|
|
@@ -86,27 +55,17 @@ var FileTransport = class extends LoggerTransport {
|
|
|
86
55
|
};
|
|
87
56
|
}
|
|
88
57
|
}
|
|
89
|
-
async listLogsByRunId({ runId, fromDate, toDate, logLevel, filters, page
|
|
58
|
+
async listLogsByRunId({ runId, fromDate, toDate, logLevel, filters, page, perPage }) {
|
|
90
59
|
try {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const logs = (await this.listLogs({
|
|
60
|
+
return await this.#queryLogs({
|
|
61
|
+
runId,
|
|
94
62
|
fromDate,
|
|
95
63
|
toDate,
|
|
96
64
|
logLevel,
|
|
97
|
-
filters
|
|
98
|
-
}))?.logs?.filter((log) => log?.runId === runId) || [];
|
|
99
|
-
const total = logs.length;
|
|
100
|
-
const resolvedPerPage = perPage || 100;
|
|
101
|
-
const start = (page - 1) * resolvedPerPage;
|
|
102
|
-
const end = start + resolvedPerPage;
|
|
103
|
-
return {
|
|
104
|
-
logs: logs.slice(start, end),
|
|
105
|
-
total,
|
|
65
|
+
filters,
|
|
106
66
|
page,
|
|
107
|
-
perPage
|
|
108
|
-
|
|
109
|
-
};
|
|
67
|
+
perPage
|
|
68
|
+
});
|
|
110
69
|
} catch (error) {
|
|
111
70
|
console.error("Error getting logs by runId from file:", error);
|
|
112
71
|
return {
|
|
@@ -118,6 +77,54 @@ var FileTransport = class extends LoggerTransport {
|
|
|
118
77
|
};
|
|
119
78
|
}
|
|
120
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Streams the log file line by line, counting every matching record but
|
|
82
|
+
* retaining only the requested page (or all matches when pagination is off).
|
|
83
|
+
*/
|
|
84
|
+
async #queryLogs({ runId, fromDate, toDate, logLevel, filters, returnPaginationResults = true, page: pageInput, perPage: perPageInput }) {
|
|
85
|
+
const page = pageInput === 0 ? 1 : pageInput ?? 1;
|
|
86
|
+
const perPage = (perPageInput ?? 100) || 100;
|
|
87
|
+
const start = (page - 1) * perPage;
|
|
88
|
+
const end = start + perPage;
|
|
89
|
+
const filterEntries = Object.entries(filters ?? {});
|
|
90
|
+
const logs = [];
|
|
91
|
+
let total = 0;
|
|
92
|
+
const lines = createInterface({
|
|
93
|
+
input: createReadStream(this.path, "utf8"),
|
|
94
|
+
crlfDelay: Infinity
|
|
95
|
+
});
|
|
96
|
+
for await (const line of lines) {
|
|
97
|
+
if (!line.trim()) continue;
|
|
98
|
+
let log;
|
|
99
|
+
try {
|
|
100
|
+
log = JSON.parse(line);
|
|
101
|
+
} catch {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (log === null || typeof log !== "object") continue;
|
|
105
|
+
if (runId !== void 0 && log.runId !== runId) continue;
|
|
106
|
+
if (!filterEntries.every(([key, value]) => log[key] === value)) continue;
|
|
107
|
+
if (logLevel && log.level !== logLevel) continue;
|
|
108
|
+
if (fromDate && !(new Date(log.time).getTime() >= fromDate.getTime())) continue;
|
|
109
|
+
if (toDate && !(new Date(log.time).getTime() <= toDate.getTime())) continue;
|
|
110
|
+
if (!returnPaginationResults || total >= start && total < end) logs.push(log);
|
|
111
|
+
total++;
|
|
112
|
+
}
|
|
113
|
+
if (!returnPaginationResults) return {
|
|
114
|
+
logs,
|
|
115
|
+
total,
|
|
116
|
+
page,
|
|
117
|
+
perPage: total,
|
|
118
|
+
hasMore: false
|
|
119
|
+
};
|
|
120
|
+
return {
|
|
121
|
+
logs,
|
|
122
|
+
total,
|
|
123
|
+
page,
|
|
124
|
+
perPage,
|
|
125
|
+
hasMore: end < total
|
|
126
|
+
};
|
|
127
|
+
}
|
|
121
128
|
};
|
|
122
129
|
//#endregion
|
|
123
130
|
export { FileTransport };
|
package/dist/file/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/file/index.ts"],"sourcesContent":["import type { WriteStream } from 'node:fs';\nimport { createWriteStream, existsSync
|
|
1
|
+
{"version":3,"file":"index.js","names":["#queryLogs"],"sources":["../../src/file/index.ts"],"sourcesContent":["import type { WriteStream } from 'node:fs';\nimport { createReadStream, createWriteStream, existsSync } from 'node:fs';\nimport { createInterface } from 'node:readline';\nimport { LoggerTransport } from '@mastra/core/logger';\nimport type { BaseLogMessage, LogLevel } from '@mastra/core/logger';\n\nexport class FileTransport extends LoggerTransport {\n path: string;\n fileStream: WriteStream;\n constructor({ path }: { path: string }) {\n super({ objectMode: true });\n this.path = path;\n\n if (!existsSync(this.path)) {\n console.info(this.path);\n throw new Error('File path does not exist');\n }\n\n this.fileStream = createWriteStream(this.path, { flags: 'a' });\n }\n\n _transform(chunk: any, _encoding: string, callback: (error: Error | null, chunk: any) => void) {\n try {\n this.fileStream.write(chunk);\n } catch (error) {\n console.error('Error parsing log entry:', error);\n }\n callback(null, chunk);\n }\n\n _flush(callback: Function) {\n // End the file stream when transform stream ends\n this.fileStream.end(() => {\n callback();\n });\n }\n\n _write(chunk: any, encoding?: string, callback?: (error?: Error | null) => void): boolean {\n if (typeof callback === 'function') {\n this._transform(chunk, encoding || 'utf8', callback);\n return true;\n }\n\n this._transform(chunk, encoding || 'utf8', (error: Error | null) => {\n if (error) console.error('Transform error in write:', error);\n });\n return true;\n }\n\n // Clean up resources\n _destroy(error: Error, callback: Function) {\n if (this.fileStream) {\n this.fileStream.destroy(error);\n }\n callback(error);\n }\n\n async listLogs(params?: {\n fromDate?: Date;\n toDate?: Date;\n logLevel?: LogLevel;\n filters?: Record<string, any>;\n returnPaginationResults?: boolean; // default true\n page?: number;\n perPage?: number;\n }): Promise<{\n logs: BaseLogMessage[];\n total: number;\n page: number;\n perPage: number;\n hasMore: boolean;\n }> {\n try {\n return await this.#queryLogs(params || {});\n } catch (error) {\n console.error('Error getting logs from file:', error);\n return { logs: [], total: 0, page: 0, perPage: 0, hasMore: false };\n }\n }\n\n async listLogsByRunId({\n runId,\n fromDate,\n toDate,\n logLevel,\n filters,\n page,\n perPage,\n }: {\n runId: string;\n fromDate?: Date;\n toDate?: Date;\n logLevel?: LogLevel;\n filters?: Record<string, any>;\n page?: number;\n perPage?: number;\n }): Promise<{\n logs: BaseLogMessage[];\n total: number;\n page: number;\n perPage: number;\n hasMore: boolean;\n }> {\n try {\n return await this.#queryLogs({ runId, fromDate, toDate, logLevel, filters, page, perPage });\n } catch (error) {\n console.error('Error getting logs by runId from file:', error);\n return { logs: [], total: 0, page: 0, perPage: 0, hasMore: false };\n }\n }\n\n /**\n * Streams the log file line by line, counting every matching record but\n * retaining only the requested page (or all matches when pagination is off).\n */\n async #queryLogs({\n runId,\n fromDate,\n toDate,\n logLevel,\n filters,\n returnPaginationResults = true,\n page: pageInput,\n perPage: perPageInput,\n }: {\n runId?: string;\n fromDate?: Date;\n toDate?: Date;\n logLevel?: LogLevel;\n filters?: Record<string, any>;\n returnPaginationResults?: boolean;\n page?: number;\n perPage?: number;\n }) {\n const page = pageInput === 0 ? 1 : (pageInput ?? 1);\n const perPage = (perPageInput ?? 100) || 100;\n const start = (page - 1) * perPage;\n const end = start + perPage;\n const filterEntries = Object.entries(filters ?? {});\n\n const logs: BaseLogMessage[] = [];\n let total = 0;\n\n const lines = createInterface({ input: createReadStream(this.path, 'utf8'), crlfDelay: Infinity });\n for await (const line of lines) {\n if (!line.trim()) continue;\n\n let log: any;\n try {\n log = JSON.parse(line);\n } catch {\n continue;\n }\n\n if (log === null || typeof log !== 'object') continue;\n if (runId !== undefined && log.runId !== runId) continue;\n if (!filterEntries.every(([key, value]) => log[key] === value)) continue;\n if (logLevel && log.level !== logLevel) continue;\n if (fromDate && !(new Date(log.time).getTime() >= fromDate.getTime())) continue;\n if (toDate && !(new Date(log.time).getTime() <= toDate.getTime())) continue;\n\n if (!returnPaginationResults || (total >= start && total < end)) {\n logs.push(log);\n }\n total++;\n }\n\n if (!returnPaginationResults) {\n return { logs, total, page, perPage: total, hasMore: false };\n }\n\n return { logs, total, page, perPage, hasMore: end < total };\n }\n}\n"],"mappings":"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"}
|
package/dist/http/index.cjs
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
let _mastra_core_logger = require("@mastra/core/logger");
|
|
3
3
|
//#region src/http/index.ts
|
|
4
|
+
var HttpResponseError = class extends Error {
|
|
5
|
+
status;
|
|
6
|
+
retryAfterMs;
|
|
7
|
+
constructor(status, statusText, retryAfterMs) {
|
|
8
|
+
super(`HTTP ${status}: ${statusText}`);
|
|
9
|
+
this.status = status;
|
|
10
|
+
this.retryAfterMs = retryAfterMs;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
function isRetryableStatus(status) {
|
|
14
|
+
return status === 408 || status === 425 || status === 429 || status >= 500;
|
|
15
|
+
}
|
|
16
|
+
function parseRetryAfter(headers) {
|
|
17
|
+
const value = headers?.get("retry-after")?.trim();
|
|
18
|
+
if (!value) return void 0;
|
|
19
|
+
if (/^\d+$/.test(value)) return Number(value) * 1e3;
|
|
20
|
+
const date = Date.parse(value);
|
|
21
|
+
return Number.isNaN(date) ? void 0 : Math.max(0, date - Date.now());
|
|
22
|
+
}
|
|
4
23
|
var HttpTransport = class extends _mastra_core_logger.LoggerTransport {
|
|
5
24
|
url;
|
|
6
25
|
method;
|
|
@@ -10,6 +29,10 @@ var HttpTransport = class extends _mastra_core_logger.LoggerTransport {
|
|
|
10
29
|
timeout;
|
|
11
30
|
retryOptions;
|
|
12
31
|
logBuffer;
|
|
32
|
+
maxBufferSize;
|
|
33
|
+
droppedLogCount = 0;
|
|
34
|
+
flushPromise = null;
|
|
35
|
+
flushRequested = false;
|
|
13
36
|
lastFlush;
|
|
14
37
|
flushIntervalId;
|
|
15
38
|
constructor(options) {
|
|
@@ -21,7 +44,7 @@ var HttpTransport = class extends _mastra_core_logger.LoggerTransport {
|
|
|
21
44
|
"Content-Type": "application/json",
|
|
22
45
|
...options.headers
|
|
23
46
|
};
|
|
24
|
-
this.batchSize = options.batchSize
|
|
47
|
+
this.batchSize = options.batchSize ?? 100;
|
|
25
48
|
this.flushInterval = options.flushInterval || 1e4;
|
|
26
49
|
this.timeout = options.timeout || 3e4;
|
|
27
50
|
this.retryOptions = {
|
|
@@ -29,13 +52,13 @@ var HttpTransport = class extends _mastra_core_logger.LoggerTransport {
|
|
|
29
52
|
retryDelay: options.retryOptions?.retryDelay ?? 1e3,
|
|
30
53
|
exponentialBackoff: options.retryOptions?.exponentialBackoff ?? true
|
|
31
54
|
};
|
|
55
|
+
if (!Number.isInteger(this.batchSize) || this.batchSize < 1) throw new Error("HttpTransport batchSize must be a positive integer");
|
|
56
|
+
const maxBufferSize = options.maxBufferSize ?? 1e4;
|
|
57
|
+
if (!Number.isInteger(maxBufferSize) || maxBufferSize < 1) throw new Error("HttpTransport maxBufferSize must be a positive integer");
|
|
58
|
+
this.maxBufferSize = Math.max(maxBufferSize, this.batchSize);
|
|
32
59
|
this.logBuffer = [];
|
|
33
60
|
this.lastFlush = Date.now();
|
|
34
|
-
this.flushIntervalId = setInterval(() =>
|
|
35
|
-
this._flush().catch((err) => {
|
|
36
|
-
console.error("Error flushing logs to HTTP endpoint:", err);
|
|
37
|
-
});
|
|
38
|
-
}, this.flushInterval);
|
|
61
|
+
this.flushIntervalId = setInterval(() => this.requestFlush(), this.flushInterval);
|
|
39
62
|
}
|
|
40
63
|
async makeHttpRequest(data, retryCount = 0) {
|
|
41
64
|
const controller = new AbortController();
|
|
@@ -49,27 +72,69 @@ var HttpTransport = class extends _mastra_core_logger.LoggerTransport {
|
|
|
49
72
|
signal: controller.signal
|
|
50
73
|
});
|
|
51
74
|
clearTimeout(timeoutId);
|
|
52
|
-
if (!response.ok) throw new
|
|
75
|
+
if (!response.ok) throw new HttpResponseError(response.status, response.statusText, parseRetryAfter(response.headers));
|
|
53
76
|
return response;
|
|
54
77
|
} catch (error) {
|
|
55
78
|
clearTimeout(timeoutId);
|
|
56
|
-
if (retryCount < this.retryOptions.maxRetries) {
|
|
57
|
-
const
|
|
79
|
+
if (!(error instanceof HttpResponseError && !isRetryableStatus(error.status)) && retryCount < this.retryOptions.maxRetries) {
|
|
80
|
+
const backoff = this.retryOptions.exponentialBackoff ? this.retryOptions.retryDelay * Math.pow(2, retryCount) : this.retryOptions.retryDelay;
|
|
81
|
+
const retryAfter = error instanceof HttpResponseError ? error.retryAfterMs ?? 0 : 0;
|
|
82
|
+
const delay = Math.max(backoff, Math.min(retryAfter, this.timeout));
|
|
58
83
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
59
84
|
return this.makeHttpRequest(data, retryCount + 1);
|
|
60
85
|
}
|
|
61
86
|
throw error;
|
|
62
87
|
}
|
|
63
88
|
}
|
|
64
|
-
|
|
65
|
-
|
|
89
|
+
enforceBufferLimit() {
|
|
90
|
+
const overflow = this.logBuffer.length - this.maxBufferSize;
|
|
91
|
+
if (overflow <= 0) return;
|
|
92
|
+
this.logBuffer.splice(0, overflow);
|
|
93
|
+
if (this.droppedLogCount === 0) console.warn(`HttpTransport: buffer exceeded maxBufferSize (${this.maxBufferSize}); dropping oldest logs. Use getDroppedLogCount() to track drops.`);
|
|
94
|
+
this.droppedLogCount += overflow;
|
|
95
|
+
}
|
|
96
|
+
requestFlush() {
|
|
97
|
+
if (this.flushPromise) {
|
|
98
|
+
this.flushRequested = true;
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
this._flush().catch((err) => {
|
|
102
|
+
console.error("Error flushing logs to HTTP endpoint:", err);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
_flush() {
|
|
106
|
+
if (this.flushPromise) {
|
|
107
|
+
this.flushRequested = true;
|
|
108
|
+
return this.flushPromise;
|
|
109
|
+
}
|
|
110
|
+
if (this.logBuffer.length === 0) return Promise.resolve();
|
|
111
|
+
this.flushRequested = false;
|
|
112
|
+
const flush = this.flushBatch().finally(() => {
|
|
113
|
+
this.flushPromise = null;
|
|
114
|
+
});
|
|
115
|
+
this.flushPromise = flush;
|
|
116
|
+
const continueDraining = () => {
|
|
117
|
+
if (this.logBuffer.length >= this.batchSize || this.flushRequested && this.logBuffer.length > 0) this.requestFlush();
|
|
118
|
+
};
|
|
119
|
+
flush.then(continueDraining, (error) => {
|
|
120
|
+
if (error instanceof HttpResponseError && !isRetryableStatus(error.status)) continueDraining();
|
|
121
|
+
});
|
|
122
|
+
return flush;
|
|
123
|
+
}
|
|
124
|
+
async flushBatch() {
|
|
66
125
|
const now = Date.now();
|
|
67
126
|
const logs = this.logBuffer.splice(0, this.batchSize);
|
|
68
127
|
try {
|
|
69
128
|
await this.makeHttpRequest(logs);
|
|
70
129
|
this.lastFlush = now;
|
|
71
130
|
} catch (error) {
|
|
131
|
+
if (error instanceof HttpResponseError && !isRetryableStatus(error.status)) {
|
|
132
|
+
this.droppedLogCount += logs.length;
|
|
133
|
+
console.warn(`HttpTransport: endpoint rejected a batch with HTTP ${error.status}; dropping ${logs.length} logs. Use getDroppedLogCount() to track drops.`);
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
72
136
|
this.logBuffer.unshift(...logs);
|
|
137
|
+
this.enforceBufferLimit();
|
|
73
138
|
throw error;
|
|
74
139
|
}
|
|
75
140
|
}
|
|
@@ -88,9 +153,8 @@ var HttpTransport = class extends _mastra_core_logger.LoggerTransport {
|
|
|
88
153
|
const log = typeof chunk === "string" ? JSON.parse(chunk) : chunk;
|
|
89
154
|
if (!log.time) log.time = Date.now();
|
|
90
155
|
this.logBuffer.push(log);
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
});
|
|
156
|
+
this.enforceBufferLimit();
|
|
157
|
+
if (this.logBuffer.length >= this.batchSize) this.requestFlush();
|
|
94
158
|
cb(null, chunk);
|
|
95
159
|
} catch (error) {
|
|
96
160
|
cb(error);
|
|
@@ -98,11 +162,16 @@ var HttpTransport = class extends _mastra_core_logger.LoggerTransport {
|
|
|
98
162
|
}
|
|
99
163
|
_destroy(err, cb) {
|
|
100
164
|
clearInterval(this.flushIntervalId);
|
|
101
|
-
if (this.logBuffer.length > 0
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
165
|
+
if (this.logBuffer.length > 0 || this.flushPromise) {
|
|
166
|
+
const drain = async () => {
|
|
167
|
+
await this.flushPromise?.catch(() => {});
|
|
168
|
+
while (this.flushPromise || this.logBuffer.length > 0) await (this.flushPromise ?? this._flush());
|
|
169
|
+
};
|
|
170
|
+
drain().then(() => cb(err)).catch((flushErr) => {
|
|
171
|
+
console.error("Error in final flush:", flushErr);
|
|
172
|
+
cb(err || flushErr);
|
|
173
|
+
});
|
|
174
|
+
} else cb(err);
|
|
106
175
|
}
|
|
107
176
|
async listLogs(params) {
|
|
108
177
|
console.warn("HttpTransport.listLogs: This transport is write-only. Override this method to implement log retrieval.");
|
|
@@ -130,6 +199,9 @@ var HttpTransport = class extends _mastra_core_logger.LoggerTransport {
|
|
|
130
199
|
clearBuffer() {
|
|
131
200
|
this.logBuffer = [];
|
|
132
201
|
}
|
|
202
|
+
getDroppedLogCount() {
|
|
203
|
+
return this.droppedLogCount;
|
|
204
|
+
}
|
|
133
205
|
getLastFlushTime() {
|
|
134
206
|
return this.lastFlush;
|
|
135
207
|
}
|
package/dist/http/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["LoggerTransport"],"sources":["../../src/http/index.ts"],"sourcesContent":["import { LoggerTransport } from '@mastra/core/logger';\nimport type { BaseLogMessage, LogLevel } from '@mastra/core/logger';\n\ninterface RetryOptions {\n maxRetries?: number;\n retryDelay?: number;\n exponentialBackoff?: boolean;\n}\n\ninterface HttpTransportOptions {\n url: string;\n method?: 'POST' | 'PUT' | 'PATCH';\n headers?: Record<string, string>;\n batchSize?: number;\n flushInterval?: number;\n timeout?: number;\n retryOptions?: RetryOptions;\n}\n\nexport class HttpTransport extends LoggerTransport {\n private url: string;\n private method: string;\n private headers: Record<string, string>;\n private batchSize: number;\n private flushInterval: number;\n private timeout: number;\n private retryOptions: Required<RetryOptions>;\n private logBuffer: BaseLogMessage[];\n private lastFlush: number;\n private flushIntervalId: NodeJS.Timeout;\n\n constructor(options: HttpTransportOptions) {\n super({ objectMode: true });\n\n if (!options.url) {\n throw new Error('HTTP URL is required');\n }\n\n this.url = options.url;\n this.method = options.method || 'POST';\n this.headers = {\n 'Content-Type': 'application/json',\n ...options.headers,\n };\n this.batchSize = options.batchSize || 100;\n this.flushInterval = options.flushInterval || 10000;\n this.timeout = options.timeout || 30000;\n this.retryOptions = {\n maxRetries: options.retryOptions?.maxRetries ?? 3,\n retryDelay: options.retryOptions?.retryDelay ?? 1000,\n exponentialBackoff: options.retryOptions?.exponentialBackoff ?? true,\n };\n\n this.logBuffer = [];\n this.lastFlush = Date.now();\n\n // Start flush interval\n this.flushIntervalId = setInterval(() => {\n this._flush().catch(err => {\n console.error('Error flushing logs to HTTP endpoint:', err);\n });\n }, this.flushInterval);\n }\n\n private async makeHttpRequest(data: any, retryCount = 0): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const body = JSON.stringify({ logs: data });\n\n const response = await fetch(this.url, {\n method: this.method,\n headers: this.headers,\n body,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n return response;\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (retryCount < this.retryOptions.maxRetries) {\n const delay = this.retryOptions.exponentialBackoff\n ? this.retryOptions.retryDelay * Math.pow(2, retryCount)\n : this.retryOptions.retryDelay;\n\n await new Promise(resolve => setTimeout(resolve, delay));\n return this.makeHttpRequest(data, retryCount + 1);\n }\n\n throw error;\n }\n }\n\n async _flush(): Promise<void> {\n if (this.logBuffer.length === 0) {\n return;\n }\n\n const now = Date.now();\n const logs = this.logBuffer.splice(0, this.batchSize);\n\n try {\n await this.makeHttpRequest(logs);\n this.lastFlush = now;\n } catch (error) {\n // On error, put logs back in the buffer\n this.logBuffer.unshift(...logs);\n throw error;\n }\n }\n\n _write(chunk: any, encoding?: string, callback?: (error?: Error | null) => void): boolean {\n if (typeof callback === 'function') {\n this._transform(chunk, encoding || 'utf8', callback);\n return true;\n }\n\n this._transform(chunk, encoding || 'utf8', (error: Error | null) => {\n if (error) console.error('Transform error in write:', error);\n });\n return true;\n }\n\n _transform(chunk: string, _enc: string, cb: Function): void {\n try {\n // Parse the log line if it's a string\n const log = typeof chunk === 'string' ? JSON.parse(chunk) : chunk;\n\n // Add timestamp if not present\n if (!log.time) {\n log.time = Date.now();\n }\n\n // Add to buffer\n this.logBuffer.push(log);\n\n // Flush if buffer reaches batch size\n if (this.logBuffer.length >= this.batchSize) {\n this._flush().catch(err => {\n console.error('Error flushing logs to HTTP endpoint:', err);\n });\n }\n\n // Pass through the log\n cb(null, chunk);\n } catch (error) {\n cb(error);\n }\n }\n\n _destroy(err: Error, cb: Function): void {\n clearInterval(this.flushIntervalId);\n\n // Final flush\n if (this.logBuffer.length > 0) {\n this._flush()\n .then(() => cb(err))\n .catch(flushErr => {\n console.error('Error in final flush:', flushErr);\n cb(err || flushErr);\n });\n } else {\n cb(err);\n }\n }\n\n async listLogs(params?: {\n fromDate?: Date;\n toDate?: Date;\n logLevel?: LogLevel;\n filters?: Record<string, any>;\n returnPaginationResults?: boolean;\n page?: number;\n perPage?: number;\n }): Promise<{\n logs: BaseLogMessage[];\n total: number;\n page: number;\n perPage: number;\n hasMore: boolean;\n }> {\n // HttpTransport is write-only by default\n // Subclasses can override this method to implement log retrieval\n console.warn(\n 'HttpTransport.listLogs: This transport is write-only. Override this method to implement log retrieval.',\n );\n\n return {\n logs: [],\n total: 0,\n page: params?.page ?? 1,\n perPage: params?.perPage ?? 100,\n hasMore: false,\n };\n }\n\n async listLogsByRunId({\n runId: _runId,\n fromDate: _fromDate,\n toDate: _toDate,\n logLevel: _logLevel,\n filters: _filters,\n page,\n perPage,\n }: {\n runId: string;\n fromDate?: Date;\n toDate?: Date;\n logLevel?: LogLevel;\n filters?: Record<string, any>;\n page?: number;\n perPage?: number;\n }): Promise<{\n logs: BaseLogMessage[];\n total: number;\n page: number;\n perPage: number;\n hasMore: boolean;\n }> {\n // HttpTransport is write-only by default\n // Subclasses can override this method to implement log retrieval\n console.warn(\n 'HttpTransport.listLogsByRunId: This transport is write-only. Override this method to implement log retrieval.',\n );\n\n return {\n logs: [],\n total: 0,\n page: page ?? 1,\n perPage: perPage ?? 100,\n hasMore: false,\n };\n }\n\n // Utility methods\n public getBufferedLogs(): BaseLogMessage[] {\n return [...this.logBuffer];\n }\n\n public clearBuffer(): void {\n this.logBuffer = [];\n }\n\n public getLastFlushTime(): number {\n return this.lastFlush;\n }\n}\n"],"mappings":";;;AAmBA,IAAa,gBAAb,cAAmCA,oBAAAA,gBAAgB;CACjD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA,YAAY,SAA+B;EACzC,MAAM,EAAE,YAAY,KAAK,CAAC;EAE1B,IAAI,CAAC,QAAQ,KACX,MAAM,IAAI,MAAM,sBAAsB;EAGxC,KAAK,MAAM,QAAQ;EACnB,KAAK,SAAS,QAAQ,UAAU;EAChC,KAAK,UAAU;GACb,gBAAgB;GAChB,GAAG,QAAQ;EACb;EACA,KAAK,YAAY,QAAQ,aAAa;EACtC,KAAK,gBAAgB,QAAQ,iBAAiB;EAC9C,KAAK,UAAU,QAAQ,WAAW;EAClC,KAAK,eAAe;GAClB,YAAY,QAAQ,cAAc,cAAc;GAChD,YAAY,QAAQ,cAAc,cAAc;GAChD,oBAAoB,QAAQ,cAAc,sBAAsB;EAClE;EAEA,KAAK,YAAY,CAAC;EAClB,KAAK,YAAY,KAAK,IAAI;EAG1B,KAAK,kBAAkB,kBAAkB;GACvC,KAAK,OAAO,CAAC,CAAC,OAAM,QAAO;IACzB,QAAQ,MAAM,yCAAyC,GAAG;GAC5D,CAAC;EACH,GAAG,KAAK,aAAa;CACvB;CAEA,MAAc,gBAAgB,MAAW,aAAa,GAAsB;EAC1E,MAAM,aAAa,IAAI,gBAAgB;EACvC,MAAM,YAAY,iBAAiB,WAAW,MAAM,GAAG,KAAK,OAAO;EAEnE,IAAI;GACF,MAAM,OAAO,KAAK,UAAU,EAAE,MAAM,KAAK,CAAC;GAE1C,MAAM,WAAW,MAAM,MAAM,KAAK,KAAK;IACrC,QAAQ,KAAK;IACb,SAAS,KAAK;IACd;IACA,QAAQ,WAAW;GACrB,CAAC;GAED,aAAa,SAAS;GAEtB,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,QAAQ,SAAS,OAAO,IAAI,SAAS,YAAY;GAGnE,OAAO;EACT,SAAS,OAAO;GACd,aAAa,SAAS;GAEtB,IAAI,aAAa,KAAK,aAAa,YAAY;IAC7C,MAAM,QAAQ,KAAK,aAAa,qBAC5B,KAAK,aAAa,aAAa,KAAK,IAAI,GAAG,UAAU,IACrD,KAAK,aAAa;IAEtB,MAAM,IAAI,SAAQ,YAAW,WAAW,SAAS,KAAK,CAAC;IACvD,OAAO,KAAK,gBAAgB,MAAM,aAAa,CAAC;GAClD;GAEA,MAAM;EACR;CACF;CAEA,MAAM,SAAwB;EAC5B,IAAI,KAAK,UAAU,WAAW,GAC5B;EAGF,MAAM,MAAM,KAAK,IAAI;EACrB,MAAM,OAAO,KAAK,UAAU,OAAO,GAAG,KAAK,SAAS;EAEpD,IAAI;GACF,MAAM,KAAK,gBAAgB,IAAI;GAC/B,KAAK,YAAY;EACnB,SAAS,OAAO;GAEd,KAAK,UAAU,QAAQ,GAAG,IAAI;GAC9B,MAAM;EACR;CACF;CAEA,OAAO,OAAY,UAAmB,UAAoD;EACxF,IAAI,OAAO,aAAa,YAAY;GAClC,KAAK,WAAW,OAAO,YAAY,QAAQ,QAAQ;GACnD,OAAO;EACT;EAEA,KAAK,WAAW,OAAO,YAAY,SAAS,UAAwB;GAClE,IAAI,OAAO,QAAQ,MAAM,6BAA6B,KAAK;EAC7D,CAAC;EACD,OAAO;CACT;CAEA,WAAW,OAAe,MAAc,IAAoB;EAC1D,IAAI;GAEF,MAAM,MAAM,OAAO,UAAU,WAAW,KAAK,MAAM,KAAK,IAAI;GAG5D,IAAI,CAAC,IAAI,MACP,IAAI,OAAO,KAAK,IAAI;GAItB,KAAK,UAAU,KAAK,GAAG;GAGvB,IAAI,KAAK,UAAU,UAAU,KAAK,WAChC,KAAK,OAAO,CAAC,CAAC,OAAM,QAAO;IACzB,QAAQ,MAAM,yCAAyC,GAAG;GAC5D,CAAC;GAIH,GAAG,MAAM,KAAK;EAChB,SAAS,OAAO;GACd,GAAG,KAAK;EACV;CACF;CAEA,SAAS,KAAY,IAAoB;EACvC,cAAc,KAAK,eAAe;EAGlC,IAAI,KAAK,UAAU,SAAS,GAC1B,KAAK,OAAO,CAAC,CACV,WAAW,GAAG,GAAG,CAAC,CAAC,CACnB,OAAM,aAAY;GACjB,QAAQ,MAAM,yBAAyB,QAAQ;GAC/C,GAAG,OAAO,QAAQ;EACpB,CAAC;OAEH,GAAG,GAAG;CAEV;CAEA,MAAM,SAAS,QAcZ;EAGD,QAAQ,KACN,wGACF;EAEA,OAAO;GACL,MAAM,CAAC;GACP,OAAO;GACP,MAAM,QAAQ,QAAQ;GACtB,SAAS,QAAQ,WAAW;GAC5B,SAAS;EACX;CACF;CAEA,MAAM,gBAAgB,EACpB,OAAO,QACP,UAAU,WACV,QAAQ,SACR,UAAU,WACV,SAAS,UACT,MACA,WAeC;EAGD,QAAQ,KACN,+GACF;EAEA,OAAO;GACL,MAAM,CAAC;GACP,OAAO;GACP,MAAM,QAAQ;GACd,SAAS,WAAW;GACpB,SAAS;EACX;CACF;CAGA,kBAA2C;EACzC,OAAO,CAAC,GAAG,KAAK,SAAS;CAC3B;CAEA,cAA2B;EACzB,KAAK,YAAY,CAAC;CACpB;CAEA,mBAAkC;EAChC,OAAO,KAAK;CACd;AACF"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["LoggerTransport"],"sources":["../../src/http/index.ts"],"sourcesContent":["import { LoggerTransport } from '@mastra/core/logger';\nimport type { BaseLogMessage, LogLevel } from '@mastra/core/logger';\n\ninterface RetryOptions {\n maxRetries?: number;\n retryDelay?: number;\n exponentialBackoff?: boolean;\n}\n\ninterface HttpTransportOptions {\n url: string;\n method?: 'POST' | 'PUT' | 'PATCH';\n headers?: Record<string, string>;\n batchSize?: number;\n flushInterval?: number;\n timeout?: number;\n retryOptions?: RetryOptions;\n maxBufferSize?: number;\n}\n\nclass HttpResponseError extends Error {\n constructor(\n readonly status: number,\n statusText: string,\n readonly retryAfterMs: number | undefined,\n ) {\n super(`HTTP ${status}: ${statusText}`);\n }\n}\n\n// Other 4xx responses mean the request itself is wrong and will fail the same way on every retry.\nfunction isRetryableStatus(status: number): boolean {\n return status === 408 || status === 425 || status === 429 || status >= 500;\n}\n\n// Retry-After is either delta-seconds or an HTTP date (RFC 9110). Invalid values are ignored.\nfunction parseRetryAfter(headers: Headers | undefined): number | undefined {\n const value = headers?.get('retry-after')?.trim();\n if (!value) return undefined;\n if (/^\\d+$/.test(value)) return Number(value) * 1000;\n const date = Date.parse(value);\n return Number.isNaN(date) ? undefined : Math.max(0, date - Date.now());\n}\n\nexport class HttpTransport extends LoggerTransport {\n private url: string;\n private method: string;\n private headers: Record<string, string>;\n private batchSize: number;\n private flushInterval: number;\n private timeout: number;\n private retryOptions: Required<RetryOptions>;\n private logBuffer: BaseLogMessage[];\n private maxBufferSize: number;\n private droppedLogCount = 0;\n private flushPromise: Promise<void> | null = null;\n private flushRequested = false;\n private lastFlush: number;\n private flushIntervalId: NodeJS.Timeout;\n\n constructor(options: HttpTransportOptions) {\n super({ objectMode: true });\n\n if (!options.url) {\n throw new Error('HTTP URL is required');\n }\n\n this.url = options.url;\n this.method = options.method || 'POST';\n this.headers = {\n 'Content-Type': 'application/json',\n ...options.headers,\n };\n this.batchSize = options.batchSize ?? 100;\n this.flushInterval = options.flushInterval || 10000;\n this.timeout = options.timeout || 30000;\n this.retryOptions = {\n maxRetries: options.retryOptions?.maxRetries ?? 3,\n retryDelay: options.retryOptions?.retryDelay ?? 1000,\n exponentialBackoff: options.retryOptions?.exponentialBackoff ?? true,\n };\n\n if (!Number.isInteger(this.batchSize) || this.batchSize < 1) {\n throw new Error('HttpTransport batchSize must be a positive integer');\n }\n\n const maxBufferSize = options.maxBufferSize ?? 10_000;\n if (!Number.isInteger(maxBufferSize) || maxBufferSize < 1) {\n throw new Error('HttpTransport maxBufferSize must be a positive integer');\n }\n this.maxBufferSize = Math.max(maxBufferSize, this.batchSize);\n this.logBuffer = [];\n this.lastFlush = Date.now();\n\n // Start flush interval\n this.flushIntervalId = setInterval(() => this.requestFlush(), this.flushInterval);\n }\n\n private async makeHttpRequest(data: any, retryCount = 0): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const body = JSON.stringify({ logs: data });\n\n const response = await fetch(this.url, {\n method: this.method,\n headers: this.headers,\n body,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n throw new HttpResponseError(response.status, response.statusText, parseRetryAfter(response.headers));\n }\n\n return response;\n } catch (error) {\n clearTimeout(timeoutId);\n\n const isPermanent = error instanceof HttpResponseError && !isRetryableStatus(error.status);\n if (!isPermanent && retryCount < this.retryOptions.maxRetries) {\n const backoff = this.retryOptions.exponentialBackoff\n ? this.retryOptions.retryDelay * Math.pow(2, retryCount)\n : this.retryOptions.retryDelay;\n // Honor the server's Retry-After, capped at the request timeout so a large value can't stall shutdown.\n const retryAfter = error instanceof HttpResponseError ? (error.retryAfterMs ?? 0) : 0;\n const delay = Math.max(backoff, Math.min(retryAfter, this.timeout));\n\n await new Promise(resolve => setTimeout(resolve, delay));\n return this.makeHttpRequest(data, retryCount + 1);\n }\n\n throw error;\n }\n }\n\n private enforceBufferLimit(): void {\n const overflow = this.logBuffer.length - this.maxBufferSize;\n if (overflow <= 0) {\n return;\n }\n\n this.logBuffer.splice(0, overflow);\n if (this.droppedLogCount === 0) {\n console.warn(\n `HttpTransport: buffer exceeded maxBufferSize (${this.maxBufferSize}); dropping oldest logs. Use getDroppedLogCount() to track drops.`,\n );\n }\n this.droppedLogCount += overflow;\n }\n\n // Internal fire-and-forget flush. While a request is in flight this only records the request, so writes\n // during a slow or retrying request don't each attach another handler to the pending promise.\n private requestFlush(): void {\n if (this.flushPromise) {\n this.flushRequested = true;\n return;\n }\n this._flush().catch(err => {\n console.error('Error flushing logs to HTTP endpoint:', err);\n });\n }\n\n _flush(): Promise<void> {\n // Only one request in flight at a time, so an outage doesn't fan out into overlapping retry chains.\n if (this.flushPromise) {\n this.flushRequested = true;\n return this.flushPromise;\n }\n if (this.logBuffer.length === 0) {\n return Promise.resolve();\n }\n\n this.flushRequested = false;\n const flush = this.flushBatch().finally(() => {\n this.flushPromise = null;\n });\n this.flushPromise = flush;\n // Flushes requested while this request was in flight only got this promise back, so send their logs now,\n // and keep draining full batches. On a transient failure, wait for the next interval instead of retrying\n // straight away. A permanently rejected batch was dropped, so the logs behind it can go out now.\n const continueDraining = () => {\n if (this.logBuffer.length >= this.batchSize || (this.flushRequested && this.logBuffer.length > 0)) {\n this.requestFlush();\n }\n };\n flush.then(continueDraining, error => {\n if (error instanceof HttpResponseError && !isRetryableStatus(error.status)) {\n continueDraining();\n }\n });\n return flush;\n }\n\n private async flushBatch(): Promise<void> {\n const now = Date.now();\n const logs = this.logBuffer.splice(0, this.batchSize);\n\n try {\n await this.makeHttpRequest(logs);\n this.lastFlush = now;\n } catch (error) {\n // The endpoint rejected this batch outright, so resending it can't succeed and would block the logs behind it.\n if (error instanceof HttpResponseError && !isRetryableStatus(error.status)) {\n this.droppedLogCount += logs.length;\n console.warn(\n `HttpTransport: endpoint rejected a batch with HTTP ${error.status}; dropping ${logs.length} logs. Use getDroppedLogCount() to track drops.`,\n );\n throw error;\n }\n\n // On a transient error, put logs back in the buffer\n this.logBuffer.unshift(...logs);\n this.enforceBufferLimit();\n throw error;\n }\n }\n\n _write(chunk: any, encoding?: string, callback?: (error?: Error | null) => void): boolean {\n if (typeof callback === 'function') {\n this._transform(chunk, encoding || 'utf8', callback);\n return true;\n }\n\n this._transform(chunk, encoding || 'utf8', (error: Error | null) => {\n if (error) console.error('Transform error in write:', error);\n });\n return true;\n }\n\n _transform(chunk: string, _enc: string, cb: Function): void {\n try {\n // Parse the log line if it's a string\n const log = typeof chunk === 'string' ? JSON.parse(chunk) : chunk;\n\n // Add timestamp if not present\n if (!log.time) {\n log.time = Date.now();\n }\n\n // Add to buffer\n this.logBuffer.push(log);\n this.enforceBufferLimit();\n\n // Flush if buffer reaches batch size\n if (this.logBuffer.length >= this.batchSize) {\n this.requestFlush();\n }\n\n // Pass through the log\n cb(null, chunk);\n } catch (error) {\n cb(error);\n }\n }\n\n _destroy(err: Error, cb: Function): void {\n clearInterval(this.flushIntervalId);\n\n // Final drain. Wait out any in-flight request (ignoring its failure, since its logs are back in the buffer),\n // then keep sending until the buffer is empty. A failed request ends the drain instead of retrying forever.\n if (this.logBuffer.length > 0 || this.flushPromise) {\n const drain = async () => {\n await this.flushPromise?.catch(() => {});\n while (this.flushPromise || this.logBuffer.length > 0) {\n await (this.flushPromise ?? this._flush());\n }\n };\n\n drain()\n .then(() => cb(err))\n .catch(flushErr => {\n console.error('Error in final flush:', flushErr);\n cb(err || flushErr);\n });\n } else {\n cb(err);\n }\n }\n\n async listLogs(params?: {\n fromDate?: Date;\n toDate?: Date;\n logLevel?: LogLevel;\n filters?: Record<string, any>;\n returnPaginationResults?: boolean;\n page?: number;\n perPage?: number;\n }): Promise<{\n logs: BaseLogMessage[];\n total: number;\n page: number;\n perPage: number;\n hasMore: boolean;\n }> {\n // HttpTransport is write-only by default\n // Subclasses can override this method to implement log retrieval\n console.warn(\n 'HttpTransport.listLogs: This transport is write-only. Override this method to implement log retrieval.',\n );\n\n return {\n logs: [],\n total: 0,\n page: params?.page ?? 1,\n perPage: params?.perPage ?? 100,\n hasMore: false,\n };\n }\n\n async listLogsByRunId({\n runId: _runId,\n fromDate: _fromDate,\n toDate: _toDate,\n logLevel: _logLevel,\n filters: _filters,\n page,\n perPage,\n }: {\n runId: string;\n fromDate?: Date;\n toDate?: Date;\n logLevel?: LogLevel;\n filters?: Record<string, any>;\n page?: number;\n perPage?: number;\n }): Promise<{\n logs: BaseLogMessage[];\n total: number;\n page: number;\n perPage: number;\n hasMore: boolean;\n }> {\n // HttpTransport is write-only by default\n // Subclasses can override this method to implement log retrieval\n console.warn(\n 'HttpTransport.listLogsByRunId: This transport is write-only. Override this method to implement log retrieval.',\n );\n\n return {\n logs: [],\n total: 0,\n page: page ?? 1,\n perPage: perPage ?? 100,\n hasMore: false,\n };\n }\n\n // Utility methods\n public getBufferedLogs(): BaseLogMessage[] {\n return [...this.logBuffer];\n }\n\n public clearBuffer(): void {\n this.logBuffer = [];\n }\n\n public getDroppedLogCount(): number {\n return this.droppedLogCount;\n }\n\n public getLastFlushTime(): number {\n return this.lastFlush;\n }\n}\n"],"mappings":"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"}
|
package/dist/http/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ interface HttpTransportOptions {
|
|
|
13
13
|
flushInterval?: number;
|
|
14
14
|
timeout?: number;
|
|
15
15
|
retryOptions?: RetryOptions;
|
|
16
|
+
maxBufferSize?: number;
|
|
16
17
|
}
|
|
17
18
|
export declare class HttpTransport extends LoggerTransport {
|
|
18
19
|
private url;
|
|
@@ -23,11 +24,18 @@ export declare class HttpTransport extends LoggerTransport {
|
|
|
23
24
|
private timeout;
|
|
24
25
|
private retryOptions;
|
|
25
26
|
private logBuffer;
|
|
27
|
+
private maxBufferSize;
|
|
28
|
+
private droppedLogCount;
|
|
29
|
+
private flushPromise;
|
|
30
|
+
private flushRequested;
|
|
26
31
|
private lastFlush;
|
|
27
32
|
private flushIntervalId;
|
|
28
33
|
constructor(options: HttpTransportOptions);
|
|
29
34
|
private makeHttpRequest;
|
|
35
|
+
private enforceBufferLimit;
|
|
36
|
+
private requestFlush;
|
|
30
37
|
_flush(): Promise<void>;
|
|
38
|
+
private flushBatch;
|
|
31
39
|
_write(chunk: any, encoding?: string, callback?: (error?: Error | null) => void): boolean;
|
|
32
40
|
_transform(chunk: string, _enc: string, cb: Function): void;
|
|
33
41
|
_destroy(err: Error, cb: Function): void;
|
|
@@ -63,6 +71,7 @@ export declare class HttpTransport extends LoggerTransport {
|
|
|
63
71
|
}>;
|
|
64
72
|
getBufferedLogs(): BaseLogMessage[];
|
|
65
73
|
clearBuffer(): void;
|
|
74
|
+
getDroppedLogCount(): number;
|
|
66
75
|
getLastFlushTime(): number;
|
|
67
76
|
}
|
|
68
77
|
export {};
|
package/dist/http/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpE,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,UAAU,oBAAoB;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,OAAO,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":"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"}
|
package/dist/http/index.js
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
import { LoggerTransport } from "@mastra/core/logger";
|
|
2
2
|
//#region src/http/index.ts
|
|
3
|
+
var HttpResponseError = class extends Error {
|
|
4
|
+
status;
|
|
5
|
+
retryAfterMs;
|
|
6
|
+
constructor(status, statusText, retryAfterMs) {
|
|
7
|
+
super(`HTTP ${status}: ${statusText}`);
|
|
8
|
+
this.status = status;
|
|
9
|
+
this.retryAfterMs = retryAfterMs;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
function isRetryableStatus(status) {
|
|
13
|
+
return status === 408 || status === 425 || status === 429 || status >= 500;
|
|
14
|
+
}
|
|
15
|
+
function parseRetryAfter(headers) {
|
|
16
|
+
const value = headers?.get("retry-after")?.trim();
|
|
17
|
+
if (!value) return void 0;
|
|
18
|
+
if (/^\d+$/.test(value)) return Number(value) * 1e3;
|
|
19
|
+
const date = Date.parse(value);
|
|
20
|
+
return Number.isNaN(date) ? void 0 : Math.max(0, date - Date.now());
|
|
21
|
+
}
|
|
3
22
|
var HttpTransport = class extends LoggerTransport {
|
|
4
23
|
url;
|
|
5
24
|
method;
|
|
@@ -9,6 +28,10 @@ var HttpTransport = class extends LoggerTransport {
|
|
|
9
28
|
timeout;
|
|
10
29
|
retryOptions;
|
|
11
30
|
logBuffer;
|
|
31
|
+
maxBufferSize;
|
|
32
|
+
droppedLogCount = 0;
|
|
33
|
+
flushPromise = null;
|
|
34
|
+
flushRequested = false;
|
|
12
35
|
lastFlush;
|
|
13
36
|
flushIntervalId;
|
|
14
37
|
constructor(options) {
|
|
@@ -20,7 +43,7 @@ var HttpTransport = class extends LoggerTransport {
|
|
|
20
43
|
"Content-Type": "application/json",
|
|
21
44
|
...options.headers
|
|
22
45
|
};
|
|
23
|
-
this.batchSize = options.batchSize
|
|
46
|
+
this.batchSize = options.batchSize ?? 100;
|
|
24
47
|
this.flushInterval = options.flushInterval || 1e4;
|
|
25
48
|
this.timeout = options.timeout || 3e4;
|
|
26
49
|
this.retryOptions = {
|
|
@@ -28,13 +51,13 @@ var HttpTransport = class extends LoggerTransport {
|
|
|
28
51
|
retryDelay: options.retryOptions?.retryDelay ?? 1e3,
|
|
29
52
|
exponentialBackoff: options.retryOptions?.exponentialBackoff ?? true
|
|
30
53
|
};
|
|
54
|
+
if (!Number.isInteger(this.batchSize) || this.batchSize < 1) throw new Error("HttpTransport batchSize must be a positive integer");
|
|
55
|
+
const maxBufferSize = options.maxBufferSize ?? 1e4;
|
|
56
|
+
if (!Number.isInteger(maxBufferSize) || maxBufferSize < 1) throw new Error("HttpTransport maxBufferSize must be a positive integer");
|
|
57
|
+
this.maxBufferSize = Math.max(maxBufferSize, this.batchSize);
|
|
31
58
|
this.logBuffer = [];
|
|
32
59
|
this.lastFlush = Date.now();
|
|
33
|
-
this.flushIntervalId = setInterval(() =>
|
|
34
|
-
this._flush().catch((err) => {
|
|
35
|
-
console.error("Error flushing logs to HTTP endpoint:", err);
|
|
36
|
-
});
|
|
37
|
-
}, this.flushInterval);
|
|
60
|
+
this.flushIntervalId = setInterval(() => this.requestFlush(), this.flushInterval);
|
|
38
61
|
}
|
|
39
62
|
async makeHttpRequest(data, retryCount = 0) {
|
|
40
63
|
const controller = new AbortController();
|
|
@@ -48,27 +71,69 @@ var HttpTransport = class extends LoggerTransport {
|
|
|
48
71
|
signal: controller.signal
|
|
49
72
|
});
|
|
50
73
|
clearTimeout(timeoutId);
|
|
51
|
-
if (!response.ok) throw new
|
|
74
|
+
if (!response.ok) throw new HttpResponseError(response.status, response.statusText, parseRetryAfter(response.headers));
|
|
52
75
|
return response;
|
|
53
76
|
} catch (error) {
|
|
54
77
|
clearTimeout(timeoutId);
|
|
55
|
-
if (retryCount < this.retryOptions.maxRetries) {
|
|
56
|
-
const
|
|
78
|
+
if (!(error instanceof HttpResponseError && !isRetryableStatus(error.status)) && retryCount < this.retryOptions.maxRetries) {
|
|
79
|
+
const backoff = this.retryOptions.exponentialBackoff ? this.retryOptions.retryDelay * Math.pow(2, retryCount) : this.retryOptions.retryDelay;
|
|
80
|
+
const retryAfter = error instanceof HttpResponseError ? error.retryAfterMs ?? 0 : 0;
|
|
81
|
+
const delay = Math.max(backoff, Math.min(retryAfter, this.timeout));
|
|
57
82
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
58
83
|
return this.makeHttpRequest(data, retryCount + 1);
|
|
59
84
|
}
|
|
60
85
|
throw error;
|
|
61
86
|
}
|
|
62
87
|
}
|
|
63
|
-
|
|
64
|
-
|
|
88
|
+
enforceBufferLimit() {
|
|
89
|
+
const overflow = this.logBuffer.length - this.maxBufferSize;
|
|
90
|
+
if (overflow <= 0) return;
|
|
91
|
+
this.logBuffer.splice(0, overflow);
|
|
92
|
+
if (this.droppedLogCount === 0) console.warn(`HttpTransport: buffer exceeded maxBufferSize (${this.maxBufferSize}); dropping oldest logs. Use getDroppedLogCount() to track drops.`);
|
|
93
|
+
this.droppedLogCount += overflow;
|
|
94
|
+
}
|
|
95
|
+
requestFlush() {
|
|
96
|
+
if (this.flushPromise) {
|
|
97
|
+
this.flushRequested = true;
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
this._flush().catch((err) => {
|
|
101
|
+
console.error("Error flushing logs to HTTP endpoint:", err);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
_flush() {
|
|
105
|
+
if (this.flushPromise) {
|
|
106
|
+
this.flushRequested = true;
|
|
107
|
+
return this.flushPromise;
|
|
108
|
+
}
|
|
109
|
+
if (this.logBuffer.length === 0) return Promise.resolve();
|
|
110
|
+
this.flushRequested = false;
|
|
111
|
+
const flush = this.flushBatch().finally(() => {
|
|
112
|
+
this.flushPromise = null;
|
|
113
|
+
});
|
|
114
|
+
this.flushPromise = flush;
|
|
115
|
+
const continueDraining = () => {
|
|
116
|
+
if (this.logBuffer.length >= this.batchSize || this.flushRequested && this.logBuffer.length > 0) this.requestFlush();
|
|
117
|
+
};
|
|
118
|
+
flush.then(continueDraining, (error) => {
|
|
119
|
+
if (error instanceof HttpResponseError && !isRetryableStatus(error.status)) continueDraining();
|
|
120
|
+
});
|
|
121
|
+
return flush;
|
|
122
|
+
}
|
|
123
|
+
async flushBatch() {
|
|
65
124
|
const now = Date.now();
|
|
66
125
|
const logs = this.logBuffer.splice(0, this.batchSize);
|
|
67
126
|
try {
|
|
68
127
|
await this.makeHttpRequest(logs);
|
|
69
128
|
this.lastFlush = now;
|
|
70
129
|
} catch (error) {
|
|
130
|
+
if (error instanceof HttpResponseError && !isRetryableStatus(error.status)) {
|
|
131
|
+
this.droppedLogCount += logs.length;
|
|
132
|
+
console.warn(`HttpTransport: endpoint rejected a batch with HTTP ${error.status}; dropping ${logs.length} logs. Use getDroppedLogCount() to track drops.`);
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
71
135
|
this.logBuffer.unshift(...logs);
|
|
136
|
+
this.enforceBufferLimit();
|
|
72
137
|
throw error;
|
|
73
138
|
}
|
|
74
139
|
}
|
|
@@ -87,9 +152,8 @@ var HttpTransport = class extends LoggerTransport {
|
|
|
87
152
|
const log = typeof chunk === "string" ? JSON.parse(chunk) : chunk;
|
|
88
153
|
if (!log.time) log.time = Date.now();
|
|
89
154
|
this.logBuffer.push(log);
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
});
|
|
155
|
+
this.enforceBufferLimit();
|
|
156
|
+
if (this.logBuffer.length >= this.batchSize) this.requestFlush();
|
|
93
157
|
cb(null, chunk);
|
|
94
158
|
} catch (error) {
|
|
95
159
|
cb(error);
|
|
@@ -97,11 +161,16 @@ var HttpTransport = class extends LoggerTransport {
|
|
|
97
161
|
}
|
|
98
162
|
_destroy(err, cb) {
|
|
99
163
|
clearInterval(this.flushIntervalId);
|
|
100
|
-
if (this.logBuffer.length > 0
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
164
|
+
if (this.logBuffer.length > 0 || this.flushPromise) {
|
|
165
|
+
const drain = async () => {
|
|
166
|
+
await this.flushPromise?.catch(() => {});
|
|
167
|
+
while (this.flushPromise || this.logBuffer.length > 0) await (this.flushPromise ?? this._flush());
|
|
168
|
+
};
|
|
169
|
+
drain().then(() => cb(err)).catch((flushErr) => {
|
|
170
|
+
console.error("Error in final flush:", flushErr);
|
|
171
|
+
cb(err || flushErr);
|
|
172
|
+
});
|
|
173
|
+
} else cb(err);
|
|
105
174
|
}
|
|
106
175
|
async listLogs(params) {
|
|
107
176
|
console.warn("HttpTransport.listLogs: This transport is write-only. Override this method to implement log retrieval.");
|
|
@@ -129,6 +198,9 @@ var HttpTransport = class extends LoggerTransport {
|
|
|
129
198
|
clearBuffer() {
|
|
130
199
|
this.logBuffer = [];
|
|
131
200
|
}
|
|
201
|
+
getDroppedLogCount() {
|
|
202
|
+
return this.droppedLogCount;
|
|
203
|
+
}
|
|
132
204
|
getLastFlushTime() {
|
|
133
205
|
return this.lastFlush;
|
|
134
206
|
}
|
package/dist/http/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/http/index.ts"],"sourcesContent":["import { LoggerTransport } from '@mastra/core/logger';\nimport type { BaseLogMessage, LogLevel } from '@mastra/core/logger';\n\ninterface RetryOptions {\n maxRetries?: number;\n retryDelay?: number;\n exponentialBackoff?: boolean;\n}\n\ninterface HttpTransportOptions {\n url: string;\n method?: 'POST' | 'PUT' | 'PATCH';\n headers?: Record<string, string>;\n batchSize?: number;\n flushInterval?: number;\n timeout?: number;\n retryOptions?: RetryOptions;\n}\n\nexport class HttpTransport extends LoggerTransport {\n private url: string;\n private method: string;\n private headers: Record<string, string>;\n private batchSize: number;\n private flushInterval: number;\n private timeout: number;\n private retryOptions: Required<RetryOptions>;\n private logBuffer: BaseLogMessage[];\n private lastFlush: number;\n private flushIntervalId: NodeJS.Timeout;\n\n constructor(options: HttpTransportOptions) {\n super({ objectMode: true });\n\n if (!options.url) {\n throw new Error('HTTP URL is required');\n }\n\n this.url = options.url;\n this.method = options.method || 'POST';\n this.headers = {\n 'Content-Type': 'application/json',\n ...options.headers,\n };\n this.batchSize = options.batchSize || 100;\n this.flushInterval = options.flushInterval || 10000;\n this.timeout = options.timeout || 30000;\n this.retryOptions = {\n maxRetries: options.retryOptions?.maxRetries ?? 3,\n retryDelay: options.retryOptions?.retryDelay ?? 1000,\n exponentialBackoff: options.retryOptions?.exponentialBackoff ?? true,\n };\n\n this.logBuffer = [];\n this.lastFlush = Date.now();\n\n // Start flush interval\n this.flushIntervalId = setInterval(() => {\n this._flush().catch(err => {\n console.error('Error flushing logs to HTTP endpoint:', err);\n });\n }, this.flushInterval);\n }\n\n private async makeHttpRequest(data: any, retryCount = 0): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const body = JSON.stringify({ logs: data });\n\n const response = await fetch(this.url, {\n method: this.method,\n headers: this.headers,\n body,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n return response;\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (retryCount < this.retryOptions.maxRetries) {\n const delay = this.retryOptions.exponentialBackoff\n ? this.retryOptions.retryDelay * Math.pow(2, retryCount)\n : this.retryOptions.retryDelay;\n\n await new Promise(resolve => setTimeout(resolve, delay));\n return this.makeHttpRequest(data, retryCount + 1);\n }\n\n throw error;\n }\n }\n\n async _flush(): Promise<void> {\n if (this.logBuffer.length === 0) {\n return;\n }\n\n const now = Date.now();\n const logs = this.logBuffer.splice(0, this.batchSize);\n\n try {\n await this.makeHttpRequest(logs);\n this.lastFlush = now;\n } catch (error) {\n // On error, put logs back in the buffer\n this.logBuffer.unshift(...logs);\n throw error;\n }\n }\n\n _write(chunk: any, encoding?: string, callback?: (error?: Error | null) => void): boolean {\n if (typeof callback === 'function') {\n this._transform(chunk, encoding || 'utf8', callback);\n return true;\n }\n\n this._transform(chunk, encoding || 'utf8', (error: Error | null) => {\n if (error) console.error('Transform error in write:', error);\n });\n return true;\n }\n\n _transform(chunk: string, _enc: string, cb: Function): void {\n try {\n // Parse the log line if it's a string\n const log = typeof chunk === 'string' ? JSON.parse(chunk) : chunk;\n\n // Add timestamp if not present\n if (!log.time) {\n log.time = Date.now();\n }\n\n // Add to buffer\n this.logBuffer.push(log);\n\n // Flush if buffer reaches batch size\n if (this.logBuffer.length >= this.batchSize) {\n this._flush().catch(err => {\n console.error('Error flushing logs to HTTP endpoint:', err);\n });\n }\n\n // Pass through the log\n cb(null, chunk);\n } catch (error) {\n cb(error);\n }\n }\n\n _destroy(err: Error, cb: Function): void {\n clearInterval(this.flushIntervalId);\n\n // Final flush\n if (this.logBuffer.length > 0) {\n this._flush()\n .then(() => cb(err))\n .catch(flushErr => {\n console.error('Error in final flush:', flushErr);\n cb(err || flushErr);\n });\n } else {\n cb(err);\n }\n }\n\n async listLogs(params?: {\n fromDate?: Date;\n toDate?: Date;\n logLevel?: LogLevel;\n filters?: Record<string, any>;\n returnPaginationResults?: boolean;\n page?: number;\n perPage?: number;\n }): Promise<{\n logs: BaseLogMessage[];\n total: number;\n page: number;\n perPage: number;\n hasMore: boolean;\n }> {\n // HttpTransport is write-only by default\n // Subclasses can override this method to implement log retrieval\n console.warn(\n 'HttpTransport.listLogs: This transport is write-only. Override this method to implement log retrieval.',\n );\n\n return {\n logs: [],\n total: 0,\n page: params?.page ?? 1,\n perPage: params?.perPage ?? 100,\n hasMore: false,\n };\n }\n\n async listLogsByRunId({\n runId: _runId,\n fromDate: _fromDate,\n toDate: _toDate,\n logLevel: _logLevel,\n filters: _filters,\n page,\n perPage,\n }: {\n runId: string;\n fromDate?: Date;\n toDate?: Date;\n logLevel?: LogLevel;\n filters?: Record<string, any>;\n page?: number;\n perPage?: number;\n }): Promise<{\n logs: BaseLogMessage[];\n total: number;\n page: number;\n perPage: number;\n hasMore: boolean;\n }> {\n // HttpTransport is write-only by default\n // Subclasses can override this method to implement log retrieval\n console.warn(\n 'HttpTransport.listLogsByRunId: This transport is write-only. Override this method to implement log retrieval.',\n );\n\n return {\n logs: [],\n total: 0,\n page: page ?? 1,\n perPage: perPage ?? 100,\n hasMore: false,\n };\n }\n\n // Utility methods\n public getBufferedLogs(): BaseLogMessage[] {\n return [...this.logBuffer];\n }\n\n public clearBuffer(): void {\n this.logBuffer = [];\n }\n\n public getLastFlushTime(): number {\n return this.lastFlush;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/http/index.ts"],"sourcesContent":["import { LoggerTransport } from '@mastra/core/logger';\nimport type { BaseLogMessage, LogLevel } from '@mastra/core/logger';\n\ninterface RetryOptions {\n maxRetries?: number;\n retryDelay?: number;\n exponentialBackoff?: boolean;\n}\n\ninterface HttpTransportOptions {\n url: string;\n method?: 'POST' | 'PUT' | 'PATCH';\n headers?: Record<string, string>;\n batchSize?: number;\n flushInterval?: number;\n timeout?: number;\n retryOptions?: RetryOptions;\n maxBufferSize?: number;\n}\n\nclass HttpResponseError extends Error {\n constructor(\n readonly status: number,\n statusText: string,\n readonly retryAfterMs: number | undefined,\n ) {\n super(`HTTP ${status}: ${statusText}`);\n }\n}\n\n// Other 4xx responses mean the request itself is wrong and will fail the same way on every retry.\nfunction isRetryableStatus(status: number): boolean {\n return status === 408 || status === 425 || status === 429 || status >= 500;\n}\n\n// Retry-After is either delta-seconds or an HTTP date (RFC 9110). Invalid values are ignored.\nfunction parseRetryAfter(headers: Headers | undefined): number | undefined {\n const value = headers?.get('retry-after')?.trim();\n if (!value) return undefined;\n if (/^\\d+$/.test(value)) return Number(value) * 1000;\n const date = Date.parse(value);\n return Number.isNaN(date) ? undefined : Math.max(0, date - Date.now());\n}\n\nexport class HttpTransport extends LoggerTransport {\n private url: string;\n private method: string;\n private headers: Record<string, string>;\n private batchSize: number;\n private flushInterval: number;\n private timeout: number;\n private retryOptions: Required<RetryOptions>;\n private logBuffer: BaseLogMessage[];\n private maxBufferSize: number;\n private droppedLogCount = 0;\n private flushPromise: Promise<void> | null = null;\n private flushRequested = false;\n private lastFlush: number;\n private flushIntervalId: NodeJS.Timeout;\n\n constructor(options: HttpTransportOptions) {\n super({ objectMode: true });\n\n if (!options.url) {\n throw new Error('HTTP URL is required');\n }\n\n this.url = options.url;\n this.method = options.method || 'POST';\n this.headers = {\n 'Content-Type': 'application/json',\n ...options.headers,\n };\n this.batchSize = options.batchSize ?? 100;\n this.flushInterval = options.flushInterval || 10000;\n this.timeout = options.timeout || 30000;\n this.retryOptions = {\n maxRetries: options.retryOptions?.maxRetries ?? 3,\n retryDelay: options.retryOptions?.retryDelay ?? 1000,\n exponentialBackoff: options.retryOptions?.exponentialBackoff ?? true,\n };\n\n if (!Number.isInteger(this.batchSize) || this.batchSize < 1) {\n throw new Error('HttpTransport batchSize must be a positive integer');\n }\n\n const maxBufferSize = options.maxBufferSize ?? 10_000;\n if (!Number.isInteger(maxBufferSize) || maxBufferSize < 1) {\n throw new Error('HttpTransport maxBufferSize must be a positive integer');\n }\n this.maxBufferSize = Math.max(maxBufferSize, this.batchSize);\n this.logBuffer = [];\n this.lastFlush = Date.now();\n\n // Start flush interval\n this.flushIntervalId = setInterval(() => this.requestFlush(), this.flushInterval);\n }\n\n private async makeHttpRequest(data: any, retryCount = 0): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const body = JSON.stringify({ logs: data });\n\n const response = await fetch(this.url, {\n method: this.method,\n headers: this.headers,\n body,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n throw new HttpResponseError(response.status, response.statusText, parseRetryAfter(response.headers));\n }\n\n return response;\n } catch (error) {\n clearTimeout(timeoutId);\n\n const isPermanent = error instanceof HttpResponseError && !isRetryableStatus(error.status);\n if (!isPermanent && retryCount < this.retryOptions.maxRetries) {\n const backoff = this.retryOptions.exponentialBackoff\n ? this.retryOptions.retryDelay * Math.pow(2, retryCount)\n : this.retryOptions.retryDelay;\n // Honor the server's Retry-After, capped at the request timeout so a large value can't stall shutdown.\n const retryAfter = error instanceof HttpResponseError ? (error.retryAfterMs ?? 0) : 0;\n const delay = Math.max(backoff, Math.min(retryAfter, this.timeout));\n\n await new Promise(resolve => setTimeout(resolve, delay));\n return this.makeHttpRequest(data, retryCount + 1);\n }\n\n throw error;\n }\n }\n\n private enforceBufferLimit(): void {\n const overflow = this.logBuffer.length - this.maxBufferSize;\n if (overflow <= 0) {\n return;\n }\n\n this.logBuffer.splice(0, overflow);\n if (this.droppedLogCount === 0) {\n console.warn(\n `HttpTransport: buffer exceeded maxBufferSize (${this.maxBufferSize}); dropping oldest logs. Use getDroppedLogCount() to track drops.`,\n );\n }\n this.droppedLogCount += overflow;\n }\n\n // Internal fire-and-forget flush. While a request is in flight this only records the request, so writes\n // during a slow or retrying request don't each attach another handler to the pending promise.\n private requestFlush(): void {\n if (this.flushPromise) {\n this.flushRequested = true;\n return;\n }\n this._flush().catch(err => {\n console.error('Error flushing logs to HTTP endpoint:', err);\n });\n }\n\n _flush(): Promise<void> {\n // Only one request in flight at a time, so an outage doesn't fan out into overlapping retry chains.\n if (this.flushPromise) {\n this.flushRequested = true;\n return this.flushPromise;\n }\n if (this.logBuffer.length === 0) {\n return Promise.resolve();\n }\n\n this.flushRequested = false;\n const flush = this.flushBatch().finally(() => {\n this.flushPromise = null;\n });\n this.flushPromise = flush;\n // Flushes requested while this request was in flight only got this promise back, so send their logs now,\n // and keep draining full batches. On a transient failure, wait for the next interval instead of retrying\n // straight away. A permanently rejected batch was dropped, so the logs behind it can go out now.\n const continueDraining = () => {\n if (this.logBuffer.length >= this.batchSize || (this.flushRequested && this.logBuffer.length > 0)) {\n this.requestFlush();\n }\n };\n flush.then(continueDraining, error => {\n if (error instanceof HttpResponseError && !isRetryableStatus(error.status)) {\n continueDraining();\n }\n });\n return flush;\n }\n\n private async flushBatch(): Promise<void> {\n const now = Date.now();\n const logs = this.logBuffer.splice(0, this.batchSize);\n\n try {\n await this.makeHttpRequest(logs);\n this.lastFlush = now;\n } catch (error) {\n // The endpoint rejected this batch outright, so resending it can't succeed and would block the logs behind it.\n if (error instanceof HttpResponseError && !isRetryableStatus(error.status)) {\n this.droppedLogCount += logs.length;\n console.warn(\n `HttpTransport: endpoint rejected a batch with HTTP ${error.status}; dropping ${logs.length} logs. Use getDroppedLogCount() to track drops.`,\n );\n throw error;\n }\n\n // On a transient error, put logs back in the buffer\n this.logBuffer.unshift(...logs);\n this.enforceBufferLimit();\n throw error;\n }\n }\n\n _write(chunk: any, encoding?: string, callback?: (error?: Error | null) => void): boolean {\n if (typeof callback === 'function') {\n this._transform(chunk, encoding || 'utf8', callback);\n return true;\n }\n\n this._transform(chunk, encoding || 'utf8', (error: Error | null) => {\n if (error) console.error('Transform error in write:', error);\n });\n return true;\n }\n\n _transform(chunk: string, _enc: string, cb: Function): void {\n try {\n // Parse the log line if it's a string\n const log = typeof chunk === 'string' ? JSON.parse(chunk) : chunk;\n\n // Add timestamp if not present\n if (!log.time) {\n log.time = Date.now();\n }\n\n // Add to buffer\n this.logBuffer.push(log);\n this.enforceBufferLimit();\n\n // Flush if buffer reaches batch size\n if (this.logBuffer.length >= this.batchSize) {\n this.requestFlush();\n }\n\n // Pass through the log\n cb(null, chunk);\n } catch (error) {\n cb(error);\n }\n }\n\n _destroy(err: Error, cb: Function): void {\n clearInterval(this.flushIntervalId);\n\n // Final drain. Wait out any in-flight request (ignoring its failure, since its logs are back in the buffer),\n // then keep sending until the buffer is empty. A failed request ends the drain instead of retrying forever.\n if (this.logBuffer.length > 0 || this.flushPromise) {\n const drain = async () => {\n await this.flushPromise?.catch(() => {});\n while (this.flushPromise || this.logBuffer.length > 0) {\n await (this.flushPromise ?? this._flush());\n }\n };\n\n drain()\n .then(() => cb(err))\n .catch(flushErr => {\n console.error('Error in final flush:', flushErr);\n cb(err || flushErr);\n });\n } else {\n cb(err);\n }\n }\n\n async listLogs(params?: {\n fromDate?: Date;\n toDate?: Date;\n logLevel?: LogLevel;\n filters?: Record<string, any>;\n returnPaginationResults?: boolean;\n page?: number;\n perPage?: number;\n }): Promise<{\n logs: BaseLogMessage[];\n total: number;\n page: number;\n perPage: number;\n hasMore: boolean;\n }> {\n // HttpTransport is write-only by default\n // Subclasses can override this method to implement log retrieval\n console.warn(\n 'HttpTransport.listLogs: This transport is write-only. Override this method to implement log retrieval.',\n );\n\n return {\n logs: [],\n total: 0,\n page: params?.page ?? 1,\n perPage: params?.perPage ?? 100,\n hasMore: false,\n };\n }\n\n async listLogsByRunId({\n runId: _runId,\n fromDate: _fromDate,\n toDate: _toDate,\n logLevel: _logLevel,\n filters: _filters,\n page,\n perPage,\n }: {\n runId: string;\n fromDate?: Date;\n toDate?: Date;\n logLevel?: LogLevel;\n filters?: Record<string, any>;\n page?: number;\n perPage?: number;\n }): Promise<{\n logs: BaseLogMessage[];\n total: number;\n page: number;\n perPage: number;\n hasMore: boolean;\n }> {\n // HttpTransport is write-only by default\n // Subclasses can override this method to implement log retrieval\n console.warn(\n 'HttpTransport.listLogsByRunId: This transport is write-only. Override this method to implement log retrieval.',\n );\n\n return {\n logs: [],\n total: 0,\n page: page ?? 1,\n perPage: perPage ?? 100,\n hasMore: false,\n };\n }\n\n // Utility methods\n public getBufferedLogs(): BaseLogMessage[] {\n return [...this.logBuffer];\n }\n\n public clearBuffer(): void {\n this.logBuffer = [];\n }\n\n public getDroppedLogCount(): number {\n return this.droppedLogCount;\n }\n\n public getLastFlushTime(): number {\n return this.lastFlush;\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/loggers",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.5-alpha.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -76,9 +76,9 @@
|
|
|
76
76
|
"tsx": "^4.23.1",
|
|
77
77
|
"typescript": "^7.0.2",
|
|
78
78
|
"vitest": "4.1.11",
|
|
79
|
-
"@internal/
|
|
80
|
-
"@
|
|
81
|
-
"@
|
|
79
|
+
"@internal/lint": "0.0.140",
|
|
80
|
+
"@internal/types-builder": "0.0.115",
|
|
81
|
+
"@mastra/core": "1.75.0-alpha.8"
|
|
82
82
|
},
|
|
83
83
|
"peerDependencies": {
|
|
84
84
|
"@mastra/core": ">=1.0.0-0 <2.0.0-0"
|