diff --git a/server/dev-api.ts b/server/dev-api.ts index c55a08f..162307b 100644 --- a/server/dev-api.ts +++ b/server/dev-api.ts @@ -1,5 +1,6 @@ import type { Plugin } from 'vite'; import { handleNodeRequest } from './utils/http'; +import { logInfo } from './utils/logger'; import { loadServerEnv } from './env'; import { resetOctokit } from './github/client'; @@ -12,8 +13,8 @@ export function apiMiddleware(): Plugin { server.httpServer?.once('listening', () => { const hasToken = Boolean(process.env.GITHUB_TOKEN?.trim()); - console.log( - `[gitSdm] GitHub API: ${hasToken ? 'authenticated (GITHUB_TOKEN loaded)' : 'unauthenticated — add GITHUB_TOKEN to .env'}`, + logInfo( + `[gitSdm] GitHub API: ${hasToken ? 'authenticated (GITHUB_TOKEN loaded)' : 'unauthenticated — add GITHUB_TOKEN to .env'}` ); }); diff --git a/server/prod-server.ts b/server/prod-server.ts index a7af87f..3e7b82d 100644 --- a/server/prod-server.ts +++ b/server/prod-server.ts @@ -2,6 +2,7 @@ import path from 'node:path'; import { handleApiRequest } from './api-router'; import { resetOctokit } from './github/client'; import { addSecurityHeaders } from './utils/http'; +import { logInfo } from './utils/logger'; const distDir = path.resolve(import.meta.dir, '../dist'); const indexFile = path.join(distDir, 'index.html'); @@ -46,8 +47,8 @@ Bun.serve({ }); const hasToken = Boolean(process.env.GITHUB_TOKEN?.trim()); -console.log(`[gitSdm] listening on http://${host}:${port}`); -console.log(`[gitSdm] GitHub API: ${hasToken ? 'authenticated' : 'unauthenticated'}`); +logInfo(`[gitSdm] listening on http://${host}:${port}`); +logInfo(`[gitSdm] GitHub API: ${hasToken ? 'authenticated' : 'unauthenticated'}`); function safeJoin(root: string, pathname: string): string { const normalized = pathname.replace(/^[/\\]+/, ''); diff --git a/server/utils/logger.test.ts b/server/utils/logger.test.ts index 12cc9e2..b541512 100644 --- a/server/utils/logger.test.ts +++ b/server/utils/logger.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it, spyOn } from 'bun:test'; -import { logApi, logError } from './logger'; +import { logApi, logError, logInfo } from './logger'; describe('utils/logger', () => { it('logs API request metadata to console.log', () => { @@ -76,4 +76,20 @@ describe('utils/logger', () => { errorSpy.mockRestore(); } }); + + it('logs info messages to console.log', () => { + const logSpy = spyOn(console, 'log').mockImplementation(() => {}); + + logInfo('Server started', { port: 3000 }); + + expect(logSpy).toHaveBeenCalled(); + const arg = logSpy.mock.calls[0][0]; + const parsed = JSON.parse(arg); + expect(parsed.level).toBe('info'); + expect(parsed.message).toBe('Server started'); + expect(parsed.port).toBe(3000); + expect(parsed.timestamp).toBeDefined(); + + logSpy.mockRestore(); + }); }); diff --git a/server/utils/logger.ts b/server/utils/logger.ts index b5c44c9..d00ab0e 100644 --- a/server/utils/logger.ts +++ b/server/utils/logger.ts @@ -35,3 +35,14 @@ export function logError( }), ); } + +export function logInfo(message: string, meta?: Record): void { + console.log( + JSON.stringify({ + level: 'info', + message, + timestamp: new Date().toISOString(), + ...meta, + }), + ); +}