NAME
Devel::Bug - Transparent inline debugging probe (pure Perl)
SYNOPSIS
use Devel::Bug; # output to STDERR
use Devel::Bug out => *STDOUT; # redirect output
use Devel::Bug ':pfl'; # package + filename + lineno by default
use Devel::Bug ':pfl', out => *STDOUT; # label:flags with options
use Devel::Bug bug => 'dbg'; # export under a different name
# Scalar: value passes through; appears on STDERR (no label)
my $result = bug = substr($str, $offset);
# OUTPUT: (value)
# Inline in any expression
my $path = $dir . '/' . (bug('label') = substr($str, $offset));
# OUTPUT: label=(images/logo.png)
# List: parens around bug() are required to force list-context assignment
my @items = (bug 'items') = get_items();
# OUTPUT: items=(foo bar baz)
# Flags in the label string
my @items = (bug 'items:@') = get_items(); # N: index prefixes
my %hash = (bug 'data:%') = get_pairs(); # key => value format
my %hash = (bug 'data:@%') = get_pairs(); # both
my @items = (bug 'items:m') = get_items(); # multiline
# Per-call options
my $x = (bug 'result', vc => 'green') = compute();
DESCRIPTION
Devel::Bug exports bug(), named for the wiretap sense of the word: plant it inline inside any existing assignment to tap into values as they flow through your code. The value(s) assigned through bug() will reach the left-hand side unmodified; the only side effect is output to the configured filehandle. For list assignments, bug() must be wrapped in parentheses to force list context: (bug ...) = list_expr(). Without them bug is called in scalar context and captures only a single value.
Output format:
label=(value) # scalar
label=(v1 v2 v3) # list
label=(a => 1 b => 2) # keyval
pkg file line: label=(...) # with caller info enabled
By default, ANSI colors are applied when the output handle is a terminal, and multiline layout is applied automatically when output would overflow the terminal width. Both behaviors are configurable; see color, delims, and noterm.
IMPORT AND CALL OPTIONS
Options apply in two contexts: as import-time defaults via use or import(), and as per-call overrides passed directly to bug().
use Devel::Bug out => *STDOUT, lineno => 1; # import-time defaults
my $x = (bug 'result', vc => 'green') = ...; # per-call override
Options follow an optional label:flags string as key/value pairs (see "LABEL:FLAGS SYNTAX"). The bug option (export name) is only valid at import time.
Output
- out (aliases: output, o)
-
Filehandle to print to. Accepts anything
printaccepts as an indirect filehandle: typeglobs, lexical filehandles, and filehandle objects. Default:*STDERR.use Devel::Bug out => *STDOUT; # typeglob use Devel::Bug out => $fh; # lexical filehandle or object
Caller information
When enabled, the corresponding field is prepended to every line of output.
- package (aliases: pkg, p)
-
Calling package name.
- filename (aliases: fn, f)
-
Source filename.
- lineno (aliases: line, ln, l)
-
Source line number.
Display
- multiline (aliases: ml, m)
-
Print each value on its own indented line.
- indices (aliases: indexes, index, i, @)
-
Prefix each list element with
N:. Implies multiline. - keyval (aliases: kv, k, %)
-
Treat the list as alternating key/value pairs and format each as
key => value. Combine withindices/@to addN:prefixes; the index counts pairs, not individual elements. Implies multiline. - delims (aliases: delimiters, d)
-
Controls whether the value is wrapped in parentheses. Three states:
Colors
- color
-
Controls when ANSI colors are applied. Three states:
- infocolor (alias: ic)
-
Term::ANSIColor color specification for the caller-info prefix, e.g.
'bold','cyan on_black'. Default: none. - labelcolor (alias: lc)
-
Color specification for the label. Default:
'bold'. - valcolor (aliases: vc, valuecolor)
-
Color specification for values. Default:
'red on_grey23'.
Terminal detection
- noterm (aliases: noterminal, n)
-
Disable terminal width detection. When set, neither
sttynor Term::Size::Perl is consulted, making both entirely optional. Withnotermenabled, terminal-width-based multiline layout is suppressed, andcolor => 'auto'behaves as if the output is not a terminal.A warning is issued if terminal detection is attempted,
stty sizefails, and Term::Size::Perl cannot be loaded. Setnotermto suppress both the detection and the warning.
Pretty-printer
- pp
-
Fully-qualified name of the function used to format reference values, in the form
'Module::Name::function'. The function is called with the reference as its first argument and must return a string. The module is loaded automatically on first use. If the specified module cannot be loaded or the named sub does not exist, a warning is issued and the default is used instead.Default:
'Data::Dumper::Dumper'.use Devel::Bug pp => 'Data::Dump::pp'; # import-time default my $x = (bug 'data', pp => 'Data::Dump::pp') = get_data(); # per-call
Alternative display value
- val (aliases: value, v, override)
-
Display a different value in the output than the one being assigned. The actual assigned value still passes through unchanged.
Use this when the assigned value is opaque or uninteresting, but a related value at the same point in the code is more informative. Particularly useful in ternary expressions, where the probe fires only when that branch is taken.
# Without bug(): a do {} block is needed to log and still return a value my $installed = $sub =~ /^(.+)::/ ? do { print "package=($1)\n"; *{ $caller . '::' . $name }= \&{ $sub } } : carp "Cannot determine package from '$sub'"; # With bug(): val => $1 is displayed; the glob assignment passes through my $installed = $sub =~ /^(.+)::/ ? bug('package', val => $1)= *{ $caller . '::' . $name }= \&{ $sub } : carp "Cannot determine package from '$sub'";
Export name
- bug
-
Rename or suppress the exported function.
use Devel::Bug bug => 'tap'; # exports as tap() use Devel::Bug bug => ''; # suppresses export ('', 0, undef all work)The name must be a valid Perl identifier (
/^[a-z]\w*$/ior/^_\w+$/). This option is only valid at import time; it may not be passed tobug().
LABEL:FLAGS SYNTAX
A label:flags string may optionally appear as the first argument to bug() or use (import()).
The string has the form label:flags, where both parts are optional. A leading colon means an empty label; the characters after the colon each enable a boolean option by its single-char alias.
use Devel::Bug ':pfl'; # empty label, flags p, f, l
use Devel::Bug 'app:pf'; # label 'app', flags p, f
use Devel::Bug 'app'; # label 'app', no flags
my @r = (bug 'data:@%') = ...; # label 'data', flags @ and %
my @r = (bug ':m') = ...; # empty label, flag m
Flag characters:
@ i indices % k keyval m multiline
p package f filename l lineno
d delims n noterm
CHAINING
Bug probes can be placed at different points in a pipeline to capture each intermediate value independently.
my @data = (1, 2, 3, 4, 5, 6);
my @doubled =
(bug 'doubled')= # parens make this a list assignment; bug() passes the whole list through
map { $_ * 2 }
(bug 'evens')= # parens force list context; without them bug() captures only one value
grep { $_ % 2 == 0 } @data;
# OUTPUT:
# doubled=(4 8 12)
# evens=(2 4 6)
'evens' captures the elements that passed the grep; 'doubled' captures those elements after multiplication. Output fires left-to-right as Perl frees temporaries at end-of-statement, which is the reverse of data flow - hence 'doubled' prints before 'evens'.
DEPENDENCIES
Term::ANSIColor, Data::Dumper.
Terminal width detection first tries stty size. Term::Size::Perl is loaded on demand only if stty is unavailable or returns no output, and is never consulted when noterm is set.
Data::Dump and other pretty-printer modules are optional; see the pp option.
AUTHOR
Kevin Shea
LICENSE
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.