Last active
April 2, 2020 09:12
-
-
Save wojas/9628e56045ca31cee1c6ce4467aede73 to your computer and use it in GitHub Desktop.
Tool to quickly select and view Kubernetes container logs using fzf (screenshot below in comments)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
""" | |
kubelog is a tool that lists all pods and their contains using fzf | |
and prints the logs for the selected one. | |
Options to get fzf: | |
- https://github.com/junegunn/fzf | |
- brew install fzf | |
""" | |
import os | |
import sys | |
import json | |
import argparse | |
import shlex | |
import shutil | |
from subprocess import Popen, PIPE, STDOUT | |
parser = argparse.ArgumentParser(usage=__doc__) | |
parser.add_argument("--list", "-l", action="store_true", help="List and exit") | |
parser.add_argument("--namespace", "-n", help="Specific namespace") | |
parser.add_argument("--preview", help=argparse.SUPPRESS) | |
def run(): | |
# Unknown args are passed to kubectl logs | |
opt, other = parser.parse_known_args() | |
width, height = shutil.get_terminal_size() | |
preview_height = height // 2 | |
# Hidden preview option, called by fzf | |
if opt.preview: | |
namespace, name, container, *rest = opt.preview.split() | |
os.execlp("kubectl", "kubectl", "logs", "-n", namespace, name, | |
"-c", container, "--tail={}".format(preview_height)) | |
return # never reached | |
# Get JSON with all pod info | |
# FIXME: use subprocess, UNSAFE | |
if opt.namespace: | |
qn = shlex.quote(opt.namespace) | |
get_cmd = "kubectl get -n {} pod -o json".format(qn) | |
else: | |
get_cmd = "kubectl get --all-namespaces pod -o json" | |
pods_data = os.popen(get_cmd, "r").read() | |
pods = json.loads(pods_data) | |
# Find all container info | |
containers = [] | |
def add_container(namespace, name, container, st): | |
state = list(st.keys())[0] | |
started = st[state].get('startedAt') | |
containers.append("{:20s} {:60s} {:30s} ({} {})".format( | |
namespace, name, container, state, started)) | |
for pod in pods['items']: | |
m = pod['metadata'] | |
for ck in ('containerStatuses', 'initContainerStatuses'): | |
for c in pod.get('status', {}).get(ck, []): | |
add_container(m['namespace'], m['name'], c['name'], c['state']) | |
containers.sort() | |
# For --list, list containers and exit (same if output is not a tty) | |
if opt.list or not sys.stdout.isatty(): | |
for line in containers: | |
print(line) | |
return | |
# Show fzf to select a container, calling self for --preview | |
# This keeps a '{}' placeholder for fzf | |
preview_cmd = "{} --preview={{}}".format(shlex.quote(sys.argv[0])) | |
fzf_cmd = [ | |
'fzf', | |
"--preview=" + preview_cmd, | |
'--preview-window=up:{}'.format(preview_height), | |
] | |
p = Popen(fzf_cmd, stdin=PIPE, stdout=PIPE) | |
stdin_bytes = '\n'.join(containers).encode('ascii') | |
selection = p.communicate(input=stdin_bytes)[0].decode('ascii') | |
if not selection: | |
print("No container selected") | |
sys.exit(1) | |
# Show logs for selected container | |
namespace, name, container, *rest = selection.split() | |
cmd = ["kubectl", "logs", "-n", namespace, name, "-c", container, *other] | |
print("=" * width) | |
cmd_str = ' '.join( shlex.quote(x) for x in cmd ) | |
print("=== {}".format(cmd_str)) | |
print("=" * width) | |
os.execlp(cmd[0], *cmd) | |
if __name__ == '__main__': | |
run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Don't forget to make it executable (
chmod a+x kubelog
), or the preview function won't work.