diff options
| -rw-r--r-- | core/logger.c | 7 | ||||
| -rw-r--r-- | data/client.c | 3 | ||||
| -rw-r--r-- | data/server.c | 4 | ||||
| -rwxr-xr-x | salis.py | 67 |
4 files changed, 47 insertions, 34 deletions
diff --git a/core/logger.c b/core/logger.c index e088c55..f665908 100644 --- a/core/logger.c +++ b/core/logger.c @@ -1,3 +1,10 @@ +#include <assert.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdio.h> +#include <time.h> +#include <unistd.h> + #define LOG_LINE_SIZE 1024 enum LogLevel { diff --git a/data/client.c b/data/client.c index 02c7687..31e18b8 100644 --- a/data/client.c +++ b/data/client.c @@ -1,9 +1,6 @@ -#include <assert.h> #include <curses.h> #include <locale.h> #include <stdlib.h> -#include <time.h> -#include <unistd.h> #include "logger.c" #include "tui.c" diff --git a/data/server.c b/data/server.c index 3ed2c64..7561a1a 100644 --- a/data/server.c +++ b/data/server.c @@ -1,11 +1,7 @@ #include <arpa/inet.h> -#include <assert.h> #include <json-c/json.h> #include <signal.h> -#include <stdarg.h> -#include <stdio.h> #include <threads.h> -#include <unistd.h> #include "logger.c" @@ -1,6 +1,6 @@ #!/usr/bin/env -S PYTHONDONTWRITEBYTECODE=1 python -import colorlog +import ctypes import enum import json import os @@ -18,11 +18,10 @@ from types import SimpleNamespace # ------------------------------------------------------------------------------ # Argument parser # ------------------------------------------------------------------------------ -description = "Salis: Simple A-Life Simulator" prog = sys.argv[0] epilog = f"Use '-h' to show command arguments; e.g. '{prog} new -h'" -parser = ArgumentParser(description=description, epilog=epilog, formatter_class=RawTextHelpFormatter, prog=prog) +parser = ArgumentParser(description="Salis: Simple A-Life Simulator", epilog=epilog, formatter_class=RawTextHelpFormatter, prog=prog) sub_parsers = parser.add_subparsers(dest="command", required=True) formatter_class = lambda prog: ArgumentDefaultsHelpFormatter(max_help_position=32, prog=prog) @@ -91,22 +90,15 @@ for (name, sub_parsers, _), kwargs in options.items(): args = parser.parse_args() # ------------------------------------------------------------------------------ -# Logging -# ------------------------------------------------------------------------------ -handler = colorlog.StreamHandler() -handler.setFormatter(colorlog.ColoredFormatter("%(log_color)s%(asctime)s %(process)07d [%(levelname).4s] %(reset)s%(message)s")) - -log = colorlog.getLogger() -log.setLevel(colorlog.INFO) -log.addHandler(handler) - -# ------------------------------------------------------------------------------ # Build class # ------------------------------------------------------------------------------ class Build: - def __init__(self, path, library=False): + def __init__(self, path, log, library=False): + self.log = log + self.library = library + self.tempdir = TemporaryDirectory(prefix="salis_", delete=not args.keep_temp_dir) - log.info(f"Generated temporary directory for C builds at: {self.tempdir.name}") + self.log.info(f"Generated temporary directory for C builds at: {self.tempdir.name}") self.name = os.path.splitext(os.path.basename(path))[0] self.binfile = os.path.join(self.tempdir.name, f"{self.name}{".so" if library else ""}") @@ -117,8 +109,8 @@ class Build: self.links = set() self.build_cmd = [args.compiler, f"@{self.argsfile}", path, "-o", self.binfile] - log.info(f"Build class initialized for {"library" if library else "executable"}: {path}") - log.info(f"Compiler flags stored at: {self.argsfile}") + self.log.info(f"Build class initialized for {"library" if library else "executable"}: {path}") + self.log.info(f"Compiler flags stored at: {self.argsfile}") def build(self): fmt_nl = lambda line: f"{line}\n" @@ -129,14 +121,16 @@ class Build: f.writelines(map(fmt_define, sorted(self.defines))) f.writelines(map(fmt_nl, sorted(self.links))) - log.info(f"Running build command: '{self.build_cmd}'") + self.log.info(f"Running build command: '{self.build_cmd}'") subprocess.run(self.build_cmd, check=True) def exec(self): + assert not self.library + run_cmd = args.pre_cmd.split() if args.pre_cmd else [] run_cmd.append(self.binfile) - log.info(f"Running binary with command: '{" ".join(run_cmd)}'") + self.log.info(f"Running binary with command: '{" ".join(run_cmd)}'") proc = subprocess.Popen(run_cmd, stdout=sys.stdout, stderr=sys.stderr) # When using signals (e.g. SIGTERM), they must be sent to the entire process group @@ -152,6 +146,26 @@ class Build: if code != 0: raise RuntimeError(f"Binary returned code: {code}") # ------------------------------------------------------------------------------ +# Logging +# ------------------------------------------------------------------------------ +log_logs = [] +log_ns = SimpleNamespace() +log_ns.info = lambda msg: log_logs.append(("info", msg)) +log_ns.warn = lambda msg: log_logs.append(("warn", msg)) +log_b = Build("core/logger.c", log_ns, library=True) +log_b.build() + +# Pull in logging functions from C +# This way there's only a single unified logging system to care about +log = SimpleNamespace() +log_dll = ctypes.CDLL(log_b.binfile) +log.info = lambda msg: log_dll.log_info(msg.encode()) +log.warn = lambda msg: log_dll.log_warn(msg.encode()) + +for log_level, log_msg in log_logs: + getattr(log, log_level)(log_msg) + +# ------------------------------------------------------------------------------ # Options dict formatter # ------------------------------------------------------------------------------ fmt_h2u = lambda field: field.replace("-", "_") @@ -175,7 +189,6 @@ def fmt_opts(opts): # ------------------------------------------------------------------------------ # Source configuration # ------------------------------------------------------------------------------ -log.info(description) log.info(f"Called '{prog} {args.command}' with the following options: {fmt_opts(vars(args))}") ns = SimpleNamespace() @@ -215,7 +228,7 @@ if args.command == "new": raise RuntimeError("Data push power must be equal or greater than core sync power") if os.path.isdir(ns.sim_dir) and args.force: - log.warning(f"Force flag used! Wiping old simulation at: {ns.sim_dir}") + log.warn(f"Force flag used! Wiping old simulation at: {ns.sim_dir}") shutil.rmtree(ns.sim_dir) if os.path.isdir(ns.sim_dir): @@ -331,14 +344,14 @@ def pop_data_push_vars(): ns.b.links.add("-lz") log.info(f"Data will be aggregated at: {ns.sim_db}") else: - log.warning("Data aggregation disabled") + log.warn("Data aggregation disabled") if not args.no_compress: ns.b.defines.add("-DCOMPRESS") ns.b.links.add("-lz") log.info("Save file compression enabled") else: - log.warning("Save file compression disabled") + log.warn("Save file compression disabled") def pop_sim_path_vars(): ns.b.defines.add(f"-DSIM_OPTS=\"{ns.sim_opts}\"") @@ -385,7 +398,7 @@ def pop_general(): # Populate for new if args.command == "new": - ns.b = Build("core/salis.c") + ns.b = Build("core/salis.c", log) pop_ui_vars() pop_data_push_vars() pop_sim_path_vars() @@ -396,7 +409,7 @@ if args.command == "new": # Populate for load if args.command == "load": - ns.b = Build("core/salis.c") + ns.b = Build("core/salis.c", log) pop_ui_vars() pop_data_push_vars() pop_sim_path_vars() @@ -407,14 +420,14 @@ if args.command == "load": # Populate for server if args.command == "server": - ns.b = Build("data/server.c") + ns.b = Build("data/server.c", log) pop_sim_path_vars() pop_net_vars() pop_general() # Populate for client if args.command == "client": - ns.b = Build("data/client.c") + ns.b = Build("data/client.c", log) pop_net_vars() pop_general() ns.b.defines.add(f"-DIP={args.ip}") |
