@gratheon/log-lib 2.2.5 → 2.2.7

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/dist/logger.js CHANGED
@@ -34,6 +34,7 @@ const fs = __importStar(require("fs"));
34
34
  const path = __importStar(require("path"));
35
35
  let conn = null;
36
36
  let dbInitialized = false;
37
+ let initPromise = null;
37
38
  const LOG_LEVELS = {
38
39
  debug: 0,
39
40
  info: 1,
@@ -107,7 +108,7 @@ async function initializeConnection(config) {
107
108
  INDEX idx_level (level)
108
109
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
109
110
  `);
110
- // Run migrations: Add stacktrace column if it doesn't exist (for existing tables)
111
+ // Run migrations: Add stacktrace column if it doesn't exist (for existing tables created before v2.2.0)
111
112
  try {
112
113
  const columns = await conn.query((0, mysql_1.sql) `SHOW COLUMNS FROM \`logs\` LIKE 'stacktrace'`);
113
114
  if (columns.length === 0) {
@@ -115,12 +116,16 @@ async function initializeConnection(config) {
115
116
  await conn.query((0, mysql_1.sql) `ALTER TABLE \`logs\` ADD COLUMN \`stacktrace\` TEXT AFTER \`meta\``);
116
117
  console.log('[log-lib] Migration complete: stacktrace column added');
117
118
  }
119
+ else {
120
+ console.log('[log-lib] Migration check: stacktrace column already exists');
121
+ }
118
122
  }
119
123
  catch (migrationErr) {
120
124
  console.error('[log-lib] Migration failed (non-critical):', migrationErr);
121
125
  // Don't fail initialization if migration fails
122
126
  }
123
127
  dbInitialized = true;
128
+ console.log('[log-lib] Database initialization complete');
124
129
  }
