Fix Missing Logging and Monitoring in AI-Built Apps
OverMCP Team
Quick answer
Missing logging and monitoring is a common blind spot in vibe-coded apps. AI tools generate functional code but rarely include error tracking, structured logs, or performance alerts. You can fix this in under 30 minutes by adding a logging library, instrumenting key endpoints, and setting up basic alerts — no DevOps experience required.
Why vibe-coded apps skip observability
When you build with Cursor, Bolt.new, or Replit Agent, the AI focuses on shipping features fast. It won't remind you to add console.error handlers, set up log levels, or configure a monitoring dashboard. The result: your app goes live with zero visibility into crashes, slow API calls, or unauthorized access attempts.
I've seen solo founders only discover a data breach because their hosting bill spiked from a cryptominer running on their compromised server. A simple free AI app security scanner could have caught the open port, but logging would have alerted them the minute the miner started.
What to check first
Before you add anything, audit your current codebase for these red flags:
try/catch blocks around async operations (database calls, external APIs)catch blockspino, winston, log4j)/health or /api/health)If you checked 3 or more boxes, your app is flying blind.
Step-by-step fix
1. Add a logging library
Replace console.log with a structured logger. Here's how to add Pino to a Node.js app:
npm install pinoCreate a logger module:
// lib/logger.js
const pino = require('pino');
const logger = pino({
level: process.env.LOG_LEVEL || 'info',
transport: {
target: 'pino-pretty',
options: { colorize: true }
}
});
module.exports = logger;Use it everywhere:
const logger = require('./lib/logger');
app.get('/api/users', async (req, res) => {
logger.info({ userId: req.user?.id }, 'Fetching users');
try {
const users = await db.query('SELECT * FROM users');
res.json(users);
} catch (err) {
logger.error({ err }, 'Failed to fetch users');
res.status(500).json({ error: 'Internal server error' });
}
});2. Instrument API routes with request logging
Use middleware to log every incoming request:
// middleware/requestLogger.js
const logger = require('../lib/logger');
function requestLogger(req, res, next) {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
logger.info({
method: req.method,
url: req.originalUrl,
status: res.statusCode,
duration
}, 'request completed');
});
next();
}
module.exports = requestLogger;Apply it globally:
app.use(requestLogger);3. Set up error tracking
Sign up for Sentry (free tier) and add their SDK:
npm install @sentry/node// app.js
const Sentry = require('@sentry/node');
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV || 'development'
});
// The error handler must be before any other error middleware
app.use(Sentry.Handlers.requestHandler());
app.use(Sentry.Handlers.errorHandler());4. Add a health check endpoint
Many hosting platforms (Vercel, Render, Railway) ping a health endpoint. Without one, they assume the app is dead:
app.get('/health', (req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() });
});5. Set up basic alerts
If you use a platform like Vercel, enable deployment failure alerts in the dashboard. For custom servers, use continuous security monitoring to watch for unusual traffic patterns or error spikes.
Common mistakes
1. Logging sensitive data
AI-generated code often logs full request bodies or user objects. Never log passwords, tokens, or PII. Use a redaction library or configure your logger to sanitize fields:
const logger = pino({
redact: ['req.headers.authorization', 'req.body.password']
});2. Only logging in development
Developers add console.log while debugging and forget to remove them. In production, these either clutter stdout or get stripped out entirely. Always use a proper logger that supports different levels (debug, info, warn, error).
3. No log rotation
If you write logs to files without rotation, they'll eat up disk space. Use a service like Logtail, or rotate files with logrotate. Better yet, stream logs to stdout and let your hosting provider handle collection.
4. Ignoring client-side errors
Vibe-coded frontends (React, Next.js) often lack error boundaries. Add a global error handler:
// pages/_app.js (Next.js)
import * as Sentry from '@sentry/nextjs';
Sentry.init({ dsn: process.env.NEXT_PUBLIC_SENTRY_DSN });
function MyApp({ Component, pageProps, err }) {
return <Component {...pageProps} err={err} />;
}
export default MyApp;5. No monitoring for background jobs
If your app queues emails or processes webhooks, those failures often go silent. Add logging around job handlers and set up alerts for failed jobs.
How OverMCP helps
OverMCP's Vercel security scanner automatically checks for missing monitoring endpoints and insecure configurations. It can flag if your app lacks a health check or exposes sensitive logs. Combine that with proper logging, and you'll catch issues before users do.
FAQ
Why do AI coding tools skip logging?
AI models are trained on code snippets that demonstrate features, not production readiness. They rarely include error handling or observability because those are considered "plumbing" — not the shiny part of an app.
Can I use console.log in production?
Technically yes, but it's not recommended. Console output is unstructured, hard to search, and can include sensitive data. Use a structured logger that supports levels, redaction, and different transports.
How often should I check my logs?
Set up alerts so you don't have to check manually. Monitor error rates, slow endpoints, and unusual traffic spikes. Review a weekly summary to spot trends.