AI Prompt: Forma3D.Connect — Phase 5g: Structured Logging Cleanup¶
Purpose: This prompt instructs an AI to replace console.log statements with structured logging
Estimated Effort: 1 day (~6-8 hours)
Prerequisites: Phase 5f completed (Shared API Types)
Output: All console statements replaced with Pino/NestJS logger, consistent log format
Status: 🟡 PENDING
🎯 Mission¶
You are continuing development of Forma3D.Connect, building on the Phase 5f foundation. Your task is to implement Phase 5g: Structured Logging Cleanup — specifically addressing TD-005 (Console Logging in Production Code) from the technical debt register.
Why This Matters:
The codebase uses console.log/warn/error in some production files, causing:
- Log Format Inconsistency: Console output bypasses Pino formatting
- Missing Context: No correlation IDs, timestamps, or structured metadata
- Hard to Filter: Unstructured logs difficult to query in log aggregation tools
- Production Visibility: Console logs may not appear in container logs properly
Phase 5g delivers:
- All console statements replaced with structured logger
- Consistent log format with correlation IDs
- Proper log levels (debug, info, warn, error)
- Metadata attached to all log entries
📋 Context: Technical Debt Item¶
TD-005: Console Logging in Production Code¶
| Attribute | Value |
|---|---|
| Type | Code Debt |
| Priority | High |
| Location | Multiple files (observability, services) |
| Interest Rate | Medium |
| Principal (Effort) | 1 day |
Current State¶
| File | Console Usage | Context |
|---|---|---|
apps/api/src/observability/instrument.ts |
2 occurrences | OpenTelemetry init |
apps/web/src/observability/sentry.ts |
2 occurrences | Sentry init |
| Test files | Many | Expected (test output) |
🛠️ Implementation Phases¶
Phase 1: Backend Console Replacement (2 hours)¶
Priority: Critical | Impact: High | Dependencies: None
1. Update instrument.ts¶
Update apps/api/src/observability/instrument.ts:
import { Logger } from '@nestjs/common';
const logger = new Logger('OpenTelemetry');
// Replace:
// console.log(`OpenTelemetry initialized for service: ${serviceName}`);
// With:
logger.log({
message: 'OpenTelemetry initialized',
serviceName,
environment: process.env.NODE_ENV,
});
// Replace:
// console.warn('OpenTelemetry disabled - missing configuration');
// With:
logger.warn({
message: 'OpenTelemetry disabled',
reason: 'Missing configuration',
requiredEnvVars: ['OTEL_EXPORTER_OTLP_ENDPOINT'],
});
2. Create Logging Guidelines Document¶
Create docs/04-development/logging-guidelines.md:
# Logging Guidelines
## Overview
This document establishes logging standards for the Forma3D.Connect codebase.
## Logger Usage
### Backend (NestJS)
Always use the NestJS Logger:
\`\`\`typescript
import { Logger } from '@nestjs/common';
@Injectable()
export class MyService {
private readonly logger = new Logger(MyService.name);
doSomething() {
this.logger.log({
message: 'Action performed',
userId: 'user-123',
durationMs: 150,
});
}
}
\`\`\`
### Log Levels
| Level | Use Case | Example |
|-------|----------|---------|
| `debug` | Detailed debugging info | Variable values, state changes |
| `log` | Normal operations | Request processed, job started |
| `warn` | Potential issues | Retry triggered, deprecated usage |
| `error` | Errors requiring attention | Failed operations, exceptions |
### Structured Log Format
Always use object format with a `message` field:
\`\`\`typescript
// Good
this.logger.log({
message: 'Order processed',
orderId: 'order-123',
duration: 250,
});
// Avoid
this.logger.log('Order order-123 processed in 250ms');
\`\`\`
### Required Metadata
| Context | Required Fields |
|---------|-----------------|
| HTTP Request | `method`, `path`, `statusCode`, `duration` |
| Order Events | `orderId`, `shopifyOrderNumber`, `status` |
| Print Jobs | `printJobId`, `simplyPrintJobId`, `status` |
| Webhooks | `webhookId`, `topic`, `source` |
| Errors | `errorName`, `errorMessage`, `stack` |
### Forbidden Patterns
❌ `console.log()` - Bypasses structured logging
❌ `console.error()` - Use `logger.error()` instead
❌ String-only logs - Always use objects
❌ Logging sensitive data (API keys, passwords)
## Frontend Logging
The frontend uses Sentry for error tracking. For development logging:
\`\`\`typescript
// Development only - stripped in production
if (import.meta.env.DEV) {
console.log('Debug info:', data);
}
\`\`\`
Phase 2: Frontend Console Cleanup (2 hours)¶
Priority: Medium | Impact: Medium | Dependencies: None
1. Update Sentry Integration¶
Update apps/web/src/observability/sentry.ts:
// For frontend, we can't use NestJS Logger
// Use conditional logging that gets stripped in production
const isDev = import.meta.env.DEV;
function logInfo(message: string, data?: Record<string, unknown>): void {
if (isDev) {
console.log(`[Sentry] ${message}`, data ?? '');
}
// In production, Sentry captures its own initialization
}
function logWarn(message: string, data?: Record<string, unknown>): void {
if (isDev) {
console.warn(`[Sentry] ${message}`, data ?? '');
}
}
// Replace:
// console.log(`[Sentry] Initialized for environment: ${config.environment}`);
// With:
logInfo('Initialized', {
environment: config.environment,
dsn: config.dsn ? '[CONFIGURED]' : '[MISSING]',
});
// Replace:
// console.warn('[Sentry] Disabled - missing DSN');
// With:
logWarn('Disabled - missing DSN');
2. Create Development Logger Utility¶
Create apps/web/src/lib/dev-logger.ts:
/**
* Development-only logger that gets stripped in production builds.
* Use for debugging information that shouldn't appear in production.
*/
const isDev = import.meta.env.DEV;
export const devLog = {
info: (message: string, data?: Record<string, unknown>) => {
if (isDev) {
console.log(`[DEV] ${message}`, data ?? '');
}
},
warn: (message: string, data?: Record<string, unknown>) => {
if (isDev) {
console.warn(`[DEV] ${message}`, data ?? '');
}
},
error: (message: string, error?: unknown) => {
if (isDev) {
console.error(`[DEV] ${message}`, error ?? '');
}
// In production, errors should go to Sentry
},
table: (data: unknown) => {
if (isDev) {
console.table(data);
}
},
group: (label: string, fn: () => void) => {
if (isDev) {
console.group(label);
fn();
console.groupEnd();
}
},
};
Phase 3: Add ESLint Rule (1 hour)¶
Priority: High | Impact: High | Dependencies: None
1. Update ESLint Configuration¶
Update .eslintrc.json or relevant ESLint config:
{
"rules": {
"no-console": ["error", {
"allow": ["warn", "error"]
}]
},
"overrides": [
{
"files": ["*.spec.ts", "*.test.ts", "*.test.tsx", "*.e2e-spec.ts"],
"rules": {
"no-console": "off"
}
},
{
"files": ["apps/web/src/lib/dev-logger.ts", "apps/web/src/observability/*.ts"],
"rules": {
"no-console": "off"
}
}
]
}
Phase 4: Verify and Document (1 hour)¶
Priority: Medium | Impact: Medium | Dependencies: Phase 1-3
1. Search for Remaining Console Usage¶
# Find all console usage outside allowed files
rg "console\.(log|warn|error|info|debug)" \
--type ts \
--type tsx \
-g '!*.spec.ts' \
-g '!*.test.ts' \
-g '!*.test.tsx' \
-g '!**/test/**' \
-g '!**/e2e/**' \
-g '!dev-logger.ts'
2. Update Technical Debt Register¶
Update docs/04-development/techdebt/technical-debt-register.md:
### ~~TD-005: Console Logging in Production Code~~ ✅ RESOLVED
**Type:** Code Debt
**Status:** ✅ **Resolved in Phase 5g**
**Resolution Date:** 2026-XX-XX
#### Resolution
Replaced all console.log statements with structured logging:
- **Backend**: Using NestJS Logger with structured objects
- **Frontend**: Dev-only logger utility for development debugging
- **ESLint**: `no-console` rule enforced with test file exceptions
- **Documentation**: Logging guidelines document created
**Files Created:**
- `docs/04-development/logging-guidelines.md`
- `apps/web/src/lib/dev-logger.ts`
**Files Modified:**
- `apps/api/src/observability/instrument.ts`
- `apps/web/src/observability/sentry.ts`
- `.eslintrc.json` - Added no-console rule
📁 Files to Create/Modify¶
New Files¶
docs/04-development/logging-guidelines.md
apps/web/src/lib/dev-logger.ts
Modified Files¶
apps/api/src/observability/instrument.ts
apps/web/src/observability/sentry.ts
.eslintrc.json # Add no-console rule
docs/04-development/techdebt/technical-debt-register.md
✅ Validation Checklist¶
Phase 1: Backend¶
- instrument.ts uses NestJS Logger
- All console statements replaced
- Structured log format used
Phase 2: Frontend¶
- Sentry.ts uses conditional logging
- dev-logger utility created
- No production console output
Phase 3: ESLint¶
- no-console rule enabled
- Test files excluded
- Dev logger file excluded
- Lint passes
Final Verification¶
# Lint passes
pnpm nx lint api
pnpm nx lint web
# Search returns no results
rg "console\.log" apps/api/src --type ts -g '!*.spec.ts'
# Build passes
pnpm nx build api
pnpm nx build web
🚫 Constraints and Rules¶
MUST DO¶
- Use NestJS Logger in backend
- Use structured log format (objects with message field)
- Add no-console ESLint rule
- Document logging guidelines
MUST NOT¶
- Use console.log in production code
- Log sensitive information (API keys, passwords)
- Skip error context in error logs
- Remove console from test files
END OF PROMPT
This prompt resolves TD-005 from the technical debt register by replacing console.log statements with structured logging.