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 "print" accepts 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 with "indices"/"@" to add "N:" prefixes; the index counts pairs, not individual elements. Implies multiline. delims (aliases: delimiters, d) Controls whether the value is wrapped in parentheses. Three states: "on" (also 1) Always wrap in parentheses. "off" (also "undef") Never wrap in parentheses. "auto" (also '', default) Wrap when output is not colored; omit when colored (color already delineates the value visually). Colors color Controls when ANSI colors are applied. Three states: "on" (also 1) Always apply colors, even to non-terminal output. "off" (also "undef") Never apply colors. "auto" (also '', default) Apply colors only when the output handle is a terminal. 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 "stty" nor Term::Size::Perl is consulted, making both entirely optional. With "noterm" enabled, terminal-width-based multiline layout is suppressed, and "color => 'auto'" behaves as if the output is not a terminal. A warning is issued if terminal detection is attempted, "stty size" fails, and Term::Size::Perl cannot be loaded. Set "noterm" to 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*$/i" or "/^_\w+$/"). This option is only valid at import time; it may not be passed to bug(). 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.