logging: basics
This commit is contained in:
@@ -47,6 +47,7 @@ from aiorpcx import TaskGroup
|
||||
import certifi
|
||||
|
||||
from .i18n import _
|
||||
from .logging import get_logger, Logger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .network import Network
|
||||
@@ -54,6 +55,9 @@ if TYPE_CHECKING:
|
||||
from .simple_config import SimpleConfig
|
||||
|
||||
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
|
||||
def inv_dict(d):
|
||||
return {v: k for k, v in d.items()}
|
||||
|
||||
@@ -237,11 +241,15 @@ class PrintError(object):
|
||||
def print_msg(self, *msg):
|
||||
print_msg(self.log_name(), *msg)
|
||||
|
||||
class ThreadJob(PrintError):
|
||||
|
||||
class ThreadJob(Logger):
|
||||
"""A job that is run periodically from a thread's main loop. run() is
|
||||
called from that thread's context.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
Logger.__init__(self)
|
||||
|
||||
def run(self):
|
||||
"""Called periodically from the thread"""
|
||||
pass
|
||||
@@ -249,13 +257,14 @@ class ThreadJob(PrintError):
|
||||
class DebugMem(ThreadJob):
|
||||
'''A handy class for debugging GC memory leaks'''
|
||||
def __init__(self, classes, interval=30):
|
||||
ThreadJob.__init__(self)
|
||||
self.next_time = 0
|
||||
self.classes = classes
|
||||
self.interval = interval
|
||||
|
||||
def mem_stats(self):
|
||||
import gc
|
||||
self.print_error("Start memscan")
|
||||
self.logger.info("Start memscan")
|
||||
gc.collect()
|
||||
objmap = defaultdict(list)
|
||||
for obj in gc.get_objects():
|
||||
@@ -263,20 +272,21 @@ class DebugMem(ThreadJob):
|
||||
if isinstance(obj, class_):
|
||||
objmap[class_].append(obj)
|
||||
for class_, objs in objmap.items():
|
||||
self.print_error("%s: %d" % (class_.__name__, len(objs)))
|
||||
self.print_error("Finish memscan")
|
||||
self.logger.info(f"{class_.__name__}: {len(objs)}")
|
||||
self.logger.info("Finish memscan")
|
||||
|
||||
def run(self):
|
||||
if time.time() > self.next_time:
|
||||
self.mem_stats()
|
||||
self.next_time = time.time() + self.interval
|
||||
|
||||
class DaemonThread(threading.Thread, PrintError):
|
||||
class DaemonThread(threading.Thread, Logger):
|
||||
""" daemon thread that terminates cleanly """
|
||||
verbosity_filter = 'd'
|
||||
|
||||
def __init__(self):
|
||||
threading.Thread.__init__(self)
|
||||
Logger.__init__(self)
|
||||
self.parent_thread = threading.currentThread()
|
||||
self.running = False
|
||||
self.running_lock = threading.Lock()
|
||||
@@ -296,7 +306,7 @@ class DaemonThread(threading.Thread, PrintError):
|
||||
try:
|
||||
job.run()
|
||||
except Exception as e:
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
self.logger.exception('')
|
||||
|
||||
def remove_jobs(self, jobs):
|
||||
with self.job_lock:
|
||||
@@ -320,8 +330,8 @@ class DaemonThread(threading.Thread, PrintError):
|
||||
if 'ANDROID_DATA' in os.environ:
|
||||
import jnius
|
||||
jnius.detach()
|
||||
self.print_error("jnius detach")
|
||||
self.print_error("stopped")
|
||||
self.logger.info("jnius detach")
|
||||
self.logger.info("stopped")
|
||||
|
||||
|
||||
verbosity = ''
|
||||
@@ -375,7 +385,7 @@ def profiler(func):
|
||||
t0 = time.time()
|
||||
o = func(*args, **kw_args)
|
||||
t = time.time() - t0
|
||||
print_error("[profiler]", name, "%.4f"%t)
|
||||
_logger.debug(f"[profiler] {name} {t:,.4f}")
|
||||
return o
|
||||
return lambda *args, **kw_args: do_profile(args, kw_args)
|
||||
|
||||
@@ -393,7 +403,7 @@ def ensure_sparse_file(filename):
|
||||
try:
|
||||
os.system('fsutil sparse setflag "{}" 1'.format(filename))
|
||||
except Exception as e:
|
||||
print_error('error marking file {} as sparse: {}'.format(filename, e))
|
||||
_logger.info(f'error marking file {filename} as sparse: {e}')
|
||||
|
||||
|
||||
def get_headers_dir(config):
|
||||
@@ -893,10 +903,10 @@ def import_meta(path, validater, load_meta):
|
||||
load_meta(d)
|
||||
#backwards compatibility for JSONDecodeError
|
||||
except ValueError:
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
_logger.exception('')
|
||||
raise FileImportFailed(_("Invalid JSON code."))
|
||||
except BaseException as e:
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
_logger.exception('')
|
||||
raise FileImportFailed(e)
|
||||
|
||||
|
||||
@@ -905,7 +915,7 @@ def export_meta(meta, fileName):
|
||||
with open(fileName, 'w+', encoding='utf-8') as f:
|
||||
json.dump(meta, f, indent=4, sort_keys=True)
|
||||
except (IOError, os.error) as e:
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
_logger.exception('')
|
||||
raise FileExportFailed(e)
|
||||
|
||||
|
||||
@@ -928,12 +938,11 @@ def log_exceptions(func):
|
||||
except asyncio.CancelledError as e:
|
||||
raise
|
||||
except BaseException as e:
|
||||
print_ = self.print_error if hasattr(self, 'print_error') else print_error
|
||||
print_("Exception in", func.__name__, ":", repr(e))
|
||||
mylogger = self.logger if hasattr(self, 'logger') else _logger
|
||||
try:
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
mylogger.exception(f"Exception in {func.__name__}: {repr(e)}")
|
||||
except BaseException as e2:
|
||||
print_error("traceback.print_exc raised: {}...".format(e2))
|
||||
print(f"logging exception raised: {repr(e2)}... orig exc: {repr(e)} in {func.__name__}")
|
||||
raise
|
||||
return wrapper
|
||||
|
||||
@@ -991,12 +1000,13 @@ class SilentTaskGroup(TaskGroup):
|
||||
return super().spawn(*args, **kwargs)
|
||||
|
||||
|
||||
class NetworkJobOnDefaultServer(PrintError):
|
||||
class NetworkJobOnDefaultServer(Logger):
|
||||
"""An abstract base class for a job that runs on the main network
|
||||
interface. Every time the main interface changes, the job is
|
||||
restarted, and some of its internals are reset.
|
||||
"""
|
||||
def __init__(self, network: 'Network'):
|
||||
Logger.__init__(self)
|
||||
asyncio.set_event_loop(network.asyncio_loop)
|
||||
self.network = network
|
||||
self.interface = None # type: Interface
|
||||
|
||||
Reference in New Issue
Block a user