[3] | 1 | # log.py - adapt python logging module to SQLAlchemy |
---|
| 2 | # Copyright (C) 2006, 2007, 2008, 2009 Michael Bayer mike_mp@zzzcomputing.com |
---|
| 3 | # |
---|
| 4 | # This module is part of SQLAlchemy and is released under |
---|
| 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php |
---|
| 6 | |
---|
| 7 | """Logging control and utilities. |
---|
| 8 | |
---|
| 9 | Control of logging for SA can be performed from the regular python logging |
---|
| 10 | module. The regular dotted module namespace is used, starting at |
---|
| 11 | 'sqlalchemy'. For class-level logging, the class name is appended. |
---|
| 12 | |
---|
| 13 | The "echo" keyword parameter which is available on SQLA ``Engine`` |
---|
| 14 | and ``Pool`` objects corresponds to a logger specific to that |
---|
| 15 | instance only. |
---|
| 16 | |
---|
| 17 | E.g.:: |
---|
| 18 | |
---|
| 19 | engine.echo = True |
---|
| 20 | |
---|
| 21 | is equivalent to:: |
---|
| 22 | |
---|
| 23 | import logging |
---|
| 24 | logger = logging.getLogger('sqlalchemy.engine.Engine.%s' % hex(id(engine))) |
---|
| 25 | logger.setLevel(logging.DEBUG) |
---|
| 26 | |
---|
| 27 | """ |
---|
| 28 | |
---|
| 29 | import logging |
---|
| 30 | import sys |
---|
| 31 | |
---|
| 32 | |
---|
| 33 | rootlogger = logging.getLogger('sqlalchemy') |
---|
| 34 | if rootlogger.level == logging.NOTSET: |
---|
| 35 | rootlogger.setLevel(logging.WARN) |
---|
| 36 | |
---|
| 37 | default_enabled = False |
---|
| 38 | def default_logging(name): |
---|
| 39 | global default_enabled |
---|
| 40 | if logging.getLogger(name).getEffectiveLevel() < logging.WARN: |
---|
| 41 | default_enabled = True |
---|
| 42 | if not default_enabled: |
---|
| 43 | default_enabled = True |
---|
| 44 | handler = logging.StreamHandler(sys.stdout) |
---|
| 45 | handler.setFormatter(logging.Formatter( |
---|
| 46 | '%(asctime)s %(levelname)s %(name)s %(message)s')) |
---|
| 47 | rootlogger.addHandler(handler) |
---|
| 48 | |
---|
| 49 | def class_logger(cls, enable=False): |
---|
| 50 | logger = logging.getLogger(cls.__module__ + "." + cls.__name__) |
---|
| 51 | if enable == 'debug': |
---|
| 52 | logger.setLevel(logging.DEBUG) |
---|
| 53 | elif enable == 'info': |
---|
| 54 | logger.setLevel(logging.INFO) |
---|
| 55 | cls._should_log_debug = logger.isEnabledFor(logging.DEBUG) |
---|
| 56 | cls._should_log_info = logger.isEnabledFor(logging.INFO) |
---|
| 57 | cls.logger = logger |
---|
| 58 | |
---|
| 59 | def instance_logger(instance, echoflag=None): |
---|
| 60 | """create a logger for an instance. |
---|
| 61 | |
---|
| 62 | Warning: this is an expensive call which also results in a permanent |
---|
| 63 | increase in memory overhead for each call. Use only for |
---|
| 64 | low-volume, long-time-spanning objects. |
---|
| 65 | |
---|
| 66 | """ |
---|
| 67 | |
---|
| 68 | # limit the number of loggers by chopping off the hex(id). |
---|
| 69 | # many novice users unfortunately create an unlimited number |
---|
| 70 | # of Engines in their applications which would otherwise |
---|
| 71 | # cause the app to run out of memory. |
---|
| 72 | name = "%s.%s.0x...%s" % (instance.__class__.__module__, |
---|
| 73 | instance.__class__.__name__, |
---|
| 74 | hex(id(instance))[-4:]) |
---|
| 75 | |
---|
| 76 | if echoflag is not None: |
---|
| 77 | l = logging.getLogger(name) |
---|
| 78 | if echoflag == 'debug': |
---|
| 79 | default_logging(name) |
---|
| 80 | l.setLevel(logging.DEBUG) |
---|
| 81 | elif echoflag is True: |
---|
| 82 | default_logging(name) |
---|
| 83 | l.setLevel(logging.INFO) |
---|
| 84 | elif echoflag is False: |
---|
| 85 | l.setLevel(logging.NOTSET) |
---|
| 86 | else: |
---|
| 87 | l = logging.getLogger(name) |
---|
| 88 | instance._should_log_debug = l.isEnabledFor(logging.DEBUG) |
---|
| 89 | instance._should_log_info = l.isEnabledFor(logging.INFO) |
---|
| 90 | return l |
---|
| 91 | |
---|
| 92 | class echo_property(object): |
---|
| 93 | __doc__ = """\ |
---|
| 94 | When ``True``, enable log output for this element. |
---|
| 95 | |
---|
| 96 | This has the effect of setting the Python logging level for the namespace |
---|
| 97 | of this element's class and object reference. A value of boolean ``True`` |
---|
| 98 | indicates that the loglevel ``logging.INFO`` will be set for the logger, |
---|
| 99 | whereas the string value ``debug`` will set the loglevel to |
---|
| 100 | ``logging.DEBUG``. |
---|
| 101 | """ |
---|
| 102 | |
---|
| 103 | def __get__(self, instance, owner): |
---|
| 104 | if instance is None: |
---|
| 105 | return self |
---|
| 106 | else: |
---|
| 107 | return instance._should_log_debug and 'debug' or (instance._should_log_info and True or False) |
---|
| 108 | |
---|
| 109 | def __set__(self, instance, value): |
---|
| 110 | instance_logger(instance, echoflag=value) |
---|