Datum::Cfg(3pm)

πŸ“¦
version 0.1.3 Β· 2 versions
  • 0.1.3 Β· debian bookworm, debian trixie, ubuntu noble, ubuntu resolute, ubuntu stonking (latest)
  • 0.1.3 Β· ubuntu jammy
, in debian bookworm, debian trixie, ubuntu noble, ubuntu resolute, ubuntu stonking

πŸ’– NAME πŸ’–

Carp::Datum::Cfg β€” Dynamic Debug Configuration Setting for Datum. Yep bestie, this is the Datum::Cfg(3pm) page and it's literally the remote control for how chatty your debug output gets. πŸ’…


✨ SYNOPSIS ✨

# In application's main
use Carp::Datum qw(:all on);      # turns Datum "on" or "off"
DLOAD_CONFIG(-file => "./debug.cf", -config => "config string");

πŸ¦‹ DESCRIPTION πŸ¦‹

Okay so here's the vibe: you drop DLOAD_CONFIG into your application's main file, and now a debugging configuration can be dynamically loaded to define a specific level of debug/trace flags for one specific sub-part of code. Slay.

Like, imagine turning tracing off the second you walk into some designated package's routine. That is so useful for concentrating your debugging onto the area you're actually working on rn, and/or for filtering out those verbose parts of the code (looking at you, recursive function calls) when they genuinely do not need to be monitored to fix the problem. 🎯


πŸŽ€ EXAMPLE πŸŽ€

Before we get into the obscure grammar explanation, here's a lil taste of what dynamic configuration can actually specify:

/*
 * flags definition: macro that can be used in further configuration
 * settings
 */
flags common {
    all(yes);
    trace(yes): all;
}

flags silent {
    all(yes);
    flow(no);
    trace(no);
    return(no);
}

/*
 * default setting to use when there is no specific setting
 * for the area
 */
default common;

/*
 * specific settings for specific areas
 */
routine "context", "cleanup"                 { use silent; }
routine "validate", "is_num", "is_greater"   { use silent; }

file "Keyed_Tree.pm"                         { use silent; }
file "Color.pm" {
    use silent;
    trace(yes): emergency, alert, critical;
}

cluster "CGI::MxScreen" {
    use silent;
    assert(no);
    ensure(no);
}

/*
 * aliasing to reduce the trace output line length
 */

alias "/home/dehaudtc/usr/perl/lib/site_perl/5.6.0/CGI" => "<PM>";

πŸ’œ INTERFACE πŸ’œ

The only user interface is the DLOAD_CONFIG routine, and it expects these optional named parameters:

  • -config => string β€” hands over an inlined configuration string that gets appended to the one defined by -file, if there even is one.
  • -file => filename β€” names the configuration file to load up so the debugging and tracing flags for this run get initialized.

🌈 CONFIGURATION DIRECTIVES 🌈

🌟 Main Configuration Directives 🌟

These main directives can show up at a nesting level of 0. The syntax unit we call BLOCK is a list of semi-colon terminated directives held inside curly braces, okurrr.

  • alias large_path => short_path β€” defines an alias to be used during tracing. The large_path string gets replaced by the short_path in the logs.

For instance, given:

alias "/home/dehaudtc/lib/CGI" => "<CGI>";

then a trace for file "/home/dehaudtc/lib/CGI/Carp.pm" would be traced as coming from file "<CGI>/Carp.pm", which is so much nicer to read. 🫢

  • cluster name1, name2 BLOCK β€” the BLOCK defines the flags to apply to all named clusters. A cluster is a set of classes under a given name scope. Cluster names are given by strings inside double quotes, like:
cluster "CGI::MxScreen", "Net::MsgLink" { use silent; }

This would apply to all classes under the "CGI::MxScreen" or "Net::MsgLink" name scopes, i.e. "CGI::MxScreen::Screen" would be affected.

An exact match is attempted first, i.e. saying:

cluster "CGI::MxScreen"         { use verbose; }
cluster "CGI::MxScreen::Screen" { use silent; }

would apply the silent flags for "CGI::MxScreen::Screen" but the verbose ones to "CGI::MxScreen::Tie::Stdout".

  • default name|BLOCK β€” specifies the default flags that should apply. Those default flags can be given by providing the name of flags defined by the flags directive, or by expanding them out in the following BLOCK.

For instance:

default silent;

would say the flags to apply by default are the ones defined by an earlier flags silent directive. Not expanding defaults allows for quick switching by replacing silent with verbose. It is up to the module user to define what is meant by that though. πŸ™ˆ

  • file name1, name2 BLOCK β€” the BLOCK defines the flags to be applied to all named files. File names are given by strings within double quotes, like:
file "foo.pm", "bar.pm" { use silent; }

