3 ms·
Decorators are one of my favorite parts of Python. One thing I did with them really saved our hash at my last company multiple times: Our infrastructure daemon
by amyjess 11y ago
Decorators are one of my favorite parts of Python. One thing I did with them really saved our hash at my last company multiple times:
Our infrastructure daemons were written in Python, and I wanted to make sure we had a debuggable system that allows me to trace any error without having to manually reproduce it (especially when, say, problems specific to a customer's network can't be reproduced on ours). I wrote a decorator, called @logme, that would log a function's name and parameters plus the module it belonged to (easier said than done!), run the function, then log and return the return value. Every function was decorated with @logme. I also made a variant for methods called @logmethod that would also log data about the class the method belonged to.
Now, obviously, this generated massive amounts of logs, so I put in a healthy amount of log rotation (the Python logger is beautifully customizable). On average, logs would keep for a few days.
So many times, I debugged customer problems -- problems that would've been impossible to reproduce in our lab because of edge cases our customers encountered -- just from the incredibly detailed logs they'd send me.
Also, it was imperative that the main infrastructure daemon never, ever crashes. It sat and waited for commands to be sent to it. When it finishes executing one command, it goes back to listening. If it got an error running some command, it should report that error and then go back to listening for the next command; an error running an individual command should never bring down the system. The decorators took care of that too. In addition to logging what goes into and out of every function, @logme and @logmethod also caught any exception those functions raised and logged them, allowing the system to recover following any exception just by decorating everything (I would not recommend this for a more stateful system: it only worked as well as it did because any configuration needed was always loaded from disk when each command was run, so the daemon overall had no state that could be corrupted by an error).