Skip to content

Commit a599163

Browse files
authored
Merge pull request #8611 from sfayer/fix_mysqllog
[int] Improve mysql logging
2 parents 8f84677 + 4de2c1f commit a599163

1 file changed

Lines changed: 54 additions & 6 deletions

File tree

src/DIRAC/Core/Utilities/MySQL.py

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,32 @@ def _safeCmd(self, command):
701701
"""Just replaces password, if visible, with *********"""
702702
return command.replace(self.__passwd, "**********")
703703

704+
def _logCmd(self, cmd, args=None):
705+
"""Return a copy of the SQL command with %s placeholders
706+
replaced by their actual values including basic string quoting.
707+
The formatting may not be perfect SQL in every case, but it should be
708+
good enough to see what's going to the database in the log.
709+
If formatting is not possibe, the unformatted cmd will be returned.
710+
"""
711+
safe = self._safeCmd(cmd)
712+
if args is None or not isinstance(args, (list, tuple)) or not args:
713+
return safe
714+
715+
subs = []
716+
for v in args:
717+
if v is None:
718+
subs.append("NULL")
719+
elif isinstance(v, (int, float)):
720+
subs.append(str(v))
721+
else:
722+
escaped = str(v).replace('"', '""')
723+
subs.append(f'"{escaped}"')
724+
725+
try:
726+
return safe % tuple(subs)
727+
except TypeError:
728+
return safe
729+
704730
def _connect(self):
705731
"""
706732
open connection to MySQL DB and put Connection into Queue
@@ -724,18 +750,23 @@ def _connect(self):
724750
return S_OK()
725751

726752
@captureOptimizerTraces
727-
def _query(self, cmd, *, args=None, conn=None, debug=True):
753+
def _query(self, cmd, *, args=None, logArgs=None, conn=None, debug=True):
728754
"""
729755
execute MySQL query command
730756
731757
:param debug: print or not the errors
758+
:param logArgs: alternative args list for logging only; when set it is
759+
used by ``_logCmd`` so that secrets present in *args*
760+
can be omitted from the log.
732761
733762
return S_OK structure with fetchall result as tuple
734763
it returns an empty tuple if no matching rows are found
735764
return S_ERROR upon error
736765
"""
737766

738-
self.log.debug(f"_query: {self._safeCmd(cmd)}")
767+
if logArgs is None:
768+
logArgs = args
769+
self.log.debug(f"_query: {self._logCmd(cmd, logArgs)}")
739770

740771
if conn:
741772
connection = conn
@@ -772,10 +803,13 @@ def _query(self, cmd, *, args=None, conn=None, debug=True):
772803
return retDict
773804

774805
@captureOptimizerTraces
775-
def _update(self, cmd, *, args=None, conn=None, debug=True):
806+
def _update(self, cmd, *, args=None, logArgs=None, conn=None, debug=True):
776807
"""execute MySQL update command
777808
778809
:param args: parameters passed to cursor.execute(..., args=args) method.
810+
:param logArgs: alternative args list for logging only; when set it is
811+
used by ``_logCmd`` so that secrets present in *args*
812+
can be omitted from the log.
779813
:param conn: connection object.
780814
:param debug: print or not the errors
781815
@@ -784,7 +818,9 @@ def _update(self, cmd, *, args=None, conn=None, debug=True):
784818
lastRowId: if set, added to the returned dictionary
785819
"""
786820

787-
self.log.debug(f"_update: {self._safeCmd(cmd)}")
821+
if logArgs is None:
822+
logArgs = args
823+
self.log.debug(f"_update: {self._logCmd(cmd, logArgs)}")
788824
if conn:
789825
connection = conn
790826
else:
@@ -812,16 +848,28 @@ def _update(self, cmd, *, args=None, conn=None, debug=True):
812848
return retDict
813849

814850
@captureOptimizerTraces
815-
def _updatemany(self, cmd, data, *, conn=None, debug=True):
851+
def _updatemany(self, cmd, data, *, logData=None, conn=None, debug=True):
816852
"""execute MySQL updatemany command
817853
854+
:param cmd: SQL command template.
855+
:param data: iterable of parameter tuples for ``executemany``.
856+
:param logData: alternative data for logging only; when set it is
857+
used by ``_logCmd`` so that secrets present in *data*
858+
can be omitted from the log.
859+
logData may have fewer entries than data if logging
860+
a sub-set of example entries is required.
861+
:param conn: connection object.
818862
:param debug: print or not the errors
819863
820864
:return: S_OK with number of updated registers upon success.
821865
S_ERROR upon error.
822866
"""
823867

824-
self.log.debug(f"_updatemany: {self._safeCmd(cmd)}")
868+
if logData is None:
869+
logData = data
870+
for idx, row in enumerate(logData, 1):
871+
self.log.debug(f"_updatemany [{idx}]: {self._logCmd(cmd, row)}")
872+
825873
if conn:
826874
connection = conn
827875
else:

0 commit comments

Comments
 (0)