_tracing.py 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. """
  2. Tracing utils
  3. """
  4. from .callers import _Result
  5. class TagTracer(object):
  6. def __init__(self):
  7. self._tag2proc = {}
  8. self.writer = None
  9. self.indent = 0
  10. def get(self, name):
  11. return TagTracerSub(self, (name,))
  12. def format_message(self, tags, args):
  13. if isinstance(args[-1], dict):
  14. extra = args[-1]
  15. args = args[:-1]
  16. else:
  17. extra = {}
  18. content = " ".join(map(str, args))
  19. indent = " " * self.indent
  20. lines = ["%s%s [%s]\n" % (indent, content, ":".join(tags))]
  21. for name, value in extra.items():
  22. lines.append("%s %s: %s\n" % (indent, name, value))
  23. return lines
  24. def processmessage(self, tags, args):
  25. if self.writer is not None and args:
  26. lines = self.format_message(tags, args)
  27. self.writer("".join(lines))
  28. try:
  29. self._tag2proc[tags](tags, args)
  30. except KeyError:
  31. pass
  32. def setwriter(self, writer):
  33. self.writer = writer
  34. def setprocessor(self, tags, processor):
  35. if isinstance(tags, str):
  36. tags = tuple(tags.split(":"))
  37. else:
  38. assert isinstance(tags, tuple)
  39. self._tag2proc[tags] = processor
  40. class TagTracerSub(object):
  41. def __init__(self, root, tags):
  42. self.root = root
  43. self.tags = tags
  44. def __call__(self, *args):
  45. self.root.processmessage(self.tags, args)
  46. def setmyprocessor(self, processor):
  47. self.root.setprocessor(self.tags, processor)
  48. def get(self, name):
  49. return self.__class__(self.root, self.tags + (name,))
  50. class _TracedHookExecution(object):
  51. def __init__(self, pluginmanager, before, after):
  52. self.pluginmanager = pluginmanager
  53. self.before = before
  54. self.after = after
  55. self.oldcall = pluginmanager._inner_hookexec
  56. assert not isinstance(self.oldcall, _TracedHookExecution)
  57. self.pluginmanager._inner_hookexec = self
  58. def __call__(self, hook, hook_impls, kwargs):
  59. self.before(hook.name, hook_impls, kwargs)
  60. outcome = _Result.from_call(lambda: self.oldcall(hook, hook_impls, kwargs))
  61. self.after(outcome, hook.name, hook_impls, kwargs)
  62. return outcome.get_result()
  63. def undo(self):
  64. self.pluginmanager._inner_hookexec = self.oldcall