Audible Errors - Custom non-blocking text-to-speech handler for Python's logging module
Question: I am building a screen-less Raspberry Pi-based long term art installation. A
common application of [Text-to-Speech on the Raspberry
pi](http://elinux.org/RPi_Text_to_Speech_\(Speech_Synthesis\)) is folks
configuring their Pis to speak their IP Address on boot to ease SSHing.

I have grown to love the logging module. Never again commenting out
uncountable print statements makes my heart glow. For my situation, it would
be ideal to have a logging handler that speaks the error message. The
StreamHandler and the FileHandler I am currently using are great for
development and post-problem diagnosis, but horrible for in situ problem
solving. Also, there is something delightfully SciFi about my robot shouting
errors at me.

[I found an example of a custom handler for SMS-based error
logging,](http://pantburk.info/?blog=77) and tried to implement my own with
e-speak. It speaks, but the entire program stops at the end of the first
spoken sentence.

I am looking for advice on how to implement a stream handler that does not
block the execution of the program. **My broken custom handler:**

    
    
    import logging
    import os
    
    #based on SMSHandler http://pantburk.info/?blog=77
    
    def speak(stringToSay):
        '''say whatver it is told to say, squleching annoying warnings'''
        stringToSay = "'"+stringToSay+"'"
    #English female voice, emphasis on capitals (-k), speaking slowly (-s) using direct text:-
    #the 2>/dev/null' is there because any calls to the rPi audio card result in a dozen warnings.
    #  see: http://raspberrypi.stackexchange.com/questions/3412/errors-with-espeak
        os.system('espeak  -ven+f3 -k5 -s150 '+stringToSay+' 2>/dev/null')
    
    class TALKHandler(logging.Handler): # Inherit from logging.Handler
            def __init__(self):
                    # run the regular Handler __init__
                    logging.Handler.__init__(self)
            def emit(self, record):
                    # record.message is the log message
                    speak(record.message)
    

**The snippet from the program that is logging:**

    
    
    logging.handlers.TALKHandler = speechHandler.TALKHandler
    # create the handler object
    talkingHandler = logging.handlers.TALKHandler()
    # Configure the handler to only send SMS for critical errors
    talkingHandler.setLevel(logging.CRITICAL)
    # and finally we add the handler to the logging object
    logger.addHandler(talkingHandler)
    
    ipAddress = [(s.connect(('8.8.8.8', 80)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]
    ipAddress = " ".join(ipAddress)
    ipAddress = ipAddress.replace(".","dot")
    logger.critical("Current IP Address is " + ipAddress  )
    


Answer: I know this was asked ages ago - I missed it when it was posted and stumbled
on it by chance. The following works for me:

    
    
    import logging
    import subprocess
    import sys
    
    class TalkHandler(logging.Handler):
        def emit(self, record):
            msg = self.format(record)
            cmd = ['espeak', '-ven+f3', '-s150', msg]
            p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
                                 stderr=subprocess.STDOUT)
            p.communicate()
    
    def configure_logging():
        h = TalkHandler()
        root = logging.getLogger()
        root.addHandler(h)
        root.setLevel(logging.DEBUG)
    
    def main():
        logging.info('Hello')
        logging.debug('Goodbye')
    
    if __name__ == '__main__':
        configure_logging()
        sys.exit(main())
    

When I run it, I hear "Hello" and then "Goodbye" spoken.

