Skip to content

Instantly share code, notes, and snippets.

@decatur
Last active July 18, 2021 09:59
Show Gist options
  • Save decatur/a90146b1aaddd679b89a3291adf86b46 to your computer and use it in GitHub Desktop.
Save decatur/a90146b1aaddd679b89a3291adf86b46 to your computer and use it in GitHub Desktop.
So you want your stdout, stderr and logs in a file, but you only know the final log file name somewhere down the road?
"""
So you want your stdout, stderr and logs in a file, but you only know the final log file name somewhere down the road?
"""
import io
import sys
import threading
from pathlib import Path
from typing import IO, cast
class NameChangingStream(io.TextIOBase):
def __init__(self, initial_path: Path):
self.buffer = initial_path.open('w')
self.lock = threading.RLock()
def change_name(self, final_path: Path):
assert self.lock, 'change_name() called twice'
self.lock.acquire()
self.buffer.flush()
self.buffer.close()
final_path = Path(self.buffer.buffer.raw.name).replace(final_path)
self.buffer = final_path.open('a')
self.lock.release()
self.lock = None
def write(self, s):
if self.lock:
self.lock.acquire()
self.buffer.write(s)
self.lock.release()
else:
self.buffer.write(s)
def test_usage():
stream = cast(IO, NameChangingStream(Path('initial.log'))) # https://youtrack.jetbrains.com/issue/PY-23288
sys.stdout = sys.stderr = stream
import logging
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
assert not logger.handlers
handler = logging.StreamHandler(stream)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.info('Hello')
logger.info('World')
if isinstance(stream, NameChangingStream):
stream.change_name(Path('final.log'))
logger.debug('Hello')
logger.debug('World')
print('FooBar')
assert False, 'Goes to Log!'
test_usage()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment