forked from M-Labs/artiq
generalize multiline logging to remote logs and controllers
This commit is contained in:
parent
1fed38a8dc
commit
3cf67afeb1
|
@ -7,8 +7,7 @@ from collections import OrderedDict
|
||||||
|
|
||||||
import artiq
|
import artiq
|
||||||
from artiq.protocols import pipe_ipc, pyon
|
from artiq.protocols import pipe_ipc, pyon
|
||||||
from artiq.protocols.logging import multiline_log_config
|
from artiq.tools import multiline_log_config, file_import
|
||||||
from artiq.tools import file_import
|
|
||||||
from artiq.master.worker_db import DeviceManager, DatasetManager, get_hdf5_output
|
from artiq.master.worker_db import DeviceManager, DatasetManager, get_hdf5_output
|
||||||
from artiq.language.environment import is_experiment
|
from artiq.language.environment import is_experiment
|
||||||
from artiq.language.core import set_watchdog_factory, TerminationRequested
|
from artiq.language.core import set_watchdog_factory, TerminationRequested
|
||||||
|
|
|
@ -3,7 +3,7 @@ import logging
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from artiq.protocols.asyncio_server import AsyncioServer
|
from artiq.protocols.asyncio_server import AsyncioServer
|
||||||
from artiq.tools import TaskObject
|
from artiq.tools import TaskObject, MultilineFormatter
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -86,36 +86,16 @@ class LogParser:
|
||||||
stream, self.source_cb())
|
stream, self.source_cb())
|
||||||
|
|
||||||
|
|
||||||
class MultilineFormatter(logging.Formatter):
|
|
||||||
def __init__(self):
|
|
||||||
logging.Formatter.__init__(
|
|
||||||
self, "%(levelname)s:%(name)s:%(message)s")
|
|
||||||
|
|
||||||
def format(self, record):
|
|
||||||
r = logging.Formatter.format(self, record)
|
|
||||||
linebreaks = r.count("\n")
|
|
||||||
if linebreaks:
|
|
||||||
i = r.index(":")
|
|
||||||
r = r[:i] + "<" + str(linebreaks + 1) + ">" + r[i:]
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
def multiline_log_config(level):
|
|
||||||
root_logger = logging.getLogger()
|
|
||||||
root_logger.setLevel(level)
|
|
||||||
handler = logging.StreamHandler()
|
|
||||||
handler.setFormatter(MultilineFormatter())
|
|
||||||
root_logger.addHandler(handler)
|
|
||||||
|
|
||||||
|
|
||||||
_init_string = b"ARTIQ logging\n"
|
_init_string = b"ARTIQ logging\n"
|
||||||
|
|
||||||
|
|
||||||
class Server(AsyncioServer):
|
class Server(AsyncioServer):
|
||||||
"""Remote logging TCP server.
|
"""Remote logging TCP server.
|
||||||
|
|
||||||
Takes one log entry per line, in the format:
|
Log entries are in the format:
|
||||||
source:levelno:name:message
|
source:levelno<total_lines>:name:message
|
||||||
|
continuation...
|
||||||
|
...continuation
|
||||||
"""
|
"""
|
||||||
async def _handle_connection_cr(self, reader, writer):
|
async def _handle_connection_cr(self, reader, writer):
|
||||||
try:
|
try:
|
||||||
|
@ -123,6 +103,9 @@ class Server(AsyncioServer):
|
||||||
if line != _init_string:
|
if line != _init_string:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
source = None
|
||||||
|
parser = LogParser(lambda: source)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
line = await reader.readline()
|
line = await reader.readline()
|
||||||
if not line:
|
if not line:
|
||||||
|
@ -132,20 +115,16 @@ class Server(AsyncioServer):
|
||||||
except:
|
except:
|
||||||
return
|
return
|
||||||
line = line[:-1]
|
line = line[:-1]
|
||||||
linesplit = line.split(":", 3)
|
if parser.multiline_count:
|
||||||
if len(linesplit) != 4:
|
parser.line_input(line)
|
||||||
|
else:
|
||||||
|
linesplit = line.split(":", maxsplit=1)
|
||||||
|
if len(linesplit) != 2:
|
||||||
logger.warning("received improperly formatted message, "
|
logger.warning("received improperly formatted message, "
|
||||||
"dropping connection")
|
"dropping connection")
|
||||||
return
|
return
|
||||||
source, level, name, message = linesplit
|
source, remainder = linesplit
|
||||||
try:
|
parser.line_input(remainder)
|
||||||
level = int(level)
|
|
||||||
except:
|
|
||||||
logger.warning("received improperly formatted level, "
|
|
||||||
"dropping connection")
|
|
||||||
return
|
|
||||||
log_with_name(name, level, message,
|
|
||||||
extra={"source": source})
|
|
||||||
finally:
|
finally:
|
||||||
writer.close()
|
writer.close()
|
||||||
|
|
||||||
|
@ -172,19 +151,12 @@ class LogForwarder(logging.Handler, TaskObject):
|
||||||
logging.Handler.__init__(self, **kwargs)
|
logging.Handler.__init__(self, **kwargs)
|
||||||
self.host = host
|
self.host = host
|
||||||
self.port = port
|
self.port = port
|
||||||
self.setFormatter(logging.Formatter(
|
self.setFormatter(MultilineFormatter())
|
||||||
"%(name)s:%(message)s"))
|
|
||||||
self._queue = asyncio.Queue(queue_size)
|
self._queue = asyncio.Queue(queue_size)
|
||||||
self.reconnect_timer = reconnect_timer
|
self.reconnect_timer = reconnect_timer
|
||||||
|
|
||||||
def emit(self, record):
|
def emit(self, record):
|
||||||
message = self.format(record)
|
self._queue.put_nowait(record.source + ":" + self.format(record))
|
||||||
for part in message.split("\n"):
|
|
||||||
part = "{}:{}:{}".format(record.source, record.levelno, part)
|
|
||||||
try:
|
|
||||||
self._queue.put_nowait(part)
|
|
||||||
except asyncio.QueueFull:
|
|
||||||
break
|
|
||||||
|
|
||||||
async def _do(self):
|
async def _do(self):
|
||||||
while True:
|
while True:
|
||||||
|
|
|
@ -133,8 +133,30 @@ def simple_network_args(parser, default_port):
|
||||||
group.add_argument("--port-" + name, default=default, type=int,
|
group.add_argument("--port-" + name, default=default, type=int,
|
||||||
help=h)
|
help=h)
|
||||||
|
|
||||||
|
class MultilineFormatter(logging.Formatter):
|
||||||
|
def __init__(self):
|
||||||
|
logging.Formatter.__init__(
|
||||||
|
self, "%(levelname)s:%(name)s:%(message)s")
|
||||||
|
|
||||||
|
def format(self, record):
|
||||||
|
r = logging.Formatter.format(self, record)
|
||||||
|
linebreaks = r.count("\n")
|
||||||
|
if linebreaks:
|
||||||
|
i = r.index(":")
|
||||||
|
r = r[:i] + "<" + str(linebreaks + 1) + ">" + r[i:]
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_log_config(level):
|
||||||
|
root_logger = logging.getLogger()
|
||||||
|
root_logger.setLevel(level)
|
||||||
|
handler = logging.StreamHandler()
|
||||||
|
handler.setFormatter(MultilineFormatter())
|
||||||
|
root_logger.addHandler(handler)
|
||||||
|
|
||||||
|
|
||||||
def init_logger(args):
|
def init_logger(args):
|
||||||
logging.basicConfig(level=logging.WARNING + args.quiet*10 - args.verbose*10)
|
multiline_log_config(level=logging.WARNING + args.quiet*10 - args.verbose*10)
|
||||||
|
|
||||||
|
|
||||||
def bind_address_from_args(args):
|
def bind_address_from_args(args):
|
||||||
|
|
Loading…
Reference in New Issue