logutils.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2014-2016 OpenMarket Ltd
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. from inspect import getcallargs
  16. from functools import wraps
  17. import logging
  18. import inspect
  19. import time
  20. from contextlib import contextmanager
  21. _TIME_FUNC_ID = 0
  22. logger = logging.getLogger(__name__)
  23. @contextmanager
  24. def log_duration(name):
  25. start = time.time() * 1000
  26. yield
  27. end = time.time() * 1000
  28. logger.info("Timings: %s tooke %dms", name, int(end - start))
  29. def _log_debug_as_f(f, msg, msg_args):
  30. name = f.__module__
  31. logger = logging.getLogger(name)
  32. if logger.isEnabledFor(logging.DEBUG):
  33. lineno = f.func_code.co_firstlineno
  34. pathname = f.func_code.co_filename
  35. record = logging.LogRecord(
  36. name=name,
  37. level=logging.DEBUG,
  38. pathname=pathname,
  39. lineno=lineno,
  40. msg=msg,
  41. args=msg_args,
  42. exc_info=None
  43. )
  44. logger.handle(record)
  45. def log_function(f):
  46. """ Function decorator that logs every call to that function.
  47. """
  48. func_name = f.__name__
  49. @wraps(f)
  50. def wrapped(*args, **kwargs):
  51. name = f.__module__
  52. logger = logging.getLogger(name)
  53. level = logging.DEBUG
  54. if logger.isEnabledFor(level):
  55. bound_args = getcallargs(f, *args, **kwargs)
  56. def format(value):
  57. r = str(value)
  58. if len(r) > 50:
  59. r = r[:50] + "..."
  60. return r
  61. func_args = [
  62. "%s=%s" % (k, format(v)) for k, v in bound_args.items()
  63. ]
  64. msg_args = {
  65. "func_name": func_name,
  66. "args": ", ".join(func_args)
  67. }
  68. _log_debug_as_f(
  69. f,
  70. "Invoked '%(func_name)s' with args: %(args)s",
  71. msg_args
  72. )
  73. return f(*args, **kwargs)
  74. wrapped.__name__ = func_name
  75. return wrapped
  76. def time_function(f):
  77. func_name = f.__name__
  78. @wraps(f)
  79. def wrapped(*args, **kwargs):
  80. global _TIME_FUNC_ID
  81. id = _TIME_FUNC_ID
  82. _TIME_FUNC_ID += 1
  83. start = time.clock() * 1000
  84. try:
  85. _log_debug_as_f(
  86. f,
  87. "[FUNC START] {%s-%d}",
  88. (func_name, id),
  89. )
  90. r = f(*args, **kwargs)
  91. finally:
  92. end = time.clock() * 1000
  93. _log_debug_as_f(
  94. f,
  95. "[FUNC END] {%s-%d} %f",
  96. (func_name, id, end - start,),
  97. )
  98. return r
  99. return wrapped
  100. def trace_function(f):
  101. func_name = f.__name__
  102. linenum = f.func_code.co_firstlineno
  103. pathname = f.func_code.co_filename
  104. @wraps(f)
  105. def wrapped(*args, **kwargs):
  106. name = f.__module__
  107. logger = logging.getLogger(name)
  108. level = logging.DEBUG
  109. s = inspect.currentframe().f_back
  110. to_print = [
  111. "\t%s:%s %s. Args: args=%s, kwargs=%s" % (
  112. pathname, linenum, func_name, args, kwargs
  113. )
  114. ]
  115. while s:
  116. if True or s.f_globals["__name__"].startswith("synapse"):
  117. filename, lineno, function, _, _ = inspect.getframeinfo(s)
  118. args_string = inspect.formatargvalues(*inspect.getargvalues(s))
  119. to_print.append(
  120. "\t%s:%d %s. Args: %s" % (
  121. filename, lineno, function, args_string
  122. )
  123. )
  124. s = s.f_back
  125. msg = "\nTraceback for %s:\n" % (func_name,) + "\n".join(to_print)
  126. record = logging.LogRecord(
  127. name=name,
  128. level=level,
  129. pathname=pathname,
  130. lineno=lineno,
  131. msg=msg,
  132. args=None,
  133. exc_info=None
  134. )
  135. logger.handle(record)
  136. return f(*args, **kwargs)
  137. wrapped.__name__ = func_name
  138. return wrapped
  139. def get_previous_frames():
  140. s = inspect.currentframe().f_back.f_back
  141. to_return = []
  142. while s:
  143. if s.f_globals["__name__"].startswith("synapse"):
  144. filename, lineno, function, _, _ = inspect.getframeinfo(s)
  145. args_string = inspect.formatargvalues(*inspect.getargvalues(s))
  146. to_return.append("{{ %s:%d %s - Args: %s }}" % (
  147. filename, lineno, function, args_string
  148. ))
  149. s = s.f_back
  150. return ", ". join(to_return)
  151. def get_previous_frame(ignore=[]):
  152. s = inspect.currentframe().f_back.f_back
  153. while s:
  154. if s.f_globals["__name__"].startswith("synapse"):
  155. if not any(s.f_globals["__name__"].startswith(ig) for ig in ignore):
  156. filename, lineno, function, _, _ = inspect.getframeinfo(s)
  157. args_string = inspect.formatargvalues(*inspect.getargvalues(s))
  158. return "{{ %s:%d %s - Args: %s }}" % (
  159. filename, lineno, function, args_string
  160. )
  161. s = s.f_back
  162. return None