Skip to content

🧹 [コード健全性向上] ログ出力の共通化#52

Closed
is0692vs wants to merge 1 commit intomainfrom
refactor-logging-13561573928386060371
Closed

🧹 [コード健全性向上] ログ出力の共通化#52
is0692vs wants to merge 1 commit intomainfrom
refactor-logging-13561573928386060371

Conversation

@is0692vs
Copy link
Contributor

@is0692vs is0692vs commented Mar 6, 2026

🎯 What: console.errorconsole.warn の直接呼び出しを、新設した src/lib/logger.ts ユーティリティに置き換えました。
💡 Why: ログ出力を一元化することで、将来的に外部の監視ツール(Sentry等)への移行が容易になり、コードの保守性が向上します。
Verification: スクリプトによる全ファイルのチェックを行い、console の直接呼び出しが logger に置き換わっていることを確認しました。
Result: コードの健全性が向上し、今後の拡張に対応しやすくなりました。


PR created automatically by Jules for task 13561573928386060371 started by @is0692vs

Introduced a centralized logger in src/lib/logger.ts and replaced all
instances of console.error and console.warn with logger methods to
improve maintainability.

Co-authored-by: is0692vs <135803462+is0692vs@users.noreply.github.com>
@google-labs-jules
Copy link
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@vercel
Copy link

vercel bot commented Mar 6, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
github-user-summary Ready Ready Preview, Comment Mar 6, 2026 6:46am

@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

このプルリクエストは、アプリケーションのログ出力メカニズムを標準化し、コードの健全性と保守性を向上させることを目的としています。console.errorconsole.warn の直接使用を、新しく作成された共通のロギングユーティリティに置き換えることで、エラーおよび警告メッセージの管理が中央集権化され、将来的に外部の監視サービスへの統合が容易になります。

Highlights

  • ロギングユーティリティの導入: 新しいロギングユーティリティ src/lib/logger.ts を導入し、アプリケーションのログ出力を一元化しました。
  • console呼び出しの置き換え: 既存の console.error および console.warn の直接呼び出しを、新しく導入された logger.error および logger.warn に置き換えました。
  • 保守性と拡張性の向上: ログ出力の一元化により、将来的な外部監視ツール(Sentryなど)との連携が容易になり、コードの保守性が向上します。
Changelog
  • src/app/[username]/error.tsx
    • console.error の呼び出しを logger.error に変更しました。
  • src/app/api/og/[username]/route.tsx
    • console.error の呼び出しを logger.error に変更しました。
  • src/components/CardGenerator.tsx
    • console.error の呼び出しを logger.error に変更しました。
  • src/components/ThemeController.tsx
    • console.warn の呼び出しを logger.warn に変更しました。
  • src/lib/logger.ts
    • アプリケーション全体で使用される集中型ロギングユーティリティを追加しました。
Activity
  • このプルリクエストには、これまでのところ記録されたアクティビティはありません。
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link

coderabbitai bot commented Mar 6, 2026

📝 Walkthrough

Summary by CodeRabbit

リリースノート

  • Refactor
    • 集約ロギングシステムを導入し、アプリケーション全体の記録メカニズムを統一しました。複数のコンポーネントでロギング方式を整備することで、エラーと警告の監視がより効率的になります。これにより、将来のロギングサービス連携への拡張が容易になります。

Walkthrough

アプリケーション全体で分散していたコンソールログを一元化するため、新しい logger モジュールを src/lib/logger.ts に作成し、複数のコンポーネント・ページで console.errorconsole.warnlogger.errorlogger.warn に置き換えました。

Changes

Cohort / File(s) Summary
Logger モジュール作成
src/lib/logger.ts
新規ロギング抽象化レイヤーを実装。LogFn 型、Logger インターフェース、logger インスタンスを定義。コンソールメソッドをラップし、将来的な外部ログサービス統合への基盤を提供。
ページ・API ルートのログ統合
src/app/[username]/error.tsx, src/app/api/og/[username]/route.tsx
logger モジュールをインポートし、console.error をロガー経由のエラーログに変更。エラーハンドリング機能に変更なし。
コンポーネントのログ統合
src/components/CardGenerator.tsx, src/components/ThemeController.tsx
logger モジュールをインポートし、複数の console.error および console.warn 呼び出しを対応するロガーメソッドに統一。制御フロー変更なし。

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~5 minutes

Poem

