From f7dec3b70c574c2e00ae681b6ac71fc6a47810a3 Mon Sep 17 00:00:00 2001 From: Aleksei Fedorov Date: Sun, 5 Apr 2026 14:58:11 +0000 Subject: [PATCH] logging --- kernel_ai/hooks.py | 13 ++++++- kernel_ai/http/common.py | 26 ++++++++++++- kernel_ai/services/network.py | 21 +++++++++- kernel_ai/services/processes_runtime.py | 52 ++++++++++++++++++++++--- static/js/kernel-dna.js | 0 5 files changed, 103 insertions(+), 9 deletions(-) mode change 100644 => 100755 static/js/kernel-dna.js diff --git a/kernel_ai/hooks.py b/kernel_ai/hooks.py index bb177d5..abe59dc 100644 --- a/kernel_ai/hooks.py +++ b/kernel_ai/hooks.py @@ -26,17 +26,28 @@ def add_headers(response): started_ns = getattr(g, "request_started_ns", None) duration_ns = (time.time_ns() - started_ns) if started_ns else None + source_ip = request.headers.get("X-Forwarded-For", request.remote_addr) + if source_ip and "," in source_ip: + source_ip = source_ip.split(",")[0].strip() _http_access_logger.info( "http_request", extra={ "event_data": { + "@timestamp": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()), + "event.category": "web", + "event.type": "access", "event.dataset": "kernel_ai.http", "request.id": request_id, + "source.ip": source_ip, "http.request.method": request.method, + "http.version": request.environ.get("SERVER_PROTOCOL", ""), + "host.name": request.host, "url.path": request.path, + "url.query": (request.query_string or b"").decode("utf-8", errors="ignore"), + "user_agent.original": request.headers.get("User-Agent"), "http.response.status_code": response.status_code, + "service.environment": current_app.config.get("ENV", "production"), "event.duration": duration_ns, - "network.client.ip": request.headers.get("X-Forwarded-For", request.remote_addr), } }, ) diff --git a/kernel_ai/http/common.py b/kernel_ai/http/common.py index d2ea212..ca526ae 100644 --- a/kernel_ai/http/common.py +++ b/kernel_ai/http/common.py @@ -1,6 +1,21 @@ """Common HTTP helpers.""" -from flask import jsonify +from flask import g, has_request_context, jsonify + + +def build_error_payload(message, code, details=None): + """Build a stable API error envelope.""" + payload = { + "error": str(message), + "code": str(code), + } + if has_request_context(): + request_id = getattr(g, "request_id", None) + if request_id: + payload["request_id"] = request_id + if details is not None: + payload["details"] = details + return payload def api_json(producer, error_status=500, error_extra=None, exception_statuses=None): @@ -9,12 +24,19 @@ def api_json(producer, error_status=500, error_extra=None, exception_statuses=No return jsonify(producer()) except Exception as e: status = error_status + error_code = "internal_error" if exception_statuses: for exc_type, exc_status in exception_statuses: if isinstance(e, exc_type): status = exc_status break - payload = {"error": str(e)} + if status == 400: + error_code = "bad_request" + elif status == 404: + error_code = "not_found" + elif status == 503: + error_code = "service_unavailable" + payload = build_error_payload(str(e), error_code) if error_extra: payload.update(error_extra) return jsonify(payload), status diff --git a/kernel_ai/services/network.py b/kernel_ai/services/network.py index 9d33c00..795d2b2 100644 --- a/kernel_ai/services/network.py +++ b/kernel_ai/services/network.py @@ -11,6 +11,7 @@ import psutil +from kernel_ai.logging_helpers import log_event from kernel_ai.services.infra_utils import resolve_binary logger = logging.getLogger(__name__) @@ -63,7 +64,16 @@ def hex_to_ip(hex_str): } ) return connections[:20] - except (OSError, ValueError, IndexError): + except (OSError, ValueError, IndexError) as exc: + log_event( + logger, + "DEBUG", + "Failed to parse /proc/net/tcp, using mock active connections", + event_dataset="kernel_ai.app", + component="services.network", + operation="get_active_connections", + event_data={"error": str(exc)}, + ) return get_mock_active_connections() @@ -396,6 +406,15 @@ def get_traceroute_info(remote_ip, max_hops=8, traceroute_cache=None, cache_ttl_ if target_ip.is_loopback or target_ip.is_unspecified: return {"remote_ip": remote_ip, "tool": None, "reached": False, "hop_count": 0, "hops": [], "note": "Local address, traceroute skipped"} except ValueError: + log_event( + logger, + "DEBUG", + "Invalid IP passed to traceroute info", + event_dataset="kernel_ai.app", + component="services.network", + operation="get_traceroute_info", + event_data={"remote_ip": remote_ip}, + ) raise ValueError("Invalid IP address") now = time.time() diff --git a/kernel_ai/services/processes_runtime.py b/kernel_ai/services/processes_runtime.py index 63ec4c7..d3deacf 100644 --- a/kernel_ai/services/processes_runtime.py +++ b/kernel_ai/services/processes_runtime.py @@ -12,6 +12,8 @@ import psutil +from kernel_ai.logging_helpers import log_event + logger = logging.getLogger(__name__) @@ -72,7 +74,15 @@ def get_processes_detailed_data() -> list[dict]: except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): continue except (OSError, ValueError, TypeError, KeyError) as exc: - logger.debug("Skipping process in detailed scan due to unexpected data: %s", exc) + log_event( + logger, + "DEBUG", + "Skipping process in detailed scan due to unexpected data", + event_dataset="kernel_ai.app", + component="services.processes_runtime", + operation="get_processes_detailed_data", + event_data={"error": str(exc)}, + ) continue return processes @@ -86,7 +96,15 @@ def _parse_meminfo_kb(): if len(parts) >= 2 and parts[1].isdigit(): out[parts[0].rstrip(":")] = int(parts[1]) except OSError as exc: - logger.debug("Failed to read /proc/meminfo: %s", exc) + log_event( + logger, + "DEBUG", + "Failed to read /proc/meminfo", + event_dataset="kernel_ai.app", + component="services.processes_runtime", + operation="_parse_meminfo_kb", + event_data={"error": str(exc)}, + ) return out @@ -286,7 +304,15 @@ def collect_processes_realtime(): } ) except (psutil.Error, OSError, ValueError, TypeError, KeyError) as exc: - logger.debug("Skipping process in realtime collection: %s", exc) + log_event( + logger, + "DEBUG", + "Skipping process in realtime collection", + event_dataset="kernel_ai.app", + component="services.processes_runtime", + operation="collect_processes_realtime", + event_data={"error": str(exc)}, + ) continue syscall_nodes.sort(key=lambda x: x.get("syscall_pressure", 0), reverse=True) syscall_nodes = syscall_nodes[:14] @@ -320,7 +346,15 @@ def collect_processes_realtime(): if status: bucket["states"][status] = bucket["states"].get(status, 0) + 1 except (psutil.Error, OSError) as exc: - logger.debug("Failed to sample net connections in processes realtime: %s", exc) + log_event( + logger, + "DEBUG", + "Failed to sample net connections in processes realtime", + event_dataset="kernel_ai.app", + component="services.processes_runtime", + operation="collect_processes_realtime", + event_data={"error": str(exc)}, + ) network_tracing = [] for _, row in network_nodes.items(): @@ -450,7 +484,15 @@ def _add_edge(src_pid, dst_pid, edge_type, weight): strip_rows, mem_summary = _build_memory_visual_rows(meminfo_kb, syscall_nodes, vm, swap) memory_visual = {"layout": "strips", "rows": strip_rows, "summary": mem_summary} except (psutil.Error, OSError, ValueError, TypeError) as exc: - logger.debug("Failed to build memory visual payload: %s", exc) + log_event( + logger, + "DEBUG", + "Failed to build memory visual payload", + event_dataset="kernel_ai.app", + component="services.processes_runtime", + operation="collect_processes_realtime", + event_data={"error": str(exc)}, + ) memory_visual = { "layout": "strips", "rows": [], diff --git a/static/js/kernel-dna.js b/static/js/kernel-dna.js old mode 100644 new mode 100755