Verbosity Specifiers

Verbosity specifiers are the core mechanism for controlling which messages are emitted and at what level. They provide fine-grained control over different categories of output in your applications. These are not provided by the SciMLLogging package, but instead must be implemented by a package wishing to use the SciMLLogging interface.

Abstract Base Type

Creating Verbosity Specifiers

Package authors can define their own verbosity specifier types in two ways:

Using the @verbosity_specifier Macro (Recommended)

The @verbosity_specifier macro automatically generates a parametric struct with constructors, presets, and group support:

SciMLLogging.@verbosity_specifierMacro
@verbosity_specifier name begin
    toggles = (...)
    sub_specifiers = (...)   # optional
    presets = (...)
    groups = (...)
end

Generates a parametric struct and constructors for a verbosity specifier.

Input Format

toggles: Tuple of symbols for leaf verbosity toggles. Fields are typed as MessageLevel. Each toggle controls whether (and at what level) a category of log messages is emitted.

sub_specifiers: (optional) Tuple of symbols for fields that hold another AbstractVerbositySpecifier or AbstractVerbosityPreset (a sub-spec for some nested concern, e.g. a LinearVerbosity inside a DEVerbosity). Each declared sub-specifier becomes its own type parameter on the generated struct, so the field is concretely typed at the instance level. This preserves inference when the sub-specifier is forwarded to a downstream API (e.g. solve(...; verbose = outer.linear_verbosity)), and lets the outer-spec-defining package hold a sub-specifier type that it does not depend on at definition time (e.g. DiffEqBase holding a NonlinearVerbosity without depending on NonlinearSolve).

presets: Named tuple mapping preset names to field configurations. Each preset maps field names to message levels (for toggles) or to a preset/sub-spec instance (for sub_specifiers). Must include at least Standard. Can define custom presets beyond the standard five (None, Minimal, Standard, Detailed, All).

groups: Named tuple mapping group names to tuples of toggle symbols. Groups allow setting multiple toggles at once. Group fields must be toggles, not sub_specifiers.

Generated Code

Struct: Creates name{Enabled, S1, ..., Sk} <: AbstractVerbositySpecifier{Enabled}, where S1..Sk are the type parameters for each declared subspecifier (in order). Toggle fields are ::MessageLevel. If no `subspecifiersblock is given, the struct is justname{Enabled}`.

Constructors:

  • name(): Default constructor using Standard preset
  • name(preset::AbstractVerbosityPreset): Constructor from preset (e.g., name(Minimal()))
  • name(; preset=nothing, groups..., kwargs...): Keyword constructor with precedence: individual > group > preset

Custom Preset Types: Generates struct definitions for non-standard presets.

Example

@verbosity_specifier SolverVerbosity begin
    toggles = (:convergence, :step_rejected)

    sub_specifiers = (:linear_verbosity,)

    presets = (
        Standard = (
            convergence      = InfoLevel,
            step_rejected    = WarnLevel,
            linear_verbosity = LinearVerbosity(None()),
        ),
    )

    groups = (
        solver = (:convergence, :step_rejected),
    )
end
source

Manual Implementation

Alternatively, you can manually define verbosity specifier types by subtyping AbstractVerbositySpecifier{Enabled}. The Enabled type parameter lets the compiler eliminate logging branches entirely when the specifier is disabled:

using SciMLLogging

struct MyPackageVerbosity{Enabled} <: AbstractVerbositySpecifier{Enabled}
    initialization::MessageLevel   # Controls startup and setup messages
    progress::MessageLevel         # Controls progress and iteration updates
    convergence::MessageLevel      # Controls convergence-related messages
    diagnostics::MessageLevel      # Controls diagnostic messages
    performance::MessageLevel      # Controls performance-related messages
end

Note: Concretely typing the fields as MessageLevel is recommended for performance:

  • Type stability: Eliminates type instabilities that can hurt performance
  • Compile-time optimization: Allows the compiler to constant-fold logging branches when the specifier is a constant

Configuring Message Categories

Each field in a verbosity specifier can be set to any MessageLevel:

# Create a custom configuration
custom_verbosity = MyPackageVerbosity(
    initialization = InfoLevel,     # Show startup information
    progress = Silent,             # Hide progress updates
    convergence = InfoLevel,        # Show convergence status
    diagnostics = WarnLevel,       # Show diagnostic messages
    performance = InfoLevel        # Show performance info
)

Integration with Packages

Package authors should provide verbosity arguments in their main functions:

function solve_problem(problem; verbose = MyPackageVerbosity(Standard()), kwargs...)
    @SciMLMessage("Starting computation", verbose, :initialization)

    for i in 1:max_iterations
        @SciMLMessage("Iteration $i", verbose, :progress)

        # ... computation ...

        if converged
            @SciMLMessage("Converged after $i iterations", verbose, :convergence)
            break
        end
    end

    return result
end