Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion kernel_ai/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
},
)
Expand Down
26 changes: 24 additions & 2 deletions kernel_ai/http/common.py
Original file line number Diff line number Diff line change
@@ -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):
Expand All @@ -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
21 changes: 20 additions & 1 deletion kernel_ai/services/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__)
Expand Down Expand Up @@ -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()


Expand Down Expand Up @@ -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()
Expand Down
52 changes: 47 additions & 5 deletions kernel_ai/services/processes_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

import psutil

from kernel_ai.logging_helpers import log_event

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -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

Expand All @@ -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


Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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():
Expand Down Expand Up @@ -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": [],
Expand Down
Empty file modified static/js/kernel-dna.js
100644 → 100755
Empty file.
Loading