2

I've encountered a pretty standard issue and was wondering if my solution is the right way to go.

Every time an exception occures I want it to be caught and logged by the caller, and then re-raised.

Since I dont want to repeat logging messages every time, I created a custom exception which saves the message data and also logs.

class LoggingException(Exception):
    def __init__(self, message, package_id):
        # Get caller informat
        caller = getframeinfo(stack()[2][0])
        self.filename = caller.filename
        self.function = caller.function

        # Set message info and log
        self.message = message
        if (LogManager.log_handler is None):
            print(message)
        else:
            LogManager.l(package_id, LogLevelEnum.ERROR, message)

Use case:

def main_func():
    try:
        secondary_func()
    except Exception as ex:
        raise LoggingException("Some log") from ex

def secondary_func():
    raise LoggingException("Exception info")

The problem is im not completley sure having an exception do any operations is a good idea, and this to generic for it to not have a standard python solution.

Note: I am not using the python logging module due to product constraints.

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
Rohi
  • 814
  • 1
  • 9
  • 26
  • Can you also show an example of how you use this exception? Does this hide the original exception? Also: do you want the code give up when an exception happens? – Francesco Montesano Nov 11 '18 at 09:58
  • 1
    @FrancescoMontesano Hey, Ive added a use case. – Rohi Nov 11 '18 at 10:02
  • Do you want your code to output the call stack? It's still unclear to me what you are trying to do - what should someone who catches the exception be able to do/see? – kabanus Nov 11 '18 at 10:04
  • I'm not sure I understand why [this](https://stackoverflow.com/a/14162421/5962321) would not be enough... (or [this other one one](https://stackoverflow.com/a/792163/5962321) for Py3) – Silmathoron Nov 11 '18 at 10:10
  • If you have a custom exception that prints out or logs an error message, why do you want to catch it somwhere, and then raise it again? To make the stack trace shorter? Anyway, if you reraise the exception, it will be printed out twice, unless this is what you want. Maybe you don't need to reraise the exception, or, if you need, you should add a parameter to the constructor and not to print the exception second time? – VadimK Nov 11 '18 at 10:15

1 Answers1

2

Trying to get caller information like that is going to be unreliable. Also, there will be cases where it's not the immediate caller that you are interested in.

The idea of the exception logging itself seems sensible. To compromise, I would move the logging functionality into a separate method that you could trigger explicitly. Exceptions are, after all, mostly regular objects:

class LoggingException(Exception):
    def __init__(self, message, package_id):
        # Set message info
        super.__init__(message)
        self.package_id = package_id

    def log(self, manager=None):
        if manager.log_handler is None:
            print(super().__str__())
        else:
            manager.l(self.package_id, LogLevelEnum.ERROR, super()..__str__())

Now you can trigger the logging operation whenever you want, without having to reconstruct the message:

try:
    ...
except LoggingException as e:
    e.log(some_manager)
    raise

This gives you the option of really re-raising the error, as shown here, or chaining it as in your example. I highly recommend against chaining unless you have a really good reason to do it.

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
  • Hey, I liked this solution. The seperation to a log function is probally a good idea, since I want to expand the log, Ill insert self.log() to the init function, and send the extra data. – Rohi Nov 11 '18 at 11:13