##// END OF EJS Templates
logtoprocess: extract logger class from ui wrapper...
Yuya Nishihara -
r40713:2b859742 default
parent child Browse files
Show More
@@ -1,76 +1,100 b''
1 1 # logtoprocess.py - send ui.log() data to a subprocess
2 2 #
3 3 # Copyright 2016 Facebook, Inc.
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7 """send ui.log() data to a subprocess (EXPERIMENTAL)
8 8
9 9 This extension lets you specify a shell command per ui.log() event,
10 10 sending all remaining arguments to as environment variables to that command.
11 11
12 12 Positional arguments construct a log message, which is passed in the `MSG1`
13 13 environment variables. Each keyword argument is set as a `OPT_UPPERCASE_KEY`
14 14 variable (so the key is uppercased, and prefixed with `OPT_`). The original
15 15 event name is passed in the `EVENT` environment variable, and the process ID
16 16 of mercurial is given in `HGPID`.
17 17
18 18 So given a call `ui.log('foo', 'bar %s\n', 'baz', spam='eggs'), a script
19 19 configured for the `foo` event can expect an environment with `MSG1=bar baz`,
20 20 and `OPT_SPAM=eggs`.
21 21
22 22 Scripts are configured in the `[logtoprocess]` section, each key an event name.
23 23 For example::
24 24
25 25 [logtoprocess]
26 26 commandexception = echo "$MSG1" > /var/log/mercurial_exceptions.log
27 27
28 28 would log the warning message and traceback of any failed command dispatch.
29 29
30 30 Scripts are run asynchronously as detached daemon processes; mercurial will
31 31 not ensure that they exit cleanly.
32 32
33 33 """
34 34
35 35 from __future__ import absolute_import
36 36
37 37 import os
38 38
39 39 from mercurial import (
40 40 pycompat,
41 util,
41 42 )
42 43 from mercurial.utils import (
43 44 procutil,
44 45 )
45 46
46 47 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
47 48 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
48 49 # be specifying the version(s) of Mercurial they are tested with, or
49 50 # leave the attribute unspecified.
50 51 testedwith = 'ships-with-hg-core'
51 52
53 class processlogger(object):
54 """Map log events to external commands
55
56 Arguments are passed on as environment variables.
57 """
58
59 def __init__(self, ui):
60 self._scripts = dict(ui.configitems(b'logtoprocess'))
61
62 def tracked(self, event):
63 return bool(self._scripts.get(event))
64
65 def log(self, ui, event, msg, opts):
66 script = self._scripts.get(event)
67 if not script:
68 return
69 env = {
70 b'EVENT': event,
71 b'HGPID': os.getpid(),
72 b'MSG1': msg[0] % msg[1:],
73 }
74 # keyword arguments get prefixed with OPT_ and uppercased
75 env.update((b'OPT_%s' % key.upper(), value)
76 for key, value in pycompat.byteskwargs(opts).items())
77 fullenv = procutil.shellenviron(env)
78 procutil.runbgcommand(script, fullenv, shell=True)
79
52 80 def uisetup(ui):
53 81
54 82 class logtoprocessui(ui.__class__):
55 def log(self, event, *msg, **opts):
56 """Map log events to external commands
57
58 Arguments are passed on as environment variables.
83 def __init__(self, src=None):
84 super(logtoprocessui, self).__init__(src)
85 if src and r'_ltplogger' in src.__dict__:
86 self._ltplogger = src._ltplogger
59 87
60 """
61 script = self.config('logtoprocess', event)
62 if script:
63 env = {
64 b'EVENT': event,
65 b'HGPID': os.getpid(),
66 b'MSG1': msg[0] % msg[1:],
67 }
68 # keyword arguments get prefixed with OPT_ and uppercased
69 env.update((b'OPT_%s' % key.upper(), value)
70 for key, value in pycompat.byteskwargs(opts).items())
71 fullenv = procutil.shellenviron(env)
72 procutil.runbgcommand(script, fullenv, shell=True)
88 # trick to initialize logger after configuration is loaded, which
89 # can be replaced later with processlogger(ui) in uisetup(), where
90 # both user and repo configurations should be available.
91 @util.propertycache
92 def _ltplogger(self):
93 return processlogger(self)
94
95 def log(self, event, *msg, **opts):
96 self._ltplogger.log(self, event, msg, opts)
73 97 return super(logtoprocessui, self).log(event, *msg, **opts)
74 98
75 99 # Replace the class for this instance and all clones created from it:
76 100 ui.__class__ = logtoprocessui
General Comments 0
You need to be logged in to leave comments. Login now