--- a +++ b/qiita_db/logger.py @@ -0,0 +1,207 @@ +r""" +Logging objects (:mod: `qiita_db.logger`) +==================================== + +..currentmodule:: qiita_db.logger + +This module provides objects for recording log information + +Classes +------- + +..autosummary:: + :toctree: generated/ + + LogEntry +""" + +# ----------------------------------------------------------------------------- +# Copyright (c) 2014--, The Qiita Development Team. +# +# Distributed under the terms of the BSD 3-clause License. +# +# The full license is in the file LICENSE, distributed with this software. +# ----------------------------------------------------------------------------- +from json import loads, dumps + +import qiita_db as qdb + + +class LogEntry(qdb.base.QiitaObject): + """ + Attributes + ---------- + severity + time + info + msg + + Methods + ------- + clear_info + add_info + """ + + _table = 'logging' + + @classmethod + def newest_records(cls, numrecords=100): + """Return a list of the newest records in the logging table + + Parameters + ---------- + numrecords : int, optional + The number of records to return. Default 100 + + Returns + ------- + list of LogEntry objects + list of the log entries + """ + with qdb.sql_connection.TRN: + sql = """SELECT logging_id + FROM qiita.{0} + ORDER BY logging_id DESC LIMIT %s""".format(cls._table) + qdb.sql_connection.TRN.add(sql, [numrecords]) + + return [cls(i) + for i in qdb.sql_connection.TRN.execute_fetchflatten()] + + @classmethod + def create(cls, severity, msg, info=None): + """Creates a new LogEntry object + + Parameters + ---------- + severity : str {Warning, Runtime, Fatal} + The level of severity to use for the LogEntry. Refers to an entry + in the SEVERITY table. + msg : str + The message text + info : dict, optional + Defaults to ``None``. If supplied, the information will be added + as the first entry in a list of information dicts. If ``None``, + an empty dict will be added. + + Notes + ----- + - When `info` is added, keys can be of any type, but upon retrieval, + they will be of type str + """ + if info is None: + info = {} + + info = dumps([info]) + + with qdb.sql_connection.TRN: + sql = """INSERT INTO qiita.{} (time, severity_id, msg, information) + VALUES (NOW(), %s, %s, %s) + RETURNING logging_id""".format(cls._table) + severity_id = qdb.util.convert_to_id(severity, "severity") + qdb.sql_connection.TRN.add(sql, [severity_id, msg, info]) + + return cls(qdb.sql_connection.TRN.execute_fetchlast()) + + @property + def severity(self): + """Returns the severity_id associated with this LogEntry + + Returns + ------- + int + This is a key to the SEVERITY table + """ + with qdb.sql_connection.TRN: + sql = """SELECT severity_id FROM qiita.{} + WHERE logging_id = %s""".format(self._table) + qdb.sql_connection.TRN.add(sql, [self.id]) + return qdb.sql_connection.TRN.execute_fetchlast() + + @property + def time(self): + """Returns the time that this LogEntry was created + + Returns + ------- + datetime + """ + with qdb.sql_connection.TRN: + sql = "SELECT time FROM qiita.{} WHERE logging_id = %s".format( + self._table) + qdb.sql_connection.TRN.add(sql, [self.id]) + + return qdb.sql_connection.TRN.execute_fetchlast() + + @property + def info(self): + """Returns the info associated with this LogEntry + + Returns + ------- + list of dict + Each entry in the list is information that was added (the info + added upon creation will be index 0, and if additional info + was supplied subsequently, those entries will occupy subsequent + indices) + + Notes + ----- + - When `info` is added, keys can be of any type, but upon retrieval, + they will be of type str + """ + with qdb.sql_connection.TRN: + sql = """SELECT information FROM qiita.{} WHERE + logging_id = %s""".format(self._table) + qdb.sql_connection.TRN.add(sql, [self.id]) + + rows = qdb.sql_connection.TRN.execute_fetchlast() + + if rows: + results = loads(rows) + else: + results = {} + + return results + + @property + def msg(self): + """Gets the message text for this LogEntry + + Returns + ------- + str + """ + with qdb.sql_connection.TRN: + sql = "SELECT msg FROM qiita.{0} WHERE logging_id = %s".format( + self._table) + qdb.sql_connection.TRN.add(sql, [self.id]) + + return qdb.sql_connection.TRN.execute_fetchlast() + + def clear_info(self): + """Resets the list of info dicts to be an empty list + """ + sql = """UPDATE qiita.{} SET information = %s + WHERE logging_id = %s""".format(self._table) + qdb.sql_connection.perform_as_transaction(sql, [dumps([]), self.id]) + + def add_info(self, info): + """Adds new information to the info associated with this LogEntry + + Parameters + ---------- + info : dict + The information to add. + + Notes + ----- + - When `info` is added, keys can be of any type, but upon retrieval, + they will be of type str + """ + current_info = self.info + current_info.append(info) + new_info = dumps(current_info) + + sql = """UPDATE qiita.{} SET information = %s + WHERE logging_id = %s""".format(self._table) + qdb.sql_connection.perform_as_transaction(sql, [new_info, self.id])