{
"tool_response": {
"type": "text",
"file": {
"filePath": "\/var\/www\/tools\/ki-protokoll\/claude-hook\/log_to_db.py",
"content": "#!\/usr\/bin\/env python3\n\"\"\"\nClaude Code Hook Logger v3 - Modularisiert\nOrchestriert Parsing, Formatting und Storage von Hook-Events\n\"\"\"\n\nimport json\nimport sys\nfrom typing import Dict, Any, Optional\n\n# Importiere modularisierte Komponenten\nfrom log_parser import (\n parse_event_data,\n sanitize_data,\n get_conversation_pairs_from_session\n)\nfrom log_formatter import (\n format_request_to_json,\n format_response_to_json,\n create_response_data,\n calculate_tokens,\n get_client_metadata,\n get_model_name,\n format_tool_response,\n should_suppress_output\n)\nfrom log_storage import (\n find_matching_request,\n save_pending_request,\n insert_log_entry,\n update_request_with_response,\n close_pending_user_prompts\n)\n\n\ndef log_to_database(data: Dict[str, Any]) -> Optional[int]:\n \"\"\"\n Hauptfunktion: Orchestriert das Logging eines Events\n\n Args:\n data: Event-Daten vom Hook\n\n Returns:\n Database ID des Log-Eintrags oder None bei Fehler\n \"\"\"\n try:\n event_name = data.get('hook_event_name', 'Unknown')\n session_id = data.get('session_id', '')\n\n # Prüfe auf matching Request für Response-Events (PostToolUse)\n if event_name == 'PostToolUse':\n matching_request_id = find_matching_request(data)\n if matching_request_id:\n # Update existing request mit response\n tool_response = sanitize_data(data.get('tool_response', {}))\n response_str = format_tool_response(tool_response)\n tokens = calculate_tokens('', response_str)\n\n update_request_with_response(\n matching_request_id,\n response_str,\n tokens['tokens_output']\n )\n return matching_request_id\n\n # Bei Stop-Events: Schließe alle pending UserPrompts\n if event_name in ['Stop', 'SubagentStop'] and session_id:\n pairs = get_conversation_pairs_from_session(session_id)\n close_pending_user_prompts(session_id, pairs)\n\n # Parse Event-Daten\n request_data = parse_event_data(data)\n\n # Erstelle Response-Daten (falls direkt verfügbar)\n response_data = create_response_data(event_name, data)\n\n # Formatiere zu JSON\n request_str = format_request_to_json(request_data)\n response_str = format_response_to_json(response_data)\n\n # Berechne Tokens\n tokens = calculate_tokens(request_str, response_str)\n\n # Hole Client-Metadaten\n client_meta = get_client_metadata()\n model_name = get_model_name()\n\n # Insert in DB\n db_id = insert_log_entry(\n request_str=request_str,\n client_ip=client_meta['client_ip'],\n client_name=client_meta['client_name'],\n response_str=response_str,\n tokens_input=tokens['tokens_input'],\n tokens_output=tokens['tokens_output'],\n model_name=model_name\n )\n\n # Speichere pending Requests für spätere Response-Zuordnung\n if db_id and not response_str:\n save_pending_request(data, db_id)\n\n return db_id\n\n except Exception as e:\n print(f\"Database logging error: {e}\", file=sys.stderr)\n return None\n\n\ndef main():\n \"\"\"Hauptfunktion des Hook-Skripts\"\"\"\n try:\n input_data = json.load(sys.stdin)\n log_to_database(input_data)\n\n event_name = input_data.get('hook_event_name', '')\n if should_suppress_output(event_name):\n print(json.dumps({\"suppressOutput\": True}))\n\n sys.exit(0)\n\n except json.JSONDecodeError as e:\n print(f\"Invalid JSON input: {e}\", file=sys.stderr)\n sys.exit(0)\n\n except Exception as e:\n print(f\"Hook execution error: {e}\", file=sys.stderr)\n sys.exit(0)\n\n\nif __name__ == '__main__':\n main()",
"numLines": 132,
"startLine": 1,
"totalLines": 132
}
}
}