dprint (coming soon)
The dprint function in the Tribler.Debug.Dprint.py module can be used to generate usefull console output during the development process. Any message is automatically prepended with the filename, linenumber, and function from where it was called.
from Tribler.Debug.Dprint import dprint
# Display a message "foo bar"
if __debug__: dprint("foo", "bar")
# filename:1 <module> foo bar
# Display a message in a function
if __debug__: dprint("foo")
# filename:2 my_function foo
# Display a value types
if __debug__: dprint("foo", 123, 1.5, meta=1)
# filename:1 <module> (StringType, len 3) foo
# filename:1 <module> (IntType) 123
# filename:1 <module> (FloatType) 1.5
# Display a message with a callstack
if __debug__: dprint("foo", stack=1)
# filename:2 my_function foo
# filename:2 my_function ---
# filename:2 my_function Stacktrace on thread: "MainThread"
# filename:2 my_function Dprint.py:489 <module>
# filename:2 my_function filename.py:4 <module>
# filename:2 my_function filename.py:2 my_function
# Display an exception
if __debug__: dprint("An exception occured", exception=1)
# filename:4 <module> An exception occured
# filename:4 <module> ---
# filename:4 <module> --- Exception: <type 'exceptions.RuntimeError'> ---
# filename:4 <module> Wrong
# filename:4 <module> Traceback where the exception originated:
# filename:4 <module> filename.py:2
# Display a cpu-intensive message
# filename:6 <module> foo-bar moo-milk
Origionally a regular print statement was used in the Tribler code. There were several issues that encouraged us to change:
- Because of some 'feature' within wxWindows we had to print everything to stderr making each print statement longer.
- To identify different print statements we had to manually include the file- and function-name making each print statement longer and causing problems with copy pasted code that wasn't updated accordingly.
- Each print statement was protected by a global DEBUG variable. Each of these variables should be set to False when checking in code. However, this was sometimes forgotten. Furthermore, evaluating this DEBUG variable costs some (a very small amount) of CPU cycles.
- We preferred a more versitile mechanism to search through messages.
As with all things there is a downside to having the system figure our filenames, linenumbers, and the other information that can be presented by dprint. To reduce the CPU footprint we strongly advise to put all dprint calls behind an if __debug__: statement. This will cause the dprint statement to be compiled out of the release version entirely (the __debug__ variable is not evaluated when running in optimized mode).
Dprint offers several configuration options. Default values are set in Dprint.py but can be overridden by two configuration files:
- dprint.conf (in the linux home directory)
- dprint.conf (in the run directory)
The following sample configuration file is not usefull but explains the syntax that the dprint.conf accepts:
# The display style
# Can be either "column" or "short"
# The default is "short"
style = column
# In the [filter] sections the rules for the "ENTRY" chain can be
# specified. Each entry has the form "source = target".
# There are several possible source rules: source, level, and
# pattern. The examples below will explain these rules.
# The target can be accept, drop, continue, or jump. When jump is
# specified a second argument must represent the chain to jump to.
# For each message a filter chain (with optional branches) is followed
# to decide to accept or drop a message. By default all messages are
# dropped (because the default policy for the "ENTRY" chain is drop).
# To display all messages the policy of the "ENTRY" chain can be
# changed to accept.
policy = accept
# The following will match filename.endwith(tribler.py), function-name
# == main, and /Tribler/ in filename. Any messages that match will be
source tribler.py, main, /Tribler/ = accept
# A source match does not require all of the parameters. The following
# will match filename.endwith(crawler.py). Any messages that match
# will be send to the crawler-chain for further filtering.
source crawler.py = jump crawler
# It is also possible to match messages of a specific level. The
# following will match messages with level warning.
level warning = accept
# The strongest matching mechanism is the pattern. This causes a
# regular expression to check each parameter to the dprint
# statement. The following will accept messages that have at least one
# parameter that start with "foo" and end with "bar".
pattern ^foo.*bar$ = accept
# New filter chains can be created by adding a [filter filter-name]
# section in dprint.conf. To use a chain a jump must be performed to
# this chain from, for instance,the "ENTRY" chain (see the above jump
# If no rules in a chain match the default policy for that chain is
# used. By default this is return. However, it can be set to accept or
# drop in the [filter-policy] section (as shown above).
# The default policy for this chain has been set to accept. However,
# if a message starts with "tmp" will will drop it anyway.
pattern ^tmp = drop
# The default policies for other filter chains can be set to: accept,
# drop, or return. The default for new chains is return.
crawler = accept
A typical dprint.conf for someone who is currently working on the crawler may look like:
style = column
source crawler.py = accept
policy = drop