Skip to main content

Accessing Run and Action Logs

Logs generated by actions within a run provide critical insights into execution flow, debugging information, and operational status. The log access utility offers capabilities to stream these logs programmatically or view them interactively.

Tailing Logs Programmatically

To retrieve raw log lines as they are generated, use the tail method. This method returns an asynchronous generator, allowing for real-time processing of log data.

The tail method requires an action_id to specify which action's logs to retrieve. Optionally, an attempt number can be provided to target a specific retry of that action.

from typing import AsyncGenerator
from your_package_name.core_classes import Logs # Assuming 'Logs' is in 'your_package_name.core_classes'
from your_package_name.identifier_pb2 import ActionIdentifier # Assuming identifier_pb2 is accessible

async def stream_action_logs(action_id: ActionIdentifier, attempt: int = 1):
"""
Streams and prints log lines for a given action and attempt.
"""
try:
async for line in Logs.tail(action_id=action_id, attempt=attempt):
print(f"[{line.timestamp.ToDatetime()}] {line.message.strip()}")
except LogsNotYetAvailableError as e:
print(f"Error: {e}")
except Exception as e:
print(f"An unexpected error occurred: {e}")

# Example usage (assuming you have an action_id instance)
# action_id_instance = ActionIdentifier(...)
# await stream_action_logs(action_id_instance)

The tail method handles transient network errors and retries automatically. If logs are not yet available after several retries, it raises a LogsNotYetAvailableError.

Interactive Log Viewing

For a more dynamic and user-friendly experience, especially in interactive environments like Jupyter notebooks or terminals, use the create_viewer method. This method sets up an asynchronous log viewer that continuously updates, displaying log lines as they arrive.

The create_viewer method takes an action_id and an optional attempt number. It supports several parameters to customize the viewer's behavior:

  • max_lines: Specifies the maximum number of log lines to display in the viewer at any given time. The viewer scrolls, keeping only the most recent max_lines in view.
  • show_ts: When True, timestamps are included with each log line.
  • raw: If True, the method prints raw log lines to the console instead of launching the interactive viewer. This is useful when the interactive viewer is not desired or supported (e.g., in environments without ipywidgets).
  • filter_system: When True, system-generated log lines are filtered out, showing only application-specific output.
  • panel: If True and raw is False, the viewer renders within a styled panel, enhancing readability. This option is only applicable when using the interactive viewer.
from your_package_name.core_classes import Logs
from your_package_name.identifier_pb2 import ActionIdentifier

async def view_action_logs_interactively(action_id: ActionIdentifier, attempt: int = 1):
"""
Launches an interactive log viewer for a given action and attempt.
"""
print(f"Starting interactive log viewer for action {action_id.name} (attempt {attempt})...")
await Logs.create_viewer(
action_id=action_id,
attempt=attempt,
max_lines=20,
show_ts=True,
filter_system=True,
panel=True,
)
print("Log viewer session ended.")

# Example usage (assuming you have an action_id instance)
# action_id_instance = ActionIdentifier(...)
# await view_action_logs_interactively(action_id_instance)

Viewer Customization and Environment

The interactive viewer leverages an AsyncLogViewer component internally to manage the display and asynchronous log stream. It is designed to work effectively in various environments.

In IPython/Jupyter notebook environments, the viewer attempts to use ipywidgets for a richer interactive experience. If ipywidgets is not available, the create_viewer method automatically falls back to printing raw console output, equivalent to setting raw=True.

The AsyncLogViewer continuously updates the display at a high refresh rate, ensuring that new log lines are visible almost immediately. It gracefully handles stream termination, cancellation, and keyboard interruptions.

Error Handling in Viewer

The interactive viewer catches LogsNotYetAvailableError and displays an informative message if the log stream cannot be established. It also handles asyncio.CancelledError and KeyboardInterrupt to ensure clean shutdown. Upon completion, it reports the total number of lines scrolled.