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

Add log support for dedicated deployment #335

Merged
merged 8 commits into from
Oct 30, 2024
14 changes: 14 additions & 0 deletions roboflow/adapters/deploymentapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,17 @@ def list_machine_types(api_key):
if response.status_code != 200:
return response.status_code, response.text
return response.status_code, response.json()


def get_deployment_log(api_key, deployment_name, from_timestamp=None, to_timestamp=None, max_entries=-1):
url = f"{DEDICATED_DEPLOYMENT_URL}/get_log?api_key={api_key}&deployment_name={deployment_name}"
if from_timestamp is not None:
url += f"&from_timestamp={from_timestamp.isoformat()}"
if to_timestamp is not None:
url += f"&to_timestamp={to_timestamp.isoformat()}"
if max_entries > 0:
url += f"&max_entries={max_entries}"
response = requests.get(url)
if response.status_code != 200:
return response.status_code, response.text
return response.status_code, response.json()
70 changes: 59 additions & 11 deletions roboflow/deployment.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import json
import time
from datetime import datetime
from datetime import datetime, timedelta

from roboflow.adapters import deploymentapi
from roboflow.config import load_roboflow_api_key
Expand All @@ -19,6 +19,7 @@ def add_deployment_parser(subparsers):
)
deployment_list_parser = deployment_subparsers.add_parser("list", help="list dedicated deployments in a workspace")
deployment_delete_parser = deployment_subparsers.add_parser("delete", help="delete a dedicated deployment")
deployment_log_parser = deployment_subparsers.add_parser("log", help="show log info for a dedicated deployment")

deployment_machine_type_parser.set_defaults(func=list_machine_types)
deployment_machine_type_parser.add_argument("-a", "--api_key", help="api key")
Expand Down Expand Up @@ -69,24 +70,35 @@ def add_deployment_parser(subparsers):
deployment_delete_parser.add_argument("-a", "--api_key", help="api key")
deployment_delete_parser.add_argument("deployment_name", help="deployment name")

deployment_log_parser.set_defaults(func=get_deployment_log)
deployment_log_parser.add_argument("-a", "--api_key", help="api key")
deployment_log_parser.add_argument("deployment_name", help="deployment name")
deployment_log_parser.add_argument(
"-d", "--duration", help="duration of log (from now) in seconds", type=int, default=3600
)
deployment_log_parser.add_argument(
"-n", "--tail", help="number of lines to show from the end of the logs (<= 50)", type=int, default=10
)
deployment_log_parser.add_argument("-f", "--follow", help="follow log output", action="store_true")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth having a flag to show the last n lines of the log?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea! Added



def list_machine_types(args):
api_key = args.api_key or load_roboflow_api_key(None)
if api_key is None:
print("Please provide an api key")
return
exit(1)
status_code, msg = deploymentapi.list_machine_types(api_key)
if status_code != 200:
print(f"{status_code}: {msg}")
return
exit(status_code)
print(json.dumps(msg, indent=2))


def add_deployment(args):
api_key = args.api_key or load_roboflow_api_key(None)
if api_key is None:
print("Please provide an api key")
return
exit(1)
status_code, msg = deploymentapi.add_deployment(
api_key,
# args.security_level,
Expand All @@ -99,7 +111,7 @@ def add_deployment(args):

if status_code != 200:
print(f"{status_code}: {msg}")
return
exit(status_code)
else:
print(f"Deployment {args.deployment_name} created successfully")
print(json.dumps(msg, indent=2))
Expand All @@ -112,12 +124,12 @@ def get_deployment(args):
api_key = args.api_key or load_roboflow_api_key(None)
if api_key is None:
print("Please provide an api key")
return
exit(1)
while True:
status_code, msg = deploymentapi.get_deployment(api_key, args.deployment_name)
if status_code != 200:
print(f"{status_code}: {msg}")
return
exit(status_code)

if (not args.wait_on_pending) or msg["status"] != "pending":
print(json.dumps(msg, indent=2))
Expand All @@ -131,21 +143,57 @@ def list_deployment(args):
api_key = args.api_key or load_roboflow_api_key(None)
if api_key is None:
print("Please provide an api key")
return
exit(1)
status_code, msg = deploymentapi.list_deployment(api_key)
if status_code != 200:
print(f"{status_code}: {msg}")
return
exit(status_code)
print(json.dumps(msg, indent=2))


def delete_deployment(args):
api_key = args.api_key or load_roboflow_api_key(None)
if api_key is None:
print("Please provide an api key")
return
exit(1)
status_code, msg = deploymentapi.delete_deployment(api_key, args.deployment_name)
if status_code != 200:
print(f"{status_code}: {msg}")
return
exit(status_code)
print(json.dumps(msg, indent=2))


def get_deployment_log(args):
api_key = args.api_key or load_roboflow_api_key(None)
if api_key is None:
print("Please provide an api key")
exit(1)

to_timestamp = datetime.now()
from_timestamp = to_timestamp - timedelta(seconds=args.duration)
last_log_timestamp = from_timestamp
log_ids = set() # to avoid duplicate logs
max_entries = args.tail
while True:
status_code, msg = deploymentapi.get_deployment_log(
api_key, args.deployment_name, from_timestamp, to_timestamp, max_entries
)
if status_code != 200:
print(f"{status_code}: {msg}")
exit(status_code)

for log in msg[::-1]: # logs are sorted by reversed timestamp
log_timestamp = datetime.fromisoformat(log["timestamp"]).replace(tzinfo=None)
if (log["insert_id"] in log_ids) or (log_timestamp < last_log_timestamp):
continue
log_ids.add(log["insert_id"])
last_log_timestamp = log_timestamp
print(f'[{log_timestamp.strftime("%Y-%m-%d %H:%M:%S.%f")}] {log["payload"]}')

if not args.follow:
break

time.sleep(10)
from_timestamp = last_log_timestamp
to_timestamp = datetime.now()
max_entries = 300 # only set max_entries for the first request