Skip to content

refactor logger to zerolog#1239

Merged
yinwm merged 6 commits intosipeed:mainfrom
cytown:d5
Mar 11, 2026
Merged

refactor logger to zerolog#1239
yinwm merged 6 commits intosipeed:mainfrom
cytown:d5

Conversation

@cytown
Copy link
Contributor

@cytown cytown commented Mar 8, 2026

📝 Description

refactor logger to zerolog.

CleanShot 2026-03-08 at 18 34 58@2x

🗣️ Type of Change

  • 🐞 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 📖 Documentation update
  • ⚡ Code refactoring (no functional changes, no api changes)

🤖 AI Code Generation

  • 🤖 Fully AI-generated (100% AI, 0% Human)
  • 🛠️ Mostly AI-generated (AI draft, Human verified/modified)
  • 👨‍💻 Mostly Human-written (Human lead, AI assisted or none)

🔗 Related Issue

📚 Technical Context (Skip for Docs)

  • Reference URL:
  • Reasoning:

🧪 Test Environment

  • Hardware: PC
  • OS: macOS 13.6
  • Model/Provider:
  • Channels:

📸 Evidence (Optional)

Click to view Logs/Screenshots

☑️ Checklist

  • My code/docs follow the style of this project.
  • I have performed a self-review of my own changes.
  • I have updated the documentation accordingly.

@sipeed-bot sipeed-bot bot added type: enhancement New feature or request domain: channel go Pull requests that update go code labels Mar 8, 2026
Copy link
Collaborator

@mengzhuo mengzhuo left a comment

Choose a reason for hiding this comment

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

Also you should update go.mod if zerolog is explicity required.

@cytown
Copy link
Contributor Author

cytown commented Mar 10, 2026

Also you should update go.mod if zerolog is explicity required.

done.

@yinwm
Copy link
Collaborator

yinwm commented Mar 10, 2026

Code review

Found 2 issues:

  1. File handle leak in EnableFileLogging - The function opens a new file but does not close the previous file handle when called multiple times. The original code had if logger.file != nil { logger.file.Close() } before opening a new file, but this was removed in the refactor.

func EnableFileLogging(filePath string) error {
mu.Lock()
defer mu.Unlock()
if err := os.MkdirAll(filepath.Dir(filePath), 0o755); err != nil {
return fmt.Errorf("failed to create log directory: %w", err)
}
file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644)
if err != nil {
return fmt.Errorf("failed to open log file: %w", err)
}
fileLogger = zerolog.New(file).With().Timestamp().Caller().Logger()
return nil
}

  1. File handle leak in DisableFileLogging - The function resets fileLogger to zero value but does not close the underlying file handle. The original code had if logger.file != nil { logger.file.Close() } which was removed.

func DisableFileLogging() {
mu.Lock()
defer mu.Unlock()
fileLogger = zerolog.Logger{}
}

Suggested fix: Store the file handle in a global variable (e.g., logFile *os.File) and close it properly in both functions:

var (
    logger     zerolog.Logger
    fileLogger zerolog.Logger
    logFile    *os.File  // Add this
    // ...
)

func EnableFileLogging(filePath string) error {
    mu.Lock()
    defer mu.Unlock()

    if err := os.MkdirAll(filepath.Dir(filePath), 0o755); err != nil {
        return fmt.Errorf("failed to create log directory: %w", err)
    }

    newFile, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644)
    if err != nil {
        return fmt.Errorf("failed to open log file: %w", err)
    }

    // Close old file if exists
    if logFile != nil {
        logFile.Close()
    }

    logFile = newFile
    fileLogger = zerolog.New(logFile).With().Timestamp().Caller().Logger()
    return nil
}

func DisableFileLogging() {
    mu.Lock()
    defer mu.Unlock()

    if logFile != nil {
        logFile.Close()
        logFile = nil
    }
    fileLogger = zerolog.Logger{}
}

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

@cytown
Copy link
Contributor Author

cytown commented Mar 10, 2026

Code review

Found 2 issues:

  1. File handle leak in EnableFileLogging - The function opens a new file but does not close the previous file handle when called multiple times. The original code had if logger.file != nil { logger.file.Close() } before opening a new file, but this was removed in the refactor.

func EnableFileLogging(filePath string) error {
mu.Lock()
defer mu.Unlock()
if err := os.MkdirAll(filepath.Dir(filePath), 0o755); err != nil {
return fmt.Errorf("failed to create log directory: %w", err)
}
file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644)
if err != nil {
return fmt.Errorf("failed to open log file: %w", err)
}
fileLogger = zerolog.New(file).With().Timestamp().Caller().Logger()
return nil
}

  1. File handle leak in DisableFileLogging - The function resets fileLogger to zero value but does not close the underlying file handle. The original code had if logger.file != nil { logger.file.Close() } which was removed.

func DisableFileLogging() {
mu.Lock()
defer mu.Unlock()
fileLogger = zerolog.Logger{}
}

Suggested fix: Store the file handle in a global variable (e.g., logFile *os.File) and close it properly in both functions:

var (
    logger     zerolog.Logger
    fileLogger zerolog.Logger
    logFile    *os.File  // Add this
    // ...
)

func EnableFileLogging(filePath string) error {
    mu.Lock()
    defer mu.Unlock()

    if err := os.MkdirAll(filepath.Dir(filePath), 0o755); err != nil {
        return fmt.Errorf("failed to create log directory: %w", err)
    }

    newFile, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644)
    if err != nil {
        return fmt.Errorf("failed to open log file: %w", err)
    }

    // Close old file if exists
    if logFile != nil {
        logFile.Close()
    }

    logFile = newFile
    fileLogger = zerolog.New(logFile).With().Timestamp().Caller().Logger()
    return nil
}

