Skip to content

fix(email): replace console logs with structured logger#30

Merged
deekshithgowda85 merged 1 commit into
deekshithgowda85:prodfrom
amna-sehgal:fix/email-structured-logging
May 28, 2026
Merged

fix(email): replace console logs with structured logger#30
deekshithgowda85 merged 1 commit into
deekshithgowda85:prodfrom
amna-sehgal:fix/email-structured-logging

Conversation

@amna-sehgal
Copy link
Copy Markdown
Contributor

@amna-sehgal amna-sehgal commented May 28, 2026

Pull Request

Summary

This PR replaces all direct console.log / console.error usage in the email service with a structured logging helper.
It ensures consistent log formatting across the email module and prevents potential sensitive data leakage by standardizing logging behavior.


Related Issue

Closes: #17


What Changed

  • Replaced all direct console.log statements in lib/email/mail-service.ts
  • Introduced a structured log() helper for consistent logging
  • Standardized log levels (info, warn, error)
  • Improved maintainability and readability of email service logs
  • Ensured no raw console logging exists in the email service flow

Screenshots or Demo

Not applicable (backend/service-level change)


Verification

  • I ran pnpm lint
  • I manually verified the email service flow works correctly
  • I confirmed no console.* usage remains in lib/email/mail-service.ts
  • I ensured no secrets or sensitive data are exposed in logs

Checklist

  • My branch name follows the repository convention
  • My commits use Conventional Commits
  • I kept the change scoped to one issue
  • I updated docs if the behavior or workflow changed (not required here)
  • I am ready for review

Summary by CodeRabbit

  • Refactor
    • Improved email service logging infrastructure with structured JSON logging format for enhanced system observability and debugging capabilities. Strengthened email input validation mechanisms. Refined logging data collection across various email delivery scenarios, including rate limiting and retry attempt handling. Core email functionality, API interactions, and overall user experience remain entirely unchanged.

Review Change Stack

@vercel
Copy link
Copy Markdown

vercel Bot commented May 28, 2026

@amna-sehgal is attempting to deploy a commit to the Deekshith Gowda HS's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

📝 Walkthrough

Walkthrough

The email service logging is refactored to replace direct console calls with a dedicated structured JSON logger. The new logger writes timestamped entries to stdout and accepts (level, message, meta?) parameters. All logging callsites in sendEmail are updated to use the new logger with revised metadata field selections that omit sensitive information from certain log events.

Changes

Email logging infrastructure and integration

