@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.
@@ -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,2 @@
1
+ export * from './file';
2
+ export * from './upstash';
@@ -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
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "moduleResolution": "bundler",
5
+ "outDir": "./dist",
6
+ "rootDir": "./src"
7
+ },
8
+ "include": ["src/**/*"],
9
+ "exclude": ["node_modules", "**/*.test.ts"]
10
+ }