User Tutorial: Configuring Package Verbosity

This tutorial is for end users who want to control the verbosity of packages that use SciMLLogging.jl. Each package will have it's own implementation of the AbstractVerbositySpecifier type, which defines the available verbosity options. This guide is meant to be a general guide to the specifics of SciMLLogging.jl, as well as give some examples of how the system is typically implemented. For details on the specific verbosity settings of a package, refer to that package's documentation.

Quick Start

Packages that use SciMLLogging typically provide a keyword argument such as verbose or verbosity to control output. The easiest way to get started is with verbosity presets.

Using Verbosity Presets (Recommended)

Most of the time, you'll want to use one of the built-in presets rather than configuring individual message categories:

Available Presets:

  • None(): Log nothing at all
  • Minimal(): Only essential messages and warnings
  • Standard(): Balanced verbosity suitable for typical usage
  • Detailed(): Comprehensive verbosity for debugging and analysis
  • All(): Maximum verbosity
using SciMLLogging

# No output at all - best for production
result = solve(problem, verbose = SolverVerbosity(None()))

# Minimal output - only critical messages
result = solve(problem, verbose = SolverVerbosity(Minimal()))

# Standard output - balanced for typical usage (recommended)
result = solve(problem, verbose = SolverVerbosity(Standard()))

# Detailed output - comprehensive information for debugging
result = solve(problem, verbose = SolverVerbosity(Detailed()))

# Maximum output - show everything
result = solve(problem, verbose = SolverVerbosity(All()))

Custom Verbosity Configuration

For more control, you can configure individual message categories:

# Example: Customizing a solve's verbosity
verbose_settings = SolverVerbosity(
    initialization = InfoLevel(),      # Show startup messages
    iterations = Silent(),             # Don't show each iteration
    convergence = InfoLevel(),         # Show convergence information
    error_control = WarnLevel()        # Show warnings related to error control of the solver
)

result = solve(problem, verbose = verbose_settings)

Message Levels:

  • Silent(): No output for this category
  • DebugLevel(): Lowest priority debug messages
  • InfoLevel(): Informational messages
  • WarnLevel(): Warning messages
  • ErrorLevel(): Error messages
  • CustomLevel(n): Custom level with integer value n

Complete Working Example

Here's a full example showing how SciMLLogging works in practice, using a simulated "solver":

using SciMLLogging
using SciMLLogging: None, Standard, All
using ConcreteStructs: @concrete

# 1. Define a verbosity specifier (this would typically be done by a package)
@concrete struct SolverVerbosity <: AbstractVerbositySpecifier
    initialization
    iterations
    convergence
    linear_solve
    warnings
end

# Likewise the constructors would typically be implemented by a package
function SolverVerbosity(;
    initialization = Info(),
    iterations = Silent(),
    convergence = InfoLevel(),
    linear_solve = Silent(),
    warnings = WarnLevel()
    )
    SolverVerbosity(initialization, iterations, convergence, linear_solve, warnings)
end

# 2. Implement preset support
function SolverVerbosity(preset::None)
    SolverVerbosity(Silent(), Silent(), Silent(), Silent(), Silent())
end

function SolverVerbosity(preset::Standard)
    SolverVerbosity(InfoLevel(), Silent(), InfoLevel(), Silent(), WarnLevel())
end

function SolverVerbosity(preset::All)
    SolverVerbosity(InfoLevel(), InfoLevel(), InfoLevel(), InfoLevel(), WarnLevel())
end

# 3. Example solver function using SciMLLogging, the specific messages and where the messages are emitted
# would be decided by the package
function example_solver(problem; verbose = SolverVerbosity(Standard()), max_iterations = 10)
    @SciMLMessage("Initializing solver for problem of size $(length(problem))", verbose, :initialization)

    # Simulate solver iterations
    for i in 1:max_iterations
        @SciMLMessage("Iteration $i: residual = $(0.1^i)", verbose, :iterations)

        if i % 3 == 0
            @SciMLMessage("Solving linear system", verbose, :linear_solve)
        end

        if 0.1^i < 1e-6
            @SciMLMessage("Converged after $i iterations", verbose, :convergence)
            return "Solution found"
        end

        if i == 8
            @SciMLMessage("Solver may be slow to converge", verbose, :warnings)
        end
    end

    @SciMLMessage("Maximum iterations reached", verbose, :warnings)
    return "Max iterations"
end

# 4. Try different verbosity levels
problem = [1.0, 2.0, 3.0]

println("=== With Standard verbosity ===")
result1 = example_solver(problem, verbose = SolverVerbosity(Standard()))

println("\n=== With All verbosity ===")
result2 = example_solver(problem, verbose = SolverVerbosity(All()))

println("\n=== With None verbosity ===")
result3 = example_solver(problem, verbose = SolverVerbosity(None()))

println("\n=== With custom verbosity ===")
custom_verbose = SolverVerbosity(
    initialization = InfoLevel(),
    iterations = Silent(),
    convergence = InfoLevel(),
    linear_solve = InfoLevel(),
    warnings = ErrorLevel()  # Treat warnings as errors for this run
)
result4 = example_solver(problem, verbose = custom_verbose)
"Solution found"