Skip to content

Fix code review findings: timestamps, error handling, tests, docs#56

Merged
umputun merged 1 commit intomasterfrom
code-review-fixes
Feb 17, 2026
Merged

Fix code review findings: timestamps, error handling, tests, docs#56
umputun merged 1 commit intomasterfrom
code-review-fixes

Conversation

@umputun
Copy link
Copy Markdown
Owner

@umputun umputun commented Feb 17, 2026

Bug fixes:

  • Fix incorrect timestamp calculations in events.goTime was divided by 1000 (already Unix seconds), TimeNano was misused as sub-second offset instead of full nanosecond timestamp. Added fallback for older Docker API versions where TimeNano may be zero
  • Fix syslog writer double-close when both files and syslog enabled — same syslogWriter was added to both log and err MultiWriter slices, getting Close() called twice. Fixed with writeNopCloser wrapper on the err copy
  • Fix typo "even listener" → "event listener" in events.go
  • Add guard for empty c.Names slice in emitRunningContainers()

Error handling improvements:

  • Replace log.Fatalf in makeLogWriters with proper error returns — signature changed to (logWriter, errWriter io.WriteCloser, err error), callers handle gracefully
  • Add missing filter validation: IncludesPattern + ExcludesPattern, Includes + ExcludesPattern, IncludesPattern + Excludes combinations now rejected
  • Extract duplicated stream cleanup logic into closeStreamWriters helper in runEventLoop

Code quality:

  • Fix variable shadowing in MultiWriter.Write and Close — loop variable w shadowed receiver

Test reliability:

  • Replace flaky time.Sleep patterns with require.Eventually and channel-based synchronization across main_test.go and logger_test.go
  • Improve syslog test quality with actual UDP listener verification
  • Add MixErr coverage for runEventLoop
  • Add timestamp validation tests, error path tests for makeLogWriters

Documentation:

  • Add missing CLI flags to README: --loc/LOG_FILES_LOC, --syslog-prefix/SYSLOG_PREFIX, --dbg/DEBUG
  • Add --exclude/--exclude-pattern mutual exclusivity note to README
  • Fix README typo "inlcudes" → "includes"
  • Improve godoc for GetWriter, LogStreamer.Go(), Close(), Wait()
  • Update CLAUDE.md with makeLogWriters signature change and writeNopCloser pattern

Copilot AI review requested due to automatic review settings February 17, 2026 05:23
@coveralls
Copy link
Copy Markdown

coveralls commented Feb 17, 2026

Pull Request Test Coverage Report for Build 22087845807

Details

  • 94 of 106 (88.68%) changed or added relevant lines in 4 files are covered.
  • 1 unchanged line in 1 file lost coverage.
  • Overall coverage increased (+3.9%) to 79.339%

Changes Missing Coverage Covered Lines Changed/Added Lines %
app/discovery/events.go 24 27 88.89%
app/main.go 58 67 86.57%
Files with Coverage Reduction New Missed Lines %
app/main.go 1 84.16%
Totals Coverage Status
Change from base Build 22058265196: 3.9%
Covered Lines: 384
Relevant Lines: 484

💛 - Coveralls

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses a set of issues found during a full-project code review, focusing on correctness (timestamps, writer lifecycle), improved error handling, more reliable tests, and updated documentation.

Changes:

  • Fix Docker event timestamp handling (including TimeNano fallback) and add guards/tests for edge cases in discovery.
  • Replace fatal exits in makeLogWriters with error returns; harden writer lifecycle (syslog double-close) and improve validation.
  • Reduce test flakiness by replacing time.Sleep with require.Eventually, and expand syslog + MixErr coverage; update README/godoc/CLAUDE docs accordingly.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
docs/plans/completed/20260216-code-review-fixes.md Adds a completed implementation plan/trace for the review-driven fixes.
app/syslog/syslog_unix.go Clarifies GetWriter godoc re: syslog prefix usage.
app/main_test.go Removes sleep-based waits; adds sentinel/eventually synchronization; adds new writer/syslog/MixErr tests.
app/main.go Adds filter/destination validation; changes makeLogWriters to return errors; prevents syslog double-close via writeNopCloser.
app/logger/multiwriter.go Fixes loop variable shadowing in Write/Close.
app/logger/logger_test.go Replaces sleeps with require.Eventually to reduce flakiness.
app/logger/logger.go Improves godoc for Go, Close, and Wait.
app/discovery/events_test.go Adds timestamp validation and coverage for containers with no names + TimeNano fallback.
app/discovery/events.go Fixes event listener typo; corrects timestamp calculation and adds guard for empty container names.
README.md Adds missing CLI flags and documents additional mutual exclusivity rules; fixes one typo.
CLAUDE.md Documents makeLogWriters signature change and the syslog no-double-close pattern; adds testing guidance.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

