Commit 00e2ebf6 authored by Guillaume Seguin's avatar Guillaume Seguin

WIP #561: Add log_path option to store log

This commit changes the way the Tee in Pronterface works. When no log is
specified, sys.stdout is redirected as before to a tee between the
console panel and the true sys.stdout. When a log is specified,
sys.stdout is untouched and logging output is saved in both the console
panel and the log file.
The side effect is that all output must now go through the logging
module to properly get in the console panel and in the log.
Now we have to catch all "print" statements =)
parent b423156f
...@@ -249,7 +249,8 @@ class pronsole(cmd.Cmd): ...@@ -249,7 +249,8 @@ class pronsole(cmd.Cmd):
return False return False
def log(self, *msg): def log(self, *msg):
print u"".join(unicode(i) for i in msg) msg = u"".join(unicode(i) for i in msg)
logging.info(msg)
def logError(self, *msg): def logError(self, *msg):
msg = u"".join(unicode(i) for i in msg) msg = u"".join(unicode(i) for i in msg)
......
...@@ -63,12 +63,20 @@ from .settings import wxSetting, HiddenSetting, StringSetting, SpinSetting, \ ...@@ -63,12 +63,20 @@ from .settings import wxSetting, HiddenSetting, StringSetting, SpinSetting, \
from printrun import gcoder from printrun import gcoder
from .pronsole import REPORT_NONE, REPORT_POS, REPORT_TEMP from .pronsole import REPORT_NONE, REPORT_POS, REPORT_TEMP
class Tee(object): class ConsoleOutputHandler(object):
def __init__(self, target): """Handle console output. All messages go through the logging submodule. We setup a logging handler to get logged messages and write them to both stdout (unless a log file path is specified, in which case we add another logging handler to write to this file) and the log panel.
self.stdout = sys.stdout When no file path is specified, we also redirect stdout to ourself to catch print messages and al."""
sys.stdout = self
setup_logging(sys.stdout) def __init__(self, target, log_path):
self.target = target if log_path:
self.stdout = None
setup_logging(self, log_path)
self.target = target
else:
self.stdout = sys.stdout
sys.stdout = self
setup_logging(sys.stdout)
self.target = target
def __del__(self): def __del__(self):
sys.stdout = self.stdout sys.stdout = self.stdout
...@@ -78,14 +86,16 @@ class Tee(object): ...@@ -78,14 +86,16 @@ class Tee(object):
self.target(data) self.target(data)
except: except:
pass pass
try: if self.stdout:
data = data.encode("utf-8") try:
except: data = data.encode("utf-8")
pass except:
self.stdout.write(data) pass
self.stdout.write(data)
def flush(self): def flush(self):
self.stdout.flush() if self.stdout:
self.stdout.flush()
class ComboSetting(wxSetting): class ComboSetting(wxSetting):
...@@ -208,7 +218,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -208,7 +218,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.statusbar = self.CreateStatusBar() self.statusbar = self.CreateStatusBar()
self.statusbar.SetStatusText(_("Not connected to printer.")) self.statusbar.SetStatusText(_("Not connected to printer."))
self.t = Tee(self.catchprint) self.t = ConsoleOutputHandler(self.catchprint, self.settings.log_path)
self.stdout = sys.stdout self.stdout = sys.stdout
self.slicing = False self.slicing = False
self.loading_gcode = False self.loading_gcode = False
...@@ -806,6 +816,7 @@ Printrun. If not, see <http://www.gnu.org/licenses/>.""" ...@@ -806,6 +816,7 @@ Printrun. If not, see <http://www.gnu.org/licenses/>."""
# -------------------------------------------------------------- # --------------------------------------------------------------
def _add_settings(self, size): def _add_settings(self, size):
self.settings._add(StringSetting("log_path", "", _("Log path"), _("Path to the log file. An empty path will log to the console."), "UI"))
self.settings._add(BooleanSetting("monitor", True, _("Monitor printer status"), _("Regularly monitor printer temperatures (required to have functional temperature graph or gauges)"), "Printer"), self.update_monitor) self.settings._add(BooleanSetting("monitor", True, _("Monitor printer status"), _("Regularly monitor printer temperatures (required to have functional temperature graph or gauges)"), "Printer"), self.update_monitor)
self.settings._add(StringSetting("simarrange_path", "", _("Simarrange command"), _("Path to the simarrange binary to use in the STL plater"), "External")) self.settings._add(StringSetting("simarrange_path", "", _("Simarrange command"), _("Path to the simarrange binary to use in the STL plater"), "External"))
self.settings._add(BooleanSetting("circular_bed", False, _("Circular build platform"), _("Draw a circular (or oval) build platform instead of a rectangular one"), "Printer"), self.update_bed_viz) self.settings._add(BooleanSetting("circular_bed", False, _("Circular build platform"), _("Draw a circular (or oval) build platform instead of a rectangular one"), "Printer"), self.update_bed_viz)
......
...@@ -34,13 +34,32 @@ def install_locale(domain): ...@@ -34,13 +34,32 @@ def install_locale(domain):
else: else:
gettext.install(domain, './locale', unicode = 1) gettext.install(domain, './locale', unicode = 1)
def setup_logging(out): class LogFormatter(logging.Formatter):
def __init__(self, format_default, format_info):
super(LogFormatter, self).__init__(format_info)
self.format_default = format_default
self.format_info = format_info
def format(self, record):
if record.levelno == logging.INFO:
self._fmt = self.format_info
else:
self._fmt = self.format_default
return super(LogFormatter, self).format(record)
def setup_logging(out, filepath = None):
logger = logging.getLogger() logger = logging.getLogger()
logger.setLevel(logging.INFO) logger.setLevel(logging.INFO)
formatter = LogFormatter("[%(levelname)s] %(message)s", "%(message)s")
logger.handlers = [] logger.handlers = []
logging_handler = logging.StreamHandler(out) logging_handler = logging.StreamHandler(out)
logging_handler.setFormatter(logging.Formatter("[%(levelname)s] %(message)s")) logging_handler.setFormatter(formatter)
logger.addHandler(logging_handler) logger.addHandler(logging_handler)
if filepath is not None:
formatter = LogFormatter("%(asctime)s - [%(levelname)s] %(message)s", "%(asctime)s - %(message)s")
logging_handler = logging.FileHandler(filepath)
logging_handler.setFormatter(formatter)
logger.addHandler(logging_handler)
def iconfile(filename): def iconfile(filename):
if hasattr(sys, "frozen") and sys.frozen == "windows_exe": if hasattr(sys, "frozen") and sys.frozen == "windows_exe":
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment