mercurial/loggingutil.py
changeset 43076 2372284d9457
parent 40821 96be0ecad648
child 43077 687b865b95ad
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
     8 
     8 
     9 from __future__ import absolute_import
     9 from __future__ import absolute_import
    10 
    10 
    11 import errno
    11 import errno
    12 
    12 
    13 from . import (
    13 from . import pycompat
    14     pycompat,
       
    15 )
       
    16 
    14 
    17 from .utils import (
    15 from .utils import (
    18     dateutil,
    16     dateutil,
    19     procutil,
    17     procutil,
    20     stringutil,
    18     stringutil,
    21 )
    19 )
    22 
    20 
       
    21 
    23 def openlogfile(ui, vfs, name, maxfiles=0, maxsize=0):
    22 def openlogfile(ui, vfs, name, maxfiles=0, maxsize=0):
    24     """Open log file in append mode, with optional rotation
    23     """Open log file in append mode, with optional rotation
    25 
    24 
    26     If maxsize > 0, the log file will be rotated up to maxfiles.
    25     If maxsize > 0, the log file will be rotated up to maxfiles.
    27     """
    26     """
       
    27 
    28     def rotate(oldpath, newpath):
    28     def rotate(oldpath, newpath):
    29         try:
    29         try:
    30             vfs.unlink(newpath)
    30             vfs.unlink(newpath)
    31         except OSError as err:
    31         except OSError as err:
    32             if err.errno != errno.ENOENT:
    32             if err.errno != errno.ENOENT:
    33                 ui.debug("warning: cannot remove '%s': %s\n" %
    33                 ui.debug(
    34                          (newpath, err.strerror))
    34                     "warning: cannot remove '%s': %s\n"
       
    35                     % (newpath, err.strerror)
       
    36                 )
    35         try:
    37         try:
    36             if newpath:
    38             if newpath:
    37                 vfs.rename(oldpath, newpath)
    39                 vfs.rename(oldpath, newpath)
    38         except OSError as err:
    40         except OSError as err:
    39             if err.errno != errno.ENOENT:
    41             if err.errno != errno.ENOENT:
    40                 ui.debug("warning: cannot rename '%s' to '%s': %s\n" %
    42                 ui.debug(
    41                          (newpath, oldpath, err.strerror))
    43                     "warning: cannot rename '%s' to '%s': %s\n"
       
    44                     % (newpath, oldpath, err.strerror)
       
    45                 )
    42 
    46 
    43     if maxsize > 0:
    47     if maxsize > 0:
    44         try:
    48         try:
    45             st = vfs.stat(name)
    49             st = vfs.stat(name)
    46         except OSError:
    50         except OSError:
    47             pass
    51             pass
    48         else:
    52         else:
    49             if st.st_size >= maxsize:
    53             if st.st_size >= maxsize:
    50                 path = vfs.join(name)
    54                 path = vfs.join(name)
    51                 for i in pycompat.xrange(maxfiles - 1, 1, -1):
    55                 for i in pycompat.xrange(maxfiles - 1, 1, -1):
    52                     rotate(oldpath='%s.%d' % (path, i - 1),
    56                     rotate(
    53                            newpath='%s.%d' % (path, i))
    57                         oldpath='%s.%d' % (path, i - 1),
    54                 rotate(oldpath=path,
    58                         newpath='%s.%d' % (path, i),
    55                        newpath=maxfiles > 0 and path + '.1')
    59                     )
       
    60                 rotate(oldpath=path, newpath=maxfiles > 0 and path + '.1')
    56     return vfs(name, 'a', makeparentdirs=False)
    61     return vfs(name, 'a', makeparentdirs=False)
       
    62 
    57 
    63 
    58 def _formatlogline(msg):
    64 def _formatlogline(msg):
    59     date = dateutil.datestr(format=b'%Y/%m/%d %H:%M:%S')
    65     date = dateutil.datestr(format=b'%Y/%m/%d %H:%M:%S')
    60     pid = procutil.getpid()
    66     pid = procutil.getpid()
    61     return b'%s (%d)> %s' % (date, pid, msg)
    67     return b'%s (%d)> %s' % (date, pid, msg)
    62 
    68 
       
    69 
    63 def _matchevent(event, tracked):
    70 def _matchevent(event, tracked):
    64     return b'*' in tracked or event in tracked
    71     return b'*' in tracked or event in tracked
       
    72 
    65 
    73 
    66 class filelogger(object):
    74 class filelogger(object):
    67     """Basic logger backed by physical file with optional rotation"""
    75     """Basic logger backed by physical file with optional rotation"""
    68 
    76 
    69     def __init__(self, vfs, name, tracked, maxfiles=0, maxsize=0):
    77     def __init__(self, vfs, name, tracked, maxfiles=0, maxsize=0):
    77         return _matchevent(event, self._trackedevents)
    85         return _matchevent(event, self._trackedevents)
    78 
    86 
    79     def log(self, ui, event, msg, opts):
    87     def log(self, ui, event, msg, opts):
    80         line = _formatlogline(msg)
    88         line = _formatlogline(msg)
    81         try:
    89         try:
    82             with openlogfile(ui, self._vfs, self._name,
    90             with openlogfile(
    83                              maxfiles=self._maxfiles,
    91                 ui,
    84                              maxsize=self._maxsize) as fp:
    92                 self._vfs,
       
    93                 self._name,
       
    94                 maxfiles=self._maxfiles,
       
    95                 maxsize=self._maxsize,
       
    96             ) as fp:
    85                 fp.write(line)
    97                 fp.write(line)
    86         except IOError as err:
    98         except IOError as err:
    87             ui.debug(b'cannot write to %s: %s\n'
    99             ui.debug(
    88                      % (self._name, stringutil.forcebytestr(err)))
   100                 b'cannot write to %s: %s\n'
       
   101                 % (self._name, stringutil.forcebytestr(err))
       
   102             )
       
   103 
    89 
   104 
    90 class fileobjectlogger(object):
   105 class fileobjectlogger(object):
    91     """Basic logger backed by file-like object"""
   106     """Basic logger backed by file-like object"""
    92 
   107 
    93     def __init__(self, fp, tracked):
   108     def __init__(self, fp, tracked):
   101         line = _formatlogline(msg)
   116         line = _formatlogline(msg)
   102         try:
   117         try:
   103             self._fp.write(line)
   118             self._fp.write(line)
   104             self._fp.flush()
   119             self._fp.flush()
   105         except IOError as err:
   120         except IOError as err:
   106             ui.debug(b'cannot write to %s: %s\n'
   121             ui.debug(
   107                      % (stringutil.forcebytestr(self._fp.name),
   122                 b'cannot write to %s: %s\n'
   108                         stringutil.forcebytestr(err)))
   123                 % (
       
   124                     stringutil.forcebytestr(self._fp.name),
       
   125                     stringutil.forcebytestr(err),
       
   126                 )
       
   127             )
       
   128 
   109 
   129 
   110 class proxylogger(object):
   130 class proxylogger(object):
   111     """Forward log events to another logger to be set later"""
   131     """Forward log events to another logger to be set later"""
   112 
   132 
   113     def __init__(self):
   133     def __init__(self):