# -*- coding: utf-8 -*- """ $Id$ Copyright 2010 Lars Kruse This file is part of PyCAM. PyCAM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. PyCAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with PyCAM. If not, see . """ import locale import logging def get_logger(suffix=None): name = "PyCAM" if suffix: name += ".%s" % str(suffix) logger = logging.getLogger(name) if len(logger.handlers) == 0: init_logger(logger) return logger def init_logger(log, logfilename=None): if logfilename: datetime_format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" logfile_handler = logging.FileHandler(logfilename) logfile_handler.setFormatter(datetime_format) log.addHandler(logfile_handler) console_output = logging.StreamHandler() log.addHandler(console_output) log.setLevel(logging.INFO) # store the latest log items in a queue (for pushing them into new handlers) log.addHandler(BufferHandler()) def _push_back_old_logs(new_handler): log = get_logger() # push all older log items into the new handler for handler in log.handlers: if hasattr(handler, "push_back"): handler.push_back(new_handler) def add_stream(stream, level=None): log = get_logger() logstream = logging.StreamHandler(stream) if not level is None: logstream.setLevel(level) log.addHandler(logstream) _push_back_old_logs(logstream) def add_hook(callback, level=None): log = get_logger() loghook = HookHandler(callback) if not level is None: loghook.setLevel(level) log.addHandler(loghook) _push_back_old_logs(loghook) def add_gtk_gui(parent_window, level=None): log = get_logger() loggui = GTKHandler(parent_window) if not level is None: loggui.setLevel(level) log.addHandler(loggui) _push_back_old_logs(loggui) class BufferHandler(logging.Handler): MAX_LENGTH = 100 def __init__(self, **kwargs): logging.Handler.__init__(self, **kwargs) self.record_buffer = [] def emit(self, record): self.record_buffer.append(record) # reduce the record_buffer queue if necessary while len(self.record_buffer) > self.MAX_LENGTH: self.record_buffer.pop(0) def push_back(self, other_handler): for record in self.record_buffer: if record.levelno >= other_handler.level: other_handler.emit(record) class GTKHandler(logging.Handler): def __init__(self, parent_window=None, **kwargs): logging.Handler.__init__(self, **kwargs) self.parent_window = parent_window def emit(self, record): raw_message = self.format(record) try: message = raw_message.encode("utf-8") except UnicodeDecodeError: try: # try to decode the string with the current locale current_encoding = locale.getpreferredencoding() message = raw_message.decode(current_encoding) except (UnicodeDecodeError, LookupError): # remove all critical characters message = re.sub("[^\w\s]", "", raw_message) import gtk if record.levelno <= 20: message_type = gtk.MESSAGE_INFO message_title = "Information" elif record.levelno <= 30: message_type = gtk.MESSAGE_WARNING message_title = "Warning" else: message_type = gtk.MESSAGE_ERROR message_title = "Error" window = gtk.MessageDialog(self.parent_window, type=message_type, buttons=gtk.BUTTONS_OK, message_format=str(message)) try: message_title = message_title.encode("utf-8") except UnicodeDecodeError: # remove all non-ascii characters message_title = "".join([char for char in message_title if ord(char) < 128]) window.set_title(message_title) window.run() window.destroy() class HookHandler(logging.Handler): def __init__(self, callback, **kwargs): logging.Handler.__init__(self, **kwargs) self.callback = callback def emit(self, record): message = self.format(record) message_type = record.levelname self.callback(message_type, message, record=record)