[debug] syntax highlight SQL and RQL debug output

This prevent DBG_RQL and DBG_SQL output to looks like a gigantic blob of white text.

Do this only if we detect that we are in a tty and that pygments is installed.

Closes #17222885

authorLaurent Peuch <cortex@worlddomination.be>
changesetc6f8ca03718f
branchdefault
phasepublic
hiddenno
parent revision#a54037a68b14 [logging] send logs by default to stdout
child revision#6e98699d3a9a [logging/debug] move transaction operations logs from self.debug to DBG_OPS
files modified by this revision
cubicweb/misc/source_highlight.py
cubicweb/server/querier.py
cubicweb/server/sources/__init__.py
cubicweb/server/sources/native.py
# HG changeset patch
# User Laurent Peuch <cortex@worlddomination.be>
# Date 1566346212 -7200
# Wed Aug 21 02:10:12 2019 +0200
# Node ID c6f8ca03718fa3554b46825c58982a195f5c9462
# Parent a54037a68b144497440852eddd80708b1a57a9d7
[debug] syntax highlight SQL and RQL debug output

This prevent DBG_RQL and DBG_SQL output to looks like a gigantic blob of white
text.

Do this only if we detect that we are in a tty and that pygments is installed.

Closes #17222885

diff --git a/cubicweb/misc/source_highlight.py b/cubicweb/misc/source_highlight.py
@@ -0,0 +1,21 @@
1 +"""This module provide syntaxe highlight functions"""
2 +
3 +from logilab.common.logging_ext import _colorable_terminal
4 +
5 +try:
6 +    from pygments import highlight as pygments_highlight
7 +    from pygments.lexers import get_lexer_by_name
8 +    from pygments.formatters.terminal import TerminalFormatter
9 +    has_pygments = True
10 +except ImportError:
11 +    has_pygments = False
12 +
13 +
14 +def highlight(code, language):
15 +    if not has_pygments:
16 +        return code
17 +
18 +    if not _colorable_terminal():
19 +        return code
20 +
21 +    return pygments_highlight(code, get_lexer_by_name(language), TerminalFormatter())
diff --git a/cubicweb/server/querier.py b/cubicweb/server/querier.py
@@ -29,10 +29,11 @@
22  from cubicweb.rqlrewrite import RQLRelationRewriter
23  from cubicweb import Binary, server
24  from cubicweb.rset import ResultSet
25 
26  from cubicweb.utils import QueryCache, RepeatList
27 +from cubicweb.misc.source_highlight import highlight
28  from cubicweb.server.rqlannotation import SQLGenAnnotator, set_qdata
29  from cubicweb.server.ssplanner import READ_ONLY_RTYPES, add_types_restriction
30  from cubicweb.server.edition import EditedEntity
31  from cubicweb.server.ssplanner import SSPlanner
32  from cubicweb.statsd_logger import statsd_timeit, statsd_c
@@ -517,11 +518,11 @@
33          'Any X WHERE X eid 123'!)
34          """
35          if server.DEBUG & (server.DBG_RQL | server.DBG_SQL):
36              if server.DEBUG & (server.DBG_MORE | server.DBG_SQL):
37                  print('*'*80)
38 -            print('querier input', repr(rql), repr(args))
39 +            print("querier input", highlight(repr(rql)[1:-1], 'RQL'), repr(args))
40          try:
41              rqlst, cachekey = self.rql_cache.get(cnx, rql, args)
42          except UnknownEid:
43              # we want queries such as "Any X WHERE X eid 9999"
44              # return an empty result instead of raising UnknownEid
diff --git a/cubicweb/server/sources/__init__.py b/cubicweb/server/sources/__init__.py
@@ -25,16 +25,17 @@
45 
46  from yams.schema import role_name
47 
48  from cubicweb import ValidationError, set_log_methods, server, _
49  from cubicweb.server import SOURCE_TYPES
50 +from cubicweb.misc.source_highlight import highlight
51 
52 
53  def dbg_st_search(uri, union, args, cachekey=None, prefix='rql for'):
54      if server.DEBUG & server.DBG_RQL:
55          global t
56 -        print('  %s %s source: %s' % (prefix, uri, repr(union.as_string())))
57 +        print(" ", prefix, uri, "source:", highlight(repr(union.as_string())[1:-1], 'RQL'))
58          t = time()
59          if server.DEBUG & server.DBG_MORE:
60              print('    args', repr(args))
61              print('    cache key', cachekey)
62              print('    solutions', ','.join(str(s.solutions)
diff --git a/cubicweb/server/sources/native.py b/cubicweb/server/sources/native.py
@@ -48,10 +48,11 @@
63  from cubicweb.server.rqlannotation import set_qdata
64  from cubicweb.server.hook import CleanupDeletedEidsCacheOp
65  from cubicweb.server.edition import EditedEntity
66  from cubicweb.server.sources import AbstractSource, dbg_st_search, dbg_results
67  from cubicweb.server.sources.rql2sql import SQLGenerator
68 +from cubicweb.misc.source_highlight import highlight
69  from cubicweb.statsd_logger import statsd_timeit
70 
71 
72  ATTR_MAP = {}
73  NONSYSTEM_ETYPES = set()
@@ -65,16 +66,16 @@
74      def execute(self, query, args=None):
75          """Execute a query.
76          it's a function just so that it shows up in profiling
77          """
78          if server.DEBUG & server.DBG_SQL:
79 -            print('exec', query, args)
80 +            print('exec', highlight(query, "SQL"), args)
81          try:
82              self.cu.execute(str(query), args)
83          except Exception as ex:
84              print("sql: %r\n args: %s\ndbms message: %r" % (
85 -                query, args, ex.args[0]))
86 +                highlight(query, "SQL"), args, ex.args[0]))
87              raise
88 
89      def fetchall(self):
90          return self.cu.fetchall()
91 
@@ -683,11 +684,11 @@
92          """Execute a query.
93          it's a function just so that it shows up in profiling
94          """
95          cursor = cnx.cnxset.cu
96          if server.DEBUG & server.DBG_SQL:
97 -            print('exec', query, args, cnx.cnxset.cnx)
98 +            print('exec', highlight(query, "SQL"), args, cnx.cnxset.cnx)
99          try:
100              # str(query) to avoid error if it's a unicode string
101              cursor.execute(str(query), args)
102          except Exception as ex:
103              if self.repo.config.mode != 'test':
@@ -746,11 +747,12 @@
104      def doexecmany(self, cnx, query, args):
105          """Execute a query.
106          it's a function just so that it shows up in profiling
107          """
108          if server.DEBUG & server.DBG_SQL:
109 -            print('execmany', query, 'with', len(args), 'arguments', cnx.cnxset.cnx)
110 +            print('execmany', highlight(query, "SQL"), 'with', len(args), 'arguments',
111 +                  cnx.cnxset.cnx)
112          cursor = cnx.cnxset.cu
113          try:
114              # str(query) to avoid error if it's a unicode string
115              cursor.executemany(str(query), args)
116          except Exception as ex: