Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/SQLAlchemy-1.3.25.dev0-py3.11-linux-x86_64.egg/sqlalchemy/log.py: 50%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

80 statements  

1# sqlalchemy/log.py 

2# Copyright (C) 2006-2021 the SQLAlchemy authors and contributors 

3# <see AUTHORS file> 

4# Includes alterations by Vinay Sajip vinay_sajip@yahoo.co.uk 

5# 

6# This module is part of SQLAlchemy and is released under 

7# the MIT License: http://www.opensource.org/licenses/mit-license.php 

8 

9"""Logging control and utilities. 

10 

11Control of logging for SA can be performed from the regular python logging 

12module. The regular dotted module namespace is used, starting at 

13'sqlalchemy'. For class-level logging, the class name is appended. 

14 

15The "echo" keyword parameter, available on SQLA :class:`_engine.Engine` 

16and :class:`_pool.Pool` objects, corresponds to a logger specific to that 

17instance only. 

18 

19""" 

20 

21import logging 

22import sys 

23 

24 

25# set initial level to WARN. This so that 

26# log statements don't occur in the absence of explicit 

27# logging being enabled for 'sqlalchemy'. 

28rootlogger = logging.getLogger("sqlalchemy") 

29if rootlogger.level == logging.NOTSET: 

30 rootlogger.setLevel(logging.WARN) 

31 

32 

33def _add_default_handler(logger): 

34 handler = logging.StreamHandler(sys.stdout) 

35 handler.setFormatter( 

36 logging.Formatter("%(asctime)s %(levelname)s %(name)s %(message)s") 

37 ) 

38 logger.addHandler(handler) 

39 

40 

41_logged_classes = set() 

42 

43 

44def class_logger(cls): 

45 logger = logging.getLogger(cls.__module__ + "." + cls.__name__) 

46 cls._should_log_debug = lambda self: logger.isEnabledFor(logging.DEBUG) 

47 cls._should_log_info = lambda self: logger.isEnabledFor(logging.INFO) 

48 cls.logger = logger 

49 _logged_classes.add(cls) 

50 return cls 

51 

52 

53class Identified(object): 

54 logging_name = None 

55 

56 def _should_log_debug(self): 

57 return self.logger.isEnabledFor(logging.DEBUG) 

58 

59 def _should_log_info(self): 

60 return self.logger.isEnabledFor(logging.INFO) 

61 

62 

63class InstanceLogger(object): 

64 """A logger adapter (wrapper) for :class:`.Identified` subclasses. 

65 

66 This allows multiple instances (e.g. Engine or Pool instances) 

67 to share a logger, but have its verbosity controlled on a 

68 per-instance basis. 

69 

70 The basic functionality is to return a logging level 

71 which is based on an instance's echo setting. 

72 

73 Default implementation is: 

74 

75 'debug' -> logging.DEBUG 

76 True -> logging.INFO 

77 False -> Effective level of underlying logger ( 

78 logging.WARNING by default) 

79 None -> same as False 

80 """ 

81 

82 # Map echo settings to logger levels 

83 _echo_map = { 

84 None: logging.NOTSET, 

85 False: logging.NOTSET, 

86 True: logging.INFO, 

87 "debug": logging.DEBUG, 

88 } 

89 

90 def __init__(self, echo, name): 

91 self.echo = echo 

92 self.logger = logging.getLogger(name) 

93 

94 # if echo flag is enabled and no handlers, 

95 # add a handler to the list 

96 if self._echo_map[echo] <= logging.INFO and not self.logger.handlers: 

97 _add_default_handler(self.logger) 

98 

99 # 

100 # Boilerplate convenience methods 

101 # 

102 def debug(self, msg, *args, **kwargs): 

103 """Delegate a debug call to the underlying logger.""" 

104 

105 self.log(logging.DEBUG, msg, *args, **kwargs) 

106 

107 def info(self, msg, *args, **kwargs): 

