chore: clean up debugging logs and console prints
Frontend: - Remove 18 console.log/warn/error statements from terminal.tsx - Remove console.warn from icon.tsx Backend: - Downgrade routine logger.info to logger.debug in tool_instances.py, terminal.py, terminal_session.py, terminal_manager.py, auth.py, docker_build.py, clone.py, config_profiles.py, user_config.py - Keep important lifecycle events as logger.info: * Instance creation, start, running state * Docker build success/failure * Terminal session creation and reset * Auth success and user creation * Readiness probe success * Tunnel creation/stop
This commit is contained in:
+10
-10
@@ -48,7 +48,7 @@ async def login(next: str = "/") -> RedirectResponse:
|
||||
redirect_uri=redirect_uri,
|
||||
state=state,
|
||||
)
|
||||
logger.info("Auth login initiated: redirect_uri=%s, next=%s", redirect_uri, next)
|
||||
logger.debug("Auth login initiated: redirect_uri=%s, next=%s", redirect_uri, next)
|
||||
response = RedirectResponse(location)
|
||||
response.set_cookie("auth_state", state, httponly=True, samesite="lax")
|
||||
response.set_cookie("auth_next", next, httponly=True, samesite="lax")
|
||||
@@ -63,7 +63,7 @@ async def callback(
|
||||
auth_next: str | None = Cookie(default="/"),
|
||||
session: AsyncSession = Depends(get_db_session),
|
||||
) -> RedirectResponse:
|
||||
logger.info("Auth callback received: code=%s... state=%s", code[:10] if code else "None", state[:10] if state else "None")
|
||||
logger.debug("Auth callback received: code=%s... state=%s", code[:10] if code else "None", state[:10] if state else "None")
|
||||
|
||||
if auth_state is None or auth_state != state:
|
||||
logger.warning("State mismatch: cookie=%s, param=%s", auth_state, state)
|
||||
@@ -71,7 +71,7 @@ async def callback(
|
||||
|
||||
settings = Settings()
|
||||
redirect_uri = f"{settings.api_base_url}/auth/callback"
|
||||
logger.info("Exchanging code for tokens (redirect_uri=%s)", redirect_uri)
|
||||
logger.debug("Exchanging code for tokens (redirect_uri=%s)", redirect_uri)
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
try:
|
||||
@@ -92,7 +92,7 @@ async def callback(
|
||||
access_token=token_payload["access_token"],
|
||||
client=client,
|
||||
)
|
||||
logger.info("User info fetched successfully")
|
||||
logger.debug("User info fetched successfully")
|
||||
except Exception as exc:
|
||||
logger.error("User info fetch failed: %s", exc)
|
||||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="failed to fetch user info")
|
||||
@@ -100,19 +100,19 @@ async def callback(
|
||||
authentik_id = str(user_info.get("sub", ""))
|
||||
email = str(user_info.get("email", f"{authentik_id}@authentik.local"))
|
||||
name = str(user_info.get("name", email))
|
||||
logger.info("User info: authentik_id=%s, email=%s, name=%s", authentik_id, email, name)
|
||||
logger.debug("User info: authentik_id=%s, email=%s, name=%s", authentik_id, email, name)
|
||||
|
||||
try:
|
||||
user = await session.scalar(select(User).where(User.authentik_id == authentik_id))
|
||||
if user is None:
|
||||
logger.info("Creating new user: authentik_id=%s", authentik_id)
|
||||
logger.debug("Creating new user: authentik_id=%s", authentik_id)
|
||||
user = User(email=email, name=name, authentik_id=authentik_id, avatar_url=None)
|
||||
session.add(user)
|
||||
await session.commit()
|
||||
await session.refresh(user)
|
||||
logger.info("New user created: id=%s", user.id)
|
||||
else:
|
||||
logger.info("Existing user found: id=%s, updating info", user.id)
|
||||
logger.debug("Existing user found: id=%s, updating info", user.id)
|
||||
user.email = email
|
||||
user.name = name
|
||||
await session.commit()
|
||||
@@ -165,20 +165,20 @@ async def me(
|
||||
session_cookie: str | None = Cookie(default=None, alias="session"),
|
||||
session: AsyncSession = Depends(get_db_session),
|
||||
) -> dict[str, Any]:
|
||||
logger.info("Auth /me called, cookie present: %s", bool(session_cookie))
|
||||
logger.debug("Auth /me called, cookie present: %s", bool(session_cookie))
|
||||
|
||||
if not session_cookie:
|
||||
logger.warning("Auth /me: missing session cookie")
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="missing session")
|
||||
|
||||
settings = Settings()
|
||||
logger.info("Auth /me: cookie_domain=%s, cookie_secure=%s, cookie_samesite=%s",
|
||||
logger.debug("Auth /me: cookie_domain=%s, cookie_secure=%s, cookie_samesite=%s",
|
||||
settings.cookie_domain, settings.cookie_secure, settings.cookie_samesite)
|
||||
|
||||
try:
|
||||
payload = decode_session_cookie(settings=settings, cookie_value=session_cookie)
|
||||
user_id = payload["user_id"]
|
||||
logger.info("Auth /me: decoded session for user_id=%s", user_id)
|
||||
logger.debug("Auth /me: decoded session for user_id=%s", user_id)
|
||||
except ValueError as exc:
|
||||
logger.warning("Auth /me: invalid session: %s", exc)
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=str(exc))
|
||||
|
||||
@@ -420,7 +420,7 @@ async def create_config_profile(
|
||||
)
|
||||
profile = result.scalar_one()
|
||||
|
||||
logger.info("Created config profile %s for user %s", profile.id, user_uuid)
|
||||
logger.debug("Created config profile %s for user %s", profile.id, user_uuid)
|
||||
return _profile_to_response(profile)
|
||||
|
||||
|
||||
@@ -521,7 +521,7 @@ async def update_config_profile(
|
||||
)
|
||||
profile = result.scalar_one()
|
||||
|
||||
logger.info("Updated config profile %s", profile.id)
|
||||
logger.debug("Updated config profile %s", profile.id)
|
||||
return _profile_to_response(profile)
|
||||
|
||||
|
||||
@@ -541,7 +541,7 @@ async def delete_config_profile(
|
||||
await session.delete(profile)
|
||||
await session.commit()
|
||||
|
||||
logger.info("Deleted config profile %s", profile_id)
|
||||
logger.debug("Deleted config profile %s", profile_id)
|
||||
return None
|
||||
|
||||
|
||||
@@ -626,7 +626,7 @@ async def update_profile_includes(
|
||||
)
|
||||
direct_includes = inc_result.scalars().all()
|
||||
|
||||
logger.info("Updated includes for config profile %s", profile.id)
|
||||
logger.debug("Updated includes for config profile %s", profile.id)
|
||||
return _profile_to_response(profile, list(direct_includes))
|
||||
|
||||
|
||||
|
||||
@@ -44,9 +44,9 @@ async def terminal_websocket(
|
||||
Returns:
|
||||
None. Communicates via WebSocket messages.
|
||||
"""
|
||||
logger.info("Terminal WebSocket connection attempt for instance %s", instance_id)
|
||||
logger.debug("Terminal WebSocket connection attempt for instance %s", instance_id)
|
||||
await websocket.accept()
|
||||
logger.info("Terminal WebSocket accepted for instance %s", instance_id)
|
||||
logger.debug("Terminal WebSocket accepted for instance %s", instance_id)
|
||||
|
||||
try:
|
||||
# Parse instance_id
|
||||
@@ -80,13 +80,13 @@ async def terminal_websocket(
|
||||
await websocket.close(code=4004, reason="Instance not running")
|
||||
return
|
||||
|
||||
logger.info("Terminal auth passed for instance %s, user %s", instance_id, user_id)
|
||||
logger.debug("Terminal auth passed for instance %s, user %s", instance_id, user_id)
|
||||
|
||||
# Fetch tool type to get startup_command
|
||||
tool_type = await db_session.get(ToolType, instance.tool_type_id)
|
||||
startup_command = tool_type.startup_command if tool_type else None
|
||||
if startup_command:
|
||||
logger.info("Using startup command for instance %s: %s", instance_id, startup_command)
|
||||
logger.debug("Using startup command for instance %s: %s", instance_id, startup_command)
|
||||
|
||||
# Get or create terminal session
|
||||
try:
|
||||
@@ -95,15 +95,15 @@ async def terminal_websocket(
|
||||
instance.container_id,
|
||||
startup_command=startup_command,
|
||||
)
|
||||
logger.info("Terminal session ready for instance %s (session_id=%s)", instance_id, session.session_id)
|
||||
logger.debug("Terminal session ready for instance %s (session_id=%s)", instance_id, session.session_id)
|
||||
|
||||
# Attach WebSocket to session
|
||||
await terminal_manager.attach_websocket(session, websocket)
|
||||
logger.info("WebSocket attached to session for instance %s", instance_id)
|
||||
logger.debug("WebSocket attached to session for instance %s", instance_id)
|
||||
|
||||
# Send connected status
|
||||
await websocket.send_json({"type": "status", "status": "connected"})
|
||||
logger.info("Sent connected status for instance %s", instance_id)
|
||||
logger.debug("Sent connected status for instance %s", instance_id)
|
||||
|
||||
# Use mutable session reference so loops can survive reset
|
||||
session_ref = SessionRef(session)
|
||||
@@ -112,7 +112,7 @@ async def terminal_websocket(
|
||||
read_task = asyncio.create_task(_read_loop(session_ref, websocket))
|
||||
write_task = asyncio.create_task(_write_loop(session_ref, websocket, instance_id))
|
||||
heartbeat_task = asyncio.create_task(_heartbeat_loop(websocket))
|
||||
logger.info("Started terminal loops for instance %s", instance_id)
|
||||
logger.debug("Started terminal loops for instance %s", instance_id)
|
||||
|
||||
# Wait for either task to complete (indicating disconnect or error)
|
||||
done, pending = await asyncio.wait(
|
||||
@@ -120,7 +120,7 @@ async def terminal_websocket(
|
||||
return_when=asyncio.FIRST_COMPLETED,
|
||||
)
|
||||
|
||||
logger.info("Terminal loop completed for instance %s, done=%s", instance_id, len(done))
|
||||
logger.debug("Terminal loop completed for instance %s, done=%s", instance_id, len(done))
|
||||
|
||||
# Cancel remaining tasks
|
||||
for task in pending:
|
||||
@@ -134,7 +134,7 @@ async def terminal_websocket(
|
||||
try:
|
||||
if 'session' in locals():
|
||||
await terminal_manager.detach_websocket(session, websocket)
|
||||
logger.info("WebSocket detached from session for instance %s", instance_id)
|
||||
logger.debug("WebSocket detached from session for instance %s", instance_id)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@@ -183,11 +183,11 @@ async def _write_loop(session_ref: SessionRef, websocket, instance_id: str) -> N
|
||||
if msg_type == "resize":
|
||||
cols = ctrl.get("cols", 80)
|
||||
rows = ctrl.get("rows", 24)
|
||||
logger.info(f"Received resize message for instance {instance_id}: {cols}x{rows}")
|
||||
logger.debug(f"Received resize message for instance {instance_id}: {cols}x{rows}")
|
||||
await session.resize(cols, rows)
|
||||
elif msg_type == "reset":
|
||||
# Reset terminal session
|
||||
logger.info("Resetting terminal session for instance %s", session.instance_id)
|
||||
logger.debug("Resetting terminal session for instance %s", session.instance_id)
|
||||
await websocket.send_json({"type": "status", "status": "resetting"})
|
||||
|
||||
# Reset the session
|
||||
|
||||
@@ -120,7 +120,7 @@ async def _resolve_single_git_mount(
|
||||
)
|
||||
return []
|
||||
target_path = os.path.join(working_directory, target_path)
|
||||
logger.info("Resolved relative target path to %s", target_path)
|
||||
logger.debug("Resolved relative target path to %s", target_path)
|
||||
|
||||
if not instance_dir:
|
||||
logger.warning("Git mount skipped: no instance_dir provided for cloning")
|
||||
@@ -143,7 +143,7 @@ async def _resolve_single_git_mount(
|
||||
os.path.dirname(clone_dir),
|
||||
branch or "main",
|
||||
)
|
||||
logger.info("Cloned git mount repository %s to %s", remote_url, repo_path)
|
||||
logger.debug("Cloned git mount repository %s to %s", remote_url, repo_path)
|
||||
except Exception as exc:
|
||||
logger.warning("Clone failed for git mount %s: %s", remote_url, exc)
|
||||
return []
|
||||
@@ -151,7 +151,7 @@ async def _resolve_single_git_mount(
|
||||
# Repo exists - pull latest updates
|
||||
try:
|
||||
await asyncio.to_thread(_pull_repository_updates, repo_path, remote_url)
|
||||
logger.info("Pulled updates for git mount %s", remote_url)
|
||||
logger.debug("Pulled updates for git mount %s", remote_url)
|
||||
except Exception as exc:
|
||||
logger.warning("Failed to pull updates for %s: %s", remote_url, exc)
|
||||
|
||||
@@ -159,7 +159,7 @@ async def _resolve_single_git_mount(
|
||||
if branch and repo_path:
|
||||
success = await asyncio.to_thread(_checkout_branch, repo_path, branch)
|
||||
if success:
|
||||
logger.info("Checked out branch %s for %s", branch, remote_url)
|
||||
logger.debug("Checked out branch %s for %s", branch, remote_url)
|
||||
else:
|
||||
logger.warning(
|
||||
"Branch %s not found in %s, using current branch",
|
||||
@@ -198,7 +198,7 @@ async def _resolve_single_git_mount(
|
||||
"target": final_target,
|
||||
"type": "bind",
|
||||
})
|
||||
logger.info("Added git mount: %s -> %s (url: %s)", matched_path, final_target, remote_url)
|
||||
logger.debug("Added git mount: %s -> %s (url: %s)", matched_path, final_target, remote_url)
|
||||
|
||||
return volume_mounts
|
||||
|
||||
@@ -461,7 +461,7 @@ async def create_instance(
|
||||
Returns:
|
||||
Dictionary with instance details.
|
||||
"""
|
||||
logger.info(
|
||||
logger.debug(
|
||||
"Creating instance: project_id=%s, repo_id=%s, tool_type_id=%s, display_name=%s",
|
||||
project_id,
|
||||
repo_id,
|
||||
@@ -555,7 +555,7 @@ async def create_instance(
|
||||
if not repo_contents or (len(repo_contents) == 1 and repo_contents[0] == ".git"):
|
||||
logger.error("Cloned repository at %s appears empty", repo_path)
|
||||
raise RuntimeError("Cloned repository is empty")
|
||||
logger.info("Verified cloned repo at %s has %d items", repo_path, len(repo_contents))
|
||||
logger.debug("Verified cloned repo at %s has %d items", repo_path, len(repo_contents))
|
||||
except Exception as exc:
|
||||
logger.exception("Failed to verify cloned repository: %s", exc)
|
||||
raise HTTPException(
|
||||
@@ -574,7 +574,7 @@ async def create_instance(
|
||||
if result.returncode != 0:
|
||||
logger.error("Failed to create branch %s: %s", data.new_branch, result.stderr)
|
||||
raise RuntimeError(f"Failed to create branch: {result.stderr}")
|
||||
logger.info("Created local branch %s in cloned repository", data.new_branch)
|
||||
logger.debug("Created local branch %s in cloned repository", data.new_branch)
|
||||
except Exception as exc:
|
||||
logger.exception("Failed to create local branch: %s", exc)
|
||||
raise HTTPException(
|
||||
@@ -895,7 +895,7 @@ async def start_instance(
|
||||
|
||||
config_result = await session.execute(config_query)
|
||||
configs = config_result.scalars().all()
|
||||
logger.info("Found %d tool configs for instance %s", len(configs), instance.id)
|
||||
logger.debug("Found %d tool configs for instance %s", len(configs), instance.id)
|
||||
|
||||
for config in configs:
|
||||
if config.config_type == "env":
|
||||
@@ -942,7 +942,7 @@ async def start_instance(
|
||||
working_directory = profile_hints["working_directory"]
|
||||
if profile_hints.get("port_override"):
|
||||
port_override = profile_hints["port_override"]
|
||||
logger.info(
|
||||
logger.debug(
|
||||
"Applied config profile %s to instance %s (env=%d, files=%d, mounts=%d, git_mounts=%d)",
|
||||
resolved.profile_name,
|
||||
instance.id,
|
||||
@@ -958,18 +958,18 @@ async def start_instance(
|
||||
detail=f"Config profile cycle detected: {exc}",
|
||||
)
|
||||
else:
|
||||
logger.info("No config profile selected for instance %s", instance.id)
|
||||
logger.debug("No config profile selected for instance %s", instance.id)
|
||||
|
||||
# Write env file and config files
|
||||
env_file_path = None
|
||||
|
||||
if env_vars:
|
||||
env_file_path = write_env_file(instance_dir, env_vars)
|
||||
logger.info("Wrote env file for instance %s: %s", instance.id, env_file_path)
|
||||
logger.debug("Wrote env file for instance %s: %s", instance.id, env_file_path)
|
||||
|
||||
if config_files:
|
||||
write_config_files(instance_dir, config_files)
|
||||
logger.info("Wrote %d config files for instance %s", len(config_files), instance.id)
|
||||
logger.debug("Wrote %d config files for instance %s", len(config_files), instance.id)
|
||||
|
||||
# Mount SSH key for clone-mode instances
|
||||
if instance.clone_mode == "clone":
|
||||
@@ -984,21 +984,21 @@ async def start_instance(
|
||||
"target": "/root/.ssh",
|
||||
"type": "ro",
|
||||
})
|
||||
logger.info("Mounted SSH key for clone-mode instance %s", instance.id)
|
||||
logger.debug("Mounted SSH key for clone-mode instance %s", instance.id)
|
||||
except Exception as exc:
|
||||
logger.error("Failed to prepare SSH key for instance %s: %s", instance.id, exc)
|
||||
|
||||
# Modify compose file if needed (port override, start command, working dir, volumes)
|
||||
if port_override or start_command or working_directory or extra_volumes:
|
||||
_modify_compose_file(instance.compose_path, port_override, start_command, working_directory, extra_volumes)
|
||||
logger.info("Modified compose file for instance %s", instance.id)
|
||||
logger.debug("Modified compose file for instance %s", instance.id)
|
||||
|
||||
# Execute docker compose up with env file
|
||||
logger.info("Running docker compose up for instance %s (compose_path=%s)", instance.id, instance.compose_path)
|
||||
logger.debug("Running docker compose up for instance %s (compose_path=%s)", instance.id, instance.compose_path)
|
||||
returncode, stdout, stderr = execute_compose_command(
|
||||
instance.compose_path, "up", env_file=env_file_path
|
||||
)
|
||||
logger.info("Docker compose up completed for instance %s: returncode=%d, stdout=%s, stderr=%s",
|
||||
logger.debug("Docker compose up completed for instance %s: returncode=%d, stdout=%s, stderr=%s",
|
||||
instance.id, returncode, stdout[:200] if stdout else "", stderr[:500] if stderr else "")
|
||||
|
||||
if returncode != 0:
|
||||
@@ -1014,18 +1014,18 @@ async def start_instance(
|
||||
container_id = get_container_id(instance.name)
|
||||
if container_id:
|
||||
instance.container_id = container_id
|
||||
logger.info("Container ID for instance %s: %s", instance.id, container_id)
|
||||
logger.debug("Container ID for instance %s: %s", instance.id, container_id)
|
||||
|
||||
container_name = get_container_name(instance.name)
|
||||
if container_name:
|
||||
instance.container_name = container_name
|
||||
logger.info("Container name for instance %s: %s", instance.id, container_name)
|
||||
logger.debug("Container name for instance %s: %s", instance.id, container_name)
|
||||
|
||||
# Connect container to backend network so API can reach it
|
||||
logger.info("Connecting container %s to backend network...", container_name)
|
||||
logger.debug("Connecting container %s to backend network...", container_name)
|
||||
connected = connect_container_to_network(container_name, "backend")
|
||||
if connected:
|
||||
logger.info("Successfully connected %s to backend network", container_name)
|
||||
logger.debug("Successfully connected %s to backend network", container_name)
|
||||
else:
|
||||
logger.warning("Failed to connect %s to backend network", container_name)
|
||||
|
||||
@@ -1034,7 +1034,7 @@ async def start_instance(
|
||||
instance.status = "starting"
|
||||
instance.last_started_at = datetime.now()
|
||||
await session.commit()
|
||||
logger.info("Instance %s: verifying container startup...", instance.id)
|
||||
logger.debug("Instance %s: verifying container startup...", instance.id)
|
||||
|
||||
startup_result = wait_for_container_running(instance.container_id, timeout=30, interval=2.0)
|
||||
|
||||
@@ -1062,7 +1062,7 @@ async def start_instance(
|
||||
"logs": logs,
|
||||
}
|
||||
|
||||
logger.info(
|
||||
logger.debug(
|
||||
"Instance %s container started successfully after %.1fs",
|
||||
instance.id,
|
||||
startup_result["waited_seconds"],
|
||||
@@ -1090,7 +1090,7 @@ async def start_instance(
|
||||
if probe_command:
|
||||
instance.status = "probing"
|
||||
await session.commit()
|
||||
logger.info(
|
||||
logger.debug(
|
||||
"Executing readiness probe for instance %s: command='%s', timeout=%d, interval=%d",
|
||||
instance.id, probe_command, probe_timeout, probe_interval
|
||||
)
|
||||
@@ -1143,14 +1143,14 @@ async def start_instance(
|
||||
}
|
||||
|
||||
instance_port = tool_type.default_port or 0
|
||||
logger.info("Tool type for instance %s: name=%s, default_port=%s, interface_type=%s",
|
||||
logger.debug("Tool type for instance %s: name=%s, default_port=%s, interface_type=%s",
|
||||
instance.id, tool_type.name, instance_port, tool_type.interface_type)
|
||||
|
||||
# Only create Cloudflare tunnel for web-enabled tools
|
||||
if tool_type.interface_type == "web":
|
||||
# Create temporary Cloudflare tunnel for public access
|
||||
try:
|
||||
logger.info("Creating temporary tunnel for instance %s (container=%s, port=%d)",
|
||||
logger.debug("Creating temporary tunnel for instance %s (container=%s, port=%d)",
|
||||
instance.id, instance.container_name, instance_port)
|
||||
tunnel_info = start_cloudflared_tunnel(
|
||||
container_name=instance.container_name or instance.name,
|
||||
@@ -1160,7 +1160,7 @@ async def start_instance(
|
||||
instance.public_url = tunnel_info["url"]
|
||||
instance.url = tunnel_info["url"]
|
||||
await session.commit()
|
||||
logger.info(
|
||||
logger.debug(
|
||||
"Created temporary tunnel for instance %s: pid=%s, url=%s",
|
||||
instance.id,
|
||||
tunnel_info["pid"],
|
||||
@@ -1230,7 +1230,7 @@ async def stop_instance(
|
||||
if instance.tunnel_id:
|
||||
try:
|
||||
stop_cloudflared_tunnel(instance.tunnel_id)
|
||||
logger.info("Stopped tunnel for instance %s (pid=%s)", instance.id, instance.tunnel_id)
|
||||
logger.debug("Stopped tunnel for instance %s (pid=%s)", instance.id, instance.tunnel_id)
|
||||
except Exception as exc:
|
||||
logger.warning("Failed to stop tunnel for instance %s: %s", instance.id, exc)
|
||||
|
||||
@@ -1284,7 +1284,7 @@ async def restart_instance(
|
||||
if instance.tunnel_id:
|
||||
try:
|
||||
stop_cloudflared_tunnel(instance.tunnel_id)
|
||||
logger.info("Stopped old tunnel for instance %s (pid=%s)", instance.id, instance.tunnel_id)
|
||||
logger.debug("Stopped old tunnel for instance %s (pid=%s)", instance.id, instance.tunnel_id)
|
||||
except Exception as exc:
|
||||
logger.warning("Failed to stop old tunnel for instance %s: %s", instance.id, exc)
|
||||
|
||||
@@ -1300,7 +1300,7 @@ async def restart_instance(
|
||||
# Write env file with resolved profile env vars
|
||||
if profile_env:
|
||||
write_env_file(instance_dir, profile_env)
|
||||
logger.info(
|
||||
logger.debug(
|
||||
"Re-applied config profile %s on restart for instance %s",
|
||||
resolved.profile_name,
|
||||
instance.id,
|
||||
@@ -1345,7 +1345,7 @@ async def restart_instance(
|
||||
instance.tunnel_id = tunnel_info["pid"]
|
||||
instance.public_url = tunnel_info["url"]
|
||||
instance.url = tunnel_info["url"]
|
||||
logger.info(
|
||||
logger.debug(
|
||||
"Created new tunnel for instance %s: %s",
|
||||
instance.id,
|
||||
tunnel_info["url"],
|
||||
@@ -1431,7 +1431,7 @@ async def delete_instance(
|
||||
if instance.tunnel_id:
|
||||
try:
|
||||
stop_cloudflared_tunnel(instance.tunnel_id)
|
||||
logger.info("Stopped tunnel for instance %s (pid=%s)", instance.id, instance.tunnel_id)
|
||||
logger.debug("Stopped tunnel for instance %s (pid=%s)", instance.id, instance.tunnel_id)
|
||||
except Exception as exc:
|
||||
logger.warning("Failed to stop tunnel for instance %s: %s", instance.id, exc)
|
||||
|
||||
@@ -1556,7 +1556,7 @@ async def recreate_tunnel_endpoint(
|
||||
instance.public_url = tunnel_info["url"]
|
||||
instance.url = tunnel_info["url"]
|
||||
await session.commit()
|
||||
logger.info(
|
||||
logger.debug(
|
||||
"Recreated tunnel for instance %s: pid=%s, url=%s",
|
||||
instance.id,
|
||||
tunnel_info["pid"],
|
||||
|
||||
@@ -103,11 +103,11 @@ async def update_user_config(
|
||||
|
||||
# Merge updates
|
||||
update_data = data.model_dump(exclude_unset=True)
|
||||
logger.info("Updating user config for user %s: %s", user_id, update_data)
|
||||
logger.debug("Updating user config for user %s: %s", user_id, update_data)
|
||||
# SQLAlchemy JSON doesn't track dict mutations, so we replace the whole dict
|
||||
config.config = {**config.config, **update_data}
|
||||
|
||||
await session.commit()
|
||||
await session.refresh(config)
|
||||
logger.info("Updated config: %s", config.config)
|
||||
logger.debug("Updated config: %s", config.config)
|
||||
return UserConfigResponse.model_validate(config.config)
|
||||
|
||||
@@ -42,7 +42,7 @@ def clone_repository(
|
||||
str(clone_path),
|
||||
]
|
||||
|
||||
logger.info("Cloning repository %s (branch: %s) into %s", remote_url, branch, clone_path)
|
||||
logger.debug("Cloning repository %s (branch: %s) into %s", remote_url, branch, clone_path)
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
@@ -55,7 +55,7 @@ def clone_repository(
|
||||
logger.error("Git clone failed: %s", result.stderr)
|
||||
raise RuntimeError(f"Failed to clone repository: {result.stderr}")
|
||||
|
||||
logger.info("Successfully cloned repository into %s", clone_path)
|
||||
logger.debug("Successfully cloned repository into %s", clone_path)
|
||||
return str(clone_path)
|
||||
|
||||
|
||||
@@ -94,4 +94,4 @@ def remove_clone_directory(instance_dir: str) -> None:
|
||||
if clone_path.exists():
|
||||
import shutil
|
||||
shutil.rmtree(clone_path)
|
||||
logger.info("Removed clone directory: %s", clone_path)
|
||||
logger.debug("Removed clone directory: %s", clone_path)
|
||||
|
||||
@@ -24,7 +24,7 @@ def build_image(instance_dir: str, dockerfile: str, tag: str, build_context: dic
|
||||
# Write Dockerfile
|
||||
dockerfile_path = Path(instance_dir) / "Dockerfile"
|
||||
dockerfile_path.write_text(dockerfile)
|
||||
logger.info("Wrote Dockerfile to %s", dockerfile_path)
|
||||
logger.debug("Wrote Dockerfile to %s", dockerfile_path)
|
||||
|
||||
# Write build context files
|
||||
if build_context:
|
||||
@@ -39,10 +39,10 @@ def build_image(instance_dir: str, dockerfile: str, tag: str, build_context: dic
|
||||
|
||||
full_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
full_path.write_text(content)
|
||||
logger.info("Wrote build context file: %s", full_path)
|
||||
logger.debug("Wrote build context file: %s", full_path)
|
||||
|
||||
# Build image
|
||||
logger.info("Building Docker image with tag: %s", tag)
|
||||
logger.debug("Building Docker image with tag: %s", tag)
|
||||
cmd = [
|
||||
"docker", "build",
|
||||
"-t", tag,
|
||||
@@ -57,7 +57,7 @@ def build_image(instance_dir: str, dockerfile: str, tag: str, build_context: dic
|
||||
text=True,
|
||||
timeout=300, # 5 minute timeout for builds
|
||||
)
|
||||
logger.info("Docker build completed: returncode=%d", result.returncode)
|
||||
logger.debug("Docker build completed: returncode=%d", result.returncode)
|
||||
if result.returncode != 0:
|
||||
logger.error("Docker build failed: %s", result.stderr[:1000])
|
||||
return result.returncode, result.stdout, result.stderr
|
||||
|
||||
@@ -72,11 +72,11 @@ class TerminalManager:
|
||||
|
||||
# Check if session is still alive
|
||||
if session.is_alive():
|
||||
logger.info("Reattaching to existing terminal session for instance %s", instance_id)
|
||||
logger.debug("Reattaching to existing terminal session for instance %s", instance_id)
|
||||
return session
|
||||
else:
|
||||
# Session died, clean it up
|
||||
logger.info("Existing session for instance %s is dead, cleaning up", instance_id)
|
||||
logger.debug("Existing session for instance %s is dead, cleaning up", instance_id)
|
||||
await session.close()
|
||||
del self._sessions[instance_id_str]
|
||||
|
||||
@@ -97,7 +97,7 @@ class TerminalManager:
|
||||
"""Attach a WebSocket to an existing session."""
|
||||
# Handle concurrent connections - close existing ones
|
||||
if session.has_websockets():
|
||||
logger.info("Closing existing WebSocket connections for instance %s", session.instance_id)
|
||||
logger.debug("Closing existing WebSocket connections for instance %s", session.instance_id)
|
||||
for ws in list(session._websockets):
|
||||
try:
|
||||
await ws.close(code=4000, reason="New connection established")
|
||||
@@ -135,7 +135,7 @@ class TerminalManager:
|
||||
|
||||
# Close existing session if any
|
||||
if instance_id_str in self._sessions:
|
||||
logger.info("Resetting terminal session for instance %s", instance_id)
|
||||
logger.debug("Resetting terminal session for instance %s", instance_id)
|
||||
old_session = self._sessions.pop(instance_id_str)
|
||||
await old_session.close()
|
||||
|
||||
|
||||
@@ -60,12 +60,12 @@ class TerminalSession:
|
||||
|
||||
# Set the terminal size initially
|
||||
self._set_terminal_size(self._cols, self._rows)
|
||||
logger.info(f"Starting terminal session {self.session_id} for container {self.container_id} with initial size {self._cols}x{self._rows}")
|
||||
logger.debug(f"Starting terminal session {self.session_id} for container {self.container_id} with initial size {self._cols}x{self._rows}")
|
||||
|
||||
# Build the shell command
|
||||
if startup_command:
|
||||
shell_cmd = f'bash -c "{startup_command}" || true; exec bash -il'
|
||||
logger.info(f"Using startup command for session {self.session_id}: {startup_command}")
|
||||
logger.debug(f"Using startup command for session {self.session_id}: {startup_command}")
|
||||
else:
|
||||
shell_cmd = "bash -il"
|
||||
|
||||
@@ -102,7 +102,7 @@ class TerminalSession:
|
||||
size = struct.pack('HHHH', rows, cols, 0, 0)
|
||||
try:
|
||||
fcntl.ioctl(self._master_fd, TIOCSWINSZ, size)
|
||||
logger.info(f"Resized PTY to {cols}x{rows} (fd={self._master_fd})")
|
||||
logger.debug(f"Resized PTY to {cols}x{rows} (fd={self._master_fd})")
|
||||
except (OSError, IOError) as e:
|
||||
logger.error(f"Failed to resize PTY: {e}")
|
||||
|
||||
@@ -159,7 +159,7 @@ class TerminalSession:
|
||||
|
||||
self._cols = cols
|
||||
self._rows = rows
|
||||
logger.info(f"resize() called for session {self.session_id}: {cols}x{rows}")
|
||||
logger.debug(f"resize() called for session {self.session_id}: {cols}x{rows}")
|
||||
self._set_terminal_size(cols, rows)
|
||||
|
||||
# Docker exec -it creates its own PTY inside the container,
|
||||
|
||||
Reference in New Issue
Block a user