@mastra/loggers 0.0.1-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/LICENSE +44 -0
- package/dist/file/index.d.ts +17 -0
- package/dist/file/index.d.ts.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/loggers.cjs.development.js +665 -0
- package/dist/loggers.cjs.development.js.map +1 -0
- package/dist/loggers.cjs.production.min.js +2 -0
- package/dist/loggers.cjs.production.min.js.map +1 -0
- package/dist/loggers.esm.js +660 -0
- package/dist/loggers.esm.js.map +1 -0
- package/dist/upstash/index.d.ts +29 -0
- package/dist/upstash/index.d.ts.map +1 -0
- package/package.json +43 -0
- package/src/file/fixtures/test.log +0 -0
- package/src/file/index.test.ts +130 -0
- package/src/file/index.ts +59 -0
- package/src/index.ts +2 -0
- package/src/upstash/index.test.ts +185 -0
- package/src/upstash/index.ts +162 -0
- package/tsconfig.json +10 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loggers.esm.js","sources":["../src/file/index.ts","../src/upstash/index.ts"],"sourcesContent":["import { LoggerTransport, BaseLogMessage } from '@mastra/core';\nimport { createWriteStream, existsSync, readFileSync, WriteStream } from 'fs';\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.log(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 // 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 getLogs(): Promise<BaseLogMessage[]> {\n return readFileSync(this.path, 'utf8')\n .split('\\n')\n .filter(Boolean)\n .map(log => JSON.parse(log));\n }\n\n async getLogsByRunId({ runId }: { runId: string }): Promise<BaseLogMessage[]> {\n try {\n const allLogs = await this.getLogs();\n return (allLogs.filter(log => log?.runId === runId) || []) as BaseLogMessage[];\n } catch (error) {\n console.error('Error getting logs by runId from Upstash:', error);\n return [] as BaseLogMessage[];\n }\n }\n}\n","import { BaseLogMessage, LoggerTransport } from '@mastra/core';\n\nexport class UpstashTransport extends LoggerTransport {\n upstashUrl: string;\n upstashToken: string;\n listName: string;\n maxListLength: number;\n batchSize: number;\n flushInterval: number;\n logBuffer: any[];\n lastFlush: number;\n flushIntervalId: NodeJS.Timeout;\n\n constructor(opts: {\n listName?: string;\n maxListLength?: number;\n batchSize?: number;\n upstashUrl: string;\n flushInterval?: number;\n upstashToken: string;\n }) {\n super({ objectMode: true });\n\n if (!opts.upstashUrl || !opts.upstashToken) {\n throw new Error('Upstash URL and token are required');\n }\n\n this.upstashUrl = opts.upstashUrl;\n this.upstashToken = opts.upstashToken;\n this.listName = opts.listName || 'application-logs';\n this.maxListLength = opts.maxListLength || 10000;\n this.batchSize = opts.batchSize || 100;\n this.flushInterval = opts.flushInterval || 10000;\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 Upstash:', err);\n });\n }, this.flushInterval);\n }\n\n private async executeUpstashCommand(command: any[]): Promise<any> {\n const response = await fetch(`${this.upstashUrl}/pipeline`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.upstashToken}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify([command]),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to execute Upstash command: ${response.statusText}`);\n }\n\n return response.json();\n }\n\n async _flush() {\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 // Prepare the Upstash Redis command\n const command = ['LPUSH', this.listName, ...logs.map(log => JSON.stringify(log))];\n\n // Trim the list if it exceeds maxListLength\n if (this.maxListLength > 0) {\n command.push('LTRIM', this.listName, 0 as any, (this.maxListLength - 1) as any);\n }\n\n // Send logs to Upstash Redis\n await this.executeUpstashCommand(command);\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 _transform(chunk: string, _enc: string, cb: Function) {\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 Upstash:', 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) {\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 getLogs(): Promise<BaseLogMessage[]> {\n try {\n // Get all logs from the list\n const command = ['LRANGE', this.listName, 0, -1];\n const response = await this.executeUpstashCommand(command);\n\n // Parse the logs from JSON strings back to objects\n return response?.[0]?.result.map((log: string) => {\n try {\n return JSON.parse(log);\n } catch (e) {\n return '';\n }\n }) as BaseLogMessage[];\n } catch (error) {\n console.error('Error getting logs from Upstash:', error);\n return [];\n }\n }\n\n async getLogsByRunId({ runId }: { runId: string }): Promise<BaseLogMessage[]> {\n try {\n const allLogs = await this.getLogs();\n return (allLogs.filter((log: any) => log.msg?.runId === runId) || []) as BaseLogMessage[];\n } catch (error) {\n console.error('Error getting logs by runId from Upstash:', error);\n return [] as BaseLogMessage[];\n }\n }\n}\n"],"names":["FileTransport","_LoggerTransport","_ref","_this","path","call","objectMode","fileStream","existsSync","console","log","Error","createWriteStream","flags","_inheritsLoose","_proto","prototype","_transform","chunk","_encoding","callback","write","error","_flush","end","_destroy","destroy","getLogs","_getLogs","_asyncToGenerator","_regeneratorRuntime","mark","_callee","wrap","_callee$","_context","prev","next","abrupt","readFileSync","split","filter","Boolean","map","JSON","parse","stop","apply","arguments","getLogsByRunId","_getLogsByRunId","_callee2","_ref2","runId","allLogs","_callee2$","_context2","sent","t0","_x","LoggerTransport","UpstashTransport","opts","upstashUrl","upstashToken","listName","maxListLength","batchSize","flushInterval","logBuffer","lastFlush","flushIntervalId","Date","now","setInterval","err","executeUpstashCommand","_executeUpstashCommand","command","response","fetch","method","headers","Authorization","body","stringify","ok","statusText","json","_flush2","logs","_this$logBuffer","length","splice","concat","push","unshift","_enc","cb","time","clearInterval","then","flushErr","_callee3","_response$","_callee3$","_context3","result","e","_callee4","_callee4$","_context4","_log$msg","msg","_x2"],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { BaseLogMessage, LoggerTransport } from '@mastra/core';
|
|
2
|
+
export declare class UpstashTransport extends LoggerTransport {
|
|
3
|
+
upstashUrl: string;
|
|
4
|
+
upstashToken: string;
|
|
5
|
+
listName: string;
|
|
6
|
+
maxListLength: number;
|
|
7
|
+
batchSize: number;
|
|
8
|
+
flushInterval: number;
|
|
9
|
+
logBuffer: any[];
|
|
10
|
+
lastFlush: number;
|
|
11
|
+
flushIntervalId: NodeJS.Timeout;
|
|
12
|
+
constructor(opts: {
|
|
13
|
+
listName?: string;
|
|
14
|
+
maxListLength?: number;
|
|
15
|
+
batchSize?: number;
|
|
16
|
+
upstashUrl: string;
|
|
17
|
+
flushInterval?: number;
|
|
18
|
+
upstashToken: string;
|
|
19
|
+
});
|
|
20
|
+
private executeUpstashCommand;
|
|
21
|
+
_flush(): Promise<void>;
|
|
22
|
+
_transform(chunk: string, _enc: string, cb: Function): void;
|
|
23
|
+
_destroy(err: Error, cb: Function): void;
|
|
24
|
+
getLogs(): Promise<BaseLogMessage[]>;
|
|
25
|
+
getLogsByRunId({ runId }: {
|
|
26
|
+
runId: string;
|
|
27
|
+
}): Promise<BaseLogMessage[]>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/upstash/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/D,qBAAa,gBAAiB,SAAQ,eAAe;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,GAAG,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC,OAAO,CAAC;gBAEpB,IAAI,EAAE;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;KACtB;YAyBa,qBAAqB;IAiB7B,MAAM;IA2BZ,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ;IA2BpD,QAAQ,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ;IAgB3B,OAAO,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAoBpC,cAAc,CAAC,EAAE,KAAK,EAAE,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;CAS9E"}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mastra/loggers",
|
|
3
|
+
"version": "0.0.1-alpha.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"module": "dist/loggers.esm.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/loggers.esm.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"./package.json": "./package.json"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [],
|
|
23
|
+
"author": "",
|
|
24
|
+
"license": "ISC",
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@mastra/core": "0.1.27-alpha.69"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@babel/preset-env": "^7.26.0",
|
|
30
|
+
"@babel/preset-typescript": "^7.26.0",
|
|
31
|
+
"@tsconfig/recommended": "^1.0.7",
|
|
32
|
+
"@types/jsdom": "^21.1.7",
|
|
33
|
+
"@types/node": "^22.9.0",
|
|
34
|
+
"@types/pg": "^8.11.10",
|
|
35
|
+
"dts-cli": "^2.0.5",
|
|
36
|
+
"vitest": "^2.1.8"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "dts build",
|
|
40
|
+
"build:dev": "dts watch",
|
|
41
|
+
"test": "vitest run"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { createLogger, LogLevel } from '@mastra/core';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { describe, it, expect, beforeEach, afterEach, vi, afterAll } from 'vitest';
|
|
5
|
+
|
|
6
|
+
import { FileTransport } from './index.js';
|
|
7
|
+
|
|
8
|
+
describe('FileTransport', () => {
|
|
9
|
+
const testDir = __dirname + '/fixtures';
|
|
10
|
+
const testFile = 'test.log';
|
|
11
|
+
const testPath = path.join(testDir, testFile);
|
|
12
|
+
let fileLogger: FileTransport;
|
|
13
|
+
|
|
14
|
+
beforeEach(async () => {
|
|
15
|
+
// Create test directory
|
|
16
|
+
if (!fs.existsSync(testDir)) {
|
|
17
|
+
fs.mkdirSync(testDir);
|
|
18
|
+
}
|
|
19
|
+
fileLogger = new FileTransport({ path: testPath });
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
afterAll(async () => {
|
|
23
|
+
// Cleanup test directory
|
|
24
|
+
fs.writeFileSync(testPath, ``);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should create a file stream when instantiated', () => {
|
|
28
|
+
expect(fileLogger.fileStream).toBeDefined();
|
|
29
|
+
expect(fileLogger.path).toBe(testPath);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should work with createLogger', async () => {
|
|
33
|
+
const logger = createLogger({
|
|
34
|
+
name: 'test-logger',
|
|
35
|
+
level: LogLevel.INFO,
|
|
36
|
+
transports: {
|
|
37
|
+
file: fileLogger,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const testMessage = 'test info message';
|
|
42
|
+
logger.info(testMessage);
|
|
43
|
+
|
|
44
|
+
// Wait for file write to complete
|
|
45
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
46
|
+
|
|
47
|
+
const fileContent = fs.readFileSync(testPath, 'utf8');
|
|
48
|
+
expect(fileContent).toContain(testMessage);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should handle multiple log messages', async () => {
|
|
52
|
+
const logger = createLogger({
|
|
53
|
+
name: 'test-logger',
|
|
54
|
+
level: LogLevel.INFO,
|
|
55
|
+
transports: {
|
|
56
|
+
file: fileLogger,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const messages = ['message1', 'message2', 'message3'];
|
|
61
|
+
messages.forEach(msg => logger.info(msg));
|
|
62
|
+
|
|
63
|
+
// Wait for file writes to complete
|
|
64
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
65
|
+
|
|
66
|
+
const fileContent = fs.readFileSync(testPath, 'utf8');
|
|
67
|
+
messages.forEach(msg => {
|
|
68
|
+
expect(fileContent).toContain(msg);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should properly clean up resources on destroy', () => {
|
|
73
|
+
const destroySpy = vi.spyOn(fileLogger.fileStream, 'destroy');
|
|
74
|
+
|
|
75
|
+
fileLogger._destroy(null, () => {
|
|
76
|
+
expect(destroySpy).toHaveBeenCalled();
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should handle errors in _transform', () => {
|
|
81
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
82
|
+
const errorObj = new Error('Test error');
|
|
83
|
+
|
|
84
|
+
vi.spyOn(fileLogger.fileStream, 'write').mockImplementationOnce(() => {
|
|
85
|
+
throw errorObj;
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
fileLogger._transform('test', 'utf8', error => {
|
|
89
|
+
expect(consoleSpy).toHaveBeenCalledWith('Error parsing log entry:', errorObj);
|
|
90
|
+
expect(error).toBeNull(); // Should not propagate error
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should flush remaining data when stream ends', () => {
|
|
95
|
+
const endSpy = vi.spyOn(fileLogger.fileStream, 'end');
|
|
96
|
+
|
|
97
|
+
fileLogger._flush(() => {
|
|
98
|
+
expect(endSpy).toHaveBeenCalled();
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('getLogs and getLogsByRunId', () => {
|
|
103
|
+
it('should return empty array for getLogs', async () => {
|
|
104
|
+
const logs = await fileLogger.getLogs();
|
|
105
|
+
expect(logs.length).toBeGreaterThan(0);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should return empty array for getLogsByRunId', async () => {
|
|
109
|
+
const logger = createLogger({
|
|
110
|
+
name: 'test-logger',
|
|
111
|
+
level: LogLevel.INFO,
|
|
112
|
+
transports: {
|
|
113
|
+
file: fileLogger,
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
let logs = await fileLogger.getLogsByRunId({ runId: 'test-run-id' });
|
|
118
|
+
expect(logs.length).toBe(0);
|
|
119
|
+
|
|
120
|
+
logger.info('test info message', {
|
|
121
|
+
runId: 'test-run-id',
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
125
|
+
|
|
126
|
+
logs = await fileLogger.getLogsByRunId({ runId: 'test-run-id' });
|
|
127
|
+
expect(logs.length).toBe(1);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { LoggerTransport, BaseLogMessage } from '@mastra/core';
|
|
2
|
+
import { createWriteStream, existsSync, readFileSync, WriteStream } from 'fs';
|
|
3
|
+
|
|
4
|
+
export class FileTransport extends LoggerTransport {
|
|
5
|
+
path: string;
|
|
6
|
+
fileStream: WriteStream;
|
|
7
|
+
constructor({ path }: { path: string }) {
|
|
8
|
+
super({ objectMode: true });
|
|
9
|
+
this.path = path;
|
|
10
|
+
|
|
11
|
+
if (!existsSync(this.path)) {
|
|
12
|
+
console.log(this.path);
|
|
13
|
+
throw new Error('File path does not exist');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
this.fileStream = createWriteStream(this.path, { flags: 'a' });
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
_transform(chunk: any, _encoding: string, callback: (error: Error | null, chunk: any) => void) {
|
|
20
|
+
try {
|
|
21
|
+
this.fileStream.write(chunk);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error('Error parsing log entry:', error);
|
|
24
|
+
}
|
|
25
|
+
callback(null, chunk);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
_flush(callback: Function) {
|
|
29
|
+
// End the file stream when transform stream ends
|
|
30
|
+
this.fileStream.end(() => {
|
|
31
|
+
callback();
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Clean up resources
|
|
36
|
+
_destroy(error: Error, callback: Function) {
|
|
37
|
+
if (this.fileStream) {
|
|
38
|
+
this.fileStream.destroy(error);
|
|
39
|
+
}
|
|
40
|
+
callback(error);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async getLogs(): Promise<BaseLogMessage[]> {
|
|
44
|
+
return readFileSync(this.path, 'utf8')
|
|
45
|
+
.split('\n')
|
|
46
|
+
.filter(Boolean)
|
|
47
|
+
.map(log => JSON.parse(log));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async getLogsByRunId({ runId }: { runId: string }): Promise<BaseLogMessage[]> {
|
|
51
|
+
try {
|
|
52
|
+
const allLogs = await this.getLogs();
|
|
53
|
+
return (allLogs.filter(log => log?.runId === runId) || []) as BaseLogMessage[];
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error('Error getting logs by runId from Upstash:', error);
|
|
56
|
+
return [] as BaseLogMessage[];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { createLogger, LogLevel } from '@mastra/core';
|
|
2
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import { UpstashTransport } from './index.js';
|
|
5
|
+
|
|
6
|
+
describe('UpstashTransport', () => {
|
|
7
|
+
const defaultOptions = {
|
|
8
|
+
upstashUrl: 'https://test-url.upstash.io',
|
|
9
|
+
upstashToken: 'test-token',
|
|
10
|
+
listName: 'test-logs',
|
|
11
|
+
maxListLength: 1000,
|
|
12
|
+
batchSize: 10,
|
|
13
|
+
flushInterval: 1000,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
let transport: UpstashTransport;
|
|
17
|
+
let fetchMock: any;
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
fetchMock = vi.fn(() =>
|
|
21
|
+
Promise.resolve({
|
|
22
|
+
ok: true,
|
|
23
|
+
json: () => Promise.resolve({ result: 'success' }),
|
|
24
|
+
}),
|
|
25
|
+
);
|
|
26
|
+
global.fetch = fetchMock;
|
|
27
|
+
|
|
28
|
+
vi.useFakeTimers();
|
|
29
|
+
transport = new UpstashTransport(defaultOptions);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
afterEach(() => {
|
|
33
|
+
vi.clearAllTimers();
|
|
34
|
+
vi.clearAllMocks();
|
|
35
|
+
vi.useRealTimers();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should initialize with correct options', () => {
|
|
39
|
+
expect(transport.upstashUrl).toBe(defaultOptions.upstashUrl);
|
|
40
|
+
expect(transport.upstashToken).toBe(defaultOptions.upstashToken);
|
|
41
|
+
expect(transport.listName).toBe(defaultOptions.listName);
|
|
42
|
+
expect(transport.logBuffer).toEqual([]);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should work with createLogger', async () => {
|
|
46
|
+
const logger = createLogger({
|
|
47
|
+
name: 'test-logger',
|
|
48
|
+
level: LogLevel.INFO,
|
|
49
|
+
transports: {
|
|
50
|
+
upstash: transport,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const testMessage = 'test info message';
|
|
55
|
+
logger.info(testMessage);
|
|
56
|
+
|
|
57
|
+
// Trigger flush
|
|
58
|
+
await transport._flush();
|
|
59
|
+
|
|
60
|
+
expect(fetchMock).toHaveBeenCalledWith(
|
|
61
|
+
defaultOptions.upstashUrl,
|
|
62
|
+
expect.objectContaining({
|
|
63
|
+
method: 'POST',
|
|
64
|
+
headers: {
|
|
65
|
+
Authorization: `Bearer ${defaultOptions.upstashToken}`,
|
|
66
|
+
'Content-Type': 'application/json',
|
|
67
|
+
},
|
|
68
|
+
body: expect.stringContaining(testMessage),
|
|
69
|
+
}),
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should handle multiple log messages', async () => {
|
|
74
|
+
const logger = createLogger({
|
|
75
|
+
name: 'test-logger',
|
|
76
|
+
level: LogLevel.INFO,
|
|
77
|
+
transports: {
|
|
78
|
+
upstash: transport,
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const messages = ['message1', 'message2', 'message3'];
|
|
83
|
+
messages.forEach(msg => logger.info(msg));
|
|
84
|
+
|
|
85
|
+
// Trigger flush
|
|
86
|
+
await transport._flush();
|
|
87
|
+
|
|
88
|
+
const body = JSON.parse(fetchMock.mock.calls[0][1].body);
|
|
89
|
+
messages.forEach(msg => {
|
|
90
|
+
expect(body.pipeline[0].some((cmd: string) => cmd.includes(msg))).toBe(true);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should properly clean up resources on destroy', () => {
|
|
95
|
+
const clearIntervalSpy = vi.spyOn(global, 'clearInterval');
|
|
96
|
+
const flushSpy = vi.spyOn(transport, '_flush').mockImplementation(() => Promise.resolve());
|
|
97
|
+
|
|
98
|
+
transport._destroy(null, () => {
|
|
99
|
+
expect(clearIntervalSpy).toHaveBeenCalled();
|
|
100
|
+
if (transport.logBuffer.length > 0) {
|
|
101
|
+
expect(flushSpy).toHaveBeenCalled();
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('should handle errors in _transform', () => {
|
|
107
|
+
const errorObj = new Error('Test error');
|
|
108
|
+
const callback = vi.fn();
|
|
109
|
+
|
|
110
|
+
transport._transform('invalid json', 'utf8', callback);
|
|
111
|
+
|
|
112
|
+
expect(callback).toHaveBeenCalledWith(expect.any(Error));
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should automatically flush on interval', async () => {
|
|
116
|
+
const logger = createLogger({
|
|
117
|
+
name: 'test-logger',
|
|
118
|
+
level: LogLevel.INFO,
|
|
119
|
+
transports: {
|
|
120
|
+
upstash: transport,
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
logger.info('test message');
|
|
125
|
+
|
|
126
|
+
// Advance timer by flush interval
|
|
127
|
+
vi.advanceTimersByTime(defaultOptions.flushInterval);
|
|
128
|
+
await Promise.resolve();
|
|
129
|
+
|
|
130
|
+
expect(fetchMock).toHaveBeenCalled();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
describe('error handling', () => {
|
|
134
|
+
it('should handle Upstash API errors', async () => {
|
|
135
|
+
fetchMock.mockImplementationOnce(() =>
|
|
136
|
+
Promise.resolve({
|
|
137
|
+
ok: false,
|
|
138
|
+
statusText: 'Test Error',
|
|
139
|
+
}),
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
const logger = createLogger({
|
|
143
|
+
name: 'test-logger',
|
|
144
|
+
level: LogLevel.INFO,
|
|
145
|
+
transports: {
|
|
146
|
+
upstash: transport,
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
logger.info('test message');
|
|
151
|
+
|
|
152
|
+
await expect(transport._flush()).rejects.toThrow('Failed to execute Upstash command: Test Error');
|
|
153
|
+
expect(transport.logBuffer.length).toBeGreaterThan(0);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('should handle network errors', async () => {
|
|
157
|
+
fetchMock.mockImplementationOnce(() => Promise.reject(new Error('Network error')));
|
|
158
|
+
|
|
159
|
+
const logger = createLogger({
|
|
160
|
+
name: 'test-logger',
|
|
161
|
+
level: LogLevel.INFO,
|
|
162
|
+
transports: {
|
|
163
|
+
upstash: transport,
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
logger.info('test message');
|
|
168
|
+
|
|
169
|
+
await expect(transport._flush()).rejects.toThrow('Network error');
|
|
170
|
+
expect(transport.logBuffer.length).toBeGreaterThan(0);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
describe('getLogs and getLogsByRunId', () => {
|
|
175
|
+
it('should return empty array for getLogs', async () => {
|
|
176
|
+
const logs = await transport.getLogs();
|
|
177
|
+
expect(logs).toEqual([]);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should return empty array for getLogsByRunId', async () => {
|
|
181
|
+
const logs = await transport.getLogsByRunId({ runId: 'test-run-id' });
|
|
182
|
+
expect(logs).toEqual([]);
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
});
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { BaseLogMessage, LoggerTransport } from '@mastra/core';
|
|
2
|
+
|
|
3
|
+
export class UpstashTransport extends LoggerTransport {
|
|
4
|
+
upstashUrl: string;
|
|
5
|
+
upstashToken: string;
|
|
6
|
+
listName: string;
|
|
7
|
+
maxListLength: number;
|
|
8
|
+
batchSize: number;
|
|
9
|
+
flushInterval: number;
|
|
10
|
+
logBuffer: any[];
|
|
11
|
+
lastFlush: number;
|
|
12
|
+
flushIntervalId: NodeJS.Timeout;
|
|
13
|
+
|
|
14
|
+
constructor(opts: {
|
|
15
|
+
listName?: string;
|
|
16
|
+
maxListLength?: number;
|
|
17
|
+
batchSize?: number;
|
|
18
|
+
upstashUrl: string;
|
|
19
|
+
flushInterval?: number;
|
|
20
|
+
upstashToken: string;
|
|
21
|
+
}) {
|
|
22
|
+
super({ objectMode: true });
|
|
23
|
+
|
|
24
|
+
if (!opts.upstashUrl || !opts.upstashToken) {
|
|
25
|
+
throw new Error('Upstash URL and token are required');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
this.upstashUrl = opts.upstashUrl;
|
|
29
|
+
this.upstashToken = opts.upstashToken;
|
|
30
|
+
this.listName = opts.listName || 'application-logs';
|
|
31
|
+
this.maxListLength = opts.maxListLength || 10000;
|
|
32
|
+
this.batchSize = opts.batchSize || 100;
|
|
33
|
+
this.flushInterval = opts.flushInterval || 10000;
|
|
34
|
+
|
|
35
|
+
this.logBuffer = [];
|
|
36
|
+
this.lastFlush = Date.now();
|
|
37
|
+
|
|
38
|
+
// Start flush interval
|
|
39
|
+
this.flushIntervalId = setInterval(() => {
|
|
40
|
+
this._flush().catch(err => {
|
|
41
|
+
console.error('Error flushing logs to Upstash:', err);
|
|
42
|
+
});
|
|
43
|
+
}, this.flushInterval);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private async executeUpstashCommand(command: any[]): Promise<any> {
|
|
47
|
+
const response = await fetch(`${this.upstashUrl}/pipeline`, {
|
|
48
|
+
method: 'POST',
|
|
49
|
+
headers: {
|
|
50
|
+
Authorization: `Bearer ${this.upstashToken}`,
|
|
51
|
+
'Content-Type': 'application/json',
|
|
52
|
+
},
|
|
53
|
+
body: JSON.stringify([command]),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
if (!response.ok) {
|
|
57
|
+
throw new Error(`Failed to execute Upstash command: ${response.statusText}`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return response.json();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async _flush() {
|
|
64
|
+
if (this.logBuffer.length === 0) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const now = Date.now();
|
|
69
|
+
const logs = this.logBuffer.splice(0, this.batchSize);
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
// Prepare the Upstash Redis command
|
|
73
|
+
const command = ['LPUSH', this.listName, ...logs.map(log => JSON.stringify(log))];
|
|
74
|
+
|
|
75
|
+
// Trim the list if it exceeds maxListLength
|
|
76
|
+
if (this.maxListLength > 0) {
|
|
77
|
+
command.push('LTRIM', this.listName, 0 as any, (this.maxListLength - 1) as any);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Send logs to Upstash Redis
|
|
81
|
+
await this.executeUpstashCommand(command);
|
|
82
|
+
this.lastFlush = now;
|
|
83
|
+
} catch (error) {
|
|
84
|
+
// On error, put logs back in the buffer
|
|
85
|
+
this.logBuffer.unshift(...logs);
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
_transform(chunk: string, _enc: string, cb: Function) {
|
|
91
|
+
try {
|
|
92
|
+
// Parse the log line if it's a string
|
|
93
|
+
const log = typeof chunk === 'string' ? JSON.parse(chunk) : chunk;
|
|
94
|
+
|
|
95
|
+
// Add timestamp if not present
|
|
96
|
+
if (!log.time) {
|
|
97
|
+
log.time = Date.now();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Add to buffer
|
|
101
|
+
this.logBuffer.push(log);
|
|
102
|
+
|
|
103
|
+
// Flush if buffer reaches batch size
|
|
104
|
+
if (this.logBuffer.length >= this.batchSize) {
|
|
105
|
+
this._flush().catch(err => {
|
|
106
|
+
console.error('Error flushing logs to Upstash:', err);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Pass through the log
|
|
111
|
+
cb(null, chunk);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
cb(error);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
_destroy(err: Error, cb: Function) {
|
|
118
|
+
clearInterval(this.flushIntervalId);
|
|
119
|
+
|
|
120
|
+
// Final flush
|
|
121
|
+
if (this.logBuffer.length > 0) {
|
|
122
|
+
this._flush()
|
|
123
|
+
.then(() => cb(err))
|
|
124
|
+
.catch(flushErr => {
|
|
125
|
+
console.error('Error in final flush:', flushErr);
|
|
126
|
+
cb(err || flushErr);
|
|
127
|
+
});
|
|
128
|
+
} else {
|
|
129
|
+
cb(err);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async getLogs(): Promise<BaseLogMessage[]> {
|
|
134
|
+
try {
|
|
135
|
+
// Get all logs from the list
|
|
136
|
+
const command = ['LRANGE', this.listName, 0, -1];
|
|
137
|
+
const response = await this.executeUpstashCommand(command);
|
|
138
|
+
|
|
139
|
+
// Parse the logs from JSON strings back to objects
|
|
140
|
+
return response?.[0]?.result.map((log: string) => {
|
|
141
|
+
try {
|
|
142
|
+
return JSON.parse(log);
|
|
143
|
+
} catch (e) {
|
|
144
|
+
return '';
|
|
145
|
+
}
|
|
146
|
+
}) as BaseLogMessage[];
|
|
147
|
+
} catch (error) {
|
|
148
|
+
console.error('Error getting logs from Upstash:', error);
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async getLogsByRunId({ runId }: { runId: string }): Promise<BaseLogMessage[]> {
|
|
154
|
+
try {
|
|
155
|
+
const allLogs = await this.getLogs();
|
|
156
|
+
return (allLogs.filter((log: any) => log.msg?.runId === runId) || []) as BaseLogMessage[];
|
|
157
|
+
} catch (error) {
|
|
158
|
+
console.error('Error getting logs by runId from Upstash:', error);
|
|
159
|
+
return [] as BaseLogMessage[];
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|