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
Beautifully colored, quick and simple Python logging

Python Quick Logging | QLogging Beautifully colored, quick and simple Python logging. This logger is based on Python logging package Screenshots: Term

45 Sep 25, 2022
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
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
dash-manufacture-spc-dashboard is a dashboard for monitoring read-time process quality along manufacture production line

In our solution based on plotly, dash and influxdb, the user will firstly generate the specifications for different robots, and then a wide range of interactive visualizations for different machines

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

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

腾讯蓝鲸 102 Dec 22, 2022
Track Nano accounts and notify via log file or email

nano-address-notifier Track accounts and notify via log file or email Required python libs

Joohansson (Json) 4 Nov 08, 2021
pyEventLogger - a simple Python Library for making customized Logs of certain events that occur in a program

pyEventLogger is a simple Python Library for making customized Logs of certain events that occur in a program. The logs can be fully customized and can be printed in colored format or can be stored i

Siddhesh Chavan 2 Nov 03, 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
Command-line tool that instantly fetches Stack Overflow results when an exception is thrown

rebound Rebound is a command-line tool that instantly fetches Stack Overflow results when an exception is thrown. Just use the rebound command to exec

Jonathan Shobrook 3.9k Jan 03, 2023
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
Translating symbolicated Apple JSON format crash log into our old friends :)

CrashTranslation Translating symbolicated Apple JSON format crash log into our old friends :) Usage python3 translation.py -i {input_sybolicated_json_

Kam-To 11 May 16, 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
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
Discord-Image-Logger - Discord Image Logger With Python

Discord-Image-Logger A exploit I found in discord. Working as of now. Explanatio

111 Dec 31, 2022
Progressbar 2 - A progress bar for Python 2 and Python 3 - "pip install progressbar2"

Text progress bar library for Python. Travis status: Coverage: Install The package can be installed through pip (this is the recommended method): pip

Rick van Hattem 795 Dec 18, 2022
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
Summarize LSF job properties by parsing log files.

Summarize LSF job properties by parsing log files of workflows executed by Snakemake.

Kim 4 Jan 09, 2022
Integrates a UPS monitored by NUT into OctoPrint

OctoPrint UPS This OctoPrint plugin interfaces with a UPS monitored by NUT (Network UPS Tools). Requirements NUT must be configured by the user. This

Shawn Bruce 11 Jul 05, 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
giving — the reactive logger

giving is a simple, magical library that lets you log or "give" arbitrary data throughout a program and then process it as an event stream.

Olivier Breuleux 0 May 24, 2022