build_logs.py (2824B)
1 #!/usr/bin/env python 2 # encoding: utf-8 3 # Thomas Nagy, 2013 (ita) 4 5 """ 6 A system for recording all outputs to a log file. Just add the following to your wscript file:: 7 8 def init(ctx): 9 ctx.load('build_logs') 10 """ 11 12 import atexit, sys, time, os, shutil, threading 13 from waflib import ansiterm, Logs, Context 14 15 # adding the logs under the build/ directory will clash with the clean/ command 16 try: 17 up = os.path.dirname(Context.g_module.__file__) 18 except AttributeError: 19 up = '.' 20 LOGFILE = os.path.join(up, 'logs', time.strftime('%Y_%m_%d_%H_%M.log')) 21 22 wlock = threading.Lock() 23 class log_to_file(object): 24 def __init__(self, stream, fileobj, filename): 25 self.stream = stream 26 self.encoding = self.stream.encoding 27 self.fileobj = fileobj 28 self.filename = filename 29 self.is_valid = True 30 def replace_colors(self, data): 31 for x in Logs.colors_lst.values(): 32 if isinstance(x, str): 33 data = data.replace(x, '') 34 return data 35 def write(self, data): 36 try: 37 wlock.acquire() 38 self.stream.write(data) 39 self.stream.flush() 40 if self.is_valid: 41 self.fileobj.write(self.replace_colors(data)) 42 finally: 43 wlock.release() 44 def fileno(self): 45 return self.stream.fileno() 46 def flush(self): 47 self.stream.flush() 48 if self.is_valid: 49 self.fileobj.flush() 50 def isatty(self): 51 return self.stream.isatty() 52 53 def init(ctx): 54 global LOGFILE 55 filename = os.path.abspath(LOGFILE) 56 try: 57 os.makedirs(os.path.dirname(os.path.abspath(filename))) 58 except OSError: 59 pass 60 61 if hasattr(os, 'O_NOINHERIT'): 62 fd = os.open(LOGFILE, os.O_CREAT | os.O_TRUNC | os.O_WRONLY | os.O_NOINHERIT) 63 fileobj = os.fdopen(fd, 'w') 64 else: 65 fileobj = open(LOGFILE, 'w') 66 old_stderr = sys.stderr 67 68 # sys.stdout has already been replaced, so __stdout__ will be faster 69 #sys.stdout = log_to_file(sys.stdout, fileobj, filename) 70 #sys.stderr = log_to_file(sys.stderr, fileobj, filename) 71 def wrap(stream): 72 if stream.isatty(): 73 return ansiterm.AnsiTerm(stream) 74 return stream 75 sys.stdout = log_to_file(wrap(sys.__stdout__), fileobj, filename) 76 sys.stderr = log_to_file(wrap(sys.__stderr__), fileobj, filename) 77 78 # now mess with the logging module... 79 for x in Logs.log.handlers: 80 try: 81 stream = x.stream 82 except AttributeError: 83 pass 84 else: 85 if id(stream) == id(old_stderr): 86 x.stream = sys.stderr 87 88 def exit_cleanup(): 89 try: 90 fileobj = sys.stdout.fileobj 91 except AttributeError: 92 pass 93 else: 94 sys.stdout.is_valid = False 95 sys.stderr.is_valid = False 96 fileobj.close() 97 filename = sys.stdout.filename 98 99 Logs.info('Output logged to %r', filename) 100 101 # then copy the log file to "latest.log" if possible 102 up = os.path.dirname(os.path.abspath(filename)) 103 try: 104 shutil.copy(filename, os.path.join(up, 'latest.log')) 105 except OSError: 106 # this may fail on windows due to processes spawned 107 pass 108 109 atexit.register(exit_cleanup) 110