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
Rich is a Python library for rich text and beautiful formatting in the terminal.

Rich 中文 readme • lengua española readme • Läs på svenska Rich is a Python library for rich text and beautiful formatting in the terminal. The Rich API

Will McGugan 41.5k Jan 07, 2023
A very basic esp32-based logic analyzer capable of sampling digital signals at up to ~3.2MHz.

A very basic esp32-based logic analyzer capable of sampling digital signals at up to ~3.2MHz.

Davide Della Giustina 43 Dec 27, 2022
A python logging library

logi v1.3.4 instolation the lib works on python 3x versions pip install logi examples import import logi log = logger(path='C:/file path', timestamp=T

2 Jul 06, 2022
Soda SQL Data testing, monitoring and profiling for SQL accessible data.

Soda SQL Data testing, monitoring and profiling for SQL accessible data. What does Soda SQL do? Soda SQL allows you to Stop your pipeline when bad dat

Soda Data Monitoring 51 Jan 01, 2023
Splunk Add-On to collect audit log events from Github Enterprise Cloud

GitHub Enterprise Audit Log Monitoring Splunk modular input plugin to fetch the enterprise audit log from GitHub Enterprise Support for modular inputs

Splunk GitHub 12 Aug 18, 2022
Multi-processing capable print-like logger for Python

MPLogger Multi-processing capable print-like logger for Python Requirements and Installation Python 3.8+ is required Pip pip install mplogger Manual P

Eötvös Loránd University Department of Digital Humanities 1 Jan 28, 2022
Vibrating-perimeter - Simple helper mod that logs how fast you are mining together with a simple buttplug.io script to control a vibrator

Vibrating Perimeter This project consists of a small minecraft helper mod that writes too a log file and a script that reads said log. Currently it on

Heart[BOT] 0 Nov 20, 2022
Monitoring plugin to check disk io with Icinga, Nagios and other compatible monitoring solutions

check_disk_io - Monitor disk io This is a monitoring plugin for Icinga, Nagios and other compatible monitoring solutions to check the disk io. It uses

DinoTools 3 Nov 15, 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
A Python package which supports global logfmt formatted logging.

Python Logfmter A Python package which supports global logfmt formatted logging. Install $ pip install logfmter Usage Before integrating this library,

Joshua Taylor Eppinette 15 Dec 29, 2022
Small toolkit for python multiprocessing logging to file

Small Toolkit for Python Multiprocessing Logging This is a small toolkit for solving unsafe python mutliprocess logging (file logging and rotation) In

Qishuai 1 Nov 10, 2021
🐑 Syslog Simulator hazır veya kullanıcıların eklediği logları belirtilen adreslere ve port'a seçilen döngüde syslog ile gönderilmesini sağlayan araçtır. | 🇹🇷

syslogsimulator hazır ürün loglarını SIEM veya log toplayıcısına istediğiniz portta belirli sürelerde göndermeyi sağlayan küçük bir araçtır.

Enes Aydın 3 Sep 28, 2021
Greppin' Logs: Leveling Up Log Analysis

This repo contains sample code and example datasets from Jon Stewart and Noah Rubin's presentation at the 2021 SANS DFIR Summit titled Greppin' Logs. The talk was centered around the idea that Forens

Stroz Friedberg 20 Sep 14, 2022
Pretty and useful exceptions in Python, automatically.

better-exceptions Pretty and more helpful exceptions in Python, automatically. Usage Install better_exceptions via pip: $ pip install better_exception

Qix 4.3k Dec 29, 2022
Simple and versatile logging library for python 3.6 above

Simple and versatile logging library for python 3.6 above

Miguel 1 Nov 23, 2022
Outlog it's a library to make logging a simple task

outlog Outlog it's a library to make logging a simple task!. I'm a lazy python user, the times that i do logging on my apps it's hard to do, a lot of

ZSendokame 2 Mar 05, 2022
A Python library that tees the standard output & standard error from the current process to files on disk, while preserving terminal semantics

A Python library that tees the standard output & standard error from the current process to files on disk, while preserving terminal semantics (so breakpoint(), etc work as normal)

Greg Brockman 7 Nov 30, 2022
A Prometheus exporter for monitoring & analyzing Grafana Labs' technical documentation

grafana-docs-exporter A Prometheus exporter for monitoring & analyzing Grafana Labs' technical documentation Here is the public endpoint.

Matt Abrams 5 May 02, 2022
Prettify Python exception output to make it legible.

pretty-errors Prettifies Python exception output to make it legible. Install it with python -m pip install pretty_errors If you want pretty_errors to

Iain King 2.6k Jan 04, 2023
Docker container log aggregation with Elasticsearch, Kibana & Filebeat

Epilog Dead simple container log aggregation with ELK stack Preface Epilog aims to demonstrate a language-agnostic, non-invasive, and straightfo

Redowan Delowar 23 Oct 26, 2022