167 lines
4.0 KiB
Python
167 lines
4.0 KiB
Python
import os
|
|
import sys
|
|
import threading
|
|
import time
|
|
|
|
from hydrus.core import HydrusConstants as HC
|
|
|
|
class HydrusLogger( object ):
|
|
|
|
def __init__( self, db_dir, prefix ):
|
|
|
|
self._db_dir = db_dir
|
|
self._prefix = prefix
|
|
|
|
self._lock = threading.Lock()
|
|
|
|
self._log_closed = False
|
|
|
|
self._problem_with_previous_stdout = False
|
|
|
|
self._previous_sys_stdout = None
|
|
self._previous_sys_stderr = None
|
|
|
|
|
|
def __enter__( self ):
|
|
|
|
self._previous_sys_stdout = sys.stdout
|
|
self._previous_sys_stderr = sys.stderr
|
|
|
|
self._problem_with_previous_stdout = False
|
|
|
|
self._OpenLog()
|
|
|
|
sys.stdout = self
|
|
sys.stderr = self
|
|
|
|
return self
|
|
|
|
|
|
def __exit__( self, exc_type, exc_val, exc_tb ):
|
|
|
|
self._CloseLog()
|
|
|
|
sys.stdout = self._previous_sys_stdout
|
|
sys.stderr = self._previous_sys_stderr
|
|
|
|
self._previous_sys_stdout = None
|
|
self._previous_sys_stderr = None
|
|
|
|
self._log_closed = True
|
|
|
|
return False
|
|
|
|
|
|
def _CloseLog( self ) -> None:
|
|
|
|
self._log_file.close()
|
|
|
|
|
|
def _GetLogPath( self ) -> str:
|
|
|
|
current_time_struct = time.localtime()
|
|
|
|
( current_year, current_month ) = ( current_time_struct.tm_year, current_time_struct.tm_mon )
|
|
|
|
log_filename = '{} - {}-{:02}.log'.format( self._prefix, current_year, current_month )
|
|
|
|
log_path = os.path.join( self._db_dir, log_filename )
|
|
|
|
return log_path
|
|
|
|
|
|
def _OpenLog( self ) -> None:
|
|
|
|
self._log_path = self._GetLogPath()
|
|
|
|
is_new_file = not os.path.exists( self._log_path )
|
|
|
|
self._log_file = open( self._log_path, 'a', encoding = 'utf-8' )
|
|
|
|
if is_new_file:
|
|
|
|
self._log_file.write( HC.UNICODE_BYTE_ORDER_MARK ) # Byte Order Mark, BOM, to help reader software interpret this as utf-8
|
|
|
|
|
|
|
|
def _SwitchToANewLogFileIfDue( self ) -> None:
|
|
|
|
correct_log_path = self._GetLogPath()
|
|
|
|
if correct_log_path != self._log_path:
|
|
|
|
self._CloseLog()
|
|
|
|
self._OpenLog()
|
|
|
|
|
|
|
|
def flush( self ) -> None:
|
|
|
|
if self._log_closed:
|
|
|
|
return
|
|
|
|
|
|
with self._lock:
|
|
|
|
if not self._problem_with_previous_stdout:
|
|
|
|
try:
|
|
|
|
self._previous_sys_stdout.flush()
|
|
|
|
except IOError:
|
|
|
|
self._problem_with_previous_stdout = True
|
|
|
|
|
|
|
|
self._log_file.flush()
|
|
|
|
self._SwitchToANewLogFileIfDue()
|
|
|
|
|
|
|
|
def isatty( self ) -> bool:
|
|
|
|
return False
|
|
|
|
|
|
def write( self, value ) -> None:
|
|
|
|
if self._log_closed:
|
|
|
|
return
|
|
|
|
|
|
with self._lock:
|
|
|
|
if value in ( '\n', '\n' ):
|
|
|
|
prefix = ''
|
|
|
|
else:
|
|
|
|
prefix = 'v{}, {}: '.format( HC.SOFTWARE_VERSION, time.strftime( '%Y-%m-%d %H:%M:%S' ) )
|
|
|
|
|
|
message = prefix + value
|
|
|
|
if not self._problem_with_previous_stdout:
|
|
|
|
try:
|
|
|
|
self._previous_sys_stdout.write( message )
|
|
|
|
except:
|
|
|
|
self._problem_with_previous_stdout = True
|
|
|
|
|
|
|
|
self._log_file.write( message )
|
|
|
|
|
|
|