Skip to content
This repository was archived by the owner on Aug 11, 2020. It is now read-only.

Commit 2280201

Browse files
committed
feat: Logging for experiments.
1 parent 11a344e commit 2280201

File tree

4 files changed

+134
-9
lines changed

4 files changed

+134
-9
lines changed

paperspace/cli/experiments.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,3 +308,34 @@ def list_experiments(project_ids, api_key):
308308
def get_experiment_details(experiment_id, api_key):
309309
experiments_api = client.API(config.CONFIG_EXPERIMENTS_HOST, api_key=api_key)
310310
experiments_commands.get_experiment_details(experiment_id, api=experiments_api)
311+
312+
313+
@experiments.command("logs", help="List experiment logs")
314+
@click.option(
315+
"--experimentId",
316+
"experiment_id",
317+
required=True
318+
)
319+
@click.option(
320+
"--line",
321+
"line",
322+
required=False,
323+
default=0
324+
)
325+
@click.option(
326+
"--limit",
327+
"limit",
328+
required=False,
329+
default=10000
330+
)
331+
@click.option(
332+
"--follow",
333+
"follow",
334+
required=False,
335+
default=False
336+
)
337+
@api_key_option
338+
def list_logs(experiment_id, line, limit, follow, api_key=None):
339+
logs_api = client.API(config.CONFIG_LOG_HOST, api_key=api_key)
340+
command = experiments_commands.ExperimentLogsCommand(api=logs_api)
341+
command.execute(experiment_id, line, limit, follow)

paperspace/cli/jobs.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,17 +94,35 @@ def create_job(api_key, **kwargs):
9494
command.execute(kwargs)
9595

9696

97-
@jobs_group.command("log", help="List job logs")
97+
@jobs_group.command("logs", help="List job logs")
9898
@click.option(
9999
"--jobId",
100100
"job_id",
101101
required=True
102102
)
103+
@click.option(
104+
"--line",
105+
"line",
106+
required=False,
107+
default=0
108+
)
109+
@click.option(
110+
"--limit",
111+
"limit",
112+
required=False,
113+
default=10000
114+
)
115+
@click.option(
116+
"--follow",
117+
"follow",
118+
required=False,
119+
default=False
120+
)
103121
@api_key_option
104-
def list_logs(job_id, api_key=None):
122+
def list_logs(job_id, line, limit, follow, api_key=None):
105123
logs_api = client.API(config.CONFIG_LOG_HOST, api_key=api_key)
106124
command = jobs_commands.JobLogsCommand(api=logs_api)
107-
command.execute(job_id)
125+
command.execute(job_id, line, limit, follow)
108126

109127

110128
@jobs_group.group("artifacts", help="Manage jobs' artifacts", cls=ClickGroup)

paperspace/commands/experiments.py

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
import pydoc
2+
13
import terminaltables
4+
from click import style
25

36
from paperspace import logger, constants, client, config
47
from paperspace.logger import log_response
5-
from paperspace.workspace import S3WorkspaceHandler
68
from paperspace.commands import common
9+
from paperspace.utils import get_terminal_lines
10+
from paperspace.workspace import S3WorkspaceHandler
711

812
experiments_api = client.API(config.CONFIG_EXPERIMENTS_HOST, headers=client.default_headers)
913

@@ -168,3 +172,71 @@ def get_experiment_details(experiment_id, api=experiments_api):
168172
logger.error("Error parsing response data")
169173

170174
log_response(response, details, "Unknown error while retrieving details of the experiment")
175+
176+
177+
class ExperimentLogsCommand(common.CommandBase):
178+
last_line_number = 0
179+
base_url = "/jobs/logs?experimentId={}&line={}&limit={}"
180+
other_url = "/jobs/logs"
181+
182+
is_logs_complete = False
183+
184+
def execute(self, experiment_id, line, limit, follow):
185+
self.last_line_number = line
186+
table_title = "Experiment %s logs" % experiment_id
187+
table_data = [("LINE", "MESSAGE")]
188+
table = terminaltables.AsciiTable(table_data, title=table_title)
189+
190+
while not self.is_logs_complete:
191+
print ("follow " + str(follow))
192+
response = self._get_logs(experiment_id, self.last_line_number, limit)
193+
194+
print ("got data")
195+
try:
196+
data = response.json()
197+
if not response.ok:
198+
self.logger.log_error_response(data)
199+
return
200+
except (ValueError, KeyError) as e:
201+
if response.status_code == 204:
202+
continue
203+
self.logger.log("Error while parsing response data: {}".format(e))
204+
return
205+
else:
206+
print ("parsed data")
207+
self._log_logs_list(data, table, table_data)
208+
print ("logged data")
209+
210+
print ("follow " + follow)
211+
if not follow:
212+
self.is_logs_complete = True
213+
214+
def _get_logs(self, experiment_id, line, limit):
215+
url = self.base_url.format(experiment_id, line, limit)
216+
params = {
217+
'experimentId': experiment_id,
218+
'line': line,
219+
'limit': limit
220+
};
221+
return self.api.get(self.other_url, params=params)
222+
223+
def _log_logs_list(self, data, table, table_data):
224+
if not data:
225+
self.logger.log("No Logs found")
226+
else:
227+
table_str = self._make_table(data, table, table_data)
228+
if len(table_str.splitlines()) > get_terminal_lines():
229+
pydoc.pager(table_str)
230+
else:
231+
self.logger.log(table_str)
232+
233+
def _make_table(self, logs, table, table_data):
234+
if logs[-1].get("message") == "PSEOF":
235+
self.is_logs_complete = True
236+
else:
237+
self.last_line_number = logs[-1].get("line")
238+
239+
for log in logs:
240+
table_data.append((style(fg="blue", text=str(log.get("jobId"))), style(fg="red", text=str(log.get("line"))), log.get("message")))
241+
242+
return table.table

paperspace/commands/jobs.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,17 +72,18 @@ def _get_table_data(self, jobs):
7272

7373
class JobLogsCommand(common.CommandBase):
7474
last_line_number = 0
75-
base_url = "/jobs/logs?jobId={}&line={}"
75+
base_url = "/jobs/logs?jobId={}&line={}&limit={}"
7676

7777
is_logs_complete = False
7878

79-
def execute(self, job_id):
79+
def execute(self, job_id, line, limit, follow):
80+
self.last_line_number = line
8081
table_title = "Job %s logs" % job_id
8182
table_data = [("LINE", "MESSAGE")]
8283
table = terminaltables.AsciiTable(table_data, title=table_title)
8384

8485
while not self.is_logs_complete:
85-
response = self._get_logs(job_id)
86+
response = self._get_logs(job_id, self.last_line_number, limit)
8687

8788
try:
8889
data = response.json()
@@ -97,8 +98,11 @@ def execute(self, job_id):
9798
else:
9899
self._log_logs_list(data, table, table_data)
99100

100-
def _get_logs(self, job_id):
101-
url = self.base_url.format(job_id, self.last_line_number)
101+
if not follow:
102+
self.is_logs_complete = True
103+
104+
def _get_logs(self, job_id, line, limit):
105+
url = self.base_url.format(job_id, line, limit)
102106
return self.api.get(url)
103107

104108
def _log_logs_list(self, data, table, table_data):

0 commit comments

Comments
 (0)