loggingutil: add basic logger backends
authorYuya Nishihara <yuya@tcha.org>
Sun, 18 Nov 2018 18:58:06 +0900
changeset 53586 96be0ecad6485c616fec15ac8debfbadcb6c22a4
parent 53585 cb372d09d30a94f220624fe64c5a0dfd20733305
child 53587 6a75363f834a299b85ad88dd2e96ca61804fc232
push id1079
push usergszorc@mozilla.com
push dateMon, 10 Dec 2018 19:44:59 +0000
loggingutil: add basic logger backends These classes will be used in command server. They are similar to the blackboxlogger, but it can't be factored out since the blackbox is so tightly coupled with a repo object.
mercurial/loggingutil.py
--- a/mercurial/loggingutil.py
+++ b/mercurial/loggingutil.py
@@ -9,16 +9,22 @@
 from __future__ import absolute_import
 
 import errno
 
 from . import (
     pycompat,
 )
 
+from .utils import (
+    dateutil,
+    procutil,
+    stringutil,
+)
+
 def openlogfile(ui, vfs, name, maxfiles=0, maxsize=0):
     """Open log file in append mode, with optional rotation
 
     If maxsize > 0, the log file will be rotated up to maxfiles.
     """
     def rotate(oldpath, newpath):
         try:
             vfs.unlink(newpath)
@@ -44,16 +50,68 @@ def openlogfile(ui, vfs, name, maxfiles=
                 path = vfs.join(name)
                 for i in pycompat.xrange(maxfiles - 1, 1, -1):
                     rotate(oldpath='%s.%d' % (path, i - 1),
                            newpath='%s.%d' % (path, i))
                 rotate(oldpath=path,
                        newpath=maxfiles > 0 and path + '.1')
     return vfs(name, 'a', makeparentdirs=False)
 
+def _formatlogline(msg):
+    date = dateutil.datestr(format=b'%Y/%m/%d %H:%M:%S')
+    pid = procutil.getpid()
+    return b'%s (%d)> %s' % (date, pid, msg)
+
+def _matchevent(event, tracked):
+    return b'*' in tracked or event in tracked
+
+class filelogger(object):
+    """Basic logger backed by physical file with optional rotation"""
+
+    def __init__(self, vfs, name, tracked, maxfiles=0, maxsize=0):
+        self._vfs = vfs
+        self._name = name
+        self._trackedevents = set(tracked)
+        self._maxfiles = maxfiles
+        self._maxsize = maxsize
+
+    def tracked(self, event):
+        return _matchevent(event, self._trackedevents)
+
+    def log(self, ui, event, msg, opts):
+        line = _formatlogline(msg)
+        try:
+            with openlogfile(ui, self._vfs, self._name,
+                             maxfiles=self._maxfiles,
+                             maxsize=self._maxsize) as fp:
+                fp.write(line)
+        except IOError as err:
+            ui.debug(b'cannot write to %s: %s\n'
+                     % (self._name, stringutil.forcebytestr(err)))
+
+class fileobjectlogger(object):
+    """Basic logger backed by file-like object"""
+
+    def __init__(self, fp, tracked):
+        self._fp = fp
+        self._trackedevents = set(tracked)
+
+    def tracked(self, event):
+        return _matchevent(event, self._trackedevents)
+
+    def log(self, ui, event, msg, opts):
+        line = _formatlogline(msg)
+        try:
+            self._fp.write(line)
+            self._fp.flush()
+        except IOError as err:
+            ui.debug(b'cannot write to %s: %s\n'
+                     % (stringutil.forcebytestr(self._fp.name),
+                        stringutil.forcebytestr(err)))
+
 class proxylogger(object):
     """Forward log events to another logger to be set later"""
 
     def __init__(self):
         self.logger = None
 
     def tracked(self, event):
         return self.logger is not None and self.logger.tracked(event)