Skip to content

feat(cli): write a log in the project when a command has a problem - #9

Merged
UltiPro merged 1 commit into
mainfrom
feat/command-log
Nov 12, 2026
Merged

UltiPro merged 1 commit into
mainfrom
feat/command-log

Conversation

@UltiPro

@UltiPro UltiPro commented Nov 12, 2026

Copy link
Copy Markdown
Owner

Summary

A command that has a problem inside a project now leaves its log in .miniops/logs/miniops.log: what it logged and the full traceback of the error. Until now nothing kept a traceback: an error that miniOPs reports ended with a short message and the traceback was lost.

  • cli/log.py (new): CommandLog is a logging.Handler that keeps what a command logs in memory, the last 1000 records. The first warning or error writes all of it to the file, with the traceback, and every later record goes there directly. What was logged before the problem is the context that a bare traceback lacks.
  • A command without problems writes nothing and does not create .miniops/logs/. The log exists to diagnose problems: lines for successful commands would bury the errors and push them out of the size limit sooner, a read-only command should not write to disk, and the history of what was done belongs to the metadata store.
  • On screen an expected error (MiniopsError) still shows Error: <message>. An unexpected error now shows two lines instead of a traceback, Error: miniOPs hit an unexpected error (<type>: <message>). This is a bug. and Details: <path of the log>, but only when the log was really written. Otherwise the traceback is still shown, as it is outside a project.
  • A command should not fail because of its log. If the file cannot be written or the current directory was removed, the command runs without a log. A log call that cannot be formatted is dropped through handleError, and text that cannot be encoded as UTF-8 is written with escapes.
  • The log is a local file, because a command always runs on the user's machine, whatever the target, and miniops init already adds .miniops/ to .gitignore. It is opened only for each write, so no handle is held while a command runs. A file over about 1 MB is set aside as miniops.log.1 at the first problem of a command, and if Windows refuses the rename because another process has the file open, the command adds to the existing file.
  • miniOPs code logs through the standard logging module, under the logger miniops with logging.getLogger(__name__) in modules, and the local store logs the backup made before a schema upgrade and the new schema version. miniops/__init__.py adds a NullHandler, because without one Python prints logged errors to stderr itself and an error outside a project would show twice. find_root in config/project.py is now public: the log needs only the project directory and must not fail on a broken miniops.toml.

Checklist

  • PR title follows Conventional Commits (e.g. feat(registry): ...)
  • Larger or architectural changes were discussed in an issue first (n/a: no issue, this is the maintainer's own planned work and not an architectural change)
  • Tests added or updated (if applicable)
  • No OS-specific assumptions (paths, shell commands, file encodings); works on Linux, macOS and Windows
  • Documentation updated (n/a: the README describes the current release and the planned interface, and both stay accurate until this is released)
  • CHANGELOG.md updated under "Unreleased"

@UltiPro
UltiPro merged commit 799dda7 into main Nov 12, 2026
16 checks passed
@UltiPro
UltiPro deleted the feat/command-log branch November 12, 2026 11:13
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.

1 participant