From 3a8373db6ec93cb128fec20b67a7ebc512f01767 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bonicoli Date: Tue, 26 Aug 2014 16:50:25 +0200 Subject: [PATCH] Use a configuration file for logging issue4040 review10441002 --- CHANGELOG | 1 + bin/trytond | 6 +++--- doc/topics/index.rst | 1 + doc/topics/logs.rst | 49 ++++++++++++++++++++++++++++++++++++++++++++ etc/trytond.conf | 2 +- trytond/config.py | 8 ++++---- trytond/server.py | 45 ++++++++++------------------------------ 7 files changed, 70 insertions(+), 42 deletions(-) create mode 100644 doc/topics/logs.rst diff --git a/CHANGELOG b/CHANGELOG index 6d4dda26d5..216918cc2c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Use a configuration field for logging * Add translated descriptor for Selection field * Add tree_state attribute on tree view * Allow to sync XML data diff --git a/bin/trytond b/bin/trytond index d8b84ef4af..1e43cacb0e 100755 --- a/bin/trytond +++ b/bin/trytond @@ -38,8 +38,8 @@ def parse_commandline(): parser.add_argument("--pidfile", dest="pidfile", help="file where the server pid will be stored") - parser.add_argument("--logfile", dest="logfile", - help="file where the server log will be stored") + parser.add_argument("--logconf", dest="logconf", + help="logging configuration file (ConfigParser format)") parser.add_argument("--disable-cron", dest="cron", action="store_false", help="disable cron") @@ -61,7 +61,7 @@ def parse_commandline(): 'verbose', 'debug_mode', 'pidfile', - 'logfile', + 'logconf', 'cron', ): if getattr(opt, arg) is not None: diff --git a/doc/topics/index.rst b/doc/topics/index.rst index bae4107169..a74763bdb9 100644 --- a/doc/topics/index.rst +++ b/doc/topics/index.rst @@ -10,6 +10,7 @@ Introduction to all the key parts of trytond: :maxdepth: 1 install + logs models/index models/fields_default_value models/fields_on_change diff --git a/doc/topics/logs.rst b/doc/topics/logs.rst new file mode 100644 index 0000000000..ccd4e6d0c2 --- /dev/null +++ b/doc/topics/logs.rst @@ -0,0 +1,49 @@ +.. _topics-logs: + +===================== +Logging configuration +===================== + +Without any configuration, trytond write INFO messages to standard output. + +Logs can be configured using a `configparser-format`_ file. The filename can +be specified using trytond ``logconf`` parameter. + +.. _`configparser-format`: https://docs.python.org/2/library/logging.config.html#configuration-file-format + +Example +======= + +This example allows to write INFO messages on standard output and on a disk log +file rotated every day. + +.. highlight:: ini + +:: + + [formatters] + keys: simple + + [handlers] + keys: rotate, console + + [loggers] + keys: root + + [formatter_simple] + format: %(asctime)s] %(levelname)s:%(name)s:%(message)s + datefmt: %a %b %d %H:%M:%S %Y + + [handler_rotate] + class: handlers.TimedRotatingFileHandler + args: ('/tmp/tryton.log', 'D', 1, 30) + formatter: simple + + [handler_console] + class: StreamHandler + formatter: simple + args: (sys.stdout,) + + [logger_root] + level: INFO + handlers: rotate, console diff --git a/etc/trytond.conf b/etc/trytond.conf index f70a6d6168..b2e70cdf51 100644 --- a/etc/trytond.conf +++ b/etc/trytond.conf @@ -46,7 +46,7 @@ jsonrpc = localhost:8000 # Configure the path of the files for the pid and the logs #pidfile = False -#logfile = False +#logconf = False #privatekey = server.pem #certificate = server.pem diff --git a/trytond/config.py b/trytond/config.py index ba67332c16..5c52e69d1b 100644 --- a/trytond/config.py +++ b/trytond/config.py @@ -61,7 +61,7 @@ class ConfigManager(object): 'verbose': False, 'debug_mode': False, 'pidfile': None, - 'logfile': None, + 'logconf': None, 'privatekey': '/etc/ssl/trytond/server.key', 'certificate': '/etc/ssl/trytond/server.pem', 'smtp_server': 'localhost', @@ -89,10 +89,10 @@ class ConfigManager(object): def update_cmdline(self, cmdline_options): self.options.update(cmdline_options) - # Verify that we want to log or not, + # Verify that logging configuration is defined in an external file, # if not the output will go to stdout - if self.options['logfile'] in ('None', 'False'): - self.options['logfile'] = False + if self.options['logconf'] in ('None', 'False'): + self.options['logconf'] = False # the same for the pidfile if self.options['pidfile'] in ('None', 'False'): self.options['pidfile'] = False diff --git a/trytond/server.py b/trytond/server.py index 720b224b61..ee978ca625 100644 --- a/trytond/server.py +++ b/trytond/server.py @@ -4,6 +4,7 @@ %prog [options] """ import logging +import logging.config import logging.handlers import sys import os @@ -22,45 +23,21 @@ from .transaction import Transaction class TrytonServer(object): def __init__(self, options): - format = '[%(asctime)s] %(levelname)s:%(name)s:%(message)s' - datefmt = '%a %b %d %H:%M:%S %Y' - logging.basicConfig(level=logging.INFO, format=format, - datefmt=datefmt) CONFIG.update_etc(options['configfile']) CONFIG.update_cmdline(options) - if CONFIG['logfile']: - logf = CONFIG['logfile'] - # test if the directories exist, else create them - try: - diff = 0 - if os.path.isfile(logf): - diff = int(time.time()) - int(os.stat(logf)[-1]) - handler = logging.handlers.TimedRotatingFileHandler( - logf, 'D', 1, 30) - handler.rolloverAt -= diff - except Exception, exception: - sys.stderr.write( - "ERROR: couldn't create the logfile directory:" - + str(exception)) - else: - formatter = logging.Formatter(format, datefmt) - # tell the handler to use this format - handler.setFormatter(formatter) + if CONFIG['logconf']: + logging.config.fileConfig(CONFIG['logconf']) + logging.getLogger('server').info('using %s as logging ' + 'configuration file', CONFIG['logconf']) + else: + logformat = '[%(asctime)s] %(levelname)s:%(name)s:%(message)s' + datefmt = '%a %b %d %H:%M:%S %Y' + logging.basicConfig(level=logging.INFO, format=logformat, + datefmt=datefmt) - # add the handler to the root logger - logging.getLogger().addHandler(handler) - logging.getLogger().setLevel(logging.INFO) - elif os.name != 'nt': - reverse = '\x1b[7m' - reset = '\x1b[0m' - # reverse color for error and critical messages - for level in logging.ERROR, logging.CRITICAL: - msg = reverse + logging.getLevelName(level) + reset - logging.addLevelName(level, msg) - - self.logger = logging.getLogger("server") + self.logger = logging.getLogger('server') if CONFIG.configfile: self.logger.info('using %s as configuration file'