diff -r 61463ff7dc68 Doc/library/logging.handlers.rst --- a/Doc/library/logging.handlers.rst Wed Oct 23 22:03:45 2013 +0200 +++ b/Doc/library/logging.handlers.rst Sun Nov 03 12:29:04 2013 +0200 @@ -77,13 +77,16 @@ :class:`StreamHandler`. -.. class:: FileHandler(filename, mode='a', encoding=None, delay=False) +.. class:: FileHandler(filename, mode='a', encoding=None, delay=False, chown=None) Returns a new instance of the :class:`FileHandler` class. The specified file is opened and used as the stream for logging. If *mode* is not specified, :const:`'a'` is used. If *encoding* is not *None*, it is used to open the file with that encoding. If *delay* is true, then file opening is deferred until the - first call to :meth:`emit`. By default, the file grows indefinitely. + first call to :meth:`emit`. + If *chown* is not *None*, it is used to change the owner and the group of the + specified file. *chown* argument must be a (``username``, ``groupname``) tuple. + By default, the file grows indefinitely. .. method:: close() @@ -95,6 +98,9 @@ Outputs the record to the file. +.. versionadded:: 3.4 + +*chown* argument added. .. _null-handler: diff -r 61463ff7dc68 Lib/logging/__init__.py --- a/Lib/logging/__init__.py Wed Oct 23 22:03:45 2013 +0200 +++ b/Lib/logging/__init__.py Sun Nov 03 12:29:04 2013 +0200 @@ -25,6 +25,7 @@ import sys, os, time, io, traceback, warnings, weakref from string import Template +import shutil __all__ = ['BASIC_FORMAT', 'BufferingFormatter', 'CRITICAL', 'DEBUG', 'ERROR', 'FATAL', 'FileHandler', 'Filter', 'Formatter', 'Handler', 'INFO', @@ -962,7 +963,8 @@ """ A handler class which writes formatted logging records to disk files. """ - def __init__(self, filename, mode='a', encoding=None, delay=False): + def __init__(self, filename, mode='a', encoding=None, + delay=False, chown=None): """ Open the specified file and use it as the stream for logging. """ @@ -972,6 +974,7 @@ self.mode = mode self.encoding = encoding self.delay = delay + self.chown = chown if delay: #We don't open the stream, but we still need to call the #Handler constructor to set level, formatter, lock etc. @@ -1000,6 +1003,10 @@ Open the current base file with the (original) mode and encoding. Return the resulting stream. """ + if self.chown is not None: + shutil.chown(self.baseFilename, + self.chown[0], + self.chown[1]) return open(self.baseFilename, self.mode, encoding=self.encoding) def emit(self, record): diff -r 61463ff7dc68 Lib/test/test_logging.py --- a/Lib/test/test_logging.py Wed Oct 23 22:03:45 2013 +0200 +++ b/Lib/test/test_logging.py Sun Nov 03 12:29:04 2013 +0200 @@ -77,6 +77,12 @@ import zlib except ImportError: pass +try: + import grp + import pwd + UID_GID_SUPPORT = True +except ImportError: + UID_GID_SUPPORT = False class BaseTest(unittest.TestCase): @@ -3833,6 +3839,24 @@ self.assertTrue(os.path.exists(self.fn)) fh.close() + @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support") + @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown') + def test_chown(self): + def check_chown(path, uid=None, gid=None): + s = os.stat(path) + if uid is not None: + self.assertEqual(uid, s.st_uid) + if gid is not None: + self.assertEqual(gid, s.st_gid) + + uid = os.getuid() + gid = os.getgid() + user = pwd.getpwuid(uid)[0] + group = grp.getgrgid(gid)[0] + fh = logging.FileHandler(self.fn, chown=(user, group)) + self.addCleanup(fh.close) + check_chown(self.fn, uid, gid) + class RotatingFileHandlerTest(BaseFileTest): def next_rec(self): return logging.LogRecord('n', logging.DEBUG, 'p', 1,