11import json
22import time
3- from datetime import datetime
3+ from datetime import datetime , timedelta
44
55from roboflow .adapters import deploymentapi
66from roboflow .config import load_roboflow_api_key
@@ -19,6 +19,7 @@ def add_deployment_parser(subparsers):
1919 )
2020 deployment_list_parser = deployment_subparsers .add_parser ("list" , help = "list dedicated deployments in a workspace" )
2121 deployment_delete_parser = deployment_subparsers .add_parser ("delete" , help = "delete a dedicated deployment" )
22+ deployment_log_parser = deployment_subparsers .add_parser ("log" , help = "show log info for a dedicated deployment" )
2223
2324 deployment_machine_type_parser .set_defaults (func = list_machine_types )
2425 deployment_machine_type_parser .add_argument ("-a" , "--api_key" , help = "api key" )
@@ -69,24 +70,35 @@ def add_deployment_parser(subparsers):
6970 deployment_delete_parser .add_argument ("-a" , "--api_key" , help = "api key" )
7071 deployment_delete_parser .add_argument ("deployment_name" , help = "deployment name" )
7172
73+ deployment_log_parser .set_defaults (func = get_deployment_log )
74+ deployment_log_parser .add_argument ("-a" , "--api_key" , help = "api key" )
75+ deployment_log_parser .add_argument ("deployment_name" , help = "deployment name" )
76+ deployment_log_parser .add_argument (
77+ "-d" , "--duration" , help = "duration of log (from now) in seconds" , type = int , default = 3600
78+ )
79+ deployment_log_parser .add_argument (
80+ "-n" , "--tail" , help = "number of lines to show from the end of the logs (<= 50)" , type = int , default = 10
81+ )
82+ deployment_log_parser .add_argument ("-f" , "--follow" , help = "follow log output" , action = "store_true" )
83+
7284
7385def list_machine_types (args ):
7486 api_key = args .api_key or load_roboflow_api_key (None )
7587 if api_key is None :
7688 print ("Please provide an api key" )
77- return
89+ exit ( 1 )
7890 status_code , msg = deploymentapi .list_machine_types (api_key )
7991 if status_code != 200 :
8092 print (f"{ status_code } : { msg } " )
81- return
93+ exit ( status_code )
8294 print (json .dumps (msg , indent = 2 ))
8395
8496
8597def add_deployment (args ):
8698 api_key = args .api_key or load_roboflow_api_key (None )
8799 if api_key is None :
88100 print ("Please provide an api key" )
89- return
101+ exit ( 1 )
90102 status_code , msg = deploymentapi .add_deployment (
91103 api_key ,
92104 # args.security_level,
@@ -99,7 +111,7 @@ def add_deployment(args):
99111
100112 if status_code != 200 :
101113 print (f"{ status_code } : { msg } " )
102- return
114+ exit ( status_code )
103115 else :
104116 print (f"Deployment { args .deployment_name } created successfully" )
105117 print (json .dumps (msg , indent = 2 ))
@@ -112,12 +124,12 @@ def get_deployment(args):
112124 api_key = args .api_key or load_roboflow_api_key (None )
113125 if api_key is None :
114126 print ("Please provide an api key" )
115- return
127+ exit ( 1 )
116128 while True :
117129 status_code , msg = deploymentapi .get_deployment (api_key , args .deployment_name )
118130 if status_code != 200 :
119131 print (f"{ status_code } : { msg } " )
120- return
132+ exit ( status_code )
121133
122134 if (not args .wait_on_pending ) or msg ["status" ] != "pending" :
123135 print (json .dumps (msg , indent = 2 ))
@@ -131,21 +143,57 @@ def list_deployment(args):
131143 api_key = args .api_key or load_roboflow_api_key (None )
132144 if api_key is None :
133145 print ("Please provide an api key" )
134- return
146+ exit ( 1 )
135147 status_code , msg = deploymentapi .list_deployment (api_key )
136148 if status_code != 200 :
137149 print (f"{ status_code } : { msg } " )
138- return
150+ exit ( status_code )
139151 print (json .dumps (msg , indent = 2 ))
140152
141153
142154def delete_deployment (args ):
143155 api_key = args .api_key or load_roboflow_api_key (None )
144156 if api_key is None :
145157 print ("Please provide an api key" )
146- return
158+ exit ( 1 )
147159 status_code , msg = deploymentapi .delete_deployment (api_key , args .deployment_name )
148160 if status_code != 200 :
149161 print (f"{ status_code } : { msg } " )
150- return
162+ exit ( status_code )
151163 print (json .dumps (msg , indent = 2 ))
164+
165+
166+ def get_deployment_log (args ):
167+ api_key = args .api_key or load_roboflow_api_key (None )
168+ if api_key is None :
169+ print ("Please provide an api key" )
170+ exit (1 )
171+
172+ to_timestamp = datetime .now ()
173+ from_timestamp = to_timestamp - timedelta (seconds = args .duration )
174+ last_log_timestamp = from_timestamp
175+ log_ids = set () # to avoid duplicate logs
176+ max_entries = args .tail
177+ while True :
178+ status_code , msg = deploymentapi .get_deployment_log (
179+ api_key , args .deployment_name , from_timestamp , to_timestamp , max_entries
180+ )
181+ if status_code != 200 :
182+ print (f"{ status_code } : { msg } " )
183+ exit (status_code )
184+
185+ for log in msg [::- 1 ]: # logs are sorted by reversed timestamp
186+ log_timestamp = datetime .fromisoformat (log ["timestamp" ]).replace (tzinfo = None )
187+ if (log ["insert_id" ] in log_ids ) or (log_timestamp < last_log_timestamp ):
188+ continue
189+ log_ids .add (log ["insert_id" ])
190+ last_log_timestamp = log_timestamp
191+ print (f'[{ log_timestamp .strftime ("%Y-%m-%d %H:%M:%S.%f" )} ] { log ["payload" ]} ' )
192+
193+ if not args .follow :
194+ break
195+
196+ time .sleep (10 )
197+ from_timestamp = last_log_timestamp
198+ to_timestamp = datetime .now ()
199+ max_entries = 300 # only set max_entries for the first request
0 commit comments