diff --git a/tailor.py b/tailor.py index a35cf45..4378ed1 100755 --- a/tailor.py +++ b/tailor.py @@ -6,13 +6,15 @@ u"""Afficher les lignes d'un fichier en mettant en surbrillance certains pattern import sys, subprocess, re from collections import OrderedDict -def bluef(line, *ignored): return '\x1B[34m%s\x1B[0m' % line -def greenf(line, *ignored): return '\x1B[32m%s\x1B[0m' % line -def yellowf(line, *ignored): return '\x1B[33m%s\x1B[0m' % line -def redf(line, *ignored): return '\x1B[31m%s\x1B[0m' % line -def nonef(line, *ignored): return re.sub('\x1B\[.*?m', '', line) +def fixnlf(line, mo): return re.sub(r'\\n', '\n', line) +def bluef(line, mo): return '\x1B[34m%s\x1B[0m' % line +def greenf(line, mo): return '\x1B[32m%s\x1B[0m' % line +def yellowf(line, mo): return '\x1B[33m%s\x1B[0m' % line +def redf(line, mo): return '\x1B[31m%s\x1B[0m' % line +def nonef(line, mo): return re.sub('\x1B\[.*?m', '', line) FORMATS = OrderedDict([ + ('fixnl', fixnlf), ('blue', bluef), ('green', greenf), ('yellow', yellowf), @@ -20,6 +22,7 @@ FORMATS = OrderedDict([ ('none', nonef), ]) FORMAT_ALIASES = { + 'f': 'fixnl', 'b': 'blue', 'g': 'green', 'y': 'yellow', @@ -27,30 +30,35 @@ FORMAT_ALIASES = { '': 'none', } -APACHE_PATTERNS = OrderedDict([ +DEFAULT_PATTERNS = OrderedDict([ (r'(?i)error', redf), (r'(?i)warn(ing)?', yellowf), (r'(?i)info', bluef), (None, nonef), ]) -PHP_PATTERNS = OrderedDict([ - (r'(?i)php fatal error', redf), - (r'(?i)php notice', yellowf), - (r'(?i)php warning', bluef), - (None, nonef), -]) + +APACHE_PATTERNS = [ + r'(?i)error:red', + r'(?i)warn(ing)?:yellow', + r'(?i)info:blue', + r':none', +] +PHP_PATTERNS = [ + r'(?i)php fatal error:fixnl,red', + r'(?i)php notice:yellow,fixnl', + r'(?i)php warning:fixnl,blue', + r':fixnl,none', +] PRESETS = { - 'apache': ('/var/log/apache2/error.log', True, APACHE_PATTERNS), - 'php': ('/var/log/apache2/error.log', True, PHP_PATTERNS), + 'apache': ('/var/log/apache2/error.log', True, APACHE_PATTERNS, False), + 'php': ('/var/log/apache2/error.log', True, PHP_PATTERNS, False), } PRESET_ALIASES = { 'a': 'apache', 'p': 'php', } -DEFAULT_PATTERNS = APACHE_PATTERNS - def strip_nl(s): if s is None: return None elif s.endswith("\r\n"): s = s[:-2] @@ -146,7 +154,7 @@ Les lignes qui ne correspondent à aucun pattern ne sont pas affichées.""" % pa default_patterns = [u"%s:%s" % (p or '', f.__name__[:-1]) for (p, f) in DEFAULT_PATTERNS.items()] no_defaults_vars = dict(default_patterns='\n'.join([u">>> %s" % pattern for pattern in default_patterns])) no_defaults_help = u"""\ -Ne pas ajouter les patterns par défaut. Sans cette option, les patterns par défaut sont: +Ne pas ajouter les patterns par défaut à ceux définis par l'option --pattern. Sans cette option, les patterns par défaut sont: %(default_patterns)s""" % no_defaults_vars follow_help = u"""Suivre le contenu du fichier spécifié""" presets_help = u"""Utiliser un ensemble prédéfini de paramètres. @@ -165,6 +173,7 @@ Si cet argument n'est pas spécifié, l'entrée standard est utilisée comme sou AP.set_defaults(inputfile=None, follow=False, patterns=None, defaults=True, presets=None) AP.add_argument('-e', '--pattern', action='append', dest='patterns', metavar='PATTERN:FORMAT', help=pattern_help) AP.add_argument('-z', '--no-defaults', action='store_false', dest='defaults', help=no_defaults_help) + AP.add_argument('-d', '--defaults', action='store_true', dest='defaults', help=no_defaults_help) AP.add_argument('-f', '--follow', action='store_true', dest='follow', help=follow_help) AP.add_argument('-p', '--presets', action='store', dest='presets', help=presets_help) AP.add_argument('inputfile', metavar='INPUTFILE', nargs='?', help=inputfile_help) @@ -174,29 +183,38 @@ Si cet argument n'est pas spécifié, l'entrée standard est utilisée comme sou presets = PRESET_ALIASES.get(o.presets, o.presets) if presets not in PRESETS: raise ValueError("%s: argument invalide" % presets) - inputfile, follow, patterns = PRESETS.get(presets) + inputfile, follow, opatterns, odefaults = PRESETS.get(presets) else: - inputfile, follow, patterns = o.inputfile, o.follow, o.patterns + inputfile, follow, opatterns, odefaults = o.inputfile, o.follow, o.patterns, o.defaults - if patterns is None: + if opatterns is None: patterns = DEFAULT_PATTERNS - elif o.patterns is not None: + else: patterns = OrderedDict() - for pf in o.patterns: - mo = re.match('(.*):([a-zA-Z]*)$', pf) + for pf in opatterns: + mo = re.match('(.*):([a-zA-Z,]*)$', pf) if mo is not None: p = mo.group(1) - of = mo.group(2) + ofs = mo.group(2) else: p = pf - of = 'red' + ofs = 'red' if p == '': p = None - f = of.lower() - f = FORMAT_ALIASES.get(f, f) - if f not in FORMATS: - raise ValueError("%s: format invalide" % of) - patterns[p] = FORMATS[f] - if o.defaults: + ofs = filter(None, ofs.lower().split(',')) + fs = None + for of in ofs: + f = FORMAT_ALIASES.get(of, of) + if f not in FORMATS: + raise ValueError("%s: format invalide" % of) + f = FORMATS[f] + if fs is None: + fs = f + else: + def wrapf(line, mo, curf=f, prevf=fs): + return curf(prevf(line, mo)) + fs = wrapf + patterns[p] = fs + if odefaults: for p, f in DEFAULT_PATTERNS.items(): patterns.setdefault(p, f)