-
Notifications
You must be signed in to change notification settings - Fork 4.6k
feat(cli): add langgraph deploy logs subcommand #7100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Andrew Nguonly (andrewnguonly)
merged 17 commits into
main
from
vishnu/cli-logs-command
Mar 12, 2026
+365
−11
Merged
Changes from 15 commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
c2e2494
feat(cli): add API_KEY_ENV_NAMES to constants
vishnu-ssuresh 26d5d9f
feat(cli): add log-fetching methods to HostBackendClient
vishnu-ssuresh 98b744b
feat(cli): add helpers module for log formatting and resolution
vishnu-ssuresh c0d852f
feat(cli): add langgraph logs command
vishnu-ssuresh 762fc92
test(cli): add tests for log-fetching and log helpers
vishnu-ssuresh fac2558
style(cli): fix formatting and import sorting
vishnu-ssuresh 5ffbb00
feat(cli): implement default command handling in CLI and add deploy g…
vishnu-ssuresh b6ddae0
Merge remote-tracking branch 'origin/main' into vishnu/cli-logs-command
vishnu-ssuresh 41c21af
feat(cli): add host API key and URL options, enhance command help for…
vishnu-ssuresh 5e2b655
Merge branch 'main' into vishnu/cli-logs-command
hari-dhanushkodi 3ff8ed7
remove langsmith client
hari-dhanushkodi ca6d3e0
share deployment name
hari-dhanushkodi 7c10857
fix merge conflict
hari-dhanushkodi e0e999e
fix log order and remove langsmith client
hari-dhanushkodi e2b0d70
remove constant change
hari-dhanushkodi 010f00b
comments
hari-dhanushkodi 229fde9
fix lint
hari-dhanushkodi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| """Helpers for the ``langgraph logs`` CLI command.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from datetime import datetime, timezone | ||
|
|
||
| import click | ||
|
|
||
| from langgraph_cli.host_backend import HostBackendClient | ||
|
|
||
|
|
||
| def resolve_deployment_id( | ||
| client: HostBackendClient, | ||
| deployment_id: str | None, | ||
| name: str | None, | ||
| ) -> str: | ||
| """Resolve a deployment ID from --deployment-id or --name.""" | ||
| if deployment_id: | ||
| return deployment_id | ||
| if not name: | ||
| raise click.UsageError("Either --deployment-id or --name is required.") | ||
| existing = client.list_deployments(name_contains=name) | ||
| if isinstance(existing, dict): | ||
| for dep in existing.get("resources", []): | ||
| if isinstance(dep, dict) and dep.get("name") == name: | ||
| found_id = dep.get("id") | ||
| if found_id: | ||
| return str(found_id) | ||
| raise click.ClickException(f"Deployment '{name}' not found.") | ||
|
|
||
|
|
||
| def format_timestamp(ts) -> str: | ||
| """Convert a timestamp (epoch ms or string) to a readable string.""" | ||
| if isinstance(ts, (int, float)): | ||
| dt = datetime.fromtimestamp(ts / 1000, tz=timezone.utc) | ||
| return dt.strftime("%Y-%m-%d %H:%M:%S") | ||
| return str(ts) if ts else "" | ||
|
|
||
|
|
||
| def format_log_entry(entry: dict) -> str: | ||
| """Format a single log entry for display.""" | ||
| ts = format_timestamp(entry.get("timestamp", "")) | ||
| level = entry.get("level", "") | ||
| message = entry.get("message", "") | ||
| if ts and level: | ||
| return f"[{ts}] [{level}] {message}" | ||
| elif ts: | ||
| return f"[{ts}] {message}" | ||
| return message | ||
|
|
||
|
|
||
| def level_fg(level: str) -> str | None: | ||
| """Return click color for a log level.""" | ||
| level_upper = level.upper() if level else "" | ||
| if level_upper == "ERROR": | ||
| return "red" | ||
| if level_upper == "WARNING": | ||
| return "yellow" | ||
| return None |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,7 +19,12 @@ def __init__(self, message: str, status_code: int | None = None): | |
| class HostBackendClient: | ||
| """Minimal JSON HTTP client for the host backend deployment service.""" | ||
|
|
||
| def __init__(self, base_url: str, api_key: str, tenant_id: str | None = None): | ||
| def __init__( | ||
| self, | ||
| base_url: str, | ||
| api_key: str, | ||
| tenant_id: str | None = None, | ||
| ): | ||
| if not base_url: | ||
| raise click.UsageError("Host backend URL is required") | ||
| transport = httpx.HTTPTransport(retries=3) | ||
|
|
@@ -30,7 +35,6 @@ def __init__(self, base_url: str, api_key: str, tenant_id: str | None = None): | |
| if tenant_id: | ||
| headers["X-Tenant-ID"] = tenant_id | ||
| self._base_url = base_url.rstrip("/") | ||
| self._api_key = api_key | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this removed?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. its not used in any of the helper functions, we just use it to set the header |
||
| self._client = httpx.Client( | ||
| base_url=self._base_url, | ||
| headers=headers, | ||
|
|
@@ -116,3 +120,24 @@ def get_revision(self, deployment_id: str, revision_id: str) -> dict[str, Any]: | |
| "GET", | ||
| f"/v2/deployments/{deployment_id}/revisions/{revision_id}", | ||
| ) | ||
|
|
||
| def get_build_logs( | ||
| self, project_id: str, revision_id: str, payload: dict[str, Any] | ||
| ) -> Any: | ||
| return self._request( | ||
| "POST", | ||
| f"/v1/projects/{project_id}/revisions/{revision_id}/build_logs", | ||
hari-dhanushkodi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| payload, | ||
| ) | ||
|
|
||
| def get_deploy_logs( | ||
| self, | ||
| project_id: str, | ||
| payload: dict[str, Any], | ||
| revision_id: str | None = None, | ||
| ) -> Any: | ||
| if revision_id: | ||
| path = f"/v1/projects/{project_id}/revisions/{revision_id}/deploy_logs" | ||
| else: | ||
| path = f"/v1/projects/{project_id}/deploy_logs" | ||
| return self._request("POST", path, payload) | ||
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
Oops, something went wrong.
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.