import time, logging, sys, traceback, os, shutil, io from threading import Thread testdurationsecs = 10 threadcount = 4 linesperiteration = 50 log = logging.getLogger('mylogger') log.setLevel(logging.INFO) logging.getLogger().addHandler(logging.NullHandler()) OUTPUT_DIR = 'output-logger-race' if os.path.exists(OUTPUT_DIR): shutil.rmtree(OUTPUT_DIR) os.makedirs(OUTPUT_DIR) endtime = time.time()+testdurationsecs def mythread(threadid): try: it = 0 while time.time()< endtime: it += 1 filenames = [OUTPUT_DIR+'/thread-%s-it%05d-A.log'%(threadid, it)] h1 = logging.FileHandler(filenames[0]) log.addHandler(h1) s2 = io.StringIO() h2 = logging.StreamHandler(s2) log.addHandler(h2) for i in range(linesperiteration): log.info('Log line: thread-%s %04d.'%(threadid, i+1)) # removing handlers on this thread can mess up callHandlers() from other threads log.removeHandler(h1) log.removeHandler(h2) # check all lines were written errors = [] for fn in filenames: with open(fn) as f: contents = f.read() for i in range(linesperiteration): if ('Log line: thread-%s %04d.'%(threadid, i+1)) not in contents: errors.append('%s is missing line %d'%(fn, i)) if errors: sys.stderr.write('%d errors: %s\n'%(len(errors), '\n '.join(errors))) #raise Exception('Got %d errors: %s\n'%(len(errors), '\n '.join(errors))) for fn in filenames: try: os.remove(fn) except Exception: # try to cleanup, but windows file locking means this sometimes fails, and don't care pass #if not errors: sys.stderr.write('PASSED - %s iteration %s\n'%(threadid, it)) print('Thread finished after %d iterations'%it) except Exception as e: sys.stderr.write('\n%s Failed with exception: %s\n'%(threadid, repr(e))) traceback.print_exc() sys.exit(100) for t in range(threadcount): t = Thread(target = mythread, args=['thread%02d'%(t+1)]) t.start()