🐰 ログたちが散らばっていたけど
ひとつの箱に集めたよ
logger さんが管理する
きれいに整ったロギング
未来への一歩だ ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed プルリクエストのタイトルはログ出力の共通化という主要な変更内容を正確に反映しており、明確で簡潔です。
Description check ✅ Passed プルリクエストの説明はログ出力を一元化する目的、今後の外部ツール対応、検証方法を明確に説明しており、変更内容と完全に関連しています。

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor-logging-13561573928386060371

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

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

このプルリクエストは、console の呼び出しを中央集権的な logger ユーティリティに置き換えることで、ログ出力の一元化を目指すものですね。全体的なアプローチは素晴らしく、将来のメンテナンス性向上に大きく貢献すると思います。

新しく追加された src/lib/logger.ts について、1点改善提案があります。現在の実装ではロガー関数の最初の引数が文字列に限定されていますが、これをより柔軟にすることで、console と同じように任意の型のデータをログ出力できるようになり、さらに使いやすさが向上します。詳細はコメントをご確認ください。

Comment on lines +7 to +25
type LogFn = (message: string, ...args: unknown[]) => void;

interface Logger {
info: LogFn;
warn: LogFn;
error: LogFn;
}

export const logger: Logger = {
info: (message, ...args) => {
console.info(message, ...args);
},
warn: (message, ...args) => {
console.warn(message, ...args);
},
error: (message, ...args) => {
console.error(message, ...args);
},
};

Choose a reason for hiding this comment

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

medium

現在の LogFn 型は、最初の引数を文字列に限定しています。これは、ラップしている console メソッドよりも制限が厳しいです。console メソッドは、最初の引数として任意の型を受け入れることができます(例: console.error(errorObject))。
ロガーをより柔軟にし、console メソッドの完全な代替として機能させるために、シグネチャを可変長引数を受け入れるように変更することをお勧めします。これにより、将来的にSentryなどのエラー追跡ツールと統合する際にも、エラーオブジェクトを直接渡しやすくなります。

Suggested change
type LogFn = (message: string, ...args: unknown[]) => void;
interface Logger {
info: LogFn;
warn: LogFn;
error: LogFn;
}
export const logger: Logger = {
info: (message, ...args) => {
console.info(message, ...args);
},
warn: (message, ...args) => {
console.warn(message, ...args);
},
error: (message, ...args) => {
console.error(message, ...args);
},
};
type LogFn = (...args: unknown[]) => void;
interface Logger {
info: LogFn;
warn: LogFn;
error: LogFn;
}
export const logger: Logger = {
info: (...args) => {
console.info(...args);
},
warn: (...args) => {
console.warn(...args);
},
error: (...args) => {
console.error(...args);
},
};

Copy link

@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 the current code and only fix it if needed.

Inline comments:
In `@src/app/`[username]/error.tsx:
- Around line 15-17: Remove the redundant useEffect that calls logger.error in
the error boundary (the block using useEffect(() => { logger.error("User page
error:", error); }, [error])); either delete that entire useEffect and also
remove the now-unused imports of useEffect and logger from the module, or
replace it with a guarded call that only logs when an explicit
external-error-forwarding flag/handler is present (e.g., check for a configured
externalErrorHandler before calling logger.error). Ensure you update imports
accordingly so no unused symbols remain.

In `@src/app/api/og/`[username]/route.tsx:
- Around line 34-35: Replace the dynamic interpolated log message in
logger.error so it uses a fixed string and moves the username into structured
context: update the catch block that calls logger.error (the call referencing
logger.error and the username variable) to log a constant message like "Failed
to fetch GitHub profile for OG image" and pass the username and the caught error
as structured fields/metadata (e.g., an object with username and error) instead
of embedding ${username} in the message.

In `@src/lib/logger.ts`:
- Around line 15-24: 現在の logger 定義 (export const logger: Logger with
info/warn/error arrow functions) wraps console calls and loses original callsite
info in DevTools; replace these wrappers by exporting the bound console methods
directly (e.g. set logger.info = console.info.bind(console), same for warn and
error) so the Debugger sees correct callsites while keeping the Logger shape;
update the logger constant (info, warn, error) to use bound methods rather than
arrow wrappers.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ed93c3cb-7d51-418e-b7c7-1d9d08bce002

📥 Commits

Reviewing files that changed from the base of the PR and between 3cfdea1 and fff9325.

📒 Files selected for processing (5)
  • src/app/[username]/error.tsx
  • src/app/api/og/[username]/route.tsx
  • src/components/CardGenerator.tsx
  • src/components/ThemeController.tsx
  • src/lib/logger.ts

Comment on lines 15 to 17
useEffect(() => {
console.error("User page error:", error);
logger.error("User page error:", error);
}, [error]);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

React 19 Error Boundary automatic console.error logging behavior

💡 Result:

In React 19, errors that are thrown during rendering and caught by an Error Boundary are still automatically logged by React (i.e., React calls console.error by default), but the shape/amount of logging changed:

  • React ≤18 (DEV): a single caught render error often produced multiple console entries (the error could be thrown/logged more than once, plus the “The above error occurred…” message), which looked like duplicate console.error noise. [1]
  • React 19 (DEV): React deduplicates this so you typically see one consolidated console error that includes both the error + component-stack context (“The above error occurred… React will try to recreate…”) in the same log. [1]
  • React 19 render bailout behavior: after the first render error in a subtree, React 19 is more likely to bail out sooner (so later siblings might not render/log), which can change what you see in the console compared to React 18. [2]

Can you turn off React’s automatic console.error for caught errors?

Not via Error Boundary APIs directly—React logs by default. What React 19 adds is root-level hooks so you can implement your own reporting behavior:

  • createRoot(container, { onCaughtError, onUncaughtError, onRecoverableError }) [3]
  • hydrateRoot(domNode, reactNode, { onCaughtError, onUncaughtError, onRecoverableError }) [4]

The createRoot docs explicitly note: “By default, React will log all errors to the console.” and then show using these hooks for custom reporting. [3]

Practical implication: if you also console.error(...) inside componentDidCatch, you’ll get your log plus React’s default log (so it can look “duplicated”), unless you move logging to onCaughtError (or otherwise dedupe/filter on your side). [1][3]

Sources: [1] React 19 “Better error reporting” section (React blog) https://react.dev/blog/2024/12/05/react-19 • [2] Example/observed behavior change after upgrading to React 19 https://andrei-calazans.com/posts/react-19-error-boundary-changed/ • [3] createRoot docs (“By default, React will log all errors…”) https://react.dev/reference/react-dom/client/createRoot • [4] hydrateRoot docs (root error hooks) https://react.dev/reference/react-dom/client/hydrateRoot


React 19 の Error Boundary による自動ログのため、エラーログが二重記録されます。

React 19 では Error Boundary に捕捉されたエラーが自動的に console.error に報告されます。このため、line 16 の logger.error("User page error:", error) を残すと、React による自動ログと合わせて同じエラーが二重に記録されます。将来 logger を Sentry などの外部サービスに切り替えた場合、同じイベントが重複して送信されることになります。

対応としては以下のいずれかを推奨します:

  • useEffect ごと削除する
  • 外部送信用の特別なハンドラーがある場合のみログを出力するよう条件を追加する

useEffect を削除する場合は、loggeruseEffect の import も不要になります。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/`[username]/error.tsx around lines 15 - 17, Remove the redundant
useEffect that calls logger.error in the error boundary (the block using
useEffect(() => { logger.error("User page error:", error); }, [error])); either
delete that entire useEffect and also remove the now-unused imports of useEffect
and logger from the module, or replace it with a guarded call that only logs
when an explicit external-error-forwarding flag/handler is present (e.g., check
for a configured externalErrorHandler before calling logger.error). Ensure you
update imports accordingly so no unused symbols remain.

Comment on lines 34 to +35
} catch (error) {
console.error(`Failed to fetch GitHub profile for OG image: ${username}`, error);
logger.error(`Failed to fetch GitHub profile for OG image: ${username}`, error);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

メッセージ文字列に username を埋め込まないでください。

Line 35 のような動的メッセージは、logger の送信先を外部監視へ切り替えたときにイベント集約を壊し、ユーザー識別子もそのまま残ります。固定メッセージ + 構造化コンテキストにしてください。

🩹 提案差分
-    logger.error(`Failed to fetch GitHub profile for OG image: ${username}`, error);
+    logger.error("Failed to fetch GitHub profile for OG image", { username }, error);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/api/og/`[username]/route.tsx around lines 34 - 35, Replace the
dynamic interpolated log message in logger.error so it uses a fixed string and
moves the username into structured context: update the catch block that calls
logger.error (the call referencing logger.error and the username variable) to
log a constant message like "Failed to fetch GitHub profile for OG image" and
pass the username and the caught error as structured fields/metadata (e.g., an
object with username and error) instead of embedding ${username} in the message.

Comment on lines +15 to +24
export const logger: Logger = {
info: (message, ...args) => {
console.info(message, ...args);
},
warn: (message, ...args) => {
console.warn(message, ...args);
},
error: (message, ...args) => {
console.error(message, ...args);
},
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

🧩 Analysis chain

🌐 Web query:

DevTools console callsite attribution wrapped function vs console.bind preserving caller location

💡 Result:

In Chrome/Edge DevTools, the “callsite” link on a console message is basically the top non-ignored JavaScript stack frame that ultimately invoked the console method. That’s why the two patterns behave differently:

Why a wrapper changes the callsite

If you do:

const orig = console.log.bind(console);
function log(...args) {
  // extra behavior
  orig(...args);
}

DevTools sees the stack as caller → log(…) → orig(…) → (native console), so the first visible frame is your wrapper, and the callsite link points at the wrapper file/line. This is the behavior people run into when “decorating” console methods. [1], [2]

Why console.log.bind(console) (often) preserves the callsite

If you do:

const log = console.log.bind(console);
log("hi");

you’re still calling the native console method (just with this fixed), so there’s no extra userland wrapper frame added by you—DevTools can attribute the callsite to the actual caller.

Also, if your goal is only to prepend fixed arguments (timestamp/prefix/styles) and keep caller attribution, binding/partial application can work because it stays a direct call into the console implementation:

console.log = Function.prototype.bind.call(console.log, console, new Date(), "You logged:");

This pattern is specifically noted as keeping line numbers/callsite “preserved” while adding a prefix. [3]

If you must run extra code and still want the “real” callsite

You generally can’t make an arbitrary JS wrapper “transparent” to DevTools purely with language features; the practical fix is to hide/ignore the wrapper in DevTools so the next frame (the real caller) becomes the attributed callsite:

  • Blackbox / Ignore-list the wrapper script (DevTools Settings → Blackboxing, or “Add script to ignore list”). Then console messages will attribute to the caller instead of the wrapper. [1], [2]
  • For build tooling, you can also use source map ignore lists (the modern ignoreList mechanism) so Chrome ignores specific generated files automatically. [3]

Rule of thumb

  • Want same callsite: store a bound console method (or bind-with-prefix).
  • Want extra behavior: wrap, but then ignore-list/blackbox that wrapper file if you want DevTools to point to the original caller.

Sources: [1] [2] [3]


console を関数で包むと DevTools 上の出力元が追いづらくなります。

この形だと DevTools が src/lib/logger.ts をコールサイトとして指定しやすく、実際の呼び出し元を辿りにくくなります。共通化だけが目的なら、bind 済みメソッドをそのまま公開したほうがデバッグ性を損なわせません。

♻️ 提案差分
 export const logger: Logger = {
-  info: (message, ...args) => {
-    console.info(message, ...args);
-  },
-  warn: (message, ...args) => {
-    console.warn(message, ...args);
-  },
-  error: (message, ...args) => {
-    console.error(message, ...args);
-  },
+  info: console.info.bind(console) as LogFn,
+  warn: console.warn.bind(console) as LogFn,
+  error: console.error.bind(console) as LogFn,
 };
📝 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
export const logger: Logger = {
info: (message, ...args) => {
console.info(message, ...args);
},
warn: (message, ...args) => {
console.warn(message, ...args);
},
error: (message, ...args) => {
console.error(message, ...args);
},
export const logger: Logger = {
info: console.info.bind(console) as LogFn,
warn: console.warn.bind(console) as LogFn,
error: console.error.bind(console) as LogFn,
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/logger.ts` around lines 15 - 24, 現在の logger 定義 (export const logger:
Logger with info/warn/error arrow functions) wraps console calls and loses
original callsite info in DevTools; replace these wrappers by exporting the
bound console methods directly (e.g. set logger.info =
console.info.bind(console), same for warn and error) so the Debugger sees
correct callsites while keeping the Logger shape; update the logger constant
(info, warn, error) to use bound methods rather than arrow wrappers.

@is0692vs
Copy link
Contributor Author

is0692vs commented Mar 6, 2026

Consolidated into the fix/consolidated-prs-latest branch (PR #56).

@is0692vs is0692vs closed this Mar 6, 2026
@google-labs-jules
Copy link
Contributor

Consolidated into the fix/consolidated-prs-latest branch (PR #56).

Acknowledged. Thank you for the update regarding consolidation into the fix/consolidated-prs-latest branch (PR #56).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant