Skip to content

Commit

Permalink
feat(app): return logs from all containers (#887)
Browse files Browse the repository at this point in the history
Co-authored-by: Ralf Grubenmann <ralf.grubenmann@sdsc.ethz.ch>
  • Loading branch information
olevski and Panaetius authored Mar 14, 2022
1 parent a8636e3 commit 3defae5
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 31 deletions.
42 changes: 28 additions & 14 deletions renku_notebooks/api/classes/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import gitlab
from itertools import chain
from kubernetes import client
from kubernetes.client.rest import ApiException
from kubernetes.client.exceptions import ApiException
from kubernetes.client.models import V1DeleteOptions
import base64
import json
Expand Down Expand Up @@ -475,24 +475,38 @@ def stop(self, forced=False):
else:
return status

def get_logs(self, max_log_lines=0, container_name="jupyter-server"):
"""Get the logs of the k8s pod that runs the user server."""
def get_logs(self, max_log_lines=0):
"""Get the logs of all containers in the server pod."""
js = self.js
if js is None:
return None
output = {}
pod_name = js["status"]["mainPod"]["name"]
if max_log_lines == 0:
logs = self._k8s_client.read_namespaced_pod_log(
pod_name, self._k8s_namespace, container=container_name
)
all_containers = js["status"]["mainPod"]["status"].get(
"containerStatuses", []
) + js["status"]["mainPod"]["status"].get("initContainerStatuses", [])
for container in all_containers:
container_name = container["name"]
try:
logs = self._k8s_client.read_namespaced_pod_log(
pod_name,
self._k8s_namespace,
container=container_name,
tail_lines=max_log_lines if max_log_lines > 0 else None,
timestamps=True,
)
except ApiException as err:
if err.status in [400, 404]:
continue # container does not exist or is not ready yet
else:
raise
else:
output[container_name] = logs

if len(output.keys()) == 0:
return None
else:
logs = self._k8s_client.read_namespaced_pod_log(
pod_name,
self._k8s_namespace,
tail_lines=max_log_lines,
container=container_name,
)
return logs
return output

@property
def server_url(self):
Expand Down
8 changes: 1 addition & 7 deletions renku_notebooks/api/notebooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,9 +350,6 @@ def server_logs(user, server_name):
content:
application/json:
schema: ServerLogs
example:
- Line 1 of logs
- Line 2 of logs
404:
description: The specified server does not exist.
tags:
Expand All @@ -363,10 +360,7 @@ def server_logs(user, server_name):
max_lines = request.args.get("max_lines", default=250, type=int)
logs = server.get_logs(max_lines)
if logs is not None:
return (
ServerLogs().dumps({"items": str.splitlines(logs)}),
200,
)
return ServerLogs().dump(logs)
return make_response(jsonify({"messages": {"error": "Cannot find server"}}), 404)


Expand Down
19 changes: 9 additions & 10 deletions renku_notebooks/api/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -647,18 +647,17 @@ class ServerOptionsUI(Schema):
# cloudstorage = fields.Nested(CloudStorageServerOption(), required=True)


class ServerLogs(Schema):
"""
The list of k8s logs (one log line per list element)
for the pod that runs the jupyter server.
"""
_ServerLogs = Schema.from_dict({"jupyter-server": fields.String(required=False)})

items = fields.List(fields.Str())

@post_dump
@post_load
def remove_item_key(self, data, **kwargs):
return data.get("items", [])
class ServerLogs(_ServerLogs):
class Meta:
unknown = INCLUDE # only affects loading, not dumping

@post_dump(pass_original=True)
def keep_unknowns(self, output, orig, **kwargs):
output = {**orig, **output}
return output


def _in_range(value, value_range):
Expand Down

0 comments on commit 3defae5

Please sign in to comment.