add metrics example from grok
This commit is contained in:
parent
361857d362
commit
2b21d62682
114
src/metric_client.py
Normal file
114
src/metric_client.py
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Minimal metric client with custom binary protocol.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import socket
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
import threading
|
||||||
|
|
||||||
|
# Same constants as server
|
||||||
|
MSG_PING = 0x01
|
||||||
|
MSG_PONG = 0x02
|
||||||
|
MSG_METRIC_REQ = 0x03
|
||||||
|
MSG_METRIC_RESP = 0x04
|
||||||
|
MSG_ERROR = 0xFF
|
||||||
|
|
||||||
|
HEADER_FMT = "!BH"
|
||||||
|
HEADER_SIZE = struct.calcsize(HEADER_FMT)
|
||||||
|
|
||||||
|
|
||||||
|
def send_message(sock: socket.socket, msg_type: int, payload: bytes = b"") -> None:
|
||||||
|
header = struct.pack(HEADER_FMT, msg_type, len(payload))
|
||||||
|
sock.sendall(header + payload)
|
||||||
|
|
||||||
|
|
||||||
|
def recv_exact(sock: socket.socket, n: int) -> bytes:
|
||||||
|
buf = bytearray()
|
||||||
|
while len(buf) < n:
|
||||||
|
chunk = sock.recv(n - len(buf))
|
||||||
|
if not chunk:
|
||||||
|
return b""
|
||||||
|
buf.extend(chunk)
|
||||||
|
return bytes(buf)
|
||||||
|
|
||||||
|
|
||||||
|
def recv_message(sock: socket.socket) -> tuple[int, bytes]:
|
||||||
|
header = recv_exact(sock, HEADER_SIZE)
|
||||||
|
if not header:
|
||||||
|
raise ConnectionError("Server disconnected")
|
||||||
|
msg_type, length = struct.unpack(HEADER_FMT, header)
|
||||||
|
payload = recv_exact(sock, length) if length > 0 else b""
|
||||||
|
return msg_type, payload
|
||||||
|
|
||||||
|
|
||||||
|
def listener_thread(sock: socket.socket, running: threading.Event):
|
||||||
|
while running.is_set():
|
||||||
|
try:
|
||||||
|
msg_type, payload = recv_message(sock)
|
||||||
|
if msg_type == MSG_PONG:
|
||||||
|
print("\n [PONG] server alive")
|
||||||
|
elif msg_type == MSG_METRIC_RESP:
|
||||||
|
value = struct.unpack("!d", payload)[0]
|
||||||
|
print(f"\n [METRIC] {value:.2f}")
|
||||||
|
elif msg_type == MSG_ERROR:
|
||||||
|
print(f"\n [ERROR] {payload.decode('utf-8')}")
|
||||||
|
else:
|
||||||
|
print(f"\n [???] Unknown type 0x{msg_type:02X}")
|
||||||
|
print("> ", end="", flush=True)
|
||||||
|
except ConnectionError:
|
||||||
|
if running.is_set():
|
||||||
|
print("\nServer disconnected.")
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
def show_wire_comparison():
|
||||||
|
our_size = HEADER_SIZE + len(b"cpu")
|
||||||
|
http_req = b"GET /metrics/cpu HTTP/1.1\r\nHost: localhost:9999\r\nAccept: application/json\r\n\r\n"
|
||||||
|
print(f"\n--- Wire overhead comparison ---")
|
||||||
|
print(f"Our protocol (METRIC_REQ 'cpu'): {our_size} bytes")
|
||||||
|
print(f"Equivalent HTTP GET: {len(http_req)} bytes")
|
||||||
|
print(f"HTTP is ~{len(http_req) / our_size:.0f}x larger\n")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
host = sys.argv[1] if len(sys.argv) > 1 else "127.0.0.1"
|
||||||
|
port = int(sys.argv[2]) if len(sys.argv) > 2 else 9999
|
||||||
|
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
sock.connect((host, port))
|
||||||
|
print(f"Connected to {host}:{port}")
|
||||||
|
show_wire_comparison()
|
||||||
|
|
||||||
|
running = threading.Event()
|
||||||
|
running.set()
|
||||||
|
threading.Thread(target=listener_thread, args=(sock, running), daemon=True).start()
|
||||||
|
|
||||||
|
print("Commands: ping | get <metric> | quit")
|
||||||
|
print("Metrics: cpu, memory, disk, loadavg, uptime\n")
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
line = input("> ").strip()
|
||||||
|
if not line:
|
||||||
|
continue
|
||||||
|
parts = line.split()
|
||||||
|
cmd = parts[0].lower()
|
||||||
|
|
||||||
|
if cmd == "quit":
|
||||||
|
break
|
||||||
|
elif cmd == "ping":
|
||||||
|
send_message(sock, MSG_PING)
|
||||||
|
elif cmd == "get" and len(parts) == 2:
|
||||||
|
send_message(sock, MSG_METRIC_REQ, parts[1].encode("utf-8"))
|
||||||
|
else:
|
||||||
|
print(" Unknown command.")
|
||||||
|
finally:
|
||||||
|
running.clear()
|
||||||
|
sock.close()
|
||||||
|
print("Disconnected.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
116
src/metric_server.py
Normal file
116
src/metric_server.py
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Minimal metric server with custom binary protocol (cannibalised from Claude).
|
||||||
|
Demonstrates low-overhead sockets vs HTTP/REST.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import socket
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import threading
|
||||||
|
|
||||||
|
# Protocol constants (shared with client)
|
||||||
|
MSG_PING = 0x01
|
||||||
|
MSG_PONG = 0x02
|
||||||
|
MSG_METRIC_REQ = 0x03
|
||||||
|
MSG_METRIC_RESP = 0x04
|
||||||
|
MSG_ERROR = 0xFF
|
||||||
|
|
||||||
|
HEADER_FMT = "!BH" # 1 byte type + 2 bytes length (big-endian)
|
||||||
|
HEADER_SIZE = struct.calcsize(HEADER_FMT)
|
||||||
|
|
||||||
|
|
||||||
|
def get_metric(name: str) -> float:
|
||||||
|
metrics = {
|
||||||
|
"cpu": lambda: random.uniform(5.0, 95.0),
|
||||||
|
"memory": lambda: random.uniform(30.0, 80.0),
|
||||||
|
"disk": lambda: random.uniform(40.0, 90.0),
|
||||||
|
"loadavg": lambda: os.getloadavg()[0] if hasattr(os, "getloadavg") else random.uniform(0.5, 4.0),
|
||||||
|
"uptime": lambda: float(int(time.time()) % 100000),
|
||||||
|
}
|
||||||
|
fn = metrics.get(name)
|
||||||
|
if fn is None:
|
||||||
|
raise KeyError(f"Unknown metric: {name}")
|
||||||
|
return fn()
|
||||||
|
|
||||||
|
|
||||||
|
def send_message(sock: socket.socket, msg_type: int, payload: bytes = b"") -> None:
|
||||||
|
header = struct.pack(HEADER_FMT, msg_type, len(payload))
|
||||||
|
sock.sendall(header + payload)
|
||||||
|
|
||||||
|
|
||||||
|
def recv_exact(sock: socket.socket, n: int) -> bytes:
|
||||||
|
buf = bytearray()
|
||||||
|
while len(buf) < n:
|
||||||
|
chunk = sock.recv(n - len(buf))
|
||||||
|
if not chunk:
|
||||||
|
return b""
|
||||||
|
buf.extend(chunk)
|
||||||
|
return bytes(buf)
|
||||||
|
|
||||||
|
|
||||||
|
def recv_message(sock: socket.socket) -> tuple[int, bytes]:
|
||||||
|
header = recv_exact(sock, HEADER_SIZE)
|
||||||
|
if not header:
|
||||||
|
raise ConnectionError("Client disconnected")
|
||||||
|
msg_type, length = struct.unpack(HEADER_FMT, header)
|
||||||
|
payload = recv_exact(sock, length) if length > 0 else b""
|
||||||
|
return msg_type, payload
|
||||||
|
|
||||||
|
|
||||||
|
def handle_client(conn: socket.socket, addr: tuple) -> None:
|
||||||
|
print(f"[+] Connected: {addr[0]}:{addr[1]}")
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
msg_type, payload = recv_message(conn)
|
||||||
|
|
||||||
|
if msg_type == MSG_PING:
|
||||||
|
print(f" <- PING from {addr[0]}")
|
||||||
|
send_message(conn, MSG_PONG)
|
||||||
|
|
||||||
|
elif msg_type == MSG_METRIC_REQ:
|
||||||
|
name = payload.decode("utf-8")
|
||||||
|
print(f" <- METRIC_REQ: {name}")
|
||||||
|
try:
|
||||||
|
value = get_metric(name)
|
||||||
|
send_message(conn, MSG_METRIC_RESP, struct.pack("!d", value))
|
||||||
|
except KeyError as e:
|
||||||
|
send_message(conn, MSG_ERROR, str(e).encode("utf-8"))
|
||||||
|
|
||||||
|
else:
|
||||||
|
send_message(conn, MSG_ERROR, f"Unknown type 0x{msg_type:02X}".encode("utf-8"))
|
||||||
|
|
||||||
|
except ConnectionError:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
print(f"[-] Disconnected: {addr[0]}:{addr[1]}")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
host = sys.argv[1] if len(sys.argv) > 1 else "127.0.0.1"
|
||||||
|
port = int(sys.argv[2]) if len(sys.argv) > 2 else 9999
|
||||||
|
|
||||||
|
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
srv.bind((host, port))
|
||||||
|
srv.listen(5)
|
||||||
|
|
||||||
|
print(f"Metric server listening on {host}:{port}")
|
||||||
|
print("Available metrics: cpu, memory, disk, loadavg, uptime\n")
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
conn, addr = srv.accept()
|
||||||
|
threading.Thread(target=handle_client, args=(conn, addr), daemon=True).start()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\nShutting down.")
|
||||||
|
finally:
|
||||||
|
srv.close()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Loading…
Reference in New Issue
Block a user