[{"data":1,"prerenderedAt":438},["ShallowReactive",2],{"blog-best-practices/logging":3},{"id":4,"title":5,"body":6,"category":414,"date":415,"dateModified":415,"description":416,"draft":417,"extension":418,"faq":419,"featured":417,"headerVariant":423,"image":424,"keywords":424,"meta":425,"navigation":426,"ogDescription":427,"ogTitle":424,"path":428,"readTime":429,"schemaOrg":430,"schemaType":431,"seo":432,"sitemap":433,"stem":434,"tags":435,"twitterCard":436,"__hash__":437},"blog/blog/best-practices/logging.md","Secure Logging Best Practices: What to Log (and Never Log)",{"type":7,"value":8,"toc":403},"minimark",[9,16,25,30,33,58,73,77,80,158,167,171,174,183,187,190,199,203,206,278,287,291,294,311,317,322,344,348,351,372,391],[10,11,12],"tldr",{},[13,14,15],"p",{},"The #1 logging security best practice is never log sensitive data like passwords, tokens, or PII. Log security events (auth attempts, access denied, errors) with timestamps and user context. Use structured JSON logging, centralize logs, and set up alerts for suspicious patterns. Proper logging catches attacks early and is essential for incident response.",[17,18,19],"quotable-box",{},[20,21,22],"blockquote",{},[13,23,24],{},"\"Your logs are your security camera footage. Record everything important, but never point the camera at your passwords.\"",[26,27,29],"h2",{"id":28},"best-practice-1-log-security-events-3-min","Best Practice 1: Log Security Events 3 min",[13,31,32],{},"Capture events that matter for security:",[34,35,36,40,43,46,49,52,55],"ul",{},[37,38,39],"li",{},"Authentication attempts (success and failure)",[37,41,42],{},"Authorization failures (access denied)",[37,44,45],{},"Input validation failures",[37,47,48],{},"Account changes (password reset, email change)",[37,50,51],{},"Admin actions and privilege escalations",[37,53,54],{},"Rate limit violations",[37,56,57],{},"Error responses (4xx, 5xx)",[59,60,62],"code-block",{"label":61},"Security event logging",[63,64,69],"pre",{"className":65,"code":67,"language":68},[66],"language-text","import { logger } from './logger';\n\n// Log authentication events\nasync function login(email, password) {\n  const user = await findUserByEmail(email);\n\n  if (!user) {\n    logger.warn('auth.login.user_not_found', {\n      email: maskEmail(email),\n      ip: req.ip,\n      userAgent: req.headers['user-agent'],\n    });\n    throw new AuthError('Invalid credentials');\n  }\n\n  const valid = await verifyPassword(password, user.passwordHash);\n\n  if (!valid) {\n    logger.warn('auth.login.invalid_password', {\n      userId: user.id,\n      ip: req.ip,\n      attemptCount: await getFailedAttempts(user.id),\n    });\n    throw new AuthError('Invalid credentials');\n  }\n\n  logger.info('auth.login.success', {\n    userId: user.id,\n    ip: req.ip,\n  });\n\n  return createSession(user);\n}\n","text",[70,71,67],"code",{"__ignoreMap":72},"",[26,74,76],{"id":75},"best-practice-2-never-log-sensitive-data-2-min","Best Practice 2: Never Log Sensitive Data 2 min",[13,78,79],{},"These should never appear in your logs:",[81,82,83,99],"table",{},[84,85,86],"thead",{},[87,88,89,93,96],"tr",{},[90,91,92],"th",{},"Never Log",[90,94,95],{},"Why",[90,97,98],{},"Alternative",[100,101,102,114,125,136,147],"tbody",{},[87,103,104,108,111],{},[105,106,107],"td",{},"Passwords",[105,109,110],{},"Credential exposure",[105,112,113],{},"Log \"password provided: true\"",[87,115,116,119,122],{},[105,117,118],{},"API keys/tokens",[105,120,121],{},"Auth bypass",[105,123,124],{},"Log last 4 characters only",[87,126,127,130,133],{},[105,128,129],{},"Credit card numbers",[105,131,132],{},"PCI compliance",[105,134,135],{},"Log last 4 digits",[87,137,138,141,144],{},[105,139,140],{},"SSN/Government IDs",[105,142,143],{},"Identity theft",[105,145,146],{},"Log \"ID verified: true\"",[87,148,149,152,155],{},[105,150,151],{},"Full emails (sometimes)",[105,153,154],{},"Privacy/GDPR",[105,156,157],{},"Mask: u***@example.com",[59,159,161],{"label":160},"Masking sensitive data",[63,162,165],{"className":163,"code":164,"language":68},[66],"// Utility functions for safe logging\nfunction maskEmail(email) {\n  const [local, domain] = email.split('@');\n  return `${local.charAt(0)}***@${domain}`;\n}\n\nfunction maskToken(token) {\n  if (!token) return 'none';\n  return `***${token.slice(-4)}`;\n}\n\nfunction maskCardNumber(card) {\n  return `****${card.slice(-4)}`;\n}\n\n// WRONG: Logging sensitive data\nlogger.info('Payment processed', {\n  cardNumber: '4111111111111111',  // NEVER\n  cvv: '123',                       // NEVER\n});\n\n// CORRECT: Masked logging\nlogger.info('payment.processed', {\n  cardLast4: maskCardNumber(cardNumber),\n  amount: payment.amount,\n  userId: user.id,\n});\n",[70,166,164],{"__ignoreMap":72},[26,168,170],{"id":169},"best-practice-3-use-structured-logging-2-min","Best Practice 3: Use Structured Logging 2 min",[13,172,173],{},"JSON logs are searchable and parseable:",[59,175,177],{"label":176},"Structured logger setup",[63,178,181],{"className":179,"code":180,"language":68},[66],"import pino from 'pino';\n\nconst logger = pino({\n  level: process.env.LOG_LEVEL || 'info',\n  formatters: {\n    level: (label) => ({ level: label }),\n  },\n  timestamp: pino.stdTimeFunctions.isoTime,\n  base: {\n    service: 'api',\n    environment: process.env.NODE_ENV,\n  },\n});\n\n// Add request context\nfunction createRequestLogger(req) {\n  return logger.child({\n    requestId: req.id,\n    ip: req.ip,\n    path: req.path,\n    method: req.method,\n  });\n}\n\n// Usage in route\napp.post('/api/orders', (req, res) => {\n  const log = createRequestLogger(req);\n\n  log.info('order.create.started', {\n    userId: req.user.id,\n    itemCount: req.body.items.length,\n  });\n\n  // ... process order\n\n  log.info('order.create.completed', {\n    orderId: order.id,\n    total: order.total,\n  });\n});\n",[70,182,180],{"__ignoreMap":72},[26,184,186],{"id":185},"best-practice-4-include-context-2-min","Best Practice 4: Include Context 2 min",[13,188,189],{},"Good logs answer who, what, when, where:",[59,191,193],{"label":192},"Contextual logging",[63,194,197],{"className":195,"code":196,"language":68},[66],"// Good log entry includes:\nlogger.info('resource.access.denied', {\n  // WHO\n  userId: user?.id || 'anonymous',\n  userRole: user?.role,\n\n  // WHAT\n  action: 'delete',\n  resource: 'document',\n  resourceId: documentId,\n\n  // WHEN (automatic with structured logger)\n\n  // WHERE\n  ip: req.ip,\n  userAgent: req.headers['user-agent'],\n\n  // WHY (reason for denial)\n  reason: 'insufficient_permissions',\n  required: 'admin',\n  actual: user?.role,\n});\n\n// Output:\n// {\n//   \"level\": \"info\",\n//   \"time\": \"2026-01-24T10:30:00.000Z\",\n//   \"msg\": \"resource.access.denied\",\n//   \"userId\": \"user_123\",\n//   \"userRole\": \"member\",\n//   \"action\": \"delete\",\n//   \"resource\": \"document\",\n//   \"resourceId\": \"doc_456\",\n//   \"ip\": \"192.168.1.1\",\n//   \"reason\": \"insufficient_permissions\"\n// }\n",[70,198,196],{"__ignoreMap":72},[26,200,202],{"id":201},"best-practice-5-set-up-log-alerts-3-min","Best Practice 5: Set Up Log Alerts 3 min",[13,204,205],{},"Monitor for suspicious patterns:",[81,207,208,221],{},[84,209,210],{},[87,211,212,215,218],{},[90,213,214],{},"Alert Condition",[90,216,217],{},"Threshold",[90,219,220],{},"Indicates",[100,222,223,234,245,256,267],{},[87,224,225,228,231],{},[105,226,227],{},"Failed logins per IP",[105,229,230],{},">10 in 5 min",[105,232,233],{},"Brute force attack",[87,235,236,239,242],{},[105,237,238],{},"Failed logins per account",[105,240,241],{},">5 in 5 min",[105,243,244],{},"Account targeting",[87,246,247,250,253],{},[105,248,249],{},"Access denied errors",[105,251,252],{},"Spike from baseline",[105,254,255],{},"Privilege escalation attempt",[87,257,258,261,264],{},[105,259,260],{},"500 errors",[105,262,263],{},">1% of requests",[105,265,266],{},"System issue or attack",[87,268,269,272,275],{},[105,270,271],{},"Unusual admin activity",[105,273,274],{},"Outside business hours",[105,276,277],{},"Compromised account",[59,279,281],{"label":280},"Example alert rules (Datadog/CloudWatch style)",[63,282,285],{"className":283,"code":284,"language":68},[66],"// Alert: Brute force detection\n{\n  \"name\": \"Brute Force Attack\",\n  \"query\": \"logs('auth.login.invalid_password').count() by ip\",\n  \"threshold\": 10,\n  \"window\": \"5m\",\n  \"severity\": \"high\",\n  \"action\": \"page_security_team\"\n}\n\n// Alert: Unusual access patterns\n{\n  \"name\": \"Suspicious Access Denied Spike\",\n  \"query\": \"logs('*.access.denied').count()\",\n  \"condition\": \"> 3x baseline\",\n  \"window\": \"15m\",\n  \"severity\": \"medium\"\n}\n",[70,286,284],{"__ignoreMap":72},[26,288,290],{"id":289},"best-practice-6-log-retention-and-security-2-min","Best Practice 6: Log Retention and Security 2 min",[13,292,293],{},"Protect your logs and comply with regulations:",[34,295,296,299,302,305,308],{},[37,297,298],{},"Encrypt logs at rest and in transit",[37,300,301],{},"Restrict access to log systems (need-to-know)",[37,303,304],{},"Set retention policies (30-90 days active, archive longer)",[37,306,307],{},"Ensure immutability to prevent tampering",[37,309,310],{},"Separate log storage from application servers",[312,313,314],"info-box",{},[13,315,316],{},"Compliance Note:\nGDPR requires you to delete or anonymize personal data in logs when no longer needed. Set up automated retention policies to handle this.",[312,318,319],{},[13,320,321],{},"External Resources:\nFor comprehensive logging security guidance, see the\nOWASP Logging Cheat Sheet\nand the\nOWASP Logging Vocabulary Cheat Sheet\nfor industry-standard security recommendations.",[323,324,325,332,338],"faq-section",{},[326,327,329],"faq-item",{"question":328},"Should I log user actions in detail?",[13,330,331],{},"Log actions that matter for security and compliance (logins, data access, admin actions). Avoid logging every click or page view unless you need it for specific analytics. Balance visibility with storage costs and privacy.",[326,333,335],{"question":334},"How long should I keep logs?",[13,336,337],{},"Keep active logs 30-90 days for operational use. Archive security-relevant logs for 1-7 years depending on compliance requirements (PCI, HIPAA, SOC2). Set up automatic rotation and archival.",[326,339,341],{"question":340},"What logging library should I use?",[13,342,343],{},"For Node.js, pino is fast and structured. For Python, structlog or python-json-logger work well. For Go, zap or zerolog. The key is structured JSON output that your log aggregator can parse.",[26,345,347],{"id":346},"further-reading","Further Reading",[13,349,350],{},"Put these practices into action with our step-by-step guides.",[34,352,353,360,366],{},[37,354,355],{},[356,357,359],"a",{"href":358},"/blog/how-to/add-security-headers","Add security headers to your app",[37,361,362],{},[356,363,365],{"href":364},"/blog/checklists/pre-deployment-security-checklist","Pre-deployment security checklist",[37,367,368],{},[356,369,371],{"href":370},"/blog/getting-started/first-scan","Run your first security scan",[373,374,375,381,386],"related-articles",{},[376,377],"related-card",{"description":378,"href":379,"title":380},"Real-time security monitoring","/blog/best-practices/monitoring","Monitoring Best Practices",[376,382],{"description":383,"href":384,"title":385},"Secure error responses","/blog/best-practices/error-handling","Error Handling",[376,387],{"description":388,"href":389,"title":390},"Auth security patterns","/blog/best-practices/authentication","Authentication",[392,393,396,400],"cta-box",{"href":394,"label":395},"/","Start Free Scan",[26,397,399],{"id":398},"audit-your-logging","Audit Your Logging",[13,401,402],{},"Check if your logs expose sensitive data or miss critical events.",{"title":72,"searchDepth":404,"depth":404,"links":405},2,[406,407,408,409,410,411,412,413],{"id":28,"depth":404,"text":29},{"id":75,"depth":404,"text":76},{"id":169,"depth":404,"text":170},{"id":185,"depth":404,"text":186},{"id":201,"depth":404,"text":202},{"id":289,"depth":404,"text":290},{"id":346,"depth":404,"text":347},{"id":398,"depth":404,"text":399},"best-practices","2026-01-27","Security logging best practices. Learn what to log for security, what never to log, structured logging patterns, and log monitoring for incident response.",false,"md",[420,421,422],{"question":328,"answer":331},{"question":334,"answer":337},{"question":340,"answer":343},"vibe-green",null,{},true,"Build secure logging that helps detect threats without exposing sensitive data.","/blog/best-practices/logging","11 min read","[object Object]","Article",{"title":5,"description":416},{"loc":428},"blog/best-practices/logging",[],"summary_large_image","N3aY0wvb0B6U2cW_7uc6Lm9Sje7QfrY6bjL6CrkSXV4",1775843926031]