func DisableFileLogging() {
    mu.Lock()
    defer mu.Unlock()

    if logFile != nil {
        logFile.Close()
        logFile = nil
    }
    fileLogger = zerolog.Logger{}
}

🤖 Generated with Claude Code

  • If this code review was useful, please react with 👍. Otherwise, react with 👎.

done,

@cytown cytown requested a review from mengzhuo March 10, 2026 07:25
@mengzhuo
Copy link
Collaborator

@yinwm Could you take a look?

@yinwm
Copy link
Collaborator

yinwm commented Mar 10, 2026

Code Review

Found 4 issues that should be addressed before merging:

1. FATAL level uses wrong zerolog method

At pkg/logger/logger.go#L119-L120:

case zerolog.FatalLevel:
    event = logger.Error()  // Should use logger.Fatal()

Then manually calling os.Exit(1) at the end. This bypasses zerolog's Fatal() mechanism and skips OnFatal hooks. Should use logger.Fatal() directly and remove the manual exit.

2. DRY violation - duplicate switch-case

The level-to-event switch logic is duplicated for console logger and file logger in logMessage(). Extract to a helper function like getEvent(logger zerolog.Logger, level LogLevel) *zerolog.Event.

3. API inconsistency

Only Fatalf was added, but there's no corresponding Debugf, Infof, Warnf, Errorf. Either add all of them or remove Fatalf for consistency.

4. TODO comment should not be merged

TimeFormat: "15:04:05", // TODO: make it configurable???

The three question marks indicate uncertainty. Either implement the configuration or remove the TODO entirely. Don't merge unresolved TODOs.


Good aspects

  • Using mature zerolog library is the right direction
  • Maintained backward API compatibility
  • Auto-creating log directory is a nice improvement
  • Third-party SDK logger integration looks correct

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

@cytown
Copy link
Contributor Author

cytown commented Mar 11, 2026

Code Review

Found 4 issues that should be addressed before merging:

1. FATAL level uses wrong zerolog method

At pkg/logger/logger.go#L119-L120:

case zerolog.FatalLevel:
    event = logger.Error()  // Should use logger.Fatal()

Then manually calling os.Exit(1) at the end. This bypasses zerolog's Fatal() mechanism and skips OnFatal hooks. Should use logger.Fatal() directly and remove the manual exit.

2. DRY violation - duplicate switch-case

The level-to-event switch logic is duplicated for console logger and file logger in logMessage(). Extract to a helper function like getEvent(logger zerolog.Logger, level LogLevel) *zerolog.Event.

3. API inconsistency

Only Fatalf was added, but there's no corresponding Debugf, Infof, Warnf, Errorf. Either add all of them or remove Fatalf for consistency.

4. TODO comment should not be merged

TimeFormat: "15:04:05", // TODO: make it configurable???

The three question marks indicate uncertainty. Either implement the configuration or remove the TODO entirely. Don't merge unresolved TODOs.

Good aspects

  • Using mature zerolog library is the right direction
  • Maintained backward API compatibility
  • Auto-creating log directory is a nice improvement
  • Third-party SDK logger integration looks correct

🤖 Generated with Claude Code

  • If this code review was useful, please react with 👍. Otherwise, react with 👎.

1/2 fixed. 3 it's for 3rd party logger usage, no need to fix. 4 it's a feature need negotiate later, so make it TODO, please check the previous review comment.

@yinwm yinwm merged commit d920b78 into sipeed:main Mar 11, 2026
4 checks passed
dj-oyu pushed a commit to dj-oyu/picoclaw that referenced this pull request Mar 14, 2026
* refactor logger to zerolog

* modify dingtalk and discord logger

* fix for lint

* fix for review

* fix for file leak

* fix for review
dj-oyu pushed a commit to dj-oyu/picoclaw that referenced this pull request Mar 16, 2026
* refactor logger to zerolog

* modify dingtalk and discord logger

* fix for lint

* fix for review

* fix for file leak

* fix for review
vanitu pushed a commit to vanitu/picoclaw that referenced this pull request Mar 17, 2026
This merge brings in upstream changes including:
- zerolog logger refactoring (sipeed#1239)
- Anthropic Messages API support (sipeed#1284)
- Global WebSocket for Pico chat (sipeed#1507)
- ModelScope and LongCat providers (sipeed#1317, sipeed#1486)
- Web gateway hot reload and polling (sipeed#1684)
- Credential encryption with AES-GCM (sipeed#1521)
- Cross-platform systray UI (sipeed#1649)
- Security fixes for LINE webhooks, identity allowlist
- And many more improvements

Conflict resolved:
- pkg/agent/instance.go: merged buildAllowReadPatterns/mediaTempDirPattern
  functions from upstream while preserving A2A registry Close() handling

Custom features preserved:
- A2A channel (Agent-to-Agent protocol)
- Krabot channel
- Enhanced Docker multi-channel support
@cytown cytown deleted the d5 branch March 19, 2026 06:36
j0904 pushed a commit to j0904/picoclaw that referenced this pull request Mar 22, 2026
* refactor logger to zerolog

* modify dingtalk and discord logger

* fix for lint

* fix for review

* fix for file leak

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

Labels

domain: channel go Pull requests that update go code type: enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants