Allow filtering of logs #127

Merged
hjacobs merged 3 commits from filter-logs into master 1 year ago
  1. 24
      kube_web/templates/resource-logs.html
  2. 17
      kube_web/web.py
  3. 12
      tests/e2e/test_view.py

24
kube_web/templates/resource-logs.html

@ -32,26 +32,32 @@
{% else: %}
<div class="section">
Showing last {{ tail_lines }} log lines {% if all_containers|length > 2: %} of {{container_name}} container {% else: %} per container {% endif %}for {{ pods|length }} pods.
</div>
<form method="get" action="#">
<div class="section">
Get last <input class="input" style="width:7rem;vertical-align:baseline" type="number" min="1" name="tail_lines" value="{{ tail_lines }}"> log lines {% if all_containers|length > 2: %} of {{container_name}} container {% else: %} per container {% endif %}for {{ pods|length }} pods
and filter by
<input class="input" style="width:10rem;vertical-align:baseline" name="filter" value="{{ filter_text or "" }}" placeholder="filter text">
<button type="submit" class="button is-primary">Refresh</button>
</div>
</form>
{% if all_container_names|length > 2: %}
<div class="tabs is-small">
<ul>
{% for container_tab in all_container_names|sort: %}
{% if container_tab == container_name: %}
<li class="is-active"><a>{{ container_tab or "all" }}</a></li>
{% else: %}
<li ><a href="/clusters/{{ cluster }}/namespaces/{{ resource.metadata.namespace }}/{{ resource.endpoint }}/{{ resource.name }}/logs?container={{ container_tab }}">{{ container_tab or "all" }}</a></li>
{% endif %}
{% if container_tab == container_name: %}
<li class="is-active"><a>{{ container_tab or "all" }}</a></li>
{% else: %}
<li ><a href="/clusters/{{ cluster }}/namespaces/{{ resource.metadata.namespace }}/{{ resource.endpoint }}/{{ resource.name }}/logs?{{ {"container": container_tab, "tail_lines": tail_lines, "filter": filter_text or ""}|urlencode }}">{{ container_tab or "all" }}</a></li>
{% endif %}
{% endfor %}
</ul>
</div>
{% endif %}
<pre>
{% for log in logs: %}<span style="color:{{ log[2] }}">{{ log[1] }}</span> <span class="has-text-grey">{{ log[3] }}</span> {{ log[0] }}{{ '\n' }}{% endfor %}
{% for log in logs: %}<span style="color:{{ log[2] }}">{{ log[1] }}</span> {% if not container_name: %}<span class="has-text-grey">{{ log[3] }}</span> {% endif %}{{ log[0] }}{{ '\n' }}{% endfor %}
{% if filter_text and not logs: %}<em>No matching logs found. Please note that the filter text is case sensitive!</em>{% endif %}
</pre>
{% endif %}

17
kube_web/web.py

@ -912,7 +912,11 @@ def pod_color(name: Optional[str]) -> str:
async def get_log_from_container(
color: str, pod: Pod, container_name: str, tail_lines: int
color: str,
pod: Pod,
container_name: str,
tail_lines: int,
filter_text: Optional[str],
):
"""Return array of logs of single container."""
@ -921,6 +925,9 @@ async def get_log_from_container(
pod, container=container_name, timestamps=True, tail_lines=tail_lines,
)
for line in container_log.split("\n"):
# note that the filter is case-sensitive!
if filter_text and filter_text not in line:
continue
# this is a hacky way to determine whether it's a multi-line log message
# (our current year of the timestamp starts with "20"..)
if line.startswith("20") or not logs:
@ -946,6 +953,7 @@ async def get_resource_logs(request, session):
name = request.match_info["name"]
container_name = request.query.get("container") or ALL_CONTAINER_LOGS
tail_lines = int(request.rel_url.query.get("tail_lines") or 200)
filter_text = request.query.get("filter")
clazz = await cluster.resource_registry.get_class_by_plural_name(
plural, namespaced=True
)
@ -981,7 +989,9 @@ async def get_resource_logs(request, session):
color = pod_color(pod.name)
if container_name != ALL_CONTAINER_LOGS:
logs.extend(
await get_log_from_container(color, pod, container_name, tail_lines)
await get_log_from_container(
color, pod, container_name, tail_lines, filter_text
)
)
else:
# show logs for all containers
@ -993,7 +1003,7 @@ async def get_resource_logs(request, session):
for container in containers:
logs.extend(
await get_log_from_container(
color, pod, container["name"], tail_lines
color, pod, container["name"], tail_lines, filter_text
)
)
@ -1005,6 +1015,7 @@ async def get_resource_logs(request, session):
"plural": plural,
"resource": resource,
"tail_lines": tail_lines,
"filter_text": filter_text,
"pods": pods,
"logs": logs,
"show_container_logs": show_container_logs,

12
tests/e2e/test_view.py

@ -85,7 +85,17 @@ def test_logs_from_single_container(session):
)
response.raise_for_status()
main = response.html.find("main pre", first=True)
print(main.text)
assert "MESSAGE FROM INIT CONTAINER!" not in main.text
assert "MESSAGE FROM SECOND INIT CONTAINER!" in main.text
def test_logs_filter(session):
response = session.get(
"/clusters/local/namespaces/deployment-with-init-container/deployments/deployment-with-init-container/logs",
params={"filter": "SECOND"},
)
response.raise_for_status()
main = response.html.find("main pre", first=True)
assert "MESSAGE FROM INIT CONTAINER!" not in main.text
assert "MESSAGE FROM SECOND INIT CONTAINER!" in main.text

Loading…
Cancel
Save