Files
darkfi/contrib/clean_logs.py
2023-05-09 15:15:55 +02:00

238 lines
7.4 KiB
Python

import glob, re, os.path, textwrap
from colorama import Fore, Back, Style
def target_prefix(dir):
if dir.startswith("net"):
return "net"
elif dir.startswith("serial"):
return "serial"
elif dir.startswith("util"):
return "util"
elif dir.startswith("runtime"):
return "runtime"
elif dir.startswith("zk"):
return "zk"
elif dir.startswith("raft"):
return "raft"
elif dir.startswith("sdk/src/crypto"):
return "sdk::crypto"
elif dir.startswith("sdk"):
return "sdk"
elif dir.startswith("contract/dao"):
return "dao"
elif dir.startswith("contract/money"):
return "money"
elif dir.startswith("rpc"):
return "rpc"
elif dir.startswith("system"):
return "system"
elif dir.startswith("dht"):
return "dht"
elif dir.startswith("consensus"):
return "consensus"
elif dir.startswith("zkas"):
return "zkas"
elif dir.startswith("blockchain"):
return "blockchain"
elif dir.startswith("wallet"):
return "wallet"
else:
assert not dir or dir == "tx"
return ""
def target_suffix(prefix, base):
if prefix in ("dao", "money"):
# Just shorten the target to simply "dao" or "money"
# We don't need the fine grained details
return ""
elif base in ("mod.rs", "lib.rs"):
# Just use the module name as the target with these files
return ""
# Otherwise just use the filename as the target suffix
return base.removesuffix(".rs")
def log_target(fname):
dir, base = os.path.dirname(fname), os.path.basename(fname)
prefix = target_prefix(dir)
suffix = target_suffix(prefix, base)
# you don't need :: when the suffix is empty
if not suffix and not prefix:
return ""
if not suffix:
return prefix
if not prefix:
return suffix
return f"{prefix}::{suffix}"
def replace(fname, contents):
target = log_target(fname)
# You can debug like this:
#if target != "net::protocol_seed":
# return None
print(f"Replacing {target}" + " "*(40 - len(target)) + f"[{fname}]")
result = []
lines = contents.split("\n")
i = 0
while i < len(lines):
line = lines[i]
# Line number
ln = lambda: i + 1
# only used for debug output
old_text = None
new_text = None
# This is used as a debug goto
is_modified = False
log_level = None
if "trace!(" in line:
log_level = "trace"
elif "debug!(" in line:
log_level = "debug"
elif "info!(" in line:
log_level = "info"
elif "warn!(" in line:
log_level = "warn"
elif "error!(" in line:
log_level = "error"
if log_level is not None:
# Walk backwards to find the function name
# Range is (i, 0]
function_name = None
for j in range(i - 1, -1, -1):
past_line = lines[j]
if (match := re.search(
r"fn ([\w]+)(<[\w: \+']+>)?\(",
past_line
)):
function_name = match.group(1)
break
assert function_name is not None
local_target = target
if target in (
"consensus::protocol_proposal",
"consensus::protocol_sync",
"consensus::protocol_sync_consensus",
"consensus::protocol_tx",
"runtime::db",
"net::hosts",
"net::protocol_address",
"net::protocol_ping",
"net::protocol_seed",
"net::protocol_version",
"net::p2p",
"net::message_subscriber",
"net::channel",
):
local_target += f"::{function_name}()"
# No target exists for this file at all. Just ignore these
# We would normally delete any target set for these files
# but so far we have none of them, so just ignore them.
if not target:
print(
" "
+ Back.RED + "Skip [no target]:" + Style.RESET_ALL
+ f" {line}"
)
# Single lines with a target that's a constant or string
elif re.search(rf'{log_level}!\(target: ([\w]+|"[\w:\-\(\)]+"),', line):
old_text = f"{ln()}: {line}"
line = re.sub(
r'target: ([\w]+|"[\w:\-\(\)]+"),',
f'target: "{local_target}",',
line
)
is_modified = True
new_text = f"{ln()}: {line}"
# Normal single lines with no target set
elif f'{log_level}!("' in line:
old_text = f"{ln()}: {line}"
#print(f" No target: {line}")
line = line.replace(f'{log_level}!(',
f'{log_level}!(target: "{local_target}", ')
is_modified = True
new_text = f"{ln()}: {line}"
# Multiline logs
# We read the next line and check if there's a target set or not
else:
assert re.search(rf"{log_level}!\($", line)
old_text = f"{ln()}: {line}"
new_text = f"{ln()}: {line}"
result.append(line)
i += 1
assert i < len(lines)
line = lines[i]
old_text += f"\n{ln()}: {line}"
# Constants or target strings set
if re.search(r'target: ([\w]+|"[\w:\-\(\)]+"),', line):
line = re.sub(
r'target: ([\w]+|"[\w:\-\(\)]+"),',
f'target: "{local_target}",',
line
)
new_text += f"\n{ln()}: {line}"
# Multi-line logs with no target set
# Insert an extra line with the target
else:
assert re.search('^"', line)
leading_space = lambda line: len(line) - len(line.lstrip())
added_line = (" "*leading_space(line)
+ f'target: "{local_target}",')
result.append(added_line)
new_text += f"\n{ln()}: {added_line}\n{ln() + 1}: {line}"
is_modified = True
if is_modified:
assert old_text is not None and new_text is not None
print(
Fore.RED
+ textwrap.indent(old_text, " < ")
+ Style.RESET_ALL
)
print(
Fore.GREEN
+ textwrap.indent(new_text, " > ")
+ Style.RESET_ALL
)
print()
result.append(line)
i += 1
return "\n".join(result)
def main():
for fname in glob.glob("**/*.rs", root_dir="src/", recursive=True):
with open(f"src/{fname}", "r") as f:
contents = f.read()
if (contents := replace(fname, contents)) is None:
# Skip this file
continue
# Uncomment this to apply the changes
with open(f"src/{fname}", "w") as f:
f.write(contents)
if __name__ == "__main__":
main()