summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2017-01-01 11:11:39 -0500
committerNed Batchelder <ned@nedbatchelder.com>2017-01-01 11:11:39 -0500
commitfbd93df732617e171503b96a336d57cf8cff926f (patch)
treeea524a1e493e2678dbe3ffc3ae7f66f36997a811
parenta52e3caaa7343ff73ba1151012cb7fa8cc5e133c (diff)
downloadpython-coveragepy-fbd93df732617e171503b96a336d57cf8cff926f.tar.gz
Better logging file, combined with aspectlib support
-rw-r--r--coverage/debug.py80
1 files changed, 49 insertions, 31 deletions
diff --git a/coverage/debug.py b/coverage/debug.py
index e75a895..79e037a 100644
--- a/coverage/debug.py
+++ b/coverage/debug.py
@@ -132,19 +132,56 @@ def dump_stack_frames(limit=None, out=None, skip=0):
out.write("\n")
-LOGGED_PROCESS = False
+class DebugOutputFile(object): # pragma: debugging
+ """A file-like object that includes pid and cwd information."""
+ def __init__(self, outfile):
+ self.outfile = outfile
+ self.cwd = None
+
+ SYS_MOD_NAME = '$coverage.debug.DebugOutputFile.the_one'
+
+ @classmethod
+ def the_one(cls, filename):
+ """Get the process-wide singleton DebugOutputFile."""
+ # Because of the way igor.py deletes and re-imports modules,
+ # this class can be defined more than once. But we really want
+ # a process-wide singleton. So stash it in sys.modules instead of
+ # on a class attribute. Yes, this is aggressively gross.
+ the_one = sys.modules.get(cls.SYS_MOD_NAME)
+ if the_one is None:
+ sys.modules[cls.SYS_MOD_NAME] = the_one = cls(open(filename, "a"))
-def log(msg, stack=False): # pragma: debugging
- """Write a log message as forcefully as possible."""
- global LOGGED_PROCESS
- with open("/tmp/covlog.txt", "a") as f:
- if not LOGGED_PROCESS:
- LOGGED_PROCESS = True
cmd = " ".join(getattr(sys, 'argv', ['???']))
- log("New process: executable %s, cmd: %s" % (sys.executable, cmd))
- f.write("{pid}.{tid}: {msg}\n".format(pid=os.getpid(), tid=_thread.get_ident(), msg=msg))
+ the_one._write("New process: executable: %s\n" % (sys.executable,))
+ the_one._write("New process: cmd: %s\n" % (cmd,))
+ if hasattr(os, 'getppid'):
+ the_one._write("New process: parent pid: %s\n" % (os.getppid(),))
+
+ return the_one
+
+ def write(self, text, stack=False):
+ """Just like file.write"""
+ cwd = os.getcwd()
+ if cwd != self.cwd:
+ self._write("cwd is now {0!r}\n".format(cwd))
+ self.cwd = cwd
+ self._write(text, stack=stack)
+
+ def _write(self, text, stack=False):
+ """The raw text-writer, so that we can use it ourselves."""
+ tid = _thread.get_ident()
+ for _ in range(4):
+ tid ^= tid >> 4
+ self.outfile.write("{0:5d}.{1:04x}: {2}".format(os.getpid(), tid & 0xFFFF, text))
+ self.outfile.flush()
if stack:
- dump_stack_frames(out=f, skip=1)
+ dump_stack_frames(out=self.outfile, skip=1)
+
+
+def log(msg, stack=False): # pragma: debugging
+ """Write a log message as forcefully as possible."""
+ filename = os.environ.get("COVERAGE_LOG", "tmp/covlog.txt")
+ DebugOutputFile.the_one(filename).write(msg+"\n", stack=stack)
def enable_aspectlib_maybe(): # pragma: debugging
@@ -166,28 +203,9 @@ def enable_aspectlib_maybe(): # pragma: debugging
import aspectlib # pylint: disable=import-error
import aspectlib.debug # pylint: disable=import-error
- class AspectlibOutputFile(object):
- """A file-like object that includes pid and cwd information."""
- def __init__(self, outfile):
- self.outfile = outfile
- self.cwd = None
-
- def write(self, text):
- """Just like file.write"""
- cwd = os.getcwd()
- if cwd != self.cwd:
- self._write("cwd is now {0!r}\n".format(cwd))
- self.cwd = cwd
- self._write(text)
-
- def _write(self, text):
- """The raw text-writer, so that we can use it ourselves."""
- self.outfile.write("{0:5d}: {1}".format(os.getpid(), text))
-
aspects = aspects.split(':')
- aspects_file = AspectlibOutputFile(open(aspects[0], "a"))
+ aspects_file = DebugOutputFile.the_one(aspects[0])
aspect_log = aspectlib.debug.log(print_to=aspects_file, use_logging=False)
- aspects = aspects[1:]
public_methods = re.compile(r'^(__init__|[a-zA-Z].*)$')
- for aspect in aspects:
+ for aspect in aspects[1:]:
aspectlib.weave(aspect, aspect_log, methods=public_methods)