README.md Outdated
Comment on lines +41 to +43
- both `--exclude` and `--include` flags are optional and mutually exclusive, i.e. if `--exclude` defined `--include` not allowed, and vise versa.
- both `--include` and `--include-pattern` flags are optional and mutually exclusive, i.e. if `--include` defined `--include-pattern` not allowed, and vise versa.
- both `--exclude` and `--exclude-pattern` flags are optional and mutually exclusive, i.e. if `--exclude` defined `--exclude-pattern` not allowed, and vise versa.
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

The new README bullets use the misspelling "vise versa". Please change to "vice versa" for correct wording.

Suggested change
- both `--exclude` and `--include` flags are optional and mutually exclusive, i.e. if `--exclude` defined `--include` not allowed, and vise versa.
- both `--include` and `--include-pattern` flags are optional and mutually exclusive, i.e. if `--include` defined `--include-pattern` not allowed, and vise versa.
- both `--exclude` and `--exclude-pattern` flags are optional and mutually exclusive, i.e. if `--exclude` defined `--exclude-pattern` not allowed, and vise versa.
- both `--exclude` and `--include` flags are optional and mutually exclusive, i.e. if `--exclude` defined `--include` not allowed, and vice versa.
- both `--include` and `--include-pattern` flags are optional and mutually exclusive, i.e. if `--include` defined `--include-pattern` not allowed, and vice versa.
- both `--exclude` and `--exclude-pattern` flags are optional and mutually exclusive, i.e. if `--exclude` defined `--exclude-pattern` not allowed, and vice versa.

Copilot uses AI. Check for mistakes.
app/main_test.go Outdated
Comment on lines +408 to +409
opts := cliOpts{EnableFiles: true, FilesLocation: "/dev/null/invalid/path"}
_, _, err := makeLogWriters(&opts, "container1", "gr1")
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

This test uses a hard-coded Unix-specific path ("/dev/null/invalid/path") to force a mkdir error. This is not portable (will behave differently on Windows) and can also risk creating real directories on some platforms. Prefer constructing a guaranteed-invalid path using t.TempDir() (e.g., create a file and attempt MkdirAll under it) so the failure is hermetic across OSes.

Suggested change
opts := cliOpts{EnableFiles: true, FilesLocation: "/dev/null/invalid/path"}
_, _, err := makeLogWriters(&opts, "container1", "gr1")
tmpDir := t.TempDir()
// create a regular file and then try to use a path under it as FilesLocation;
// this is guaranteed to fail when attempting to create a directory.
invalidParent := filepath.Join(tmpDir, "not-a-dir")
err := os.WriteFile(invalidParent, []byte("x"), 0o600)
require.NoError(t, err)
opts := cliOpts{
EnableFiles: true,
FilesLocation: filepath.Join(invalidParent, "subdir"),
}
_, _, err = makeLogWriters(&opts, "container1", "gr1")

Copilot uses AI. Check for mistakes.
Comment on lines 93 to 97
func (e *EventNotif) activate(client DockerClient) {
dockerEventsCh := make(chan *docker.APIEvents)
if err := client.AddEventListener(dockerEventsCh); err != nil {
log.Fatalf("[ERROR] can't add even listener, %v", err)
log.Fatalf("[ERROR] can't add event listener, %v", err)
}
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

activate still uses log.Fatalf when AddEventListener fails, which will terminate the whole process from inside the discovery component and bypass caller error handling/cleanup. Since similar paths were changed to return errors elsewhere in this PR, consider propagating this failure back to the caller (e.g., have NewEventNotif/activate return an error or send an error event) instead of exiting.

Copilot uses AI. Check for mistakes.
- improve error handling and input validation in discovery, logger, and main
- replace flaky time.Sleep patterns with channel-based synchronization in tests
- add test coverage for edge cases and error paths
- update README and CLAUDE.md documentation
@umputun umputun merged commit c0b5c52 into master Feb 17, 2026
6 checks passed
@umputun umputun deleted the code-review-fixes branch February 17, 2026 06:07
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.

3 participants