108 """Delegate an info call to the underlying logger.""" 

109 

110 self.log(logging.INFO, msg, *args, **kwargs) 

111 

112 def warning(self, msg, *args, **kwargs): 

113 """Delegate a warning call to the underlying logger.""" 

114 

115 self.log(logging.WARNING, msg, *args, **kwargs) 

116 

117 warn = warning 

118 

119 def error(self, msg, *args, **kwargs): 

120 """ 

121 Delegate an error call to the underlying logger. 

122 """ 

123 self.log(logging.ERROR, msg, *args, **kwargs) 

124 

125 def exception(self, msg, *args, **kwargs): 

126 """Delegate an exception call to the underlying logger.""" 

127 

128 kwargs["exc_info"] = 1 

129 self.log(logging.ERROR, msg, *args, **kwargs) 

130 

131 def critical(self, msg, *args, **kwargs): 

132 """Delegate a critical call to the underlying logger.""" 

133 

134 self.log(logging.CRITICAL, msg, *args, **kwargs) 

135 

136 def log(self, level, msg, *args, **kwargs): 

137 """Delegate a log call to the underlying logger. 

138 

139 The level here is determined by the echo 

140 flag as well as that of the underlying logger, and 

141 logger._log() is called directly. 

142 

143 """ 

144 

145 # inline the logic from isEnabledFor(), 

146 # getEffectiveLevel(), to avoid overhead. 

147 

148 if self.logger.manager.disable >= level: 

149 return 

150 

151 selected_level = self._echo_map[self.echo] 

152 if selected_level == logging.NOTSET: 

153 selected_level = self.logger.getEffectiveLevel() 

154 

155 if level >= selected_level: 

156 self.logger._log(level, msg, args, **kwargs) 

157 

158 def isEnabledFor(self, level): 

159 """Is this logger enabled for level 'level'?""" 

160 

161 if self.logger.manager.disable >= level: 

162 return False 

163 return level >= self.getEffectiveLevel() 

164 

165 def getEffectiveLevel(self): 

166 """What's the effective level for this logger?""" 

167 

168 level = self._echo_map[self.echo] 

169 if level == logging.NOTSET: 

170 level = self.logger.getEffectiveLevel() 

171 return level 

172 

173 

174def instance_logger(instance, echoflag=None): 

175 """create a logger for an instance that implements :class:`.Identified`.""" 

176 

177 if instance.logging_name: 

178 name = "%s.%s.%s" % ( 

179 instance.__class__.__module__, 

180 instance.__class__.__name__, 

181 instance.logging_name, 

182 ) 

183 else: 

184 name = "%s.%s" % ( 

185 instance.__class__.__module__, 

186 instance.__class__.__name__, 

187 ) 

188 

189 instance._echo = echoflag 

190 

191 if echoflag in (False, None): 

192 # if no echo setting or False, return a Logger directly, 

193 # avoiding overhead of filtering 

194 logger = logging.getLogger(name) 

195 else: 

196 # if a specified echo flag, return an EchoLogger, 

197 # which checks the flag, overrides normal log 

198 # levels by calling logger._log() 

199 logger = InstanceLogger(echoflag, name) 

200 

201 instance.logger = logger 

202 

203 

204class echo_property(object): 

205 __doc__ = """\ 

206 When ``True``, enable log output for this element. 

207 

208 This has the effect of setting the Python logging level for the namespace 

209 of this element's class and object reference. A value of boolean ``True`` 

210 indicates that the loglevel ``logging.INFO`` will be set for the logger, 

211 whereas the string value ``debug`` will set the loglevel to 

212 ``logging.DEBUG``. 

213 """ 

214 

215 def __get__(self, instance, owner): 

216 if instance is None: 

217 return self 

218 else: 

219 return instance._echo 

220 

221 def __set__(self, instance, value): 

222 instance_logger(instance, echoflag=value)