Skip to content

Instantly share code, notes, and snippets.

@scramblr
Created February 20, 2026 22:09
Show Gist options
  • Select an option

  • Save scramblr/66fca5c0539f5eeac4f5cd345132d3bf to your computer and use it in GitHub Desktop.

Select an option

Save scramblr/66fca5c0539f5eeac4f5cd345132d3bf to your computer and use it in GitHub Desktop.
Android Studio Chat Log & Extension Log File Parser, Recovery, and Formatting
# This python script is designed to fix up and make all of the text inside of the "Chat" window in Android Studio human readable.
# If you're ever in a situation where you need to find your Android Studio Gemini Chat history, or Claude, or whatever extension's
# history that integrates with Android Studio's Chat function, this script will clean it up and usually make it 100x more readable.
#
# This script will produce two files when you run it:
# 1. <original_filename>.pretty.log — This will have the same log structure, all embedded JSON, but expanded & prettified.
# 2. <original_filename>.json — Reformats everything into a big JSON array. Each entry gets a timestamp, logger,
# method, level, message, and nested json_data (when a JSON blob was already present)
#
# Sample Usage:
# prompt> cd wherescriptshide
# prompt> python android-studio-chatlogfix.py "C:/Users/user/AppData/Local/Google/AndroidStudio2025.3.1/log/gemini-backend.log"
# Parsed 1227 entries.
# Pretty log: C:\Users\user\AppData\Local\Google\AndroidStudio2025.3.1\log\gemini-backend.pretty.log
# JSON: C:\Users\user\AppData\Local\Google\AndroidStudio2025.3.1\log\gemini-backend.json
#
# Android Studio Extensions Examples:
# *** Typical Windows Location: %USERPROFILE%\AppData\Local\Google\AndroidStudio2025.3.1\log\ ***
#
# JetBrains AI / Gemini / Studio Bot logs
# - gemini-backend.log
# - ai-agent.log
# - ai-conversation.log
# - gemini-client.log
# - assistant-events.log
# - chat-service.log
#
# Kotlin LLM Code Completion / Code Insight Logs:
# - ml-completion.log
# - suggestion.log
# - generation.log
#
# Google “Studio Bot”
# - .../log/google-assistant/
# - .../log/ml/
# - .../log/studio-bot/
#
#
# Even if you don't see it listed above, changes are if it's a .log file in the Android Studio log directory, this script will help.
# YMMV.
#
# Let me know if you have any issues and feel free to open Issues or just fix it and push/pull!
#
# Peace!
# -scramblr
#
# format_log.py
import re
import json
import sys
from pathlib import Path
def _find_json_blob(text: str):
"""Find the start and end index of the first top-level JSON object in text."""
start = text.find('{')
if start == -1:
return None
depth = 0
in_string = False
escape_next = False
for i in range(start, len(text)):
c = text[i]
if escape_next:
escape_next = False
continue
if c == '\\' and in_string:
escape_next = True
continue
if c == '"':
in_string = not in_string
continue
if in_string:
continue
if c == '{':
depth += 1
elif c == '}':
depth -= 1
if depth == 0:
return start, i + 1
return None
def prettify_json_in_text(text: str) -> str:
"""Find the first JSON object in text and replace it with pretty-printed version."""
span = _find_json_blob(text)
if span is None:
return text
start, end = span
raw = text[start:end]
try:
obj = json.loads(raw)
pretty = json.dumps(obj, indent=2)
return text[:start] + pretty + text[end:]
except json.JSONDecodeError:
return text
# Header: "Feb 18, 2026 6:21:11 PM com.example.MyClass myMethod"
_HEADER_RE = re.compile(
r'^(?P<timestamp>\w+ \d+, \d+ \d+:\d+:\d+ [AP]M)'
r'\s+(?P<logger>\S+)\s+(?P<method>\S+)\s*$',
re.MULTILINE
)
def parse_log_entries(text: str) -> list[dict]:
"""Parse a Java util.logging log into a list of entry dicts."""
matches = list(_HEADER_RE.finditer(text))
entries = []
for i, m in enumerate(matches):
header_end = m.end()
body_end = matches[i + 1].start() if i + 1 < len(matches) else len(text)
body = text[header_end:body_end].strip()
# Split level from message: body starts with "INFO: ..." or similar
level = "UNKNOWN"
message = body
level_match = re.match(r'^([A-Z]+):\s*(.*)', body, re.DOTALL)
if level_match:
level = level_match.group(1)
message = level_match.group(2).strip()
logger = m.group("logger") # keep full qualified name
entry = {
"timestamp": m.group("timestamp"),
"logger": logger,
"method": m.group("method"),
"level": level,
"message": message,
}
span = _find_json_blob(message)
if span is not None:
raw = message[span[0]:span[1]]
try:
entry["json_data"] = json.loads(raw)
except json.JSONDecodeError:
pass
entries.append(entry)
return entries
def format_pretty_log(entries: list[dict]) -> str:
"""Reconstruct the log as a human-readable string with JSON prettified."""
lines = []
for e in entries:
lines.append(f"{e['timestamp']} {e['logger']} {e['method']}")
pretty_msg = prettify_json_in_text(e["message"])
lines.append(f"{e['level']}: {pretty_msg}")
lines.append("") # blank line between entries
return "\n".join(lines)
def format_structured_json(entries: list[dict]) -> str:
"""Serialize log entries as a pretty-printed JSON array."""
return json.dumps(entries, indent=2, ensure_ascii=False)
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python format_log.py <log_file>")
sys.exit(1)
input_path = Path(sys.argv[1])
if not input_path.exists():
print(f"Error: file not found: {input_path}", file=sys.stderr)
sys.exit(1)
text = input_path.read_text(encoding="utf-8", errors="replace")
entries = parse_log_entries(text)
if not entries:
print("Warning: no log entries found.", file=sys.stderr)
stem = input_path.stem
parent = input_path.parent
pretty_path = parent / f"{stem}.pretty.log"
json_path = parent / f"{stem}.json"
pretty_path.write_text(format_pretty_log(entries), encoding="utf-8")
json_path.write_text(format_structured_json(entries), encoding="utf-8")
print(f"Parsed {len(entries)} entries.")
print(f" Pretty log: {pretty_path}")
print(f" JSON: {json_path}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment