[PATCH] ui: add optional timestamp to output
Augie Fackler
raf at durin42.com
Tue Apr 11 10:15:50 EDT 2017
On Tue, Apr 11, 2017 at 10:50:08PM +0900, Matthieu Laneuville wrote:
> # HG changeset patch
> # User Matthieu Laneuville <mlaneuville at gmail.com>
> # Date 1489110756 -32400
> # Fri Mar 10 10:52:36 2017 +0900
> # Node ID f7c69a6deb56c856f6896f4f318fb125c3c5da37
> # Parent 7433b3bc55eebfa9149280339b406bd4cec64efb
> ui: add optional timestamp to output
I'm missing some context. Why do we want timestamps in our output like this?
>
> This patch adds the possibility of having a timestamp prepended to every line.
> For now, the feature is controled by an experimental config flag
> 'debug-timestamp' and format can be changed with debug-timestamp-format (default
> is %H:%M:%S.%f).
>
> The feature is still experimental because is still needs:
> * win32 support,
> * buffer support,
> * label for the timestamp,
> * a final UI.
>
> A possible final UI would be to trigger this when combining '--debug' with
> '--time' or maybe '--debug' and '--profile'. For now we focus on the
> implementation.
>
> diff -r 7433b3bc55ee -r f7c69a6deb56 mercurial/ui.py
> --- a/mercurial/ui.py Mon Mar 06 23:21:27 2017 -0800
> +++ b/mercurial/ui.py Fri Mar 10 10:52:36 2017 +0900
> @@ -164,6 +164,8 @@ class ui(object):
> self._colormode = None
> self._terminfoparams = {}
> self._styles = {}
> + # keeps track of lines start in _prependtimestamp
> + self._startline = {'std':True, 'err':True}
>
> if src:
> self.fout = src.fout
> @@ -788,6 +790,32 @@ class ui(object):
>
> return "".join(self._buffers.pop())
>
> + def _timestampprefix(self):
> + """Checks config if timestamp prefix should be used and return
> + format.
> + """
> + if not self.configbool("experimental", "debug-timestamp"):
> + return None
> + return self.config("experimental", "debug-timestamp-format",
> + default="%H:%M:%S.f")
> +
> + def _prependtimestamp(self, args, tsformat, stream):
> + """Adds timestamp at the beginning of new lines. Both stdout and stderr
> + streams are tracked separately.
> + """
> + timestamp = util.datestr(format=tsformat)
> + timestamp = self.label(timestamp, 'debug.timestamp.stdout')
> + timestamp += ' '
> + msgs = []
> + for element in args:
> + for piece in element.splitlines(True):
> + if self._startline[stream]:
> + msgs.append(timestamp)
> + msgs.append(piece)
> + self._startline[stream] = piece.endswith('\n')
> +
> + return msgs
> +
> def write(self, *args, **opts):
> '''write args to output
>
> @@ -804,6 +832,7 @@ class ui(object):
> "cmdname.type" is recommended. For example, status issues
> a label of "status.modified" for modified files.
> '''
> + tsformat = self._timestampprefix()
> if self._buffers and not opts.get('prompt', False):
> if self._bufferapplylabels:
> label = opts.get('label', '')
> @@ -819,6 +848,8 @@ class ui(object):
> if self._colormode is not None:
> label = opts.get('label', '')
> msgs = [self.label(a, label) for a in args]
> + if tsformat is not None:
> + msgs = self._prependtimestamp(msgs, tsformat, 'std')
> self._write(*msgs, **opts)
>
> def _write(self, *msgs, **opts):
> @@ -833,6 +864,7 @@ class ui(object):
> (util.timer() - starttime) * 1000
>
> def write_err(self, *args, **opts):
> + tsformat = self._timestampprefix()
> self._progclear()
> if self._bufferstates and self._bufferstates[-1][0]:
> self.write(*args, **opts)
> @@ -845,6 +877,8 @@ class ui(object):
> if self._colormode is not None:
> label = opts.get('label', '')
> msgs = [self.label(a, label) for a in args]
> + if tsformat is not None:
> + msgs = self._prependtimestamp(msgs, tsformat, 'err')
> self._write_err(*msgs, **opts)
>
> def _write_err(self, *msgs, **opts):
> diff -r 7433b3bc55ee -r f7c69a6deb56 tests/test-debug-timestamp.t
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/tests/test-debug-timestamp.t Fri Mar 10 10:52:36 2017 +0900
> @@ -0,0 +1,142 @@
> + $ hg init
> + $ touch a
> + $ touch b
> +
> +Checking when the feature is disabled
> +
> + $ hg status --config experimental.debug-timestamp=False
> + ? a
> + ? b
> +
> +Now after enabling it
> +
> + $ cat >> $HGRCPATH << EOF
> + > [experimental]
> + > debug-timestamp=True
> + > debug-timestamp-format=%H:%M
> + > EOF
> +
> +Create an extension to test all cases
> +
> + $ cat > $TESTTMP/foocommand.py << EOF
> + > from mercurial import cmdutil
> + > cmdtable = {}
> + > command = cmdutil.command(cmdtable)
> + >
> + > @command('testsinglestdout', [])
> + > def testsinglestdout(ui, repo):
> + > '''One stdout'''
> + > ui.write("stdout\n")
> + >
> + > @command('testsinglestderr', [])
> + > def testsinglestderr(ui, repo):
> + > '''One stderr'''
> + > ui.write_err("stderr\n")
> + >
> + > @command('testmultiplestdout', [])
> + > def testmultiplestdout(ui, repo):
> + > '''Multiple stdout, either multiple messages or multiple calls.'''
> + > ui.write("stdout1\n")
> + > ui.write("stdout2\n")
> + > ui.write("stdout3\n", "stdout4\n")
> + >
> + > @command('testmultiplestderr', [])
> + > def testsmultiplestderr(ui, repo):
> + > '''Multiple stderr, either multiple messages or multiple calls.'''
> + > ui.write_err("stderr1\n")
> + > ui.write_err("stderr2\n")
> + > ui.write_err("stderr3\n", "stderr4\n")
> + >
> + > @command('teststdnewline', [])
> + > def teststdnewline(ui, repo):
> + > '''stdout with multiple newlines in a message.'''
> + > ui.write("stdout1\nstdout2\n")
> + >
> + > @command('testerrnewline', [])
> + > def testerrnewline(ui, repo):
> + > '''stderr with multiple newlines in a message.'''
> + > ui.write_err("stderr1\nstderr2\n")
> + >
> + > @command('testouterr', [])
> + > def testouterr(ui, repo):
> + > '''Test both flux in sequence.'''
> + > ui.write("stdout1\n")
> + > ui.write_err("stderr1\n")
> + > ui.write("stdout2\n")
> + >
> + > @command('testinterleaved', [])
> + > def testinterleaved(ui, repo):
> + > '''Test interleaved fluxes.'''
> + > ui.write("stdout1 ")
> + > ui.write_err("stderr1\n")
> + > ui.write("stdout2 ")
> + > ui.write_err("stderr2\n")
> + > ui.write("stdout3\n")
> + >
> + > @command('testnewline2', [])
> + > def testsnewline(ui, repo):
> + > '''Multiple messages with and without newlines.'''
> + > ui.write("stdout1 ", "stdout2\n", "stdout3\n")
> + >
> + > @command('testnewline3', [])
> + > def testsnewline(ui, repo):
> + > '''Multiple calls with and without newlines.'''
> + > ui.write("stdout1 ")
> + > ui.write("stdout2\n")
> + > ui.write("stdout3\n")
> + > EOF
> +
> +Add extension to hgrc
> +
> + $ cat >> $HGRCPATH << EOF
> + > [extensions]
> + > foocommand=$TESTTMP/foocommand.py
> + > EOF
> +
> +Now test all cases
> +
> + $ hg testsinglestdout
> + *:* stdout (glob)
> +
> + $ hg testmultiplestdout
> + *:* stdout1 (glob)
> + *:* stdout2 (glob)
> + *:* stdout3 (glob)
> + *:* stdout4 (glob)
> +
> + $ hg testsinglestderr
> + *:* stderr (glob)
> +
> + $ hg testmultiplestderr
> + *:* stderr1 (glob)
> + *:* stderr2 (glob)
> + *:* stderr3 (glob)
> + *:* stderr4 (glob)
> +
> + $ hg teststdnewline
> + *:* stdout1 (glob)
> + *:* stdout2 (glob)
> +
> + $ hg testerrnewline
> + *:* stderr1 (glob)
> + *:* stderr2 (glob)
> +
> + $ hg testnewline2
> + *:* stdout1 stdout2 (glob)
> + *:* stdout3 (glob)
> +
> + $ hg testnewline3
> + *:* stdout1 stdout2 (glob)
> + *:* stdout3 (glob)
> +
> + $ hg testouterr
> + *:* stdout1 (glob)
> + *:* stderr1 (glob)
> + *:* stdout2 (glob)
> +
> + $ hg testinterleaved 2> stderr.log
> + *:* stdout1 stdout2 stdout3 (glob)
> +
> + $ cat stderr.log
> + *:* stderr1 (glob)
> + *:* stderr2 (glob)
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
More information about the Mercurial-devel
mailing list