mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +00:00 
			
		
		
		
	bpo-42378: fixed log truncation on logging shutdown (GH-27310)
Automerge-Triggered-By: GH:vsajip
This commit is contained in:
		
							parent
							
								
									9751f85914
								
							
						
					
					
						commit
						96cf5a63d2
					
				
					 4 changed files with 32 additions and 6 deletions
				
			
		|  | @ -117,6 +117,9 @@ sends logging output to a disk file.  It inherits the output functionality from | ||||||
| 
 | 
 | ||||||
|       Outputs the record to the file. |       Outputs the record to the file. | ||||||
| 
 | 
 | ||||||
|  |       Note that if the file was closed due to logging shutdown at exit and the file | ||||||
|  |       mode is 'w', the record will not be emitted (see :issue:`42378`). | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| .. _null-handler: | .. _null-handler: | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -882,6 +882,7 @@ def __init__(self, level=NOTSET): | ||||||
|         self._name = None |         self._name = None | ||||||
|         self.level = _checkLevel(level) |         self.level = _checkLevel(level) | ||||||
|         self.formatter = None |         self.formatter = None | ||||||
|  |         self._closed = False | ||||||
|         # Add the handler to the global _handlerList (for cleanup on shutdown) |         # Add the handler to the global _handlerList (for cleanup on shutdown) | ||||||
|         _addHandlerRef(self) |         _addHandlerRef(self) | ||||||
|         self.createLock() |         self.createLock() | ||||||
|  | @ -1000,6 +1001,7 @@ def close(self): | ||||||
|         #get the module data lock, as we're updating a shared structure. |         #get the module data lock, as we're updating a shared structure. | ||||||
|         _acquireLock() |         _acquireLock() | ||||||
|         try:    #unlikely to raise an exception, but you never know... |         try:    #unlikely to raise an exception, but you never know... | ||||||
|  |             self._closed = True | ||||||
|             if self._name and self._name in _handlers: |             if self._name and self._name in _handlers: | ||||||
|                 del _handlers[self._name] |                 del _handlers[self._name] | ||||||
|         finally: |         finally: | ||||||
|  | @ -1188,6 +1190,8 @@ def close(self): | ||||||
|             finally: |             finally: | ||||||
|                 # Issue #19523: call unconditionally to |                 # Issue #19523: call unconditionally to | ||||||
|                 # prevent a handler leak when delay is set |                 # prevent a handler leak when delay is set | ||||||
|  |                 # Also see Issue #42378: we also rely on | ||||||
|  |                 # self._closed being set to True there | ||||||
|                 StreamHandler.close(self) |                 StreamHandler.close(self) | ||||||
|         finally: |         finally: | ||||||
|             self.release() |             self.release() | ||||||
|  | @ -1207,9 +1211,14 @@ def emit(self, record): | ||||||
| 
 | 
 | ||||||
|         If the stream was not opened because 'delay' was specified in the |         If the stream was not opened because 'delay' was specified in the | ||||||
|         constructor, open it before calling the superclass's emit. |         constructor, open it before calling the superclass's emit. | ||||||
|  | 
 | ||||||
|  |         If stream is not open, current mode is 'w' and `_closed=True`, record | ||||||
|  |         will not be emitted (see Issue #42378). | ||||||
|         """ |         """ | ||||||
|         if self.stream is None: |         if self.stream is None: | ||||||
|  |             if self.mode != 'w' or not self._closed: | ||||||
|                 self.stream = self._open() |                 self.stream = self._open() | ||||||
|  |         if self.stream: | ||||||
|             StreamHandler.emit(self, record) |             StreamHandler.emit(self, record) | ||||||
| 
 | 
 | ||||||
|     def __repr__(self): |     def __repr__(self): | ||||||
|  |  | ||||||
|  | @ -5174,6 +5174,9 @@ def assertLogFile(self, filename): | ||||||
|                         msg="Log file %r does not exist" % filename) |                         msg="Log file %r does not exist" % filename) | ||||||
|         self.rmfiles.append(filename) |         self.rmfiles.append(filename) | ||||||
| 
 | 
 | ||||||
|  |     def next_rec(self): | ||||||
|  |         return logging.LogRecord('n', logging.DEBUG, 'p', 1, | ||||||
|  |                                  self.next_message(), None, None, None) | ||||||
| 
 | 
 | ||||||
| class FileHandlerTest(BaseFileTest): | class FileHandlerTest(BaseFileTest): | ||||||
|     def test_delay(self): |     def test_delay(self): | ||||||
|  | @ -5186,11 +5189,18 @@ def test_delay(self): | ||||||
|         self.assertTrue(os.path.exists(self.fn)) |         self.assertTrue(os.path.exists(self.fn)) | ||||||
|         fh.close() |         fh.close() | ||||||
| 
 | 
 | ||||||
| class RotatingFileHandlerTest(BaseFileTest): |     def test_emit_after_closing_in_write_mode(self): | ||||||
|     def next_rec(self): |         # Issue #42378 | ||||||
|         return logging.LogRecord('n', logging.DEBUG, 'p', 1, |         os.unlink(self.fn) | ||||||
|                                  self.next_message(), None, None, None) |         fh = logging.FileHandler(self.fn, encoding='utf-8', mode='w') | ||||||
|  |         fh.setFormatter(logging.Formatter('%(message)s')) | ||||||
|  |         fh.emit(self.next_rec())    # '1' | ||||||
|  |         fh.close() | ||||||
|  |         fh.emit(self.next_rec())    # '2' | ||||||
|  |         with open(self.fn) as fp: | ||||||
|  |             self.assertEqual(fp.read().strip(), '1') | ||||||
| 
 | 
 | ||||||
|  | class RotatingFileHandlerTest(BaseFileTest): | ||||||
|     def test_should_not_rollover(self): |     def test_should_not_rollover(self): | ||||||
|         # If maxbytes is zero rollover never occurs |         # If maxbytes is zero rollover never occurs | ||||||
|         rh = logging.handlers.RotatingFileHandler( |         rh = logging.handlers.RotatingFileHandler( | ||||||
|  |  | ||||||
|  | @ -0,0 +1,4 @@ | ||||||
|  | Fixes the issue with log file being overwritten when | ||||||
|  | :class:`logging.FileHandler` is used in :mod:`atexit` with *filemode* set to | ||||||
|  | ``'w'``. Note this will cause the message in *atexit* not being logged if | ||||||
|  | the log stream is already closed due to shutdown of logging. | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 andrei kulakov
						andrei kulakov