Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(frontend): import pino as frontend logger #178

Merged
merged 2 commits into from
Mar 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/src/build-system/utils/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export async function readFileWithRetries(
attempt++;

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

// Wait a short delay before retrying
if (attempt < maxRetries) {
Expand Down
3 changes: 3 additions & 0 deletions frontend/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
const nextConfig = {
output: 'standalone',
reactStrictMode: true,
experimental: {
serverComponentsExternalPackages: ['pino', 'pino-pretty']
},
webpack: (config, { isServer }) => {
// Fixes npm packages that depend on `fs` module
if (!isServer) {
Expand Down
2 changes: 2 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
"motion": "^12.4.7",
"next": "^14.2.13",
"next-themes": "^0.3.0",
"pino": "^9.6.0",
"pino-pretty": "^13.0.0",
"puppeteer": "^24.3.1",
"react": "^18.3.1",
"react-activity-calendar": "^2.7.8",
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/app/(main)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { ProjectContext } from '@/components/chat/code-engine/project-context';
import { SignInModal } from '@/components/sign-in-modal';
import { SignUpModal } from '@/components/sign-up-modal';
import { useRouter } from 'next/navigation';
import { logger } from '../log/logger';
export default function HomePage() {
// States for AuthChoiceModal
const [showAuthChoice, setShowAuthChoice] = useState(false);
Expand All @@ -32,7 +33,7 @@ export default function HomePage() {
await createProjectFromPrompt(message, isPublic, model);
promptFormRef.current.clearMessage();
} catch (error) {
console.error('Error creating project:', error);
logger.error('Error creating project:', error);
}
};

Expand Down
9 changes: 5 additions & 4 deletions frontend/src/app/api/file/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ import { NextResponse } from 'next/server';
import { FileReader } from '@/utils/file-reader';
import { promises as fs } from 'fs';
import path from 'path';
import { logger } from '@/app/log/logger';

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

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

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

console.log('[API] File updated successfully');
logger.info('[API] File updated successfully');
return NextResponse.json({
message: 'File updated successfully',
filePath,
});
} catch (error) {
console.error('[API] Error updating file:', error);
logger.error('[API] Error updating file:', error);
return NextResponse.json(
{ error: 'Failed to update file' },
{ status: 500 }
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/app/api/media/[...path]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { NextRequest } from 'next/server';
import fs from 'fs/promises'; // Use promises API
import path from 'path';
import { getMediaDir } from 'codefox-common';
import { logger } from '@/app/log/logger';

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

if (!normalizedPath.startsWith(mediaDir)) {
console.error('Possible directory traversal attempt:', filePath);
logger.error('Possible directory traversal attempt:', filePath);
return new Response('Access denied', { status: 403 });
}

Expand Down Expand Up @@ -53,7 +54,7 @@ export async function GET(
},
});
} catch (error) {
console.error('Error serving media file:', error);
logger.error('Error serving media file:', error);
const errorMessage =
process.env.NODE_ENV === 'development'
? `Error serving file: ${error.message}`
Expand Down
41 changes: 21 additions & 20 deletions frontend/src/app/api/runProject/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import os from 'os';

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

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

console.log(
logger.info(
'State initialization complete, cleaned up non-running containers and expired port allocations'
);
} catch (error) {
console.error('Error initializing state:', error);
logger.error('Error initializing state:', error);
// If loading fails, continue with empty state
runningContainers = new Map();
allocatedPorts = new Set();
Expand Down Expand Up @@ -134,7 +135,7 @@ async function saveState() {
JSON.stringify(portsArray, null, 2)
);
} catch (error) {
console.error('Error saving state:', error);
logger.error('Error saving state:', error);
} finally {
isUpdatingState = false;
}
Expand Down Expand Up @@ -257,12 +258,12 @@ async function ensureBaseImageExists(): Promise<void> {

// Check if base Dockerfile exists
if (!fs.existsSync(path.join(dockerfilePath, 'Dockerfile'))) {
console.error('Base Dockerfile not found at:', dockerfilePath);
logger.error('Base Dockerfile not found at:', dockerfilePath);
throw new Error('Base Dockerfile not found');
}

// Build the base image
console.log(
logger.info(
`Building base image ${BASE_IMAGE_NAME} from ${dockerfilePath}...`
);
await execWithTimeout(
Expand All @@ -271,9 +272,9 @@ async function ensureBaseImageExists(): Promise<void> {
);

baseImageBuilt = true;
console.log(`Base image ${BASE_IMAGE_NAME} built successfully`);
logger.info(`Base image ${BASE_IMAGE_NAME} built successfully`);
} catch (error) {
console.error('Error building base image:', error);
logger.error('Error building base image:', error);
throw new Error('Failed to build base image');
}
}
Expand All @@ -293,13 +294,13 @@ function execWithTimeout(

const executeWithRetry = (): Promise<string> => {
return new Promise((resolve, reject) => {
console.log(`Executing command: ${command}`);
logger.info(`Executing command: ${command}`);
exec(command, { timeout: options.timeout }, (error, stdout, stderr) => {
if (error) {
console.error(`Command execution error: ${stderr}`);
logger.error(`Command execution error: ${stderr}`);
if (retryCount < maxRetries) {
retryCount++;
console.log(`Retry ${retryCount}/${maxRetries}`);
logger.info(`Retry ${retryCount}/${maxRetries}`);
setTimeout(() => {
executeWithRetry().then(resolve).catch(reject);
}, 2000); // Wait 2 seconds before retry
Expand Down Expand Up @@ -352,9 +353,9 @@ async function runDockerContainer(
await execWithTimeout(`docker rm -f ${existingContainerId}`, {
timeout: 30000,
});
console.log(`Removed non-running container: ${existingContainerId}`);
logger.info(`Removed non-running container: ${existingContainerId}`);
} catch (error) {
console.error(`Error removing non-running container:`, error);
logger.error(`Error removing non-running container:`, error);
// Continue processing even if removal fails
}
}
Expand All @@ -376,7 +377,7 @@ async function runDockerContainer(
await execWithTimeout(`docker inspect ${containerName}`, {
timeout: 10000,
});
console.log(
logger.info(
`Found container with same name ${containerName}, removing it first`
);
await execWithTimeout(`docker rm -f ${containerName}`, {
Expand Down Expand Up @@ -423,7 +424,7 @@ async function runDockerContainer(
}

// Run container
console.log(`Executing run command: ${runCommand}`);
logger.info(`Executing run command: ${runCommand}`);
const containerActualId = await execWithTimeout(
runCommand,
{ timeout: 60000, retries: 2 } // 1 minute timeout, 2 retries
Expand All @@ -448,12 +449,12 @@ async function runDockerContainer(
});
await saveState();

console.log(
logger.info(
`Container ${containerName} is now running at ${URL_PROTOCOL_PREFIX}://${domain} (port: ${exposedPort})`
);
return { domain, containerId: containerActualId, port: exposedPort };
} catch (error: any) {
console.error(`Error running container:`, error);
logger.error(`Error running container:`, error);

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

// Initialize state when service starts
initializeState().catch((error) => {
console.error('Error initializing state:', error);
logger.error('Error initializing state:', error);
});

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

const isRunning = await checkContainerRunning(container.containerId);
if (!isRunning) {
console.log(
logger.info(
`Container ${container.containerId} is no longer running, removing from state`
);
runningContainers.delete(projectPath);
Expand Down Expand Up @@ -529,7 +530,7 @@ export async function GET(req: Request) {
}
await saveState();

console.log(
logger.info(
`Container ${existingContainer.containerId} is no longer running, will create a new one`
);
}
Expand All @@ -554,7 +555,7 @@ export async function GET(req: Request) {
containerId,
});
} catch (error: any) {
console.error(`Failed to start Docker container:`, error);
logger.error(`Failed to start Docker container:`, error);
return NextResponse.json(
{ error: error.message || 'Failed to start Docker container' },
{ status: 500 }
Expand Down
11 changes: 6 additions & 5 deletions frontend/src/app/api/screenshot/route.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { logger } from '@/app/log/logger';
import { NextResponse } from 'next/server';
import puppeteer, { Browser } from 'puppeteer';

Expand All @@ -7,7 +8,7 @@ let browserInstance: Browser | null = null;
// Function to get browser instance
async function getBrowser(): Promise<Browser> {
if (!browserInstance || !browserInstance.isConnected()) {
console.log('Creating new browser instance...');
logger.info('Creating new browser instance...');
browserInstance = await puppeteer.launch({
headless: true,
protocolTimeout: 240000,
Expand Down Expand Up @@ -67,14 +68,14 @@ export async function GET(req: Request) {
},
});
} catch (error: any) {
console.error('Screenshot error:', error);
logger.error('Screenshot error:', error);

// Ensure page is closed even if an error occurs
if (page) {
try {
await page.close();
} catch (closeError) {
console.error('Error closing page:', closeError);
logger.error('Error closing page:', closeError);
}
}

Expand All @@ -90,7 +91,7 @@ export async function GET(req: Request) {
browserInstance = null;
}
} catch (closeBrowserError) {
console.error('Error closing browser:', closeBrowserError);
logger.error('Error closing browser:', closeBrowserError);
}
}

Expand All @@ -104,7 +105,7 @@ export async function GET(req: Request) {
// Handle process termination to close browser
process.on('SIGINT', async () => {
if (browserInstance) {
console.log('Closing browser instance...');
logger.info('Closing browser instance...');
await browserInstance.close();
browserInstance = null;
}
Expand Down
19 changes: 19 additions & 0 deletions frontend/src/app/log/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import pino from 'pino';

export const logger = pino({
level: 'info',
timestamp: () => `,"time":"${new Date().toISOString()}"`,
formatters: {
level(label) {
return { level: label.toUpperCase() };
},
},
transport: {
target: 'pino-pretty',
options: {
colorize: true,
translateTime: 'yyyy-mm-dd HH:MM:ss',
ignore: 'pid,hostname',
},
},
});
3 changes: 2 additions & 1 deletion frontend/src/components/avatar-uploader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Button } from '@/components/ui/button';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { toast } from 'sonner';
import { useAuthContext } from '@/providers/AuthProvider';
import { logger } from '@/app/log/logger';

// Avatar URL normalization helper
export function normalizeAvatarUrl(
Expand Down Expand Up @@ -96,7 +97,7 @@ export const AvatarUploader: React.FC<AvatarUploaderProps> = ({
await refreshUserInfo();
}
} catch (error) {
console.error('Error uploading avatar:', error);
logger.error('Error uploading avatar:', error);

// Extract the error message if available
let errorMessage = 'Failed to upload avatar';
Expand Down
Loading
Loading