A small utility to pretty-print Python tracebacks. ⛺

Overview

TBVaccine

TBVaccine is a utility that pretty-prints Python tracebacks. It automatically highlights lines you care about and deemphasizes lines you don't, and colorizes the various elements in a traceback to make it easier to parse.

Here are some screenshots. This is the before:

misc/before.png

And this is the after:

misc/after.png

If you add the hook or call TBVaccine in your code, it can also print all variables in each stack frame. That is, it turns this:

misc/before-vars.png

into this:

misc/after-vars.png

Installation

To install, use pip:

pip install tbvaccine

You are done!

Global usage

You can have TBVaccine insert itself all up in your system and stick its tentacles in all your libraries, like a cute, useful Cthulhu. That way, every single Python traceback in your system will be pretty. Just set the TBVACCINE environment variable to 1, and you're done.

E.g. for bash:

export TBVACCINE=1

Or fish:

set -x TBVACCINE=1

If you want to prettify tracebacks even when stderr is not a tty, set TBVACCINE_FORCE to 1:

export TBVACCINE=1
export TBVACCINE_FORCE=1
python -c '1/0' 2>&1 | cat  # pretty!

NOTE: If you're on Ubuntu, you most likely have Apport installed, which overrides TBVaccine's hook with its own. To disable Apport for Python, delete a file named /etc/python<version>/sitecustomize.py. Note that this will disable Apport for Python, and you won't be asked to submit info to Ubuntu when Python programs crash any more. For some, this is a good thing.

Usage as a command-line utility

TBVaccine can be used from the command line several ways.:

python -m tbvaccine myscript.py

Or just pipe STDERR into it from the program you want to watch:

./myscript.py 2>&1 | tbvaccine

And all the tracebacks will now be pretty!

Usage as a Python library

There are various ways to use TBVaccine as a Python library.

Initialize it like so:

from tbvaccine import TBVaccine
tbv = TBVaccine(
    code_dir="/my/code/dir",
    isolate=True
)

code_dir marks the directory we code about. Files under that directory that appear in the traceback will be highlighted. If not passed, the current directory, as returned by os.getcwd() will be used.

If isolate is False, all lines are colorized, and code_dir is ignored.

If show_vars is False, variables will not be printed in each stack frame.

To use it in an except block:

from tbvaccine import TBVaccine
try:
    some_stuff()
except:
    print(TBVaccine().format_exc())

To make it the default way of printing tracebacks, use add_hook() (which also accepts any argument the TBVaccine class does):

import tbvaccine
tbvaccine.add_hook(isolate=False)

1 / 0

Bam! Instant pretty tracebacks.

Logging integration

You can integrate TBVaccine with logging like so:

class TbVaccineFormatter(logging.Formatter):
    def  formatException(self, exc_info):
        return TBVaccine(isolate=True).format_exc()

sh = logging.StreamHandler()
sh.setFormatter(TbVaccineFormatter('[%(levelname)s] %(asctime)s : %(message)s', '%Y-%m-%d %H:%M:%S'))
logger.addHandler(sh)

Configuration

