From 8402f1cdcd4cbabce31f224635052a0ac901d50d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 22 Jul 2015 05:13:50 +0800 Subject: [PATCH] master,gui: basic log support --- artiq/frontend/artiq_gui.py | 3 +++ artiq/frontend/artiq_master.py | 26 ++++++++++++++++++++------ artiq/gui/log.py | 33 +++++++++++++++++++++++++++++++++ artiq/master/worker.py | 3 +++ artiq/master/worker_impl.py | 21 ++++++++++++++++++++- 5 files changed, 79 insertions(+), 7 deletions(-) diff --git a/artiq/frontend/artiq_gui.py b/artiq/frontend/artiq_gui.py index 3a2cd17b8..f1f63bab4 100755 --- a/artiq/frontend/artiq_gui.py +++ b/artiq/frontend/artiq_gui.py @@ -105,6 +105,9 @@ def main(): atexit.register(lambda: loop.run_until_complete(d_schedule.sub_close())) d_log = LogDock() + loop.run_until_complete(d_log.sub_connect( + args.server, args.port_notify)) + atexit.register(lambda: loop.run_until_complete(d_log.sub_close())) area.addDock(d_log, "bottom") area.addDock(d_schedule, "above", d_log) diff --git a/artiq/frontend/artiq_master.py b/artiq/frontend/artiq_master.py index 196d4643c..6f7840cda 100755 --- a/artiq/frontend/artiq_master.py +++ b/artiq/frontend/artiq_master.py @@ -30,14 +30,21 @@ def get_argparser(): return parser +class Log: + def __init__(self, depth): + self.depth = depth + self.data = Notifier([]) + + def log(self, rid, message): + if len(self.data.read) >= self.depth: + del self.data[0] + self.data.append((rid, message)) + log.worker_pass_rid = True + + def main(): args = get_argparser().parse_args() - init_logger(args) - ddb = FlatFileDB("ddb.pyon") - pdb = FlatFileDB("pdb.pyon") - rtr = Notifier(dict()) - if os.name == "nt": loop = asyncio.ProactorEventLoop() asyncio.set_event_loop(loop) @@ -45,11 +52,17 @@ def main(): loop = asyncio.get_event_loop() atexit.register(lambda: loop.close()) + ddb = FlatFileDB("ddb.pyon") + pdb = FlatFileDB("pdb.pyon") + rtr = Notifier(dict()) + log = Log(1000) + worker_handlers = { "get_device": ddb.get, "get_parameter": pdb.get, "set_parameter": pdb.set, "update_rt_results": lambda mod: process_mod(rtr, mod), + "log": log.log } scheduler = Scheduler(get_last_rid() + 1, worker_handlers) worker_handlers["scheduler_submit"] = scheduler.submit @@ -74,7 +87,8 @@ def main(): "devices": ddb.data, "parameters": pdb.data, "rt_results": rtr, - "explist": repository.explist + "explist": repository.explist, + "log": log.data }) loop.run_until_complete(server_notify.start( args.bind, args.port_notify)) diff --git a/artiq/gui/log.py b/artiq/gui/log.py index ed5c9abb6..77981a37f 100644 --- a/artiq/gui/log.py +++ b/artiq/gui/log.py @@ -1,7 +1,40 @@ +import asyncio + from quamash import QtGui from pyqtgraph import dockarea +from artiq.protocols.sync_struct import Subscriber +from artiq.gui.tools import ListSyncModel + + +class _LogModel(ListSyncModel): + def __init__(self, parent, init): + ListSyncModel.__init__(self, + ["RID", "Message"], + parent, init) + + def convert(self, v, column): + return v[column] + class LogDock(dockarea.Dock): def __init__(self): dockarea.Dock.__init__(self, "Log", size=(1000, 300)) + + self.log = QtGui.QTableView() + self.log.setSelectionMode(QtGui.QAbstractItemView.NoSelection) + self.addWidget(self.log) + + @asyncio.coroutine + def sub_connect(self, host, port): + self.subscriber = Subscriber("log", self.init_log_model) + yield from self.subscriber.connect(host, port) + + @asyncio.coroutine + def sub_close(self): + yield from self.subscriber.close() + + def init_log_model(self, init): + table_model = _LogModel(self.log, init) + self.log.setModel(table_model) + return table_model diff --git a/artiq/master/worker.py b/artiq/master/worker.py index 198c97afc..919906ca2 100644 --- a/artiq/master/worker.py +++ b/artiq/master/worker.py @@ -4,6 +4,7 @@ import logging import subprocess import traceback import time +from functools import partial from artiq.protocols import pyon from artiq.tools import (asyncio_process_wait_timeout, asyncio_process_wait, @@ -174,6 +175,8 @@ class Worker: func = self.register_experiment else: func = self.handlers[action] + if getattr(func, "worker_pass_rid", False): + func = partial(func, self.rid) try: data = func(**obj) reply = {"status": "ok", "data": data} diff --git a/artiq/master/worker_impl.py b/artiq/master/worker_impl.py index b733a054d..77ff1349c 100644 --- a/artiq/master/worker_impl.py +++ b/artiq/master/worker_impl.py @@ -44,6 +44,25 @@ def make_parent_action(action, argnames, exception=ParentActionError): return parent_action + + +class LogForwarder: + def __init__(self): + self.buffer = "" + + to_parent = staticmethod(make_parent_action("log", "message")) + + def write(self, data): + self.buffer += data + while "\n" in self.buffer: + i = self.buffer.index("\n") + self.to_parent(self.buffer[:i]) + self.buffer = self.buffer[i+1:] + + def flush(self): + pass + + class ParentDDB: get = make_parent_action("get_device", "name", KeyError) @@ -133,7 +152,7 @@ def examine(dmgr, pdb, rdb, file): def main(): - sys.stdout = sys.stderr + sys.stdout = sys.stderr = LogForwarder() start_time = None rid = None