@gratheon/log-lib 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gratheon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,186 @@
1
+ # log-lib
2
+
3
+ A TypeScript logging library with console output and MySQL database persistence support.
4
+
5
+ ## Features
6
+
7
+ - **Dual Output**: Logs to both console and MySQL database
8
+ - **Color-Coded Console**: ANSI colored output for different log levels
9
+ - **TypeScript Support**: Full type definitions included
10
+ - **Fastify Integration**: Special logger interface for Fastify framework
11
+ - **Flexible Metadata**: Support for structured metadata in logs
12
+ - **Error Handling**: Graceful handling of database connection failures
13
+ - **Multiple Log Levels**: info, error, warn, debug (debug logs are not persisted to DB)
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @gratheon/log-lib
19
+ ```
20
+
21
+ ## Database Setup
22
+
23
+ Before using the logger, you need to set up the MySQL database. Run the migration script:
24
+
25
+ ```bash
26
+ mysql -u root -p < migrations/001-create-logs-table.sql
27
+ ```
28
+
29
+ This will create:
30
+ - A `logs` database
31
+ - A `logs` table with fields: id, level, message, meta, timestamp
32
+
33
+ ## Usage
34
+
35
+ ### Basic Usage
36
+
37
+ ```typescript
38
+ import { createLogger, LoggerConfig } from '@gratheon/log-lib';
39
+
40
+ const config: LoggerConfig = {
41
+ mysql: {
42
+ host: 'localhost',
43
+ port: 3306,
44
+ user: 'your_user',
45
+ password: 'your_password',
46
+ database: 'logs' // optional, defaults to 'logs'
47
+ }
48
+ };
49
+
50
+ const { logger, fastifyLogger } = createLogger(config);
51
+
52
+ // Log messages
53
+ logger.info('Application started');
54
+ logger.warn('Low memory warning', { available: '100MB' });
55
+ logger.error('Failed to connect to API', { endpoint: '/api/users' });
56
+ logger.debug('Processing item', { id: 123 }); // Not stored in DB
57
+
58
+ // Error with stack trace
59
+ try {
60
+ throw new Error('Something went wrong');
61
+ } catch (err) {
62
+ logger.error(err); // Logs error with stack trace
63
+ }
64
+
65
+ // Enriched error logging
66
+ logger.errorEnriched('Database query failed', err, { query: 'SELECT * FROM users' });
67
+ ```
68
+
69
+ ### Fastify Integration
70
+
71
+ ```typescript
72
+ import Fastify from 'fastify';
73
+ import { createLogger, LoggerConfig } from '@gratheon/log-lib';
74
+
75
+ const config: LoggerConfig = {
76
+ mysql: {
77
+ host: 'localhost',
78
+ port: 3306,
79
+ user: 'your_user',
80
+ password: 'your_password'
81
+ }
82
+ };
83
+
84
+ const { fastifyLogger } = createLogger(config);
85
+
86
+ const fastify = Fastify({
87
+ logger: fastifyLogger
88
+ });
89
+
90
+ fastify.listen(3000);
91
+ ```
92
+
93
+ ## API Reference
94
+
95
+ ### `createLogger(config: LoggerConfig)`
96
+
97
+ Creates and returns logger instances.
98
+
99
+ **Parameters:**
100
+ - `config`: Configuration object with MySQL connection details
101
+
102
+ **Returns:**
103
+ ```typescript
104
+ {
105
+ logger: Logger,
106
+ fastifyLogger: FastifyLogger
107
+ }
108
+ ```
109
+
110
+ ### Logger Methods
111
+
112
+ #### `logger.info(message: string, meta?: LogMetadata)`
113
+ Logs informational messages (console + DB)
114
+
115
+ #### `logger.error(message: string | Error, meta?: LogMetadata)`
116
+ Logs errors with automatic Error object detection (console + DB)
117
+
118
+ #### `logger.errorEnriched(message: string, error: Error, meta?: LogMetadata)`
119
+ Logs enriched error messages with context (console + DB)
120
+
121
+ #### `logger.warn(message: string, meta?: LogMetadata)`
122
+ Logs warning messages (console + DB)
123
+
124
+ #### `logger.debug(message: string, meta?: LogMetadata)`
125
+ Logs debug messages (console only, not persisted)
126
+
127
+ ### FastifyLogger Methods
128
+
129
+ Compatible with Fastify's logger interface:
130
+ - `info(msg: any)`
131
+ - `error(message: string | Error, meta?: LogMetadata)`
132
+ - `warn(msg: any)`
133
+ - `debug(msg: any)`
134
+ - `fatal(msg: any)` - Logs error and calls `process.exit(1)`
135
+ - `trace(msg: any)` - No-op
136
+ - `child(meta: any)` - Returns the same logger instance
137
+
138
+ ## Console Output Colors
139
+
140
+ - **Time**: Blue
141
+ - **Error**: Red (level) + Magenta (metadata)
142
+ - **Info**: Green (level) + Magenta (metadata)
143
+ - **Debug**: Gray (dimmed)
144
+ - **Warn**: Yellow (level) + Magenta (metadata)
145
+
146
+ ## Database Schema
147
+
148
+ ```sql
149
+ CREATE TABLE `logs` (
150
+ `id` int auto_increment primary key,
151
+ `level` varchar(16) not null,
152
+ `message` varchar(2048) not null,
153
+ `meta` varchar(2048) not null,
154
+ `timestamp` datetime not null
155
+ );
156
+ ```
157
+
158
+ ## Error Handling
159
+
160
+ The logger gracefully handles database connection failures:
161
+ - Logs are always written to console
162
+ - Database errors are logged to console only
163
+ - Application continues running even if database is unavailable
164
+ - Connection errors (ECONNREFUSED, ENOTFOUND, ETIMEDOUT) are handled with warnings
165
+
166
+ ## TypeScript Types
167
+
168
+ ```typescript
169
+ interface LoggerConfig {
170
+ mysql: {
171
+ host: string;
172
+ port: number;
173
+ user: string;
174
+ password: string;
175
+ database?: string; // defaults to 'logs'
176
+ };
177
+ }
178
+
179
+ interface LogMetadata {
180
+ [key: string]: any;
181
+ }
182
+ ```
183
+
184
+ ## License
185
+
186
+ ISC
@@ -0,0 +1,2 @@
1
+ export { createLogger } from './logger';
2
+ export { LoggerConfig, Logger, FastifyLogger, LogMetadata } from './types';
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createLogger = void 0;
4
+ var logger_1 = require("./logger");
5
+ Object.defineProperty(exports, "createLogger", { enumerable: true, get: function () { return logger_1.createLogger; } });
@@ -0,0 +1,5 @@
1
+ import { LoggerConfig, Logger, FastifyLogger } from "./types";
2
+ export declare function createLogger(config: LoggerConfig): {
3
+ logger: Logger;
4
+ fastifyLogger: FastifyLogger;
5
+ };
package/dist/logger.js ADDED
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.createLogger = void 0;
30
+ const mysql_1 = __importStar(require("@databases/mysql"));
31
+ const fast_safe_stringify_1 = __importDefault(require("fast-safe-stringify"));
32
+ let conn;
33
+ function initializeConnection(config) {
34
+ const database = config.mysql.database || 'logs';
35
+ conn = (0, mysql_1.default)(`mysql://${config.mysql.user}:${config.mysql.password}@${config.mysql.host}:${config.mysql.port}/${database}`);
36
+ }
37
+ function log(level, message, meta) {
38
+ let time = new Date().toISOString();
39
+ let hhMMTime = time.slice(11, 19);
40
+ // colorize time to have ansi blue color
41
+ hhMMTime = `\x1b[34m${hhMMTime}\x1b[0m`;
42
+ // colorize level to have ansi red color for errors
43
+ meta = meta ? (0, fast_safe_stringify_1.default)(meta) : "";
44
+ if (level === "error") {
45
+ level = `\x1b[31m${level}\x1b[0m`;
46
+ meta = `\x1b[35m${meta}\x1b[0m`;
47
+ }
48
+ else if (level === "info") {
49
+ level = `\x1b[32m${level}\x1b[0m`;
50
+ meta = `\x1b[35m${meta}\x1b[0m`;
51
+ }
52
+ else if (level === "debug") {
53
+ level = `\x1b[90m${level}\x1b[0m`;
54
+ message = `\x1b[90m${message}\x1b[0m`;
55
+ meta = `\x1b[90m${meta}\x1b[0m`;
56
+ }
57
+ else if (level === "warn") {
58
+ level = `\x1b[33m${level}\x1b[0m`;
59
+ meta = `\x1b[35m${meta}\x1b[0m`;
60
+ }
61
+ console.log(`${hhMMTime} [${level}]: ${message} ${meta}`);
62
+ }
63
+ function storeInDB(level, message, meta) {
64
+ if (!conn) {
65
+ console.error(`\x1b[31m[Logger DB Error] Logger not initialized. Call createLogger() first.\x1b[0m`);
66
+ return;
67
+ }
68
+ if (!meta)
69
+ meta = "";
70
+ // Use the logger's dedicated connection pool
71
+ conn.query((0, mysql_1.sql) `
72
+ INSERT INTO \`logs\` (\`level\`, \`message\`, \`meta\`, \`timestamp\`)
73
+ VALUES (${level}, ${message}, ${JSON.stringify(meta)}, NOW())
74
+ `).catch(err => {
75
+ // Log connection errors to console only, don't crash
76
+ console.error(`\x1b[31m[Logger DB Error] Failed to store log in DB:\x1b[0m ${err.message}`);
77
+ // Optionally check if it's a connection error vs. other query error
78
+ if (err.code && (err.code === 'ECONNREFUSED' || err.code === 'ENOTFOUND' || err.code === 'ETIMEDOUT')) {
79
+ console.warn(`\x1b[33m[Logger DB Warning] Logger DB connection failed (${err.code}). Is the DB ready?\x1b[0m`);
80
+ }
81
+ });
82
+ }
83
+ function createLogger(config) {
84
+ initializeConnection(config);
85
+ const logger = {
86
+ info: (message, meta) => {
87
+ log("info", message, meta);
88
+ storeInDB("info", message, meta);
89
+ },
90
+ error: (message, meta) => {
91
+ if (message.message && message.stack) {
92
+ // Pass the error message string, not the whole object, to storeInDB
93
+ storeInDB("error", message.message, meta);
94
+ return log("error", message.message, {
95
+ stack: message.stack,
96
+ ...meta,
97
+ });
98
+ }
99
+ // If message is not an Error object, check if it's another type of object
100
+ const messageString = typeof message === 'object' && message !== null && !Array.isArray(message)
101
+ ? (0, fast_safe_stringify_1.default)(message) // Stringify if it's a plain object
102
+ : String(message); // Otherwise, convert to string as before
103
+ log("error", messageString, meta);
104
+ // Store the original message or its stringified form in DB
105
+ storeInDB("error", typeof message === 'object' ? (0, fast_safe_stringify_1.default)(message) : message, meta);
106
+ },
107
+ errorEnriched: (message, error, meta) => {
108
+ const enrichedMessage = `${message}: ${error.message}`;
109
+ if (error.message && error.stack) {
110
+ // Store the combined error message in the DB
111
+ storeInDB("error", enrichedMessage, meta);
112
+ return log("error", enrichedMessage, {
113
+ stack: error.stack,
114
+ ...meta,
115
+ });
116
+ }
117
+ log("error", String(message), meta);
118
+ storeInDB("error", message, meta);
119
+ },
120
+ warn: (message, meta) => {
121
+ log("warn", message, meta);
122
+ storeInDB("warn", message, meta);
123
+ },
124
+ // do not store debug logs in DB
125
+ debug: (message, meta) => {
126
+ log("debug", message, meta);
127
+ },
128
+ };
129
+ const fastifyLogger = {
130
+ // Stringify potential objects passed to info/warn
131
+ info: (msg) => {
132
+ const messageString = typeof msg === 'object' ? (0, fast_safe_stringify_1.default)(msg) : String(msg);
133
+ log("info", messageString);
134
+ // storeInDB("info", messageString); // Keep commented out as original
135
+ },
136
+ error: (message, meta) => {
137
+ const errorMessage = (message && message.message) ? message.message : String(message);
138
+ log("error", errorMessage, meta);
139
+ // Ensure string is passed to storeInDB
140
+ storeInDB("error", typeof message === 'object' ? (0, fast_safe_stringify_1.default)(message) : errorMessage, meta);
141
+ },
142
+ warn: (msg) => {
143
+ const messageString = typeof msg === 'object' ? (0, fast_safe_stringify_1.default)(msg) : String(msg);
144
+ log("warn", messageString);
145
+ storeInDB("warn", messageString); // Pass stringified message
146
+ },
147
+ // do not store debug logs in DB
148
+ debug: (msg) => {
149
+ log("debug", msg);
150
+ },
151
+ fatal: (msg) => {
152
+ log("error", msg);
153
+ storeInDB("error", msg);
154
+ process.exit(1);
155
+ },
156
+ trace: (msg) => { },
157
+ child: (meta) => {
158
+ return fastifyLogger;
159
+ },
160
+ };
161
+ // Set up uncaught exception handler
162
+ process.on("uncaughtException", function (err) {
163
+ logger.errorEnriched("UncaughtException processing: %s", err);
164
+ });
165
+ return { logger, fastifyLogger };
166
+ }
167
+ exports.createLogger = createLogger;
@@ -0,0 +1,28 @@
1
+ export interface LoggerConfig {
2
+ mysql: {
3
+ host: string;
4
+ port: number;
5
+ user: string;
6
+ password: string;
7
+ database?: string;
8
+ };
9
+ }
10
+ export interface LogMetadata {
11
+ [key: string]: any;
12
+ }
13
+ export interface Logger {
14
+ info: (message: string, meta?: LogMetadata) => void;
15
+ error: (message: string | Error | any, meta?: LogMetadata) => void;
16
+ errorEnriched: (message: string, error: Error | any, meta?: LogMetadata) => void;
17
+ warn: (message: string, meta?: LogMetadata) => void;
18
+ debug: (message: string, meta?: LogMetadata) => void;
19
+ }
20
+ export interface FastifyLogger {
21
+ info: (msg: any) => void;
22
+ error: (message: string | Error | any, meta?: LogMetadata) => void;
23
+ warn: (msg: any) => void;
24
+ debug: (msg: any) => void;
25
+ fatal: (msg: any) => void;
26
+ trace: (msg: any) => void;
27
+ child: (meta: any) => FastifyLogger;
28
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/example.ts ADDED
@@ -0,0 +1,41 @@
1
+ import { createLogger, LoggerConfig } from './src/index';
2
+
3
+ // Example configuration
4
+ const config: LoggerConfig = {
5
+ mysql: {
6
+ host: 'localhost',
7
+ port: 3306,
8
+ user: 'root',
9
+ password: 'test',
10
+ database: 'logs' // optional, defaults to 'logs'
11
+ }
12
+ };
13
+
14
+ // Create logger instances
15
+ const { logger, fastifyLogger } = createLogger(config);
16
+
17
+ // Example usage
18
+ logger.info('Application started successfully');
19
+ logger.debug('Debug information', { userId: 123, action: 'login' });
20
+ logger.warn('Low memory warning', { available: '100MB', threshold: '200MB' });
21
+
22
+ // Error logging examples
23
+ try {
24
+ throw new Error('Something went wrong');
25
+ } catch (err) {
26
+ logger.error(err); // Logs with stack trace
27
+ }
28
+
29
+ // Enriched error logging
30
+ try {
31
+ // Some database operation
32
+ throw new Error('Connection timeout');
33
+ } catch (err) {
34
+ logger.errorEnriched('Database query failed', err, {
35
+ query: 'SELECT * FROM users',
36
+ timeout: 5000
37
+ });
38
+ }
39
+
40
+ // Object error logging
41
+ logger.error({ code: 'AUTH_FAILED', user: 'john@example.com' });
@@ -0,0 +1,11 @@
1
+ -- Create the logs database
2
+ CREATE DATABASE IF NOT EXISTS `logs`;
3
+
4
+ -- Create the logs table within the 'logs' database
5
+ CREATE TABLE IF NOT EXISTS `logs`.`logs` (
6
+ `id` int auto_increment primary key,
7
+ `level` varchar(16) not null,
8
+ `message` varchar(2048) not null,
9
+ `meta` varchar(2048) not null,
10
+ `timestamp` datetime not null
11
+ );
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@gratheon/log-lib",
3
+ "version": "1.0.0",
4
+ "description": "Logging library with console and MySQL database persistence",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "dev": "tsc --watch",
10
+ "prepublishOnly": "npm run build"
11
+ },
12
+ "keywords": [
13
+ "logging",
14
+ "logger",
15
+ "mysql",
16
+ "typescript"
17
+ ],
18
+ "author": "",
19
+ "license": "ISC",
20
+ "dependencies": {
21
+ "@databases/mysql": "^6.0.0",
22
+ "fast-safe-stringify": "^2.1.1"
23
+ },
24
+ "devDependencies": {
25
+ "@types/node": "^18.11.11",
26
+ "typescript": "^4.9.4"
27
+ }
28
+ }
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { createLogger } from './logger';
2
+ export { LoggerConfig, Logger, FastifyLogger, LogMetadata } from './types';
package/src/logger.ts ADDED
@@ -0,0 +1,153 @@
1
+ import createConnectionPool, { sql, ConnectionPool } from "@databases/mysql";
2
+ import jsonStringify from "fast-safe-stringify";
3
+ import { LoggerConfig, Logger, FastifyLogger, LogMetadata } from "./types";
4
+
5
+ let conn: ConnectionPool;
6
+
7
+ function initializeConnection(config: LoggerConfig) {
8
+ const database = config.mysql.database || 'logs';
9
+ conn = createConnectionPool(
10
+ `mysql://${config.mysql.user}:${config.mysql.password}@${config.mysql.host}:${config.mysql.port}/${database}`,
11
+ );
12
+ }
13
+
14
+ function log(level: string, message: string, meta?: any) {
15
+ let time = new Date().toISOString();
16
+ let hhMMTime = time.slice(11, 19);
17
+ // colorize time to have ansi blue color
18
+ hhMMTime = `\x1b[34m${hhMMTime}\x1b[0m`;
19
+
20
+ // colorize level to have ansi red color for errors
21
+ meta = meta ? jsonStringify(meta) : "";
22
+
23
+ if (level === "error") {
24
+ level = `\x1b[31m${level}\x1b[0m`;
25
+ meta = `\x1b[35m${meta}\x1b[0m`;
26
+ } else if (level === "info") {
27
+ level = `\x1b[32m${level}\x1b[0m`;
28
+ meta = `\x1b[35m${meta}\x1b[0m`;
29
+ } else if (level === "debug") {
30
+ level = `\x1b[90m${level}\x1b[0m`;
31
+ message = `\x1b[90m${message}\x1b[0m`;
32
+ meta = `\x1b[90m${meta}\x1b[0m`;
33
+ } else if (level === "warn") {
34
+ level = `\x1b[33m${level}\x1b[0m`;
35
+ meta = `\x1b[35m${meta}\x1b[0m`;
36
+ }
37
+
38
+ console.log(`${hhMMTime} [${level}]: ${message} ${meta}`);
39
+ }
40
+
41
+ function storeInDB(level: string, message: string, meta?: any) {
42
+ if (!conn) {
43
+ console.error(`\x1b[31m[Logger DB Error] Logger not initialized. Call createLogger() first.\x1b[0m`);
44
+ return;
45
+ }
46
+
47
+ if (!meta) meta = "";
48
+ // Use the logger's dedicated connection pool
49
+ conn.query(sql`
50
+ INSERT INTO \`logs\` (\`level\`, \`message\`, \`meta\`, \`timestamp\`)
51
+ VALUES (${level}, ${message}, ${JSON.stringify(meta)}, NOW())
52
+ `).catch(err => {
53
+ // Log connection errors to console only, don't crash
54
+ console.error(`\x1b[31m[Logger DB Error] Failed to store log in DB:\x1b[0m ${err.message}`);
55
+ // Optionally check if it's a connection error vs. other query error
56
+ if (err.code && (err.code === 'ECONNREFUSED' || err.code === 'ENOTFOUND' || err.code === 'ETIMEDOUT')) {
57
+ console.warn(`\x1b[33m[Logger DB Warning] Logger DB connection failed (${err.code}). Is the DB ready?\x1b[0m`);
58
+ }
59
+ });
60
+ }
61
+
62
+ export function createLogger(config: LoggerConfig): { logger: Logger; fastifyLogger: FastifyLogger } {
63
+ initializeConnection(config);
64
+
65
+ const logger: Logger = {
66
+ info: (message: string, meta?: LogMetadata) => {
67
+ log("info", message, meta);
68
+ storeInDB("info", message, meta);
69
+ },
70
+ error: (message: string | Error | any, meta?: LogMetadata) => {
71
+ if (message.message && message.stack) {
72
+ // Pass the error message string, not the whole object, to storeInDB
73
+ storeInDB("error", message.message, meta);
74
+ return log("error", message.message, {
75
+ stack: message.stack,
76
+ ...meta,
77
+ });
78
+ }
79
+ // If message is not an Error object, check if it's another type of object
80
+ const messageString = typeof message === 'object' && message !== null && !Array.isArray(message)
81
+ ? jsonStringify(message) // Stringify if it's a plain object
82
+ : String(message); // Otherwise, convert to string as before
83
+ log("error", messageString, meta);
84
+ // Store the original message or its stringified form in DB
85
+ storeInDB("error", typeof message === 'object' ? jsonStringify(message) : message, meta);
86
+ },
87
+ errorEnriched: (message: string, error: Error | any, meta?: LogMetadata) => {
88
+ const enrichedMessage = `${message}: ${error.message}`;
89
+ if (error.message && error.stack) {
90
+ // Store the combined error message in the DB
91
+ storeInDB("error", enrichedMessage, meta);
92
+ return log("error", enrichedMessage, {
93
+ stack: error.stack,
94
+ ...meta,
95
+ });
96
+ }
97
+ log("error", String(message), meta);
98
+ storeInDB("error", message, meta);
99
+ },
100
+ warn: (message: string, meta?: LogMetadata) => {
101
+ log("warn", message, meta);
102
+ storeInDB("warn", message, meta);
103
+ },
104
+
105
+ // do not store debug logs in DB
106
+ debug: (message: string, meta?: LogMetadata) => {
107
+ log("debug", message, meta);
108
+ },
109
+ };
110
+
111
+ const fastifyLogger: FastifyLogger = {
112
+ // Stringify potential objects passed to info/warn
113
+ info: (msg) => {
114
+ const messageString = typeof msg === 'object' ? jsonStringify(msg) : String(msg);
115
+ log("info", messageString);
116
+ // storeInDB("info", messageString); // Keep commented out as original
117
+ },
118
+ error: (message: string | Error | any, meta?: LogMetadata) => {
119
+ const errorMessage = (message && message.message) ? message.message : String(message);
120
+ log("error", errorMessage, meta);
121
+ // Ensure string is passed to storeInDB
122
+ storeInDB("error", typeof message === 'object' ? jsonStringify(message) : errorMessage, meta);
123
+ },
124
+ warn: (msg) => {
125
+ const messageString = typeof msg === 'object' ? jsonStringify(msg) : String(msg);
126
+ log("warn", messageString);
127
+ storeInDB("warn", messageString); // Pass stringified message
128
+ },
129
+
130
+ // do not store debug logs in DB
131
+ debug: (msg) => {
132
+ log("debug", msg);
133
+ },
134
+
135
+ fatal: (msg) => {
136
+ log("error", msg);
137
+ storeInDB("error", msg);
138
+ process.exit(1);
139
+ },
140
+
141
+ trace: (msg) => {},
142
+ child: (meta: any) => {
143
+ return fastifyLogger;
144
+ },
145
+ };
146
+
147
+ // Set up uncaught exception handler
148
+ process.on("uncaughtException", function (err) {
149
+ logger.errorEnriched("UncaughtException processing: %s", err);
150
+ });
151
+
152
+ return { logger, fastifyLogger };
153
+ }
package/src/types.ts ADDED
@@ -0,0 +1,31 @@
1
+ export interface LoggerConfig {
2
+ mysql: {
3
+ host: string;
4
+ port: number;
5
+ user: string;
6
+ password: string;
7
+ database?: string; // defaults to 'logs'
8
+ };
9
+ }
10
+
11
+ export interface LogMetadata {
12
+ [key: string]: any;
13
+ }
14
+
15
+ export interface Logger {
16
+ info: (message: string, meta?: LogMetadata) => void;
17
+ error: (message: string | Error | any, meta?: LogMetadata) => void;
18
+ errorEnriched: (message: string, error: Error | any, meta?: LogMetadata) => void;
19
+ warn: (message: string, meta?: LogMetadata) => void;
20
+ debug: (message: string, meta?: LogMetadata) => void;
21
+ }
22
+
23
+ export interface FastifyLogger {
24
+ info: (msg: any) => void;
25
+ error: (message: string | Error | any, meta?: LogMetadata) => void;
26
+ warn: (msg: any) => void;
27
+ debug: (msg: any) => void;
28
+ fatal: (msg: any) => void;
29
+ trace: (msg: any) => void;
30
+ child: (meta: any) => FastifyLogger;
31
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "commonjs",
5
+ "lib": ["ES2020"],
6
+ "declaration": true,
7
+ "outDir": "./dist",
8
+ "rootDir": "./src",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "moduleResolution": "node",
14
+ "resolveJsonModule": true
15
+ },
16
+ "include": ["src/**/*"],
17
+ "exclude": ["node_modules", "dist"]
18
+ }