To configure TBVaccine, open its configuration file in ~/.config/tbvaccine/tbvaccine.cfg (or your operating system's equivalent) and edit it. You can currently configure the color style there by specifying one of the Pygments styles <http://pygments.org/demo/6778888/?style=monokai>.

Epilogue

This library is still pretty new, please contribute patches if something doesn't work as intended, and also please tell your friends about it! Hopefully one day it will be implemented in the Python interpreters themselves.

-- Stavros

Comments
  • switching on and off using an environment variable

    switching on and off using an environment variable

    If tbvaccine provides (e.g.) a tbvaccine.pth file with contents similar to

    import os; exec("if os.environ.get('TBVACCINE'):\n    <activation code>")
    

    this would make it much easier to switch its functionality on and off without having to modify the "vaccined" code. You could even load the kwargs to TBVaccine from the environment variable, say as json: see https://github.com/anntzer/mplcursors/blob/master/setup.py for a self-contained example.

    help wanted 
    opened by anntzer 10
  • Cap long lines

    Cap long lines

    I'm having issues where I have very long variables (like a spreadsheet loaded in memory) and so when TBVaccine prints that, I lose everything else in my console buffer. Here is a quick and dirty hack to cap line length. It works by dropping ANSI sequences from long variable lines, and cap their length at 79*4 chars (approx. 4 output lines). A note is added to the line that there is more un-printed data.

    (I can't figure out how to get decent lengths with normal string slicing on strings with ANSI codes embedded. For example, the output line | __annotations__ = {} clocks in with a length of 148 (!) due to ANSI control codes.)

    The downside of dropping ANSI sequences like this is that the line won't be coloured....

    opened by MinchinWeb 6
  • ValueError: max() arg is an empty sequence

    ValueError: max() arg is an empty sequence

    Executing:

    def x():
        raise Exception('hello')
    
    def a(b):
        b()
    
    a(x)
    
    d:\...>python -m tbvaccine test_stack_trace.py
    Error in sys.excepthook:
    Traceback (most recent call last):
      File "d:\...\tbvaccine\tbv.py", line 193, in print_exception
        formatted = self._format_tb_string_with_locals(etype, value, tb)
      File "d:\...\tbvaccine\tbv.py", line 173, in _format_tb_string_with_locals
        max_length = max([len(x[0]) for x in var_tuples])
    ValueError: max() arg is an empty sequence
    
    Original exception was:
    Traceback (most recent call last):
      File "C:\...\lib\runpy.py", line 193, in _run_module_as_main
        "__main__", mod_spec)
      File "C:\...\lib\runpy.py", line 85, in _run_code
        exec(code, run_globals)
      File "d:\...\tbvaccine\__main__.py", line 67, in <module>
        exec(code, variables, variables)
      File "test_stack_trace.py", line 7, in <module>
        a(x)
      File "test_stack_trace.py", line 5, in a
        b()
      File "test_stack_trace.py", line 2, in x
        raise Exception('hello')
    Exception: hello
    
    opened by szabolcsdombi 6
  • Running tbvaccine on non python file - colors don't work

    Running tbvaccine on non python file - colors don't work

    By mistake I just called python -m tbvaccine tox.ini.

    The trace has no colors and it is longer then 100 lines, however calling python directly on a non python file causes only 4 lines for a single exception.

    image

    It would be great if tbvaccine could detect when a non python file is passed.

    opened by szabolcsdombi 5
  • Simplify isatty

    Simplify isatty

    IOBase.stderr() has existed from at latest Python 2.7.4 and 3.1 (https://github.com/python/cpython/commit/4fa88fa0b), so sys.stderr.isatty() likely exists.

    opened by wataash 3
  • Support force-enable (even when not isatty)

    Support force-enable (even when not isatty)

    Hi, thanks for creating this great library!

    I want to use this library in a kubernetes container where stderr is not a tty. It'll be convenient if we can do force-enabling by setting an environment variable.

    opened by wataash 3
  • How to integrate with flask or logging?

    How to integrate with flask or logging?

    It no effect when exception raised in flask request because the tracebacks are formatted by logging, the sys.excepthook is not called.

    eg:

    import tbvaccine
    from flask import Flask
    
    tbvaccine.add_hook(isolate=True)
    app = Flask(__name__)
    
    
    @app.route('/')
    def index():
        return 1 / 0
    
    
    if __name__ == '__main__':
        app.run()
    

    the outputs:

     * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
    [2017-06-01 21:59:08,086] ERROR in app: Exception on / [GET]
    Traceback (most recent call last):
      File "/home/guyskk/.local/share/virtualenvs/next_passport-OfYZSIo0/lib/python3.6/site-packages/flask/app.py", line 1982, in wsgi_app
        response = self.full_dispatch_request()
      File "/home/guyskk/.local/share/virtualenvs/next_passport-OfYZSIo0/lib/python3.6/site-packages/flask/app.py", line 1614, in full_dispatch_request
        rv = self.handle_user_exception(e)
      File "/home/guyskk/.local/share/virtualenvs/next_passport-OfYZSIo0/lib/python3.6/site-packages/flask/app.py", line 1517, in handle_user_exception
        reraise(exc_type, exc_value, tb)
      File "/home/guyskk/.local/share/virtualenvs/next_passport-OfYZSIo0/lib/python3.6/site-packages/flask/_compat.py", line 33, in reraise
        raise value
      File "/home/guyskk/.local/share/virtualenvs/next_passport-OfYZSIo0/lib/python3.6/site-packages/flask/app.py", line 1612, in full_dispatch_request
        rv = self.dispatch_request()
      File "/home/guyskk/.local/share/virtualenvs/next_passport-OfYZSIo0/lib/python3.6/site-packages/flask/app.py", line 1598, in dispatch_request
        return self.view_functions[rule.endpoint](**req.view_args)
      File "app.py", line 10, in index
        return 1 / 0
    ZeroDivisionError: division by zero
    127.0.0.1 - - [01/Jun/2017 21:59:08] "GET / HTTP/1.1" 500 -
    
    opened by guyskk 2
  • TBVaccine in pipe mode is broken

    TBVaccine in pipe mode is broken

    $ echo 1 | tbvaccine
    Traceback (most recent call last):
      File "/mnt/storage/miniconda3/envs/CloudSML-Computational-Backend/bin/tbvaccine", line 11, in <module>
        sys.exit(main())
      File "/mnt/storage/miniconda3/envs/CloudSML-Computational-Backend/lib/python3.5/site-packages/tbvaccine/cli.py", line 29, in main
        output = tbv.process_line(line)
    AttributeError: 'TBVaccine' object has no attribute 'process_line'
    
    opened by frol 2
  • Integration with IDEs

    Integration with IDEs

    Hello there! Thank you very much for your work.

    I'd like to get it to work in PyCharm, alas it's not trigerring at all there, but it works in consoles. Any advice here? :)

    opened by Day0Dreamer 1
  • Hooked by TBVACCINE=0 is confusing

    Hooked by TBVACCINE=0 is confusing

    README says export TBVACCINE=1 hooks tbvaccine, so I expected export TBVACCINE=0 would not hook, but it did. I think the hook should be done only if TBVACCINE is exactly 1. (but that's a breaking change...)

    opened by wataash 1
  • Fix CodeShelter link

    Fix CodeShelter link

    Otherwise it was a relative link, and so was returning a GitHub 404 error page. --> https://github.com/skorokithakis/tbvaccine/blob/master/www.codeshelter.co

    opened by MinchinWeb 1
  • Add hyperlinks to source files in traceback

    Add hyperlinks to source files in traceback

    There is a specification for hyperlinks in terminals

    https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda

    It would be good if TBVacine could link to the python files mentioned.

    Currently there isn't a way of linking to particular lines, but being able to open a file from the terminal is a nice improvement.

    This may be worth gating behind config or envvar in case a terminal doesn't support it (though most should display nothing where the link will be anyway)

    opened by stuaxo 5
  • On Ubuntu 16.04, with Python 2.7, performance impact is non-trivial

    On Ubuntu 16.04, with Python 2.7, performance impact is non-trivial

    Without adding hook to my module (tgv):

    Traceback (most recent call last): File "./tgv.py", line 618, in if name == "main": tgv() File "./tgv.py", line 426, in tgv 1/0 ZeroDivisionError: integer division or modulo by zero

    real 0m2.904s user 0m2.344s sys 0m0.536s

    With hook added

    Traceback (most recent call last): File "./tgv.py", line 618, in if name == "main": tgv() <6 variables printed> File "./tgv.py", line 426, in tgv 1/0 <20 odd variables> ZeroDivisionError: integer division or modulo by zero

    real 0m30.856s user 0m29.192s sys 0m1.572s

    I'm guessing mostly the perf degradation is due to the high count of variables being printed. Anyway to control the output?

    opened by anandr165 3
  • ipython integration

    ipython integration

    There's at least a couple problems with this working with ipython.

    1. Exporting the env var seems to have no effect.
    2. This brings the formatting of tbvaccine, and some things, but not the locals I added in the shell.
    from tbvaccine import TBVaccine 
    try:
        some_stuff()
    except:
        print(TBVaccine().format_exc())
    

    imagine this is styled:

    Traceback (most recent call last):
      File "<ipython-input-2-6c94a79ed40f>", line 4, in <module>
    >   some_stuff()
    |     __annotations__ = {}
    |     __builtins__    = <module 'builtins' (built-in)>
    |     __cached__      = None
    |     __doc__         = None
    |     __file__        = [path to]/bin/ipython
    |     __loader__      = <_frozen_importlib_external.SourceFileLoader object at 0x7f880a16fc88>
    |     __name__        = __main__
    |     __package__     = None
    |     __spec__        = None
    |     re              = <module 're' from '[path to]/lib/python3.6/re.py'>
    |     start_ipython   = <function start_ipython at 0x7f88069a18c8>
    |     sys             = <module 'sys' (built-in)>
    NameError: name 'some_stuff' is not defined
    
    
    1. This seems to not be any different from a normal exception in ipython. It looks identical either way.
    import tbvaccine
    tbvaccine.add_hook(isolate=False)
    
    1 / 0
    

    The same seems to hold for at least flask-shell-ipython, which is unsurprising.

    Possibly out-of-scope: I have no idea really, but maybe whatever is needed to get this to work would also suffice for Jupyter as well. If we're lucky.

    opened by nixjdm 4
  • [feature request] settings on displaying local variables

    [feature request] settings on displaying local variables

    All local variables displayed on each stack frame lead to huge unreadable stack pretty fast. You could add a setting to display or not display them. Also, displaying functions and modules does not seem so helpful. You might get rid of them, or add a distinct setting to display them too.

    enhancement 
    opened by afeblot 3
  • Support Python 3's 'raise Exception from e'?

    Support Python 3's 'raise Exception from e'?

    It's not clear if tbvaccine supports Python 3's 'raise MyException from e' syntax.

    Or at least the original exception is not being emitted in the tbvaccine output.

    opened by dsully 5
  • TBVaccine produces insane reporting when Dask or Dask Distributed task crashes

    TBVaccine produces insane reporting when Dask or Dask Distributed task crashes

    Here is the reproduction:

    import tbvaccine
    tbvaccine.add_hook(isolate=False)
    
    import dask
    
    def x(arg1=123):
        assert arg1 == 122, "qwe"
    
    if __name__ == '__main__':
        dask.delayed(x)().compute()
    

    The error:

      File "/tmp/env/lib/python3.5/site-packages/dask/async.py", line 272, in _execute_task
        return func(*args2)
      File "qq5.py", line 7, in x
        assert arg1 == 122, "qwe"
    |     worker_id                = None
    AssertionError: qwe
    

    I don't understand at all where worker_id came from.

    Running Dask Distributed, I see the output, which reports things which don't exist in that scope at all...

    import tbvaccine
    tbvaccine.add_hook(isolate=False)
    
    import dask
    import dask.distributed
    
    
    def x(arg1=123):
        assert arg1 == 122, "qwe"
    
    if __name__ == '__main__':
        client = dask.distributed.Client()
        dask.delayed(x)().compute(get=client.get)
    
      File "/tmp/env/lib/python3.5/site-packages/dask/base.py", line 203, in compute
        results = get(dsk, keys, **kwargs)
    |     x = b'\x80\x04\x95\xa1\x00\x00\x00\x00\x00\x00\x00\x8c\x16tblib.pickling_support\x94\x8c\x12unpickle_traceback\x94\x93\x94\x8c\x05tblib\x94\x8c\x05Frame\x94\x93\x94)\x81\x94}\x94(\x8c\x06f_code\x94h\x03\x8c\x04Code\x94\x93\x94)\x81\x94}\x94(\x8c\x07co_name\x94\x8c\x01x\x94\x8c\x0bco_filename\x94\x8c\x06qq4.py\x94ub\x8c\tf_globals\x94}\x94ubK\tN\x87\x94R\x94.'
      File "/tmp/env/lib/python3.5/site-packages/distributed/client.py", line 1590, in get
        resources=resources)
    |     ret       = <tblib.Traceback object at 0x7f95aeadfcf8>
    |     tb_frame  = <tblib.Frame object at 0x7f95aeadf908>
    |     tb_lineno = 9
    |     tb_next   = None
      File "/tmp/env/lib/python3.5/site-packages/distributed/utils.py", line 223, in sync
        six.reraise(*error[0])
    |     code   = <code object x at 0x7f95aeb33270, file "qq4.py", line 9>
    |     f_code = <tblib.Code object at 0x7f95aeadf9b0>
    |     self   = <tblib.Traceback object at 0x7f95aeadfcf8>
    |     tb     = <traceback object at 0x7f95aeaeb148>
      File "/tmp/env/lib/python3.5/site-packages/six.py", line 686, in reraise
        raise value
    AssertionError: qwe
    

    The direct call to x() produces a sane output, so it should be some magic involved with Dask. Better-Exceptions module just hangs in this situation, so TBVaccine is better in this respect, but it is still completely misleading and unhelpful.

    opened by frol 0
Releases(v0.2.2)
Owner
Stavros Korokithakis
I love writing code, making stupid devices and writing about writing code and making stupid devices.
Stavros Korokithakis
A cool logging replacement for Python.

Welcome to Logbook Travis AppVeyor Supported Versions Latest Version Test Coverage Logbook is a nice logging replacement. It should be easy to setup,

1.4k Nov 11, 2022
Keylogger with Python which logs words into server terminal.

word_logger Experimental keylogger with Python which logs words into server terminal.

Selçuk 1 Nov 15, 2021
The easy way to send notifications

See changelog for recent changes Got an app or service and you want to enable your users to use notifications with their provider of choice? Working o

Or Carmi 2.4k Dec 25, 2022
Robust and effective logging for Python 2 and 3.

Robust and effective logging for Python 2 and 3.

Chris Hager 1k Jan 04, 2023
Debugging-friendly exceptions for Python

Better tracebacks This is a more helpful version of Python's built-in exception message: It shows more code context and the current values of nearby v

Clemens Korndörfer 1.2k Dec 28, 2022
Json Formatter for the standard python logger

This library is provided to allow standard python logging to output log data as json objects. With JSON we can make our logs more readable by machines and we can stop writing custom parsers for syslo

Zakaria Zajac 1.4k Jan 04, 2023
Python logging made (stupidly) simple

Loguru is a library which aims to bring enjoyable logging in Python. Did you ever feel lazy about configuring a logger and used print() instead?... I

13.7k Jan 02, 2023
Python logging package for easy reproducible experimenting in research

smilelogging Python logging package for easy reproducible experimenting in research. Why you may need this package This project is meant to provide an

Huan Wang 20 Dec 23, 2022
蓝鲸日志平台(BK-LOG)是为解决分布式架构下日志收集、查询困难的一款日志产品,基于业界主流的全文检索引擎

蓝鲸日志平台(BK-LOG)是为解决分布式架构下日志收集、查询困难的一款日志产品,基于业界主流的全文检索引擎,通过蓝鲸智云的专属 Agent 进行日志采集,提供多种场景化的采集、查询功能。

腾讯蓝鲸 102 Dec 22, 2022
Logging system for the TPC software.

tpc_logger Logging system for the TPC software. The TPC Logger class provides a singleton for logging information within C++ code or in the python API

UC Davis Machine Learning 1 Jan 10, 2022
A colored formatter for the python logging module

Log formatting with colors! colorlog.ColoredFormatter is a formatter for use with Python's logging module that outputs records using terminal colors.

Sam Clements 778 Dec 26, 2022
Lazy Profiler is a simple utility to collect CPU, GPU, RAM and GPU Memory stats while the program is running.

lazyprofiler Lazy Profiler is a simple utility to collect CPU, GPU, RAM and GPU Memory stats while the program is running. Installation Use the packag

Shankar Rao Pandala 28 Dec 09, 2022
ScreenshotLogger works just like a keylogger but instead of capturing keystroke,it captures the screen, stores it or sends via email

ScreenshotLogger works just like a keylogger but instead of capturing keystroke,it captures the screen, stores it or sends via email. Scrapeasy is super easy to use and handles everything for you. Ju

Ifechukwudeni Oweh 17 Jul 17, 2022
A watchdog and logger to Discord for hosting ScPrime servers.

ScpDog A watchdog and logger to Discord for hosting ScPrime servers. Designed to work on Linux servers. This is only capable of sending the logs from

Keagan Landfried 3 Jan 10, 2022
Key Logger - Key Logger using Python

Key_Logger Key Logger using Python This is the basic Keylogger that i have made

Mudit Sinha 2 Jan 15, 2022
Python bindings for g3log

g3logPython Python bindings for g3log This library provides python3 bindings for g3log + g3sinks (currently logrotate, syslog, and a color-terminal ou

4 May 21, 2021
Scout: an open-source version of the monitoring tool

Badger Scout Scout is an open-source version of the monitoring tool used by Badg

Badger Finance 2 Jan 13, 2022
Pretty-print tabular data in Python, a library and a command-line utility. Repository migrated from bitbucket.org/astanin/python-tabulate.

python-tabulate Pretty-print tabular data in Python, a library and a command-line utility. The main use cases of the library are: printing small table

Sergey Astanin 1.5k Jan 06, 2023
changedetection.io - The best and simplest self-hosted website change detection monitoring service

changedetection.io - The best and simplest self-hosted website change detection monitoring service. An alternative to Visualping, Watchtower etc. Designed for simplicity - the main goal is to simply

7.3k Jan 01, 2023
Token Logger with python

Oxy Token Stealer Features Grabs discord tokens Grabs chrome passwords Grabs edge passwords Nothing else, I don't feel like releasing full on malware

oxy 1 Feb 12, 2022