Layer / File(s) Summary
Logging helpers and email validation
lib/email/mail-service.ts
Adds isValidEmail helper and replaces the prior log implementation with a structured logger that accepts (level, message, meta?), writes timestamped JSON to stdout, and merges metadata into the output.
Email send flow logging integration
lib/email/mail-service.ts
Integrates the new structured logger throughout sendEmail, updating logging calls for rate-limit warnings, success responses, non-retryable 4xx errors, per-attempt retries, exception handling, and final failure scenarios; metadata is restructured to omit subject from rate-limit and final-failure logs while including appropriate context fields for each scenario.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A logger so structured, so clean and precise,
No subjects leaked out—now that's quite nice!
JSON flows steady to stdout's bright light,
Your email logs whisper, all proper and right!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: replacing console logs with a structured logger in the email service module.
Linked Issues check ✅ Passed The PR addresses the core requirements of issue #17: removes console logging from mail-service.ts and implements structured log() usage with appropriate levels.
Out of Scope Changes check ✅ Passed All changes are focused on replacing console logs with structured logging in mail-service.ts; no unrelated modifications are present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/email/mail-service.ts`:
- Around line 151-155: The final failure log in mail-service.ts currently
includes the sensitive `subject` field; update the log call in the
retry/final-error path (the call to log("error", "Email send failed after
retries", { to, subject, error: lastError })) to omit or redact `subject` so
only non-sensitive metadata is logged (e.g., keep `to` and `error: lastError` or
replace `subject` with a redacted placeholder). Modify the object passed to the
`log` function accordingly and ensure any related tests/assertions reference the
new sanitized metadata.
- Around line 31-47: The current log() lets caller meta overwrite core fields
and may throw from JSON.stringify(entry), so harden it by sanitizing meta and
making stringify fail-safe: inside function log, create a sanitizedMeta from
meta that strips/ignores reserved keys ("ts","service","level","message") and
coerces values to primitives/strings (or shallow clones only), build entry = {
ts: new Date().toISOString(), service: "email", level, message, ...sanitizedMeta
}, then wrap JSON.stringify(entry) in try/catch and on error write a minimal
fallback JSON line (e.g., containing ts, service, level, message and a safe
"meta_error" or stringified meta) before calling process.stdout.write to ensure
logging never throws; refer to log, entry, meta, process.stdout.write, and
JSON.stringify when implementing.
- Around line 125-129: The current log call in mail-service.ts exposes the full
Brevo response body (errBody) which may leak provider payloads and be
arbitrarily large; replace body: errBody with a sanitized, bounded snippet—e.g.,
create a helper like sanitizeAndTruncateError(errBody) or
getSafeErrorSnippet(errBody) and pass that value (alongside res.status and to)
to log("error", "Brevo rejected email (non-retryable)", {...}); ensure the
helper strips sensitive fields (tokens, PII) and truncates to a safe max length
before logging.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5f93a0bf-ab10-4835-aed8-b7c1de95c1b5

📥 Commits

Reviewing files that changed from the base of the PR and between 6375d70 and 663e036.

📒 Files selected for processing (1)
  • lib/email/mail-service.ts

Comment thread lib/email/mail-service.ts
Comment on lines +31 to +47
/** Basic email format validation (RFC 5322 simplified). */
function log(
level: "info" | "warn" | "error",
message: string,
meta?: Record<string, unknown>
) {
const entry = {
ts: new Date().toISOString(),
service: "email",
level,
message,
...meta,
};
if (level === "error") console.error(JSON.stringify(entry));
else if (level === "warn") console.warn(JSON.stringify(entry));
else console.log(JSON.stringify(entry));
}

// structured logging hook (safe replacement)
process.stdout.write(JSON.stringify(entry) + "\n");
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Harden log() so metadata cannot corrupt schema or break send flow.

...meta can overwrite core fields, and JSON.stringify(entry) can throw. Logging should be fail-safe and keep a stable schema.

Proposed fix
 function log(
   level: "info" | "warn" | "error",
   message: string,
   meta?: Record<string, unknown>
 ) {
-  const entry = {
-    ts: new Date().toISOString(),
-    service: "email",
-    level,
-    message,
-    ...meta,
-  };
-
-  // structured logging hook (safe replacement)
-  process.stdout.write(JSON.stringify(entry) + "\n");
+  const entry = {
+    ts: new Date().toISOString(),
+    service: "email",
+    level,
+    message,
+    meta: meta ?? {},
+  };
+  try {
+    process.stdout.write(JSON.stringify(entry) + "\n");
+  } catch {
+    process.stdout.write(
+      JSON.stringify({
+        ts: new Date().toISOString(),
+        service: "email",
+        level: "error",
+        message: "Failed to serialize log entry",
+      }) + "\n"
+    );
+  }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/email/mail-service.ts` around lines 31 - 47, The current log() lets
caller meta overwrite core fields and may throw from JSON.stringify(entry), so
harden it by sanitizing meta and making stringify fail-safe: inside function
log, create a sanitizedMeta from meta that strips/ignores reserved keys
("ts","service","level","message") and coerces values to primitives/strings (or
shallow clones only), build entry = { ts: new Date().toISOString(), service:
"email", level, message, ...sanitizedMeta }, then wrap JSON.stringify(entry) in
try/catch and on error write a minimal fallback JSON line (e.g., containing ts,
service, level, message and a safe "meta_error" or stringified meta) before
calling process.stdout.write to ensure logging never throws; refer to log,
entry, meta, process.stdout.write, and JSON.stringify when implementing.

Comment thread lib/email/mail-service.ts
Comment on lines +125 to +129
log("error", "Brevo rejected email (non-retryable)", {
status: res.status,
body: errBody,
to
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid logging raw Brevo error bodies.

body: errBody can leak provider payload details and is unbounded. Prefer a sanitized/truncated field.

Proposed fix
         log("error", "Brevo rejected email (non-retryable)", {
           status: res.status,
-          body: errBody,
+          bodySnippet: errBody.slice(0, 500),
           to
         });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/email/mail-service.ts` around lines 125 - 129, The current log call in
mail-service.ts exposes the full Brevo response body (errBody) which may leak
provider payloads and be arbitrarily large; replace body: errBody with a
sanitized, bounded snippet—e.g., create a helper like
sanitizeAndTruncateError(errBody) or getSafeErrorSnippet(errBody) and pass that
value (alongside res.status and to) to log("error", "Brevo rejected email
(non-retryable)", {...}); ensure the helper strips sensitive fields (tokens,
PII) and truncates to a safe max length before logging.

Comment thread lib/email/mail-service.ts
Comment on lines +151 to +155
log("error", "Email send failed after retries", {
to,
subject,
error: lastError
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Final failure log still includes subject, which reintroduces sensitive logging.

This conflicts with the stated goal to omit subject from final-failure logging metadata.

Proposed fix
   log("error", "Email send failed after retries", {
     to,
-    subject,
     error: lastError
   });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
log("error", "Email send failed after retries", {
to,
subject,
error: lastError
});
log("error", "Email send failed after retries", {
to,
error: lastError
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/email/mail-service.ts` around lines 151 - 155, The final failure log in
mail-service.ts currently includes the sensitive `subject` field; update the log
call in the retry/final-error path (the call to log("error", "Email send failed
after retries", { to, subject, error: lastError })) to omit or redact `subject`
so only non-sensitive metadata is logged (e.g., keep `to` and `error: lastError`
or replace `subject` with a redacted placeholder). Modify the object passed to
the `log` function accordingly and ensure any related tests/assertions reference
the new sanitized metadata.

@deekshithgowda85 deekshithgowda85 merged commit 6850811 into deekshithgowda85:prod May 28, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Replace direct console logging in email service

2 participants