From b85ac3e0763fbadbe03b1df4aa9e901136635b4e Mon Sep 17 00:00:00 2001 From: Sebastiaan Huber Date: Sat, 9 Feb 2019 14:13:23 +0100 Subject: [PATCH] Remove unserializable data from metadata in `Log` records (#2469) If unserializable data, often found in the `exc_info` or `args` keys, is not removed from the metadata of a log record, a database exception will be thrown. --- aiida/backends/tests/orm/logs.py | 26 +++++++++++++++++++++++++- aiida/orm/logs.py | 6 ++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/aiida/backends/tests/orm/logs.py b/aiida/backends/tests/orm/logs.py index 00b18bd2c5..395f824f71 100644 --- a/aiida/backends/tests/orm/logs.py +++ b/aiida/backends/tests/orm/logs.py @@ -67,6 +67,31 @@ def test_create_log_message(self): self.assertEqual(entry.message, self.log_record['message']) self.assertEqual(entry.metadata, self.log_record['metadata']) + def test_create_log_unserializable_metadata(self): + """Test that unserializable data will be removed before reaching the database causing an error.""" + import functools + + def unbound_method(argument): + return argument + + partial = functools.partial(unbound_method, 'argument') + + node = CalculationNode().store() + + # An unbound method in the `args` of the metadata + node.logger.error('problem occurred in method %s', unbound_method) + + # A partial in the `args` of the metadata + node.logger.error('problem occurred in partial %s', partial) + + # An exception which will include an `exc_info` object + try: + raise ValueError + except ValueError: + node.logger.exception('caught an exception') + + self.assertEqual(len(Log.objects.all()), 3) + def test_log_delete_single(self): """Test that a single log entry can be deleted through the collection.""" entry, _ = self.create_log() @@ -186,7 +211,6 @@ def test_db_log_handler(self): # Launching a second log message ensuring that both messages are correctly stored message2 = message + " - Second message" node.logger.critical(message2) - # logs = Log.objects.find() order_by = [OrderSpecifier('time', ASCENDING)] logs = Log.objects.find(order_by=order_by) diff --git a/aiida/orm/logs.py b/aiida/orm/logs.py index cdcbdd7075..7c3c5f55ae 100644 --- a/aiida/orm/logs.py +++ b/aiida/orm/logs.py @@ -58,8 +58,10 @@ def create_entry_from_record(record): metadata = dict(record.__dict__) - # Get rid of the exc info because this is usually not serializable - metadata['exc_info'] = None + # Stringify the content of `exc_info` and `args` if they exist in the metadata to ensure serializability + for key in ['exc_info', 'args']: + if key in metadata: + metadata[key] = str(metadata[key]) return Log( time=timezone.make_aware(datetime.fromtimestamp(record.created)),