Skip to content

fix(debug): buffer pre-init events and flush to real logger on init#448

Open
HiddenPuppy wants to merge 2 commits intomainfrom
fix/debug-logger-pre-init-buffer
Open

fix(debug): buffer pre-init events and flush to real logger on init#448
HiddenPuppy wants to merge 2 commits intomainfrom
fix/debug-logger-pre-init-buffer

Conversation

@HiddenPuppy
Copy link
Copy Markdown
Collaborator

Summary

  • When getDebugLogger() is called before initDebugLogger(), events were silently dropped with noop stubs that returned empty DebugEvent objects
  • This fix implements a buffered noop logger that captures up to 256 events before initialization, warns to console, and flushes all buffered events to the real logger when initDebugLogger is called

Changes

packages/desktop/src/main/debug/index.ts

  • Replaced noop stubs with a createNoopLogger() factory that creates a logger with an in-memory buffer
  • Added isDebugLoggerInitialized() export for testing
  • Events logged before init are now:
    • Buffered (up to 256 events, oldest dropped first)
    • Warned to console with [debug] Logger not initialized yet message and buffer size
    • Flushed to the real logger when initDebugLogger() runs

packages/desktop/test/debug/debug-logger.test.ts

  • Added unit tests for pre-init buffering behavior:
    • Events are buffered before init
    • Buffered events are flushed to real logger after init
    • Buffer is capped at 256 events
    • Console warning is emitted on pre-init log calls

Test plan

  • pnpm --filter @clawwork/desktop test passes
  • pnpm lint passes

Fixes #412

When getDebugLogger() is called before initDebugLogger(), events were silently
dropped with noop stubs that returned empty DebugEvent objects.

This fix implements a buffered noop logger that:
- Captures up to 256 events in memory before initialization
- Warns to console with buffer size when events are logged before init
- Flushes all buffered events to the real logger when initDebugLogger runs

Also adds unit tests for the pre-init buffering behavior.

Fixes #412
@gemini-code-assist
Copy link
Copy Markdown
Contributor

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!

This pull request improves the robustness of the debug logging system by preventing the silent loss of log events that occur during application startup. By introducing a temporary buffer, the system now ensures that diagnostic information generated before the logger is fully initialized is preserved and subsequently processed once the logger becomes available.

Highlights

  • Buffered Debug Logging: Implemented a buffered noop logger that captures up to 256 debug events when the logger is accessed before initialization.
  • Event Flushing: Added functionality to automatically flush all captured pre-initialization events to the real logger once initDebugLogger is invoked.
  • Developer Feedback: Added console warnings when events are captured in the pre-initialization buffer to alert developers of early logging attempts.
  • Testing: Introduced comprehensive unit tests to verify event buffering, flushing, and console warning behavior.
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.

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.

@github-actions
Copy link
Copy Markdown
Contributor

Hi @HiddenPuppy,
Thanks for your pull request!
If the PR is ready, use the /auto-cc command to assign Reviewer to Review.
We will review it shortly.

Details

Instructions for interacting with me using comments are available here.
If you have questions or suggestions related to my behavior, please file an issue against the gh-ci-bot repository.

Copy link
Copy Markdown
Contributor

@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

This pull request introduces a pre-initialization buffering mechanism for the debug logger in the Electron main process, ensuring that events captured before the logger is fully initialized are preserved and flushed later. Feedback focuses on improving security by sanitizing logs before they are buffered in memory, correcting the buffer eviction logic to drop the oldest events first as intended, and improving test portability by using platform-agnostic temporary directories.

@@ -1,32 +1,106 @@
import { BrowserWindow } from 'electron';
import type { DebugEvent } from '@clawwork/shared';
import type { DebugEvent, LogEventInput } from '@clawwork/shared';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

security-medium medium

Import sanitizeForLog as a value to ensure that buffered events are properly sanitized before being stored in memory, preventing potential leakage of sensitive information.

Suggested change
import type { DebugEvent, LogEventInput } from '@clawwork/shared';
import { sanitizeForLog, type DebugEvent, type LogEventInput } from '@clawwork/shared';


const flushToLogger = (logger: DebugLogger): void => {
for (const event of preInitBuffer) {
logger.log({ ...event, level: event.level as LogEventInput['level'] });
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The cast and object spreading are redundant here. DebugEvent is compatible with the logger's log method input, and the original timestamp will be preserved during the spread inside the real logger's implementation.

Suggested change
logger.log({ ...event, level: event.level as LogEventInput['level'] });
logger.log(event);

Comment on lines +24 to +48
const event: DebugEvent = {
ts: new Date().toISOString(),
level,
domain: input.domain,
event: input.event,
traceId: input.traceId,
feature: input.feature,
message: input.message,
gatewayId: input.gatewayId,
sessionKey: input.sessionKey,
taskId: input.taskId,
runId: input.runId,
requestId: input.requestId,
wsFrameId: input.wsFrameId,
seq: input.seq,
attempt: input.attempt,
durationMs: input.durationMs,
ok: input.ok,
error: input.error,
data: input.data,
};

if (preInitBuffer.length < MAX_PRE_INIT_BUFFER) {
preInitBuffer.push(event);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

security-medium medium

This block can be simplified while addressing two issues:

  1. Security: Sanitizing events before buffering prevents sensitive data (like tokens) from sitting un-redacted in memory or being exposed via getRecentEvents() before initialization.
  2. Logic: The PR description states that the oldest events should be dropped first, but the current implementation drops new events once the buffer is full.
      const event = sanitizeForLog({
        ...input,
        ts: new Date().toISOString(),
        level,
      } as DebugEvent);

      preInitBuffer.push(event);
      if (preInitBuffer.length > MAX_PRE_INIT_BUFFER) {
        preInitBuffer.shift();
      }

@@ -0,0 +1,75 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Add path and os imports to support cross-platform temporary directory usage in tests.

import { join } from 'node:path';
import { tmpdir } from 'node:os';
import { describe, it, expect, vi, beforeEach } from 'vitest';


expect(isDebugLoggerInitialized()).toBe(false);

const tempDir = `/tmp/test-debug-${Date.now()}`;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Hardcoding /tmp is not portable and will cause tests to fail on Windows. Use tmpdir() for a platform-agnostic temporary path.

Suggested change
const tempDir = `/tmp/test-debug-${Date.now()}`;
const tempDir = join(tmpdir(), 'test-debug-' + Date.now());

- Import sanitizeForLog to redact sensitive data before buffering
- Fix buffer eviction: now drops oldest events (shift) instead of ignoring new ones
- Simplify flushToLogger to pass event directly
- Add test for oldest-event eviction behavior

Review feedback from #448
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] getDebugLogger noop fallback silently drops events before initDebugLogger runs

1 participant