Skip to content

Commit c54d6cd

Browse files
PengyuChen01Sma1lboyautofix-ci[bot]
authored and
pengyu
committed
chore(frontend): import pino as frontend logger (#178)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> - **New Features** - Introduced a centralized logging utility across the application to improve error reporting and operational monitoring. - **Chores** - Updated configuration settings with experimental support for external packages. - Added new dependencies that enhance log readability and performance. These changes streamline logging and error tracking without altering core functionalities. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Sma1lboy <541898146chen@gmail.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent 17ba261 commit c54d6cd

31 files changed

+288
-118
lines changed

backend/src/build-system/utils/files.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ export async function readFileWithRetries(
104104
attempt++;
105105

106106
// Optionally log a warning or debug
107-
// console.warn(`Failed to read file: ${filePath}, attempt #${attempt}`);
107+
// logger.warn(`Failed to read file: ${filePath}, attempt #${attempt}`);
108108

109109
// Wait a short delay before retrying
110110
if (attempt < maxRetries) {

frontend/next.config.mjs

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
const nextConfig = {
33
output: 'standalone',
44
reactStrictMode: true,
5+
experimental: {
6+
serverComponentsExternalPackages: ['pino', 'pino-pretty']
7+
},
58
webpack: (config, { isServer }) => {
69
// Fixes npm packages that depend on `fs` module
710
if (!isServer) {

frontend/package.json

+2
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
"motion": "^12.4.7",
5353
"next": "^14.2.13",
5454
"next-themes": "^0.3.0",
55+
"pino": "^9.6.0",
56+
"pino-pretty": "^13.0.0",
5557
"puppeteer": "^24.3.1",
5658
"react": "^18.3.1",
5759
"react-activity-calendar": "^2.7.8",

frontend/src/app/(main)/page.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { ProjectContext } from '@/components/chat/code-engine/project-context';
1111
import { SignInModal } from '@/components/sign-in-modal';
1212
import { SignUpModal } from '@/components/sign-up-modal';
1313
import { useRouter } from 'next/navigation';
14+
import { logger } from '../log/logger';
1415
export default function HomePage() {
1516
// States for AuthChoiceModal
1617
const [showAuthChoice, setShowAuthChoice] = useState(false);
@@ -32,7 +33,7 @@ export default function HomePage() {
3233
await createProjectFromPrompt(message, isPublic, model);
3334
promptFormRef.current.clearMessage();
3435
} catch (error) {
35-
console.error('Error creating project:', error);
36+
logger.error('Error creating project:', error);
3637
}
3738
};
3839

frontend/src/app/api/file/route.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@ import { NextResponse } from 'next/server';
33
import { FileReader } from '@/utils/file-reader';
44
import { promises as fs } from 'fs';
55
import path from 'path';
6+
import { logger } from '@/app/log/logger';
67

78
export async function POST(req: Request) {
8-
console.log('🚀 [API] Received POST request to update file');
9+
logger.info('🚀 [API] Received POST request to update file');
910

1011
try {
1112
const { filePath, newContent } = await req.json();
1213

1314
if (!filePath || !newContent) {
14-
console.error('[API] Missing required parameters');
15+
logger.error('[API] Missing required parameters');
1516
return NextResponse.json(
1617
{ error: "Missing 'filePath' or 'newContent'" },
1718
{ status: 400 }
@@ -20,13 +21,13 @@ export async function POST(req: Request) {
2021
const reader = FileReader.getInstance();
2122
reader.updateFile(filePath, newContent);
2223

23-
console.log('[API] File updated successfully');
24+
logger.info('[API] File updated successfully');
2425
return NextResponse.json({
2526
message: 'File updated successfully',
2627
filePath,
2728
});
2829
} catch (error) {
29-
console.error('[API] Error updating file:', error);
30+
logger.error('[API] Error updating file:', error);
3031
return NextResponse.json(
3132
{ error: 'Failed to update file' },
3233
{ status: 500 }

frontend/src/app/api/media/[...path]/route.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { NextRequest } from 'next/server';
22
import fs from 'fs/promises'; // Use promises API
33
import path from 'path';
44
import { getMediaDir } from 'codefox-common';
5+
import { logger } from '@/app/log/logger';
56

67
export async function GET(
78
request: NextRequest,
@@ -13,7 +14,7 @@ export async function GET(
1314
const normalizedPath = path.normalize(filePath);
1415

1516
if (!normalizedPath.startsWith(mediaDir)) {
16-
console.error('Possible directory traversal attempt:', filePath);
17+
logger.error('Possible directory traversal attempt:', filePath);
1718
return new Response('Access denied', { status: 403 });
1819
}
1920

@@ -53,7 +54,7 @@ export async function GET(
5354
},
5455
});
5556
} catch (error) {
56-
console.error('Error serving media file:', error);
57+
logger.error('Error serving media file:', error);
5758
const errorMessage =
5859
process.env.NODE_ENV === 'development'
5960
? `Error serving file: ${error.message}`

frontend/src/app/api/runProject/route.ts

+21-20
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import os from 'os';
1212

1313
const isWindows = os.platform() === 'win32';
1414
import { URL_PROTOCOL_PREFIX } from '@/utils/const';
15+
import { logger } from '../../log/logger';
1516

1617
// Persist container state to file system to recover after service restarts
1718
const CONTAINER_STATE_FILE = path.join(process.cwd(), 'container-state.json');
@@ -97,11 +98,11 @@ async function initializeState() {
9798
// Check if base image exists
9899
baseImageBuilt = await checkBaseImageExists();
99100

100-
console.log(
101+
logger.info(
101102
'State initialization complete, cleaned up non-running containers and expired port allocations'
102103
);
103104
} catch (error) {
104-
console.error('Error initializing state:', error);
105+
logger.error('Error initializing state:', error);
105106
// If loading fails, continue with empty state
106107
runningContainers = new Map();
107108
allocatedPorts = new Set();
@@ -134,7 +135,7 @@ async function saveState() {
134135
JSON.stringify(portsArray, null, 2)
135136
);
136137
} catch (error) {
137-
console.error('Error saving state:', error);
138+
logger.error('Error saving state:', error);
138139
} finally {
139140
isUpdatingState = false;
140141
}
@@ -257,12 +258,12 @@ async function ensureBaseImageExists(): Promise<void> {
257258

258259
// Check if base Dockerfile exists
259260
if (!fs.existsSync(path.join(dockerfilePath, 'Dockerfile'))) {
260-
console.error('Base Dockerfile not found at:', dockerfilePath);
261+
logger.error('Base Dockerfile not found at:', dockerfilePath);
261262
throw new Error('Base Dockerfile not found');
262263
}
263264

264265
// Build the base image
265-
console.log(
266+
logger.info(
266267
`Building base image ${BASE_IMAGE_NAME} from ${dockerfilePath}...`
267268
);
268269
await execWithTimeout(
@@ -271,9 +272,9 @@ async function ensureBaseImageExists(): Promise<void> {
271272
);
272273

273274
baseImageBuilt = true;
274-
console.log(`Base image ${BASE_IMAGE_NAME} built successfully`);
275+
logger.info(`Base image ${BASE_IMAGE_NAME} built successfully`);
275276
} catch (error) {
276-
console.error('Error building base image:', error);
277+
logger.error('Error building base image:', error);
277278
throw new Error('Failed to build base image');
278279
}
279280
}
@@ -293,13 +294,13 @@ function execWithTimeout(
293294

294295
const executeWithRetry = (): Promise<string> => {
295296
return new Promise((resolve, reject) => {
296-
console.log(`Executing command: ${command}`);
297+
logger.info(`Executing command: ${command}`);
297298
exec(command, { timeout: options.timeout }, (error, stdout, stderr) => {
298299
if (error) {
299-
console.error(`Command execution error: ${stderr}`);
300+
logger.error(`Command execution error: ${stderr}`);
300301
if (retryCount < maxRetries) {
301302
retryCount++;
302-
console.log(`Retry ${retryCount}/${maxRetries}`);
303+
logger.info(`Retry ${retryCount}/${maxRetries}`);
303304
setTimeout(() => {
304305
executeWithRetry().then(resolve).catch(reject);
305306
}, 2000); // Wait 2 seconds before retry
@@ -352,9 +353,9 @@ async function runDockerContainer(
352353
await execWithTimeout(`docker rm -f ${existingContainerId}`, {
353354
timeout: 30000,
354355
});
355-
console.log(`Removed non-running container: ${existingContainerId}`);
356+
logger.info(`Removed non-running container: ${existingContainerId}`);
356357
} catch (error) {
357-
console.error(`Error removing non-running container:`, error);
358+
logger.error(`Error removing non-running container:`, error);
358359
// Continue processing even if removal fails
359360
}
360361
}
@@ -376,7 +377,7 @@ async function runDockerContainer(
376377
await execWithTimeout(`docker inspect ${containerName}`, {
377378
timeout: 10000,
378379
});
379-
console.log(
380+
logger.info(
380381
`Found container with same name ${containerName}, removing it first`
381382
);
382383
await execWithTimeout(`docker rm -f ${containerName}`, {
@@ -423,7 +424,7 @@ async function runDockerContainer(
423424
}
424425

425426
// Run container
426-
console.log(`Executing run command: ${runCommand}`);
427+
logger.info(`Executing run command: ${runCommand}`);
427428
const containerActualId = await execWithTimeout(
428429
runCommand,
429430
{ timeout: 60000, retries: 2 } // 1 minute timeout, 2 retries
@@ -448,12 +449,12 @@ async function runDockerContainer(
448449
});
449450
await saveState();
450451

451-
console.log(
452+
logger.info(
452453
`Container ${containerName} is now running at ${URL_PROTOCOL_PREFIX}://${domain} (port: ${exposedPort})`
453454
);
454455
return { domain, containerId: containerActualId, port: exposedPort };
455456
} catch (error: any) {
456-
console.error(`Error running container:`, error);
457+
logger.error(`Error running container:`, error);
457458

458459
// Clean up allocated port
459460
allocatedPorts.delete(exposedPort);
@@ -465,7 +466,7 @@ async function runDockerContainer(
465466

466467
// Initialize state when service starts
467468
initializeState().catch((error) => {
468-
console.error('Error initializing state:', error);
469+
logger.error('Error initializing state:', error);
469470
});
470471

471472
// Periodically check container status (hourly)
@@ -479,7 +480,7 @@ setInterval(
479480

480481
const isRunning = await checkContainerRunning(container.containerId);
481482
if (!isRunning) {
482-
console.log(
483+
logger.info(
483484
`Container ${container.containerId} is no longer running, removing from state`
484485
);
485486
runningContainers.delete(projectPath);
@@ -529,7 +530,7 @@ export async function GET(req: Request) {
529530
}
530531
await saveState();
531532

532-
console.log(
533+
logger.info(
533534
`Container ${existingContainer.containerId} is no longer running, will create a new one`
534535
);
535536
}
@@ -554,7 +555,7 @@ export async function GET(req: Request) {
554555
containerId,
555556
});
556557
} catch (error: any) {
557-
console.error(`Failed to start Docker container:`, error);
558+
logger.error(`Failed to start Docker container:`, error);
558559
return NextResponse.json(
559560
{ error: error.message || 'Failed to start Docker container' },
560561
{ status: 500 }

frontend/src/app/api/screenshot/route.ts

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { logger } from '@/app/log/logger';
12
import { NextResponse } from 'next/server';
23
import puppeteer, { Browser } from 'puppeteer';
34

@@ -7,7 +8,7 @@ let browserInstance: Browser | null = null;
78
// Function to get browser instance
89
async function getBrowser(): Promise<Browser> {
910
if (!browserInstance || !browserInstance.isConnected()) {
10-
console.log('Creating new browser instance...');
11+
logger.info('Creating new browser instance...');
1112
browserInstance = await puppeteer.launch({
1213
headless: true,
1314
protocolTimeout: 240000,
@@ -67,14 +68,14 @@ export async function GET(req: Request) {
6768
},
6869
});
6970
} catch (error: any) {
70-
console.error('Screenshot error:', error);
71+
logger.error('Screenshot error:', error);
7172

7273
// Ensure page is closed even if an error occurs
7374
if (page) {
7475
try {
7576
await page.close();
7677
} catch (closeError) {
77-
console.error('Error closing page:', closeError);
78+
logger.error('Error closing page:', closeError);
7879
}
7980
}
8081

@@ -90,7 +91,7 @@ export async function GET(req: Request) {
9091
browserInstance = null;
9192
}
9293
} catch (closeBrowserError) {
93-
console.error('Error closing browser:', closeBrowserError);
94+
logger.error('Error closing browser:', closeBrowserError);
9495
}
9596
}
9697

@@ -104,7 +105,7 @@ export async function GET(req: Request) {
104105
// Handle process termination to close browser
105106
process.on('SIGINT', async () => {
106107
if (browserInstance) {
107-
console.log('Closing browser instance...');
108+
logger.info('Closing browser instance...');
108109
await browserInstance.close();
109110
browserInstance = null;
110111
}

frontend/src/app/log/logger.ts

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import pino from 'pino';
2+
3+
export const logger = pino({
4+
level: 'info',
5+
timestamp: () => `,"time":"${new Date().toISOString()}"`,
6+
formatters: {
7+
level(label) {
8+
return { level: label.toUpperCase() };
9+
},
10+
},
11+
transport: {
12+
target: 'pino-pretty',
13+
options: {
14+
colorize: true,
15+
translateTime: 'yyyy-mm-dd HH:MM:ss',
16+
ignore: 'pid,hostname',
17+
},
18+
},
19+
});

frontend/src/components/avatar-uploader.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { Button } from '@/components/ui/button';
77
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
88
import { toast } from 'sonner';
99
import { useAuthContext } from '@/providers/AuthProvider';
10+
import { logger } from '@/app/log/logger';
1011

1112
// Avatar URL normalization helper
1213
export function normalizeAvatarUrl(
@@ -96,7 +97,7 @@ export const AvatarUploader: React.FC<AvatarUploaderProps> = ({
9697
await refreshUserInfo();
9798
}
9899
} catch (error) {
99-
console.error('Error uploading avatar:', error);
100+
logger.error('Error uploading avatar:', error);
100101

101102
// Extract the error message if available
102103
let errorMessage = 'Failed to upload avatar';

0 commit comments

Comments
 (0)