Skip to content

Commit 43d044b

Browse files
scripts: add set log level script
1 parent a109ad6 commit 43d044b

File tree

1 file changed

+158
-0
lines changed

1 file changed

+158
-0
lines changed

scripts/set_log_level.py

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import argparse
2+
import subprocess
3+
import sys
4+
import time
5+
from typing import List
6+
7+
import requests
8+
import signal
9+
import socket
10+
11+
12+
def parse_args(args: List[str]) -> argparse.Namespace:
13+
parser = argparse.ArgumentParser(
14+
description="Set the log level for a module or crate",
15+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
16+
)
17+
18+
# Add port-forwarding arguments
19+
add_port_forward_args(parser)
20+
21+
parser.add_argument(
22+
"--target",
23+
type=str,
24+
help="Crate or module name whose log level should be inspected or updated",
25+
)
26+
parser.add_argument("--log_level", type=str, help="The log level to set for the crate")
27+
parser.add_argument(
28+
"--method",
29+
type=str,
30+
choices=["get", "post"],
31+
default="post",
32+
help="HTTP method to use: 'get' to read current log level, 'post' to set a log level",
33+
)
34+
return parser.parse_args(args)
35+
36+
37+
def add_port_forward_args(parser: argparse.ArgumentParser) -> None:
38+
"""Add port-forwarding related CLI options to the parser."""
39+
40+
pf_group = parser.add_argument_group("port-forwarding options")
41+
42+
pf_group.add_argument(
43+
"--pod_name",
44+
type=str,
45+
default="",
46+
help="Pod to port-forward to; omit when no port forwarding is needed",
47+
)
48+
49+
pf_group.add_argument(
50+
"--local_port",
51+
type=int,
52+
default=8082,
53+
help="Local port to bind the port-forward to",
54+
)
55+
56+
pf_group.add_argument(
57+
"--monitoring_port",
58+
type=int,
59+
default=8082,
60+
help="Monitoring endpoint port",
61+
)
62+
63+
64+
def port_forward(
65+
pod_name: str,
66+
local_port: int,
67+
remote_port: int,
68+
max_attempts: int = 5,
69+
) -> subprocess.Popen:
70+
"""Start a kubectl port-forward and wait until it is ready.
71+
72+
Returns the Popen handle so the caller can terminate it later.
73+
Raises RuntimeError if the local port is still unreachable after
74+
`max_attempts` connection checks.
75+
"""
76+
77+
cmd = ["kubectl", "port-forward", pod_name, f"{local_port}:{remote_port}"]
78+
print("Starting port-forward:", " ".join(cmd))
79+
proc = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
80+
81+
for _attempt in range(1, max_attempts + 1):
82+
try:
83+
with socket.create_connection(("localhost", local_port), timeout=1):
84+
print(
85+
f"✅ Port-forward to {pod_name}:{remote_port} is ready on localhost:{local_port}"
86+
)
87+
return proc
88+
except OSError:
89+
time.sleep(0.4)
90+
91+
proc.terminate()
92+
proc.wait(timeout=5)
93+
raise RuntimeError(
94+
f"❌ Port-forward to {pod_name}:{remote_port} failed after {max_attempts} attempts."
95+
)
96+
97+
98+
def main():
99+
args = parse_args(sys.argv[1:])
100+
101+
# If a pod name is supplied, establish a port-forward before making the request
102+
port_forward_proc = None
103+
104+
target_port = args.monitoring_port
105+
base_port = args.local_port if args.pod_name else target_port
106+
107+
if args.pod_name:
108+
try:
109+
port_forward_proc = port_forward(args.pod_name, args.local_port, args.monitoring_port)
110+
except RuntimeError as err:
111+
print(err)
112+
sys.exit(1)
113+
114+
try:
115+
if args.method == "get":
116+
full_url = f"http://localhost:{base_port}/monitoring/logLevel"
117+
print(f"Fetching current log level from {full_url}")
118+
response = requests.get(full_url, timeout=5)
119+
120+
if response.status_code != 200:
121+
print(f"Failed to fetch log level: {response.status_code} {response.text}")
122+
sys.exit(1)
123+
124+
print("Current log level response:\n", response.text)
125+
elif args.method == "post":
126+
# Validate required arguments
127+
if not args.target or not args.log_level:
128+
print("--target and --log_level are required when --method=post")
129+
sys.exit(1)
130+
131+
base_url = f"http://localhost:{base_port}/monitoring/setLogLevel"
132+
full_url = f"{base_url}/{args.target}/{args.log_level}"
133+
134+
print(f"Setting log level for {args.target} to {args.log_level} at {full_url}")
135+
136+
response = requests.post(full_url, timeout=5)
137+
138+
if response.status_code != 200:
139+
print(
140+
f"❌ Failed to set log level for {args.target} to {args.log_level}: {response.text}"
141+
)
142+
sys.exit(1)
143+
144+
print(f"✅ Successfully set log level for {args.target} to {args.log_level}")
145+
146+
finally:
147+
# Clean up the port-forward process if we started one
148+
if port_forward_proc:
149+
port_forward_proc.send_signal(signal.SIGINT)
150+
try:
151+
port_forward_proc.wait(timeout=5)
152+
except subprocess.TimeoutExpired:
153+
port_forward_proc.kill()
154+
port_forward_proc.wait()
155+
156+
157+
if __name__ == "__main__":
158+
main()

0 commit comments

Comments
 (0)