3
\$\begingroup\$

I've come up with a base class for exceptions for this SMS-based service I am working on. The basic idea behind the service is that a user sends a text message to a number, the message requests a particular action to be carried out by an agent that logs into a different website, from which some account information is scraped and spat back out to the user. Small take on QoL. Obviously, things don't always work as intended for different reasons.

When something goes wrong and the returned text message doesn't contain the requested information, I want the user to have a reference number to that error, should the issue persist. To accommodate for that I will keep logs, where I will quickly be able to look up what happened using the reference number. The logs will contain full error information.

Intended use of the custom exceptions:

try:
    service.login(credentials)
except AuthenticationError as e:
    sms_client.send(phone_number, f'{Something went wrong. If this keeps on happening, please contact us with this error ref: {e.reference}')

...

import logging
import uuid


logging.basicConfig(filename='errors.log', level=logging.ERROR)


class ServiceException(Exception):
    def __init__(self, message, url):
        self.reference = str(uuid.uuid4()).split('-')[0]
        error_message = f'{message}: \'{url}\' | error ref: {self.reference}'
        logging.error(error_message)
        super(Exception, self).__init__(error_message)


class AuthenticationError(ServiceException):
    """Ambiguous error prevented successful authentication."""
\$\endgroup\$
  • 1
    \$\begingroup\$ Do you have any particular concerns or something you want reviewers to look into? \$\endgroup\$ – Daniel Mar 14 '18 at 16:09
  • 2
    \$\begingroup\$ Entirely forgot to mention that! I would just like to know if I went about the code the right way. I suppose I would be concerned if cutting the UUID short will keep it unique, otherwise I'm pretty happy with how the exception works, but if there's another way, I'll be glad to hear it. @Coal_ \$\endgroup\$ – Lukasz Salitra Mar 14 '18 at 16:28
2
\$\begingroup\$

concerned if cutting the UUID short will keep it unique

Well, you're outputting 32 bits. So you can do ballpark 64k transactions (2^16) before running into Big Trouble, according to the birthday paradox.

If you realistically expect someone to report issues within a day, then the identifier is effectively (day, reference), which looks more attractive, as you can do some tens of thousands of transactions each day rather than over the lifetime of the service. More generally, resolve ties with "last one wins", and then you're comparing "typical distance between collisions" to "typical time for user to report an issue".

You're putting 4 bits of entropy into each hex nybble, which likely will be copy-n-pasted (or forwarded) by the user. If you're working within an 8-character constraint, consider using a scheme like base36 or base64 so each character sends more bits. Without pasting there will be usability limitations, such as eyeballing an 'l' and sending the digit '1'.

If you're not worried about users making up identifiers, consider using (userid, serial_num), or better: (userid, timestamp).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.