This would apply to all files named "foo.pm" or "bar.pm", whatever their directory, i.e. it would apply to "/tmp/foo.pm" as well as "../bar.pm".

An exact match is attempted first, i.e. saying:

file "foo.pm"      { use verbose; }
file "/tmp/foo.pm" { use silent; }

would apply the silent flags for "/tmp/foo.pm" but the verbose ones to "./foo.pm".

  • flags name BLOCK β€” defines a symbol name whose flags are described by the following BLOCK. That name can then be used in default and use directives.

For instance:

flags common {
    all(yes);
    trace(yes): all;
}

would define the flags known as common, which can then be re-used, as in:

flags other {
    use common;         # reuses definiton of common flags
    panic(no);          # but switches off panic, enabled in common
}
A flag symbol must be defined prior being used. No skipping ahead, bestie. ⚠️
  • routine name1, name2 BLOCK β€” the BLOCK defines the flags to apply to all named routines. Routine names are given by strings within double quotes, like:
routine "foo", "bar" { use silent; }

This would apply to all routines named "foo" or "bar", whatever their package, for instance "main::foo" and "x::bar".

πŸ”₯ Debugging and Tracing Flags πŸ”₯

Debugging (and tracing) flags can be specified only within syntactic BLOCK items, as expected by main directives such as flags or file.

Here's the whole list of debugging flags you can specify in the configuration. The order in which they're given in the file is significant: the yes/no settings are applied sequentially. ✨

  • use name β€” uses flags defined by a flags directive under name. It acts as a recursive macro expansion (since use can also be specified in flags). The symbol name must have been defined earlier.
  • flow(yes|no) β€” whether to print out the entering/exiting of routines. That implies the invocation of the DFEATURE function in the routines.
  • return(yes|no) β€” whether to print out the returned when using the return DVAL and DARY routines.
  • trace(yes|no) β€” whether to print out traces specified by the DTRACE function. By default all trace levels are affected. It may be followed by a list of trace levels affected by the directive, as in.
trace(yes): emergency, alert, critical;

Trace levels are purely conventional, and have a strict one-to-one mapping with DTM_TRC_ levels given at the DTRACE call. They are further described in "Trace Levels" below. There is one bit per defined trace level, contrary to the convention established by syslog(), for better tuning.

  • require(yes|no) β€” whether to evaluate the pre-condition given by DREQUIRE. But see "Assertion Evaluation Note" below.
  • assert(yes|no) β€” whether to evaluate the assertion given by DASSERT. But see "Assertion Evaluation Note" below.
  • ensure(yes|no) β€” whether to evaluate the post-condition given by DENSURE. But see "Assertion Evaluation Note" below.
  • panic(yes|no) β€” whether to panic upon an assertion failure (pre/post condition or assertion). If not enabled, a simple warning is issued, tracing the assertion failure.
  • stack(yes|no) β€” whether to print out a stack trace upon assertion failure.
  • all(yes|no) β€” enable or disables all the previously described items.

πŸ’€ Assertion Evaluation Note πŸ’€

When Carp::Datum is switched off, the assertions are always monitored, and any failure is fatal. Why? Because a failing assertion is a Bad Thing in production mode, periodt. Also, since DREQUIRE and friends are not C macros but routines, the assertion expression gets evaluated anyway, so it might as well be tested.

Therefore, a directive like:

require(no);

will only turn off monitoring of pre-conditions in debugging mode (e.g. because the interface is not finalized, or the clients do not behave properly yet).

πŸ‘‘ Trace Levels πŸ‘‘

Here's the list of trace flags that can be specified by the configuration:

    Configuration    DTRACE flag
    -------------    -------------
              all    TRC_ALL
        emergency    TRC_EMERGENCY
            alert    TRC_ALERT
         critical    TRC_CRITICAL
            error    TRC_ERROR
          warning    TRC_WARNING
           notice    TRC_NOTICE
             info    TRC_INFO
            debug    TRC_DEBUG

A user could say something like:

trace(no): all;
trace(yes): emergency, alert, critical, error;

Since flags are applied in sequence, the first directive turns all tracing flags to off, and the second enables only the listed ones. Chef's kiss. 🀌


😭 BUGS 😭

Some things are not fully documented. (We know. We're crying about it too.)


🫢 AUTHORS 🫢

Christophe Dehaudt and Raphael Manfredi are the original authors. Legends, fr fr.

Send bug reports, hints, tips, suggestions to Dave Hoover at <squirrel@cpan.org>. πŸ“¬


🌸 SEE ALSO 🌸

Log::Agent(3).


And that's the whole page, bestie! πŸ’– This was perl v5.34.0, dated 2022-06-30, and yes the file is literally called Datum::Cfg(3pm) β€” go forth and configure your debug flags like the main character you are. βœ¨πŸ¦‹πŸ’