125
130
  catch (err) {
126
131
  console.error('Failed to initialize logs database:', err);
@@ -312,26 +317,39 @@ function safeMeta(meta) {
312
317
  return meta;
313
318
  }
314
319
  function storeInDB(level, message, meta, stacktrace) {
315
- if (!conn || !dbInitialized) {
316
- // Database not ready yet, skip DB logging
320
+ if (!conn) {
321
+ // Database not configured, skip DB logging
317
322
  return;
318
323
  }
319
- try {
320
- const msg = safeToStringMessage(message);
321
- const metaObj = safeMeta(meta);
322
- const metaStr = (0, fast_safe_stringify_1.default)(metaObj).slice(0, 2000);
323
- const stackStr = stacktrace || '';
324
- // Fire and forget; avoid awaiting in hot path. Catch errors to avoid unhandled rejection.
325
- conn.query((0, mysql_1.sql) `INSERT INTO \`logs\` (level, message, meta, stacktrace, timestamp) VALUES (${level}, ${msg}, ${metaStr}, ${stackStr}, NOW())`).catch(e => {
324
+ // Wait for initialization to complete before writing
325
+ const doStore = async () => {
326
+ if (initPromise) {
327
+ await initPromise.catch(() => { }); // Wait but ignore errors
328
+ }
329
+ if (!dbInitialized) {
330
+ // Initialization failed, skip DB logging
331
+ return;
332
+ }
333
+ try {
334
+ const msg = safeToStringMessage(message);
335
+ const metaObj = safeMeta(meta);
336
+ const metaStr = (0, fast_safe_stringify_1.default)(metaObj).slice(0, 2000);
337
+ const stackStr = stacktrace || '';
338
+ await conn.query((0, mysql_1.sql) `INSERT INTO \`logs\` (level, message, meta, stacktrace, timestamp) VALUES (${level}, ${msg}, ${metaStr}, ${stackStr}, NOW())`);
339
+ }
340
+ catch (e) {
326
341
  // fallback console output only - but don't spam
327
342
  if (process.env.ENV_ID === 'dev') {
328
343
  console.error('Failed to persist log to DB', e);
329
344
  }
330
- });
331
- }
332
- catch (e) {
333
- console.error('Unexpected failure preparing log for DB', e);
334
- }
345
+ }
346
+ };
347
+ // Fire and forget
348
+ doStore().catch(e => {
349
+ if (process.env.ENV_ID === 'dev') {
350
+ console.error('Unexpected failure preparing log for DB', e);
351
+ }
352
+ });
335
353
  }
336
354
  function createLogger(config = {}) {
337
355
  // Set up log level filtering
@@ -340,11 +358,9 @@ function createLogger(config = {}) {
340
358
  process.env.LOG_LEVEL ||
341
359
  (process.env.ENV_ID === 'dev' ? 'debug' : 'info');
342
360
  currentLogLevel = LOG_LEVELS[configuredLevel] ?? LOG_LEVELS.info;
343
- // Start initialization asynchronously but don't wait for it (only if MySQL config provided)
361
+ // Start initialization asynchronously (only if MySQL config provided)
344
362
  if (config.mysql) {
345
- initializeConnection(config).catch(err => {
346
- console.error('Error during log database initialization:', err);
347
- });
363
+ initPromise = initializeConnection(config);
348
364
  }
349
365
  const logger = {
350
366
  info: (message, meta) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gratheon/log-lib",
3
- "version": "2.2.5",
3
+ "version": "2.2.7",
4
4
  "description": "Logging library with console and MySQL database persistence",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/logger.ts CHANGED
@@ -7,6 +7,7 @@ import { LoggerConfig, Logger, FastifyLogger, LogMetadata, LogLevel } from "./ty
7
7
 
8
8
  let conn: ConnectionPool | null = null;
9
9
  let dbInitialized = false;
10
+ let initPromise: Promise<void> | null = null;
10
11
 
11
12
  const LOG_LEVELS: Record<LogLevel, number> = {
12
13
  debug: 0,
@@ -91,13 +92,15 @@ async function initializeConnection(config: LoggerConfig) {
91
92
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
92
93
  `);
93
94
 
94
- // Run migrations: Add stacktrace column if it doesn't exist (for existing tables)
95
+ // Run migrations: Add stacktrace column if it doesn't exist (for existing tables created before v2.2.0)
95
96
  try {
96
97
  const columns = await conn.query(sql`SHOW COLUMNS FROM \`logs\` LIKE 'stacktrace'`);
97
98
  if (columns.length === 0) {
98
99
  console.log('[log-lib] Running migration: Adding stacktrace column...');
99
100
  await conn.query(sql`ALTER TABLE \`logs\` ADD COLUMN \`stacktrace\` TEXT AFTER \`meta\``);
100
101
  console.log('[log-lib] Migration complete: stacktrace column added');
102
+ } else {
103
+ console.log('[log-lib] Migration check: stacktrace column already exists');
101
104
  }
102
105
  } catch (migrationErr) {
103
106
  console.error('[log-lib] Migration failed (non-critical):', migrationErr);
@@ -105,6 +108,7 @@ async function initializeConnection(config: LoggerConfig) {
105
108
  }
106
109
 
107
110
  dbInitialized = true;
111
+ console.log('[log-lib] Database initialization complete');
108
112
  } catch (err) {
109
113
  console.error('Failed to initialize logs database:', err);
110
114
  // Don't throw - allow the service to start even if logging DB fails
@@ -294,25 +298,43 @@ function safeMeta(meta: any): any {
294
298
  }
295
299
 
296
300
  function storeInDB(level: string, message: any, meta?: any, stacktrace?: string) {
297
- if (!conn || !dbInitialized) {
298
- // Database not ready yet, skip DB logging
301
+ if (!conn) {
302
+ // Database not configured, skip DB logging
299
303
  return;
300
304
  }
301
- try {
302
- const msg = safeToStringMessage(message);
303
- const metaObj = safeMeta(meta);
304
- const metaStr = jsonStringify(metaObj).slice(0, 2000);
305
- const stackStr = stacktrace || '';
306
- // Fire and forget; avoid awaiting in hot path. Catch errors to avoid unhandled rejection.
307
- conn.query(sql`INSERT INTO \`logs\` (level, message, meta, stacktrace, timestamp) VALUES (${level}, ${msg}, ${metaStr}, ${stackStr}, NOW())`).catch(e => {
305
+
306
+ // Wait for initialization to complete before writing
307
+ const doStore = async () => {
308
+ if (initPromise) {
309
+ await initPromise.catch(() => {}); // Wait but ignore errors
310
+ }
311
+
312
+ if (!dbInitialized) {
313
+ // Initialization failed, skip DB logging
314
+ return;
315
+ }
316
+
317
+ try {
318
+ const msg = safeToStringMessage(message);
319
+ const metaObj = safeMeta(meta);
320
+ const metaStr = jsonStringify(metaObj).slice(0, 2000);
321
+ const stackStr = stacktrace || '';
322
+
323
+ await conn!.query(sql`INSERT INTO \`logs\` (level, message, meta, stacktrace, timestamp) VALUES (${level}, ${msg}, ${metaStr}, ${stackStr}, NOW())`);
324
+ } catch (e: any) {
308
325
  // fallback console output only - but don't spam
309
326
  if (process.env.ENV_ID === 'dev') {
310
327
  console.error('Failed to persist log to DB', e);
311
328
  }
312
- });
313
- } catch (e) {
314
- console.error('Unexpected failure preparing log for DB', e);
315
- }
329
+ }
330
+ };
331
+
332
+ // Fire and forget
333
+ doStore().catch(e => {
334
+ if (process.env.ENV_ID === 'dev') {
335
+ console.error('Unexpected failure preparing log for DB', e);
336
+ }
337
+ });
316
338
  }
317
339
 
318
340
  export function createLogger(config: LoggerConfig = {}): { logger: Logger; fastifyLogger: FastifyLogger } {
@@ -324,11 +346,9 @@ export function createLogger(config: LoggerConfig = {}): { logger: Logger; fasti
324
346
 
325
347
  currentLogLevel = LOG_LEVELS[configuredLevel] ?? LOG_LEVELS.info;
326
348
 
327
- // Start initialization asynchronously but don't wait for it (only if MySQL config provided)
349
+ // Start initialization asynchronously (only if MySQL config provided)
328
350
  if (config.mysql) {
329
- initializeConnection(config).catch(err => {
330
- console.error('Error during log database initialization:', err);
331
- });
351
+ initPromise = initializeConnection(config);
332
352
  }
333
353
 
334
354
  const logger: Logger = {