ConsoleLogObserver ShellObserver
📋 Overview
ConsoleLogObserver is a concrete implementation of the ShellObserver abstract base class. It provides live feedback directly to the terminal by printing detailed information about command execution lifecycle events. This observer is ideal for CLI tools, automation scripts, or any application where operators need real-time visibility into what commands are being executed and their outcomes.
🏗️ Class Hierarchy & Definition
Inheritance: ConsoleLogObserver extends the abstract observer ShellObserver. It overrides two key lifecycle methods to provide console logging behavior.
🔰 Observer Methods Overridden
| Method | Trigger | Description |
|---|---|---|
on_command_start |
Before command execution | Notifies that a command is about to run, displaying the full command line. |
on_command_result |
After command finishes | Processes the result: prints success with execution time or failure with return code and error details. |
⚙️ Method Documentation
🔹 on_command_start(executable, final_args)
Description: Called immediately before a shell command is executed. Outputs a user-friendly message indicating which command is being run. The method reconstructs the full command string from the executable and its arguments.
•
executable (str) – The executable name or path.•
final_args (List[str]) – List of arguments passed to the executable.📤 Returns:
None🖨️ Output example:
🛠️ Executing: git commit -m "initial commit"
final_args with spaces and prepends the emoji "🛠️" for visual clarity.
🔹 on_command_result(result: CommandResult)
Description: Handles the command result after execution finishes. Distinguishes between success and failure cases, providing formatted output with timing or error information.
•
result (CommandResult) – Object containing execution status, return code, execution time, standard error, and other metadata.📤 Returns:
None✅ Success branch
If result.is_success() is True, prints: ✅ OK (X.XXXs) where X.XXX is the execution time in seconds (formatted to 3 decimal places).
❌ Failure branch
If the command fails, prints: ❌ FAIL (Code: {return_code}). Additionally, if result.standard_error contains any content, it prints the stripped error message on a new line indented with " Error: " prefix.
execution_time attribute (float) represents the total duration of the command in seconds.
💻 Usage Example
Below is a practical demonstration of how ConsoleLogObserver integrates with a command executor. The observer subscribes to shell events and prints real-time logs to the console.
# Assume existence of a ShellRunner or Subject that notifies observers from shell_observer import ShellObserver, CommandResult from console_log_observer import ConsoleLogObserver # Instantiate observer observer = ConsoleLogObserver() # Attach to a command executor (pseudocode) executor.attach(observer) # When executor runs a command like 'ls -la' executor.run("ls", ["-la"]) # Console output would be: # 🛠️ Executing: ls -la # ✅ OK (0.023s) # In case of error (e.g., command not found): executor.run("invalid_cmd", []) # Output: # 🛠️ Executing: invalid_cmd # ❌ FAIL (Code: 127) # Error: command not found: invalid_cmd
CommandResult object must be provided by the shell execution engine.
🎯 Real-time Behavior & Console Output
The ConsoleLogObserver ensures that users are never left wondering about the progress of long-running or critical shell commands. Its behavior includes:
- Immediate feedback –
on_command_startfires before the command even begins, so the operator knows exactly what is being executed. - Success / Failure distinction – Uses colored emojis (✅ / ❌) and clear language to indicate outcome.
- Performance metrics – Execution time in seconds helps identify slow commands.
- Error transparency – When a command fails, the standard error output is displayed with proper indentation, making debugging straightforward.
📊 Example Output Scenarios
| Scenario | Console Output |
|---|---|
Successful command (echo "Hello") |
🛠️ Executing: echo Hello |
| Failed command (missing file) | 🛠️ Executing: cat missing.txt |
| Long-running process | 🛠️ Executing: sleep 2 |
ConsoleLogObserver fulfills the observer contract by implementing required methods. It does not rely on any shared state, making it thread-safe for concurrent command executions (if the underlying executor supports it).
🔧 Technical Notes
Dependencies: This class expects a CommandResult object with at least the following attributes/methods:
is_success()→boolexecution_time→float(seconds)return_code→intstandard_error→str(may be empty)
Inherited from ShellObserver: The base class may define additional hooks (e.g., on_command_end), but ConsoleLogObserver only overrides the two methods relevant to its purpose. It can be extended further if needed.
✨ Design Philosophy: Minimal, non-intrusive logging. Each log entry is self-contained and uses common Unicode symbols for improved scannability. The observer does not raise exceptions and gracefully handles missing attributes (as per Python's duck typing).