diff --git a/skyvern/cli/__init__.py b/skyvern/cli/__init__.py index 153ec861..ed1db13c 100644 --- a/skyvern/cli/__init__.py +++ b/skyvern/cli/__init__.py @@ -8,7 +8,6 @@ __all__ = [ "tasks_app", "docs_app", "status_app", - "stop_app", "init_app", ] @@ -17,6 +16,5 @@ from .docs import docs_app from .quickstart import quickstart_app from .run_commands import run_app from .status import status_app -from .stop_commands import stop_app from .tasks import tasks_app from .workflow import workflow_app diff --git a/skyvern/cli/commands.py b/skyvern/cli/commands.py index 7dffdc0a..019ac926 100644 --- a/skyvern/cli/commands.py +++ b/skyvern/cli/commands.py @@ -6,7 +6,6 @@ from .init_command import init, init_browser from .quickstart import quickstart_app from .run_commands import run_app from .status import status_app -from .stop_commands import stop_app from .tasks import tasks_app from .workflow import workflow_app @@ -24,7 +23,6 @@ cli_app.add_typer(workflow_app, name="workflow", help="Workflow management comma cli_app.add_typer(tasks_app, name="tasks", help="Task management commands.") cli_app.add_typer(docs_app, name="docs", help="Open Skyvern documentation.") cli_app.add_typer(status_app, name="status", help="Check if Skyvern services are running.") -cli_app.add_typer(stop_app, name="stop", help="Stop Skyvern services like the API server.") init_app = typer.Typer( invoke_without_command=True, help="Interactively configure Skyvern and its dependencies.", diff --git a/skyvern/cli/stop_commands.py b/skyvern/cli/stop_commands.py deleted file mode 100644 index ac8be7b8..00000000 --- a/skyvern/cli/stop_commands.py +++ /dev/null @@ -1,31 +0,0 @@ -import typer -from rich.panel import Panel -from rich.prompt import Confirm - -from skyvern.config import settings - -from .console import console -from .run_commands import get_pids_on_port, kill_pids - -stop_app = typer.Typer(help="Stop Skyvern services like the API server.") - - -@stop_app.command(name="server") -def stop_server( - force: bool = typer.Option(False, "--force", "-f", help="Force kill without confirmation"), -) -> None: - """Stop the Skyvern API server running on the configured port.""" - port = settings.PORT - console.print(f"[bold green]Checking for process on port {port}...[/bold green]") - pids = get_pids_on_port(port) - if not pids: - console.print(f"[yellow]No process found running on port {port}.[/yellow]") - return - if not force: - prompt = f"Process{'es' if len(pids) > 1 else ''} running on port {port}. Kill them?" - confirm = Confirm.ask(prompt) - if not confirm: - console.print("[yellow]Server not stopped.[/yellow]") - return - kill_pids(pids) - console.print(Panel(f"Stopped server on port {port}", border_style="red")) diff --git a/skyvern/client/client.py b/skyvern/client/client.py index 11b42d9b..1c08b30e 100644 --- a/skyvern/client/client.py +++ b/skyvern/client/client.py @@ -1,12 +1,8 @@ # This file was auto-generated by Fern from our API Definition. -import os import typing -import logging from .environment import SkyvernEnvironment import httpx - -logger = logging.getLogger(__name__) from .core.client_wrapper import SyncClientWrapper from .types.run_engine import RunEngine from .types.proxy_location import ProxyLocation @@ -46,9 +42,7 @@ class Skyvern: Parameters ---------- base_url : typing.Optional[str] - The base url to use for requests from the client. If omitted, the value - of the ``SKYVERN_BASE_URL`` environment variable is used when set; otherwise - it falls back to the selected ``environment``. + The base url to use for requests from the client. environment : SkyvernEnvironment The environment to use for requests from the client. from .environment import SkyvernEnvironment @@ -1628,9 +1622,7 @@ class AsyncSkyvern: Parameters ---------- base_url : typing.Optional[str] - The base url to use for requests from the client. If omitted, the value - of the ``SKYVERN_BASE_URL`` environment variable is used when set; otherwise - it falls back to the selected ``environment``. + The base url to use for requests from the client. environment : SkyvernEnvironment The environment to use for requests from the client. from .environment import SkyvernEnvironment @@ -3361,16 +3353,8 @@ class AsyncSkyvern: def _get_base_url(*, base_url: typing.Optional[str] = None, environment: SkyvernEnvironment) -> str: if base_url is not None: - logger.debug("Using explicit base_url: %s", base_url) return base_url - - env_base_url = os.getenv("SKYVERN_BASE_URL") - if env_base_url: - logger.debug("Using SKYVERN_BASE_URL from environment: %s", env_base_url) - return env_base_url - - if environment is not None: - logger.debug("Using base_url from environment enum: %s", environment.value) + elif environment is not None: return environment.value - - raise Exception("Please pass in either base_url or environment to construct the client") + else: + raise Exception("Please pass in either base_url or environment to construct the client") diff --git a/skyvern/forge/sdk/forge_log.py b/skyvern/forge/sdk/forge_log.py index 58df81f8..01f8c37f 100644 --- a/skyvern/forge/sdk/forge_log.py +++ b/skyvern/forge/sdk/forge_log.py @@ -79,12 +79,43 @@ def skyvern_logs_processor(logger: logging.Logger, method_name: str, event_dict: return event_dict +def add_filename_section(logger: logging.Logger, method_name: str, event_dict: EventDict) -> EventDict: + """ + Add a fixed-width, bracketed filename:lineno section after the log level for console logs. + """ + filename = event_dict.get("filename", "") + lineno = event_dict.get("lineno", "") + padded = f"[{filename:<30}:{lineno:<4}]" if filename else "[unknown ]" + event_dict["file"] = padded + event_dict.pop("filename", None) + event_dict.pop("lineno", None) + return event_dict + + +class CustomConsoleRenderer(structlog.dev.ConsoleRenderer): + """ + Show the bracketed filename:lineno section after the log level for console logs, and + colorize it. + """ + + def __call__(self, logger: logging.Logger, name: str, event_dict: EventDict) -> str: + file_section = event_dict.pop("file", "") + file_section_colored = f"\x1b[90m{file_section}\x1b[0m" if file_section else "" + rendered = super().__call__(logger, name, event_dict) + first_bracket = rendered.find("]") + + if first_bracket != -1: + return rendered[: first_bracket + 1] + f" {file_section_colored}" + rendered[first_bracket + 1 :] + else: + return f"{file_section_colored} {rendered}" + + def setup_logger() -> None: """ Setup the logger with the specified format """ # logging.config.dictConfig(logging_config) - renderer = structlog.processors.JSONRenderer() if settings.JSON_LOGGING else structlog.dev.ConsoleRenderer() + renderer = structlog.processors.JSONRenderer() if settings.JSON_LOGGING else CustomConsoleRenderer() additional_processors = ( [ structlog.processors.EventRenamer("msg"), @@ -100,7 +131,15 @@ def setup_logger() -> None: ), ] if settings.JSON_LOGGING - else [] + else [ + structlog.processors.CallsiteParameterAdder( + { + structlog.processors.CallsiteParameter.FILENAME, + structlog.processors.CallsiteParameter.LINENO, + } + ), + add_filename_section, + ] ) LOG_LEVEL_VAL = LOGGING_LEVEL_MAP.get(settings.LOG_LEVEL, logging.INFO)