Conversation
why: Logging standards require `logging.getLogger(__name__)` in every module for consistent, hierarchical log propagation. what: - Add `import logging` and `logger = logging.getLogger(__name__)` to 27 modules that lacked them - Covers cli/, workspace/, _internal/, and top-level modules - No behavioral changes; loggers are declared but unused until subsequent commits add log calls
…gger why: Library __init__.py needs NullHandler per logging best practices. setup_logger() targeted root logger instead of tmuxp, and its handler guard failed when NullHandler was present. what: - Add NullHandler to tmuxp root __init__.py - Add TmuxpLoggerAdapter with process() override for Python <3.13 portable extra-merging - Fix setup_logger() to target "tmuxp" logger by default - Check for non-NullHandler handlers before adding StreamHandler - Always call setLevel() regardless of existing handlers
why: CLI was passing a child logger to setup_logger instead of using the tmuxp root default. Log-file handler hardcoded INFO level, ignoring user's --log-level flag. what: - Simplify setup_logger() call to use default tmuxp root logger - Use DebugLogFormatter for log-file when log_level is DEBUG - Remove hardcoded setLevel(INFO) on tmuxp logger in log-file setup - Add logger declaration to cli/load.py
why: print() calls in library code violate logging standards. The get_pane() catch-reraise lost context, and oh_my_zsh_auto_title() had no machine-readable signal. what: - Replace print(e) in get_pane() with logger.debug() using exc_info and tmux_pane extra; raise PaneNotFound explicitly - Add logger.warning() in oh_my_zsh_auto_title() before the user-facing print block
why: Workspace build lifecycle had no logging, making debugging session creation, window/pane setup, and config resolution opaque. what: - builder.py: Add TmuxpLoggerAdapter with tmux_session/window/pane extra for session created, workspace built, window/pane created, before-script, and send-command events - finders.py: Replace tmuxp_echo() with logger.warning() for multiple-workspace-file detection; add DEBUG log for resolution - loader.py: Add DEBUG logs for expand() and trickle() entry - shell.py: Add DEBUG log for detected shell in detect_best_shell()
why: Log calls need test coverage to prevent regressions and verify structured extra fields are emitted correctly. what: - test_util: Assert get_pane() emits DEBUG with tmux_pane extra on failure; assert oh_my_zsh_auto_title() emits WARNING - test_builder: Assert build() emits INFO with tmux_session extra; assert window/pane creation emits DEBUG with tmux_window/tmux_pane - test_finder: Assert find_workspace_file() emits WARNING when multiple workspace files found in same directory
…y modules why: 5 library modules had logger stubs but zero log calls, leaving gaps in observability for config loading, session freezing, imports, validation, and plugin version checks. what: - Add DEBUG logs to freezer.freeze() (per-session + per-window) with tmux_session/tmux_window extra - Add DEBUG logs to importers.import_tmuxinator() and import_teamocil() - Add DEBUG log to validation.validate_schema() - Add DEBUG log to config_reader._from_file() with tmux_config_path extra - Add DEBUG + WARNING logs to plugin._version_check() with plugin name context
why: Existing log calls lacked structured extra for filtering/searching, finders emitted two verbose warnings for one event, and builder logged commands before execution (factually incorrect on failure). what: - Add tmux_session extra to loader.expand() and trickle() DEBUG calls - Consolidate finders.py dual WARNING into single message with tmux_config_path extra - Move builder command log after send_keys and change to past tense "sent command" - Add tmux_config_path extra to builder "before script failed" catch-log-reraise
why: tmuxp_echo wraps _echo_logger.log(), so DebugLogFormatter showed log.py as the source file instead of the actual CLI caller. what: - Add stacklevel=2 to both _echo_logger.log() calls in tmuxp_echo()
why: Two lifecycle events (session created detached, workspace saved) used print() only, lacking observability via the logging system. what: - Replace cli/load.py print() with tmuxp_echo() for detached session message - Add logger.info() with tmux_config_path extra after freeze file write
why: _compat.py was the only file in the codebase missing the standard from __future__ import annotations that all other modules have. what: - Add from __future__ import annotations at top of _compat.py
why: New and modified log calls need test coverage to prevent regressions and verify structured extra fields are emitted correctly. what: - Add test_expand_logs_debug and test_trickle_logs_debug (test_config.py) - Add test_freeze_logs_debug with tmux_session and tmux_window assertions (test_freezer.py) - Add test_import_teamocil_logs_debug (test_import_teamocil.py) - Add test_import_tmuxinator_logs_debug (test_import_tmuxinator.py) - Add test_plugin_version_check_logs_debug and warning test (test_plugin.py) - Update test_builder assertion from "sending command" to "sent command" - Update test_finder assertion for consolidated warning message
why: Enable dashboard filtering and caplog schema assertions for importer debug logs. what: - Add tmux_session extra to import_tmuxinator log call - Add tmux_session extra to import_teamocil log call via _inner peek - Add tmux_session assertion to both importer caplog tests
why: Enable dashboard filtering on tmux_session for schema validation. what: - Add tmux_session extra to validate_schema debug log - Guard with isinstance for non-dict inputs (param is t.Any)
why: Enable dashboard filtering on tmux_config_path for workspace discovery. what: - Add tmux_config_path extra to find_local_workspace_files debug log
…mpat why: LoggerAdapter became subscriptable at runtime only in Python 3.11. Base class expressions are always evaluated at runtime regardless of `from __future__ import annotations`, so this crashes on 3.10. what: - Change `LoggerAdapter[logging.Logger]` to `LoggerAdapter` - Add `# type: ignore[type-arg]` for mypy compatibility
why: After logging migration, the ambiguity warning only logged via logger.warning() with no user-visible output. Users would silently get the first file picked without knowing alternatives exist. what: - Add tmuxp_echo() after logger.warning() to show user-facing message - Fix extra key: use workspace_file directly (already a directory path) - Add tmuxp_echo import
why: before_script is a shell script path, not a workspace config path.
Using tmux_config_path for it violates the semantic contract of the key.
The adapter already provides tmux_session context.
what:
- Remove extra={"tmux_config_path": ...} from before_script log calls
why: logger.warning() immediately before raise duplicates the exception info. The TmuxpPluginException already contains the incompatibility details. Per logging standards, avoid catch-log-reraise without adding new context. what: - Remove logger.warning() call before raise in _version_check()
why: args.log_level is accessed at line 597 but was not declared in the typed Namespace class, causing type checking gaps. what: - Add log_level: str to CLILoadNamespace
…pter
why: TmuxpLoggerAdapter already has tmux_session and tmux_window in its
defaults. Passing the same keys in per-call extra is redundant since the
adapter's process() method merges them.
what:
- Remove extra={"tmux_session": ...} from "session created" log call
- Remove extra={"tmux_window": ...} from "window created" log call
why: print() bypasses the logging system. tmuxp_echo() provides both logging and print output through a unified channel. what: - Replace logger.warning() + print() with single tmuxp_echo() call - Add tmuxp_echo import
why: No tests existed for validate_schema or find_local_workspace_files logging, leaving the structured extra fields unverified. what: - Add test_validate_schema_logs_debug asserting tmux_session extra - Add test_find_local_workspace_files_logs_debug asserting tmux_config_path
why: stdlib imports (logging, sys) were split by the logger = ... line, violating import grouping conventions. what: - Group stdlib imports together before logger assignment - Remove stale flake8: NOQA comment
why: test_plugin_version_check_logs_warning_on_fail tested the warning log that was removed in the catch-log-reraise fix. The version check failure is already tested via exception assertions in other tests. what: - Remove test_plugin_version_check_logs_warning_on_fail
why: tmuxp_echo was both logging (stderr) and printing (stdout), causing duplicate output. Separating these channels fixes the regression and follows the print-for-users, logger-for-machines pattern. what: - Remove LOG_LEVELS dict, _echo_logger, unstyle import from log.py - Simplify tmuxp_echo to pure print() wrapper (no log_level/style_log) - Add explicit logger.*() calls at all operational call sites - Add logger.info for workspace loading (supports --log-file) - Fix test assertion to match lowercase log message convention
…ings why: get_pane() caught exc.TmuxpException but window.panes.get() raises ObjectDoesNotExist (not a TmuxpException subclass), making the handler unreachable. get_session() and get_window() both catch Exception. what: - Change except exc.TmuxpException to except Exception in get_pane() - Update test to raise Exception instead of TmuxpException
…uity warning
why: The logging branch replaced styled output with a plain tmuxp_echo
call, losing the red error styling and detailed guidance text that
helps users resolve multiple .tmuxp.{yaml,yml,json} files.
what:
- Replace tmuxp_echo with print() using Colors.error() for red styling
- Add guidance text about using distinct file names
- Replace tmuxp.log import with tmuxp._internal.colors import
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
logging.getLogger(__name__)declarations to all 36 source modules for consistent logger hierarchyNullHandlerin library__init__.pyto follow Python library logging best practiceTmuxpLoggerAdapterfor persistentextracontext (session/window/pane) without repeating kwargsprint()calls with structuredtmuxp_echo()orlogger.*()inutil.py,cli/load.py, andfinders.pyextrakeys (tmux_session,tmux_window,tmux_pane,tmux_config_path) to log calls across workspace builder, finders, freezer, importers, loader, and validationsetup_logger()to default to the"tmuxp"logger (not root) and skipNullHandlerwhen checking for existing handlersstacklevel=2totmuxp_echolog calls so source locations point to callerscaplog-based tests asserting onextraattributes across all instrumented modulesChanges by area
Core logging (
src/tmuxp/log.py)TmuxpLoggerAdapter: NewLoggerAdaptersubclass that mergesextradicts portably (Python < 3.13 compatible)setup_logger(): Defaults to"tmuxp"logger, ignoresNullHandlerwhen deciding whether to addStreamHandler, selectsDebugLogFormatterat DEBUG leveltmuxp_echo(): Addsstacklevel=2for accurate caller attributionWorkspace modules
builder.py: Session/window/pane lifecycle logging viaTmuxpLoggerAdapterwith appropriateextrakeysfinders.py: Structured DEBUG for local file search, WARNING for ambiguous multi-file directories (replaces rawtmuxp_echowithlogger.warning+ user-facing echo)freezer.py: DEBUG logging for freeze session/window operationsimporters.py: DEBUG logging for tmuxinator/teamocil import with session name contextloader.py: DEBUG logging for expand/trickle operationsvalidation.py: DEBUG logging for schema validationCLI and utilities
cli/__init__.py: Fixsetup_loggercall (remove explicit logger arg, use default)cli/load.py: Add missinglog_leveltoCLILoadNamespace, useDebugLogFormatterfor file handler at DEBUG level, replaceprint()withtmuxp_echo()util.py: Replaceprint()inoh_my_zsh_auto_titlewithtmuxp_echo(log_level="WARNING"), replaceprint(e)inget_panewith structuredlogger.debug+ proper re-raiseModule stubs (30 files)
import logging+logger = logging.getLogger(__name__)for future instrumentationDesign decisions
merge_extra=True: Python 3.13 addedmerge_extratoLoggerAdapter.__init__, but tmuxp supports 3.10+, soTmuxpLoggerAdapter.process()manually merges — the override is forward-compatiblesetup_loggerdefaults to"tmuxp"not root: Prevents tmuxp's handler setup from affecting unrelated libraries when used as an application entry pointlogger.warning+tmuxp_echofor ambiguity: The structured log record goes to aggregators; thetmuxp_echooutput goes to the terminal for user visibilityVerification
Verify no
print()calls remain in util.py (outside of# NOQAexemptions):$ rg 'print\(' src/tmuxp/util.pyVerify all source modules have logger declarations:
$ rg -L 'logger = logging.getLogger' src/tmuxp/ --glob '*.py' --files-without-matchVerify no f-strings in log calls:
$ rg 'logger\.\w+\(f"' src/tmuxp/Test plan
test_builder_logs_session_created— verifies INFO record withtmux_sessionextratest_builder_logs_window_and_pane_creation— verifies DEBUG records withtmux_window/tmux_paneextra and command loggingtest_expand_logs_debug— verifies expand() DEBUG withtmux_sessiontest_trickle_logs_debug— verifies trickle() DEBUG withtmux_sessiontest_validate_schema_logs_debug— verifies validation DEBUG withtmux_sessiontest_find_workspace_file_logs_warning_on_multiple— verifies WARNING on ambiguous workspace dirstest_find_local_workspace_files_logs_debug— verifies DEBUG withtmux_config_pathtest_freeze_logs_debug— verifies freeze session/window DEBUG recordstest_import_teamocil_logs_debug— verifies teamocil import DEBUG with session nametest_import_tmuxinator_logs_debug— verifies tmuxinator import DEBUG with session nametest_plugin_version_check_logs_debug— verifies plugin version check DEBUGtest_get_pane_logs_debug_on_failure— verifies structured DEBUG on pane lookup failuretest_oh_my_zsh_auto_title_logs_warning— verifies WARNING when DISABLE_AUTO_TITLE unsetuv run py.test— full test suite passesuv run ruff check .— no lint issuesuv run mypy— no type errors