| 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) |
|---|