Skip to content
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

Enhancement - Improve playground error message and introduce new CLI command for cloudwatch logs #984

Closed
wants to merge 32 commits into from
Closed
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
d4e75d8
Update - improve playground error message
aybruhm Dec 1, 2023
33f2493
Refactor - clean up view navigation component
aybruhm Dec 1, 2023
ab99363
format fix
bekossy Dec 1, 2023
0f45864
Merge branch 'main' into gh/issue-885-resolve
bekossy Dec 5, 2023
3820110
Update - improve playground error message
aybruhm Dec 1, 2023
9537585
Feat - created cli app_logs command module
aybruhm Dec 6, 2023
319848e
Update - register app_logs command to cli
aybruhm Dec 6, 2023
956f208
Feat - created retrieve_app_logs cli client
aybruhm Dec 6, 2023
2ba848e
Update - created get_app_logs router skeleton
aybruhm Dec 6, 2023
f204f46
Cleanup - arrange imports
aybruhm Dec 7, 2023
339a233
Refactor - renamed app_logs to variant_logs
aybruhm Dec 7, 2023
5fe61c7
Refactor - renamed retrieve_app_logs to retrieve_variant_logs
aybruhm Dec 7, 2023
0e71231
Feat - implemented retrieve variant logs api router
aybruhm Dec 7, 2023
877be34
Feat - implemented retrieve cloudwatch logs function
aybruhm Dec 7, 2023
253029a
:art: Format - ran black and format-fix
aybruhm Dec 7, 2023
19e4862
Update - modified retrieve_cloudwatch_logs function
aybruhm Dec 8, 2023
ad0f1b5
Update - created get_deployment_by_appId db function
aybruhm Dec 8, 2023
86ba72b
Update - modified get_variant_logs_stream function
aybruhm Dec 8, 2023
73ebda9
Update - add different error messages based on feature-flag
aybruhm Dec 8, 2023
cd64de6
:art: Format - ran prettier --write .
aybruhm Dec 8, 2023
6556116
Update - created isCloud and isEnterprise utils function
aybruhm Dec 8, 2023
2558688
Update - include region_name to logs_manager boto client
aybruhm Dec 8, 2023
385d2e6
Update - modified error message for cloud users
aybruhm Dec 8, 2023
84ffae0
Update - include return type to get_app_variant_instance_by_id db fun…
aybruhm Dec 8, 2023
365f1ce
Refactor & Cleanup - modified process (cli->client->backend) to retri…
aybruhm Dec 8, 2023
58005a4
Refactor - move logs_manager to cloud/services/ and sync changes
aybruhm Dec 8, 2023
c19bcb7
Update - clean up retrieve_variant_logs api router
aybruhm Dec 11, 2023
0ab8b58
:art: Format - ran black
aybruhm Dec 11, 2023
a0ac49e
Update - modified retrieve_variant_logs api router
aybruhm Dec 11, 2023
7d58ab4
Update - refactor messages in click.style(...)
aybruhm Dec 11, 2023
f97c368
Refactor - renamed func to get_variant_logs
aybruhm Dec 11, 2023
195e26c
Cleanup - remove console log
aybruhm Dec 12, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions agenta-backend/agenta_backend/routers/app_router.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import os
import logging
from docker.errors import DockerException
from fastapi.responses import JSONResponse
from agenta_backend.config import settings
from typing import List, Optional

from fastapi.responses import JSONResponse
from fastapi import APIRouter, HTTPException, Request

from agenta_backend.config import settings
from agenta_backend.services.selectors import get_user_own_org
from agenta_backend.services import (
app_manager,
Expand All @@ -26,6 +27,9 @@
)
from agenta_backend.models import converters

from docker.errors import DockerException


if os.environ["FEATURE_FLAG"] in ["cloud", "ee"]:
from agenta_backend.commons.services.selectors import (
get_user_and_org_id,
Expand Down
34 changes: 27 additions & 7 deletions agenta-backend/agenta_backend/routers/variants_router.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import os
import logging
from docker.errors import DockerException
from fastapi.responses import JSONResponse
from typing import Any, Optional, Union

from fastapi.responses import JSONResponse
from fastapi import APIRouter, HTTPException, Request, Body
from agenta_backend.services import (
app_manager,
db_manager,
)

from agenta_backend.services import app_manager, db_manager
from agenta_backend.utils.common import (
check_access_to_variant,
)
from agenta_backend.models import converters

from agenta_backend.models.api.api_models import (
Image,
URI,
Expand All @@ -24,10 +21,14 @@
VariantActionEnum,
)

from docker.errors import DockerException


if os.environ["FEATURE_FLAG"] in ["cloud", "ee"]:
from agenta_backend.commons.services.selectors import (
get_user_and_org_id,
) # noqa pylint: disable-all
from agenta_backend.cloud.services import logs_manager
else:
from agenta_backend.services.selectors import get_user_and_org_id

Expand Down Expand Up @@ -275,3 +276,22 @@ async def start_variant(
app_variant_db, envvars, **user_org_data
)
return url


@router.get("/{variant_id}/logs/")
async def retrieve_variant_logs(variant_id: str, request: Request):
app_variant = await db_manager.get_app_variant_instance_by_id(variant_id)
deployment = await db_manager.get_deployment_by_appId(str(app_variant.app.id))
if os.environ["FEATURE_FLAG"] == "cloud":
try:
logs_result = logs_manager.retrieve_cloudwatch_logs(
aybruhm marked this conversation as resolved.
Show resolved Hide resolved
deployment.container_name
)
except Exception as exc:
raise HTTPException(500, {"message": str(exc)})
return logs_result

if os.environ["FEATURE_FLAG"] == "ee":
...

aybruhm marked this conversation as resolved.
Show resolved Hide resolved
return "Please specify the required agenta version for retrieving the logs."
19 changes: 18 additions & 1 deletion agenta-backend/agenta_backend/services/db_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,23 @@ async def get_deployment_by_objectid(
return deployment


async def get_deployment_by_appId(app_id: str) -> DeploymentDB:
"""Get the deployment object from the database with the provided app id.

Args:
app_id (str): The app ID

Returns:
DeploymentDB: instance of deployment object
"""

deployment = await engine.find_one(
DeploymentDB, DeploymentDB.app == ObjectId(app_id)
)
logger.debug(f"deployment: {deployment}")
return deployment


async def get_organization_object(organization_id: str) -> OrganizationDB:
"""
Fetches an organization by its ID.
Expand Down Expand Up @@ -1213,7 +1230,7 @@ async def get_app_variant_by_app_name_and_environment(
return app_variant_db


async def get_app_variant_instance_by_id(variant_id: str):
async def get_app_variant_instance_by_id(variant_id: str) -> AppVariantDB:
"""Get the app variant object from the database with the provided id.

Arguments:
Expand Down
2 changes: 2 additions & 0 deletions agenta-cli/agenta/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from agenta.cli import helper
from agenta.client import client
from agenta.cli import variant_logs
from agenta.cli import variant_configs
from agenta.cli import variant_commands

Expand Down Expand Up @@ -192,6 +193,7 @@ def init(app_name: str):

# Add the commands to the CLI group
cli.add_command(init)
cli.add_command(variant_logs.get)
cli.add_command(variant_configs.config)
cli.add_command(variant_commands.variant)

Expand Down
116 changes: 116 additions & 0 deletions agenta-cli/agenta/cli/variant_logs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import toml
import click
from pathlib import Path
from agenta.client import client
from agenta.cli.variant_commands import get_host


@click.group()
def get():
"""Commands for variant logs"""
pass


def config_check(app_folder: str):
"""Check the config file and update it from the backend

Arguments:
app_folder -- the app folder
"""

click.echo(click.style("\nChecking config file...", fg="yellow"))
app_folder = Path(app_folder)
config_file = app_folder / "config.toml"
if not config_file.exists():
click.echo(
click.style(
f"Config file not found in {app_folder}. Make sure you are in the right folder and that you have run agenta init first.",
fg="red",
)
)
return
return


def get_api_key(app_folder: str) -> str:
"""Retrieve app api key.

Args:
app_folder (str): The current folder of the app

Returns:
str: the api key
"""

app_path = Path(app_folder)
config_file = app_path / "config.toml"
config = toml.load(config_file)
api_key = config.get("api_key", None)
return api_key


@get.command(
name="logs",
context_settings=dict(
ignore_unknown_options=True,
allow_extra_args=True,
),
)
@click.option("--variant", help="The ID of the variant.")
@click.option("--app_folder", default=".")
@click.pass_context
def get_variant_logs_stream(ctx, variant: str, app_folder: str):
aybruhm marked this conversation as resolved.
Show resolved Hide resolved
"""Fetch the logs stream and events for a given lambda app function"""

try:
if not variant and len(ctx.args) > 0:
variant = ctx.args[0]

config_check(app_folder)
click.echo(
click.style(
"Retrieving variant logs stream from cloudwatch...", fg="yellow"
aybruhm marked this conversation as resolved.
Show resolved Hide resolved
)
)
api_key = get_api_key(app_folder)
if not api_key:
click.echo(click.style(f"API Key is not specified\n", fg="red"))
return

backend_host = get_host(app_folder)
api_valid = client.validate_api_key(api_key=api_key, host=backend_host)
if api_valid:
logs_messages = client.retrieve_variant_logs(
variant_id=variant, api_key=api_key, host=backend_host
)
click.echo(
click.style(
f"Successfully retrieved logs stream for variant {variant}! 🎉",
aybruhm marked this conversation as resolved.
Show resolved Hide resolved
fg="green",
)
)
click.echo(
click.style(
"\n====================\nLOGS OUTPUT: \n===================="
)
)
if isinstance(logs_messages, list):
for item in logs_messages:
click.echo(click.style(f"- {item.strip()}"))
else:
click.echo(click.style(f"- {logs_messages}"))
return
else:
click.echo(
click.style(
"API Key is invalid. Please, update config.toml with the correct key.",
fg="red",
)
)
except Exception as ex:
click.echo(
click.style(
f"Error fetching logs streams for variant {variant}: {ex}\n",
fg="red",
)
)
25 changes: 25 additions & 0 deletions agenta-cli/agenta/client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -524,3 +524,28 @@ def retrieve_user_id(host: str, api_key: Optional[str] = None) -> str:
return response.json()["id"]
except RequestException as e:
raise APIRequestError(f"Request failed: {str(e)}")


def retrieve_variant_logs(variant_id: str, api_key: Optional[str], host: str):
"""Retrieve variant logs from the server.

Args:
app_name (str): The required app name
host (str): The URL of the Agenta backend
api_key (str): The API key to validate with
"""

try:
response = requests.get(
f"{host}/{BACKEND_URL_SUFFIX}/variants/{variant_id}/logs/",
headers={"Authorization": api_key},
timeout=600,
)
if response.status_code != 200:
error_message = response.json().get("detail", "Unknown error")
raise APIRequestError(
f"Request to retrieve_variant_logs endpoint failed with status code {response.status_code}. Error message: {error_message}"
)
return response.json()
except RequestException as e:
raise APIRequestError(f"Request failed: {str(e)}")
58 changes: 45 additions & 13 deletions agenta-web/src/components/Playground/ViewNavigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ import {useState} from "react"
import axios from "axios"
import {createUseStyles} from "react-jss"
import {
getProfile,
getAppContainerURL,
removeVariant,
restartAppVariantContainer,
waitForAppToStart,
} from "@/lib/services/api"
import {useAppsData} from "@/contexts/app.context"
import {isDemo} from "@/lib/helpers/utils"
import {isDemo, isCloud, isEnterprise} from "@/lib/helpers/utils"

interface Props {
variant: Variant
Expand Down Expand Up @@ -111,14 +112,16 @@ const ViewNavigation: React.FC<Props> = ({

if (isError) {
let variantDesignator = variant.templateVariantName
let imageName = `agentaai/${(currentApp?.app_name || "").toLowerCase()}_`
let appName = currentApp?.app_name || ""
let imageName = `agentaai/${appName.toLowerCase()}_`

if (!variantDesignator || variantDesignator === "") {
variantDesignator = variant.variantName
imageName += variantDesignator.toLowerCase()
} else {
imageName += variantDesignator.toLowerCase()
}
console.log("Variant: ", variant)
aybruhm marked this conversation as resolved.
Show resolved Hide resolved
aybruhm marked this conversation as resolved.
Show resolved Hide resolved

const variantContainerPath = async () => {
const url = await getAppContainerURL(appId, variant.variantId, variant.baseId)
Expand Down Expand Up @@ -154,6 +157,7 @@ const ViewNavigation: React.FC<Props> = ({
}

const apiAddress = `${containerURI}/openapi.json`
const containerName = `${appName}-${variant.baseName}-${containerURI.split("/")[3]}` // [3] is the user organization id
return (
<div>
{error ? (
Expand All @@ -170,18 +174,46 @@ const ViewNavigation: React.FC<Props> = ({
Verify whether the API is up by checking if {apiAddress} is
accessible.
</li>
<li>
Check if the Docker container for the variant {variantDesignator} is
running. The image should be called {imageName}.
</li>
{isCloud() && (
<div>
<li>
Check if the lambda function for the variant{" "}
{variantDesignator} is active by running the following
command in your terminal:
<pre>
agenta get logs --variant {variant.variantId}
</pre> or <pre>agenta get logs {variant.variantId}</pre>
Running the above command will enable you to view the lambda
function latest logs stream events.
</li>
</div>
)}
{isEnterprise() && (
<div>
<li></li>
</div>
)}
{!isCloud() && (
<div>
<li>
Check if the Docker container for the variant{" "}
{variantDesignator} is active by running the following
command in your terminal:
<pre>docker logs {containerName} --tail 50 -f</pre>
Running the above command will enable you to continuously
stream the container logs in real-time as they are
generated.
</li>
<p>
{" "}
In case the docker container is not running, please check
the Docker logs to understand the issue. Most of the time,
it is due to missing requirements. Also, please attempt
restarting it (using cli or docker desktop).
</p>
</div>
)}
</ul>
<p>
{" "}
In case the docker container is not running. Please check the logs from
docker to understand the issue. Most of the time it is a missing
requirements. Also, please attempt restarting it (using cli or docker
desktop)
</p>
<p>
{" "}
If the issue persists please file an issue in github here:
Expand Down
Loading
Loading