diff --git a/pyproject.toml b/pyproject.toml index 6702046..aba3544 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,8 +23,8 @@ dependencies = [ "requests", "tqdm", # Server + "zstdlib>=0.0.8", "waitress", - "zstdlib", "flask", # Both "human_readable", diff --git a/rpipe/__init__.py b/rpipe/__init__.py index 2d3f944..2dff3c5 100644 --- a/rpipe/__init__.py +++ b/rpipe/__init__.py @@ -1 +1 @@ -__version__: str = "9.2.4" # Must be "..", all numbers +__version__: str = "9.3.0" # Must be "..", all numbers diff --git a/rpipe/client/cli.py b/rpipe/client/cli.py index fb92d5f..01cc763 100644 --- a/rpipe/client/cli.py +++ b/rpipe/client/cli.py @@ -40,7 +40,7 @@ def cli() -> None: threads: int = max(1, (cpu := cpu_count()) - 1) parser = argparse.ArgumentParser(add_help=False) parser.set_defaults(method=None) - read_g = parser.add_argument_group("Read Options") + read_g = parser.add_argument_group("Read Mode") read_g.add_argument( "-b", "--block", action="store_true", help="Wait until a channel is available to read" ) @@ -56,7 +56,7 @@ def cli() -> None: action="store_true", help="Attempt to read data even if this is a upload/download client version mismatch", ) - write_g = parser.add_argument_group("Write Options") + write_g = parser.add_argument_group("Write Mode") write_g.add_argument( "-t", "--ttl", @@ -79,17 +79,9 @@ def cli() -> None: type=int, help=f"The number of threads to use for compression. Default: {threads}", ) - delete_g = parser.add_argument_group("Delete Options") + delete_g = parser.add_argument_group("Delete Mode") delete_g.add_argument("-d", "--delete", action="store_true", help="Delete all entries in the channel") - read_write_g = parser.add_argument_group("Read/Write Options") - # pylint: disable=duplicate-code - read_write_g.add_argument( - "-v", - "--verbose", - action="count", - default=0, - help="Increase Log verbosity, pass more than once to increase verbosity", - ) + read_write_g = parser.add_argument_group("Read Mode / Write Mode") msg = ( "Show a progress bar, if a value is passed, assume that's the number" " of bytes to be passed. Only valid while sending or receiving data." @@ -99,7 +91,7 @@ def cli() -> None: "-P", "--progress", metavar="SIZE", type=_si, default=False, const=True, nargs="?", help=msg ) # Config options - config = parser.add_argument_group("Config Options") + config = parser.add_argument_group("Configuration") config.add_argument("-u", "--url", help="The pipe url to use") config.add_argument("-c", "--channel", help="The channel to use") config.add_argument( @@ -116,6 +108,16 @@ def cli() -> None: help=f"Encrypt the data; uses {PASSWORD_ENV} as the password if set, otherwise uses saved password", ) config.add_argument("-s", "--ssl", action=argparse.BooleanOptionalAction, help="Require host use https") + log_g = parser.add_argument_group("Logging") + # pylint: disable=duplicate-code + log_g.add_argument( + "-v", + "--verbose", + action="count", + default=0, + help="Increase Log verbosity, pass more than once to increase verbosity", + ) + log_g.add_argument("-N", "--no-color-log", action="store_true", help="Disable color in the log output") # Priority Modes priority_mode = parser.add_argument_group( "Alternative Modes", @@ -148,7 +150,7 @@ def cli() -> None: title="Admin Commands", description=( "Server admin commands; must be used with --admin and should have a key file set before use." - " All arguments except --verbose, config arguments are ignored with admin commands." + " All arguments except logging and config arguments are ignored with admin commands." " Server must be configured to accept messages signed by your selected private key file" ), dest="method", diff --git a/rpipe/client/main.py b/rpipe/client/main.py index 5f0eef1..231b553 100644 --- a/rpipe/client/main.py +++ b/rpipe/client/main.py @@ -6,7 +6,7 @@ """ from __future__ import annotations -from logging import basicConfig, getLevelName, getLogger +from logging import StreamHandler, getLevelName, getLogger from inspect import Parameter, signature from typing import TYPE_CHECKING from dataclasses import asdict @@ -14,6 +14,7 @@ import argparse import sys +from zstdlib.log import CuteFormatter from human_readable import listing from ..shared import log @@ -74,14 +75,24 @@ def _admin(ns: Namespace, conf: Config) -> None: func(**{i: getattr(ns, i) for i in kw}) -# pylint: disable=too-many-locals,too-many-statements -def main(parser: argparse.ArgumentParser, parsed: Namespace) -> None: +def _config_log(parsed: Namespace) -> None: # Log config log.define_trace() - lvl = log.level(parsed.verbose) - basicConfig(level=lvl, datefmt=log.DATEFMT, format=log.FORMAT) - getLogger(_LOG).info("Logging level set to %s", getLevelName(lvl)) - del parsed.verbose + root = getLogger() + root.setLevel(lvl := log.level(parsed.verbose)) + assert len(root.handlers) == 0, "Root logger should not have any handlers" + root.addHandler(sh := StreamHandler()) + sh.setFormatter(CuteFormatter(fmt=log.FORMAT, datefmt=log.DATEFMT, colored=not parsed.no_color_log)) + getLogger(_LOG).info( + "Logging level set to %s with colors %sABLED", + getLevelName(lvl), + "DIS" if parsed.no_color_log else "EN", + ) + + +# pylint: disable=too-many-locals,too-many-statements +def main(parser: argparse.ArgumentParser, parsed: Namespace) -> None: + _config_log(parsed) # Load Config conf_d = {i: k for i, k in vars(parsed).items() if i in Config.keys()} if (pw := getenv(PASSWORD_ENV)) is not None: diff --git a/rpipe/server/app.py b/rpipe/server/app.py index b5e2c4a..4c9e4c1 100644 --- a/rpipe/server/app.py +++ b/rpipe/server/app.py @@ -1,5 +1,5 @@ from __future__ import annotations -from logging import DEBUG, INFO, StreamHandler, FileHandler, Formatter, getLevelName, getLogger, shutdown +from logging import DEBUG, INFO, StreamHandler, FileHandler, getLevelName, getLogger, shutdown from os import environ, close as fd_close from dataclasses import dataclass from tempfile import mkstemp @@ -8,6 +8,7 @@ import atexit from flask import Response, Flask, send_file, request +from zstdlib.log import CuteFormatter import waitress from ..shared import TRACE, restrict_umask, remote_addr, log, __version__ @@ -22,6 +23,7 @@ @dataclass(frozen=True, slots=True, kw_only=True) class LogConfig: + colored: bool log_file: Path verbose: int debug: bool @@ -59,7 +61,7 @@ def start(self, conf: ServerConfig, log_file: Path, favicon: Path | None): lg.info("Starting server version: %s", __version__) # pylint: disable=attribute-defined-outside-init self._objs = self.Objs(admin, Server(conf.debug, conf.state_file), favicon) - lg.info("Serving on %s:%s", conf.host, conf.port) + lg.info("Binding to %s:%s", conf.host, conf.port) if conf.debug: self.run(host=conf.host, port=conf.port, debug=True) else: @@ -243,7 +245,7 @@ def _log_config(conf: LogConfig) -> Path: if conf.debug: environ[rdlf_env] = str(log_file) # Setup logger - fmt = Formatter(log.FORMAT, log.DATEFMT) + fmt = CuteFormatter(log.FORMAT, log.DATEFMT, colored=conf.colored) fh = FileHandler(log_file, mode="a") stream = StreamHandler() root = getLogger() diff --git a/rpipe/server/main.py b/rpipe/server/main.py index 3874e28..cd70290 100644 --- a/rpipe/server/main.py +++ b/rpipe/server/main.py @@ -29,18 +29,19 @@ def cli() -> None: help="SSH ed25519 public keys to accept for admin access", ) parser.add_argument("-F", "--favicon", type=Path, help="The favicon file, if desired") - log_group = parser.add_argument_group("Logging") - log_group.add_argument( + log_g = parser.add_argument_group("Logging") + log_g.add_argument( "-l", "--log-file", type=Path, default=None, help="The log file to append to, if desired" ) # pylint: disable=duplicate-code - log_group.add_argument( + log_g.add_argument( "-v", "--verbose", action="count", default=0, help="Increase Log verbosity, pass more than once to increase verbosity", ) + log_g.add_argument("-C", "--colored", action="store_true", help="Enable color in the log output") parser.add_argument("--debug", action="store_true", help="Run the server in debug mode") ns = parser.parse_args() gen = lambda C: C(**{i: getattr(ns, i) for i in (k.name for k in fields(C))}) diff --git a/rpipe/shared/log.py b/rpipe/shared/log.py index 3fd9399..4ecbd07 100644 --- a/rpipe/shared/log.py +++ b/rpipe/shared/log.py @@ -12,7 +12,7 @@ DATEFMT = "%H:%M:%S" -FORMAT = "%(asctime)s.%(msecs)03d - %(levelname)-8s - %(name)-10s - %(message)s" +FORMAT = "%(cute_asctime)s.%(msecs)03d - %(cute_levelname)-8s - %(cute_name)-10s - %(cute_message)s" TRACE = DEBUG - 5 assert TRACE > 0