Hledger.Utils.Debug

hledger-lib-1.41: A library providing the core functionality of hledger

Safe Haskell | None
Language | Haskell2010

Hledger.Utils.Debug

Contents

- Tracing to stderr
- Logging to PROGNAME.log
- Tracing or logging based on shouldLog
- Pretty tracing/logging in pure code
- Pretty tracing/logging in IO
- Tracing/logging with a show function
- Utilities
- Re-exports

Description

Here are fancier versions of Debug.Trace, with these features:

- unsafePerformIO-based for easy usage in pure code, IO code, and program startup code
- reasonably short and memorable function names
- pretty-printing haskell values, with or without colour, using pretty-simple
- enabling/disabling debug output with --debug
- multiple debug verbosity levels, from 1 to 9
- sending debug output to stderr or to a log file
- enabling logging based on program name

The basic "trace" functions print to stderr. This debug output will be interleaved with the program's normal output, which can be useful for understanding when code executes.

The Log functions log to a file instead. The need for these is arguable, since a technically savvy user can redirect stderr output to a log file, eg: `CMD 2>debug.log`. But here is how they currently work:

The "traceLog" functions log to the program's debug log file, which is `PROGNAME.log` in the current directory, where PROGNAME is the program name returned by `getProgName`. When using this logging feature you should call `withProgName` explicitly at the start of your program to ensure a stable program name, otherwise it can change to "interactive" eg when running in GHCI. Eg: `main = withProgName MYPROG $ do ...`.

The OrLog functions can either print to stderr or log to a file.

- By default, they print to stderr.
- If the program name has been set (with @withProgName) to something ending with ".log", they log to that file instead. This can be useful for programs which should never print to stderr, eg TUI programs like hledger-ui.

The At functions produce output only when the program was run with a sufficiently high debug level, as set by a `--debug[=N]` command line option. N ranges from 1 (least debug output) to 9 (most debug output), `--debug` with no argument means 1.

The "dbgN*" functions are intended to be the most convenient API, to be embedded at points of interest in your code. They combine the conditional output of At, the conditional logging of OrLog, pretty printing, and short searchable function names.

Parsing the command line, detecting program name, and file logging is done with unsafePerformIO. If you are working in GHCI, changing the debug level requires editing and reloading this file (sometimes it's more convenient to add a dbg0 temporarily).

In hledger, debug levels are used as follows:

    Debug level:  What to show:
    ------------  ---------------------------------------------------------
    0             normal command output only (no warnings, eg)
    1             useful warnings, most common troubleshooting info (config file args, valuation..)
    2             common troubleshooting info, more detail
    3             report options selection
    4             report generation
    5             report generation, more detail
    6             input file reading
    7             input file reading, more detail
    8             command line parsing
    9             any other rarely needed / more in-depth info

We don't yet have the ability to select debug output by topic. For now, here are some standardish topic strings to search for in hledger debug messages:

acct arg budget calc csv journalFinalise multiBalanceReport opts precision price q style val

Synopsis

- debugLevel :: Int
- traceWith :: (a -> String) -> a -> a
- traceAt :: Int -> String -> a -> a
- traceAtWith :: Int -> (a -> String) -> a -> a
- ptrace :: Show a => a -> a
- ptraceAt :: Show a => Int -> String -> a -> a
- ptraceAtIO :: (MonadIO m, Show a) => Int -> String -> a -> m ()
- traceLog :: String -> a -> a
- traceLogAt :: Int -> String -> a -> a
- traceLogIO :: MonadIO m => String -> m ()
- traceLogAtIO :: MonadIO m => Int -> String -> m ()
- traceLogWith :: (a -> String) -> a -> a
- traceLogAtWith :: Int -> (a -> String) -> a -> a
- ptraceLogAt :: Show a => Int -> String -> a -> a
- ptraceLogAtIO :: (MonadIO m, Show a) => Int -> String -> a -> m ()
- traceOrLog :: String -> a -> a
- traceOrLogAt :: Int -> String -> a -> a
- ptraceOrLogAt :: Show a => Int -> String -> a -> a
- ptraceOrLogAtIO :: (MonadIO m, Show a) => Int -> String -> a -> m ()
- traceOrLogAtWith :: Int -> (a -> String) -> a -> a
- dbg0 :: Show a => String -> a -> a
- dbg1 :: Show a => String -> a -> a
- dbg2 :: Show a => String -> a -> a
- dbg3 :: Show a => String -> a -> a
- dbg4 :: Show a => String -> a -> a
- dbg5 :: Show a => String -> a -> a
- dbg6 :: Show a => String -> a -> a
- dbg7 :: Show a => String -> a -> a
- dbg8 :: Show a => String -> a -> a
- dbg9 :: Show a => String -> a -> a
- dbgExit :: Show a => String -> a -> a
- dbg0IO :: (MonadIO m, Show a) => String -> a -> m ()
- dbg1IO :: (MonadIO m, Show a) => String -> a -> m ()
- dbg2IO :: (MonadIO m, Show a) => String -> a -> m ()
- dbg3IO :: (MonadIO m, Show a) => String -> a -> m ()
- dbg4IO :: (MonadIO m, Show a) => String -> a -> m ()
- dbg5IO :: (MonadIO m, Show a) => String -> a -> m ()
- dbg6IO :: (MonadIO m, Show a) => String -> a -> m ()
- dbg7IO :: (MonadIO m, Show a) => String -> a -> m ()
- dbg8IO :: (MonadIO m, Show a) => String -> a -> m ()
- dbg9IO :: (MonadIO m, Show a) => String -> a -> m ()
- dbg0With :: (a -> String) -> a -> a
- dbg1With :: Show a => (a -> String) -> a -> a
- dbg2With :: Show a => (a -> String) -> a -> a
- dbg3With :: Show a => (a -> String) -> a -> a
- dbg4With :: Show a => (a -> String) -> a -> a
- dbg5With :: Show a => (a -> String) -> a -> a
- dbg6With :: Show a => (a -> String) -> a -> a
- dbg7With :: Show a => (a -> String) -> a -> a
- dbg8With :: Show a => (a -> String) -> a -> a
- dbg9With :: Show a => (a -> String) -> a -> a
- ghcDebugSupportedInLib :: Bool
- data GhcDebugMode
  - = GDNotSupported
  - | GDDisabled
  - | GDNoPause
  - | GDPauseAtStart
  - | GDPauseAtEnd
- ghcDebugMode :: GhcDebugMode
- withGhcDebug' :: a -> a
- ghcDebugPause' :: IO ()
- lbl_ :: String -> String -> String -> String
- progName :: String
- trace :: String -> a -> a
- traceIO :: String -> IO ()
- traceShowId :: Show a => a -> a

# Documentation

debugLevel :: Int #

The programs debug output verbosity. The default is 0 meaning no debug output. The `--debug` command line flag sets it to 1, or `--debug=N` sets it to a higher value (the = is required). Uses unsafePerformIO. When running in GHCI, changing this requires reloading this module.

# Tracing to stderr

traceWith :: (a -> String) -> a -> a #

Trace a value with the given show function before returning it.

traceAt :: Int -> String -> a -> a #

Trace (print to stderr) a string if the global debug level is at or above the specified level. At level 0, always prints. Otherwise, uses unsafePerformIO.

traceAtWith :: Int -> (a -> String) -> a -> a #

Trace (print to stderr) a showable value using a custom show function, if the global debug level is at or above the specified level. At level 0, always prints. Otherwise, uses unsafePerformIO.

ptrace :: Show a => a -> a #

Pretty-trace a showable value before returning it. Like Debug.Trace.traceShowId, but pretty-printing and easier to type.

ptraceAt :: Show a => Int -> String -> a -> a #

Pretty-print a label and a showable value to the console if the global debug level is at or above the specified level. At level 0, always prints. Otherwise, uses unsafePerformIO.

ptraceAtIO :: (MonadIO m, Show a) => Int -> String -> a -> m () #

Like ptraceAt, but convenient to insert in an IO monad and enforces monadic sequencing.

# Logging to PROGNAME.log

traceLog :: String -> a -> a #

Log a string to the debug log before returning the second argument. Uses unsafePerformIO.

traceLogAt :: Int -> String -> a -> a #

Log a string to the debug log before returning the second argument, if the global debug level is at or above the specified level. At level 0, always logs. Otherwise, uses unsafePerformIO.

traceLogIO :: MonadIO m => String -> m () #

Like traceLog but sequences properly in IO.

traceLogAtIO :: MonadIO m => Int -> String -> m () #

Like traceLogAt, but convenient to use in IO.

traceLogWith :: (a -> String) -> a -> a #

Log a value to the debug log with the given show function before returning it.

traceLogAtWith :: Int -> (a -> String) -> a -> a #

Log a string to the debug log before returning the second argument, if the global debug level is at or above the specified level. At level 0, always logs. Otherwise, uses unsafePerformIO.

ptraceLogAt :: Show a => Int -> String -> a -> a #

Pretty-log a label and showable value to the debug log, if the global debug level is at or above the specified level. At level 0, always prints. Otherwise, uses unsafePerformIO.

ptraceLogAtIO :: (MonadIO m, Show a) => Int -> String -> a -> m () #

Like ptraceAt, but convenient to insert in an IO monad and enforces monadic sequencing.

# Tracing or logging based on shouldLog

traceOrLog :: String -> a -> a #

Trace or log a string depending on shouldLog, before returning the second argument.

traceOrLogAt :: Int -> String -> a -> a #

Trace or log a string depending on shouldLog, when global debug level is at or above the specified level, before returning the second argument.

ptraceOrLogAt :: Show a => Int -> String -> a -> a #

Pretty-trace or log depending on shouldLog, when global debug level is at or above the specified level.

ptraceOrLogAtIO :: (MonadIO m, Show a) => Int -> String -> a -> m () #

Like ptraceOrLogAt, but convenient in IO.

traceOrLogAtWith :: Int -> (a -> String) -> a -> a #

Trace or log, with a show function, depending on shouldLog.

# Pretty tracing/logging in pure code

dbg0 :: Show a => String -> a -> a #

Pretty-trace to stderr (or log to debug log) a label and showable value, then return it.

dbg1 :: Show a => String -> a -> a #

Pretty-trace to stderr (or log to debug log) a label and showable value if the --debug level is high enough, then return the value. Uses unsafePerformIO.

dbg2 :: Show a => String -> a -> a #

dbg3 :: Show a => String -> a -> a #

dbg4 :: Show a => String -> a -> a #

dbg5 :: Show a => String -> a -> a #

dbg6 :: Show a => String -> a -> a #

dbg7 :: Show a => String -> a -> a #

dbg8 :: Show a => String -> a -> a #

dbg9 :: Show a => String -> a -> a #

dbgExit :: Show a => String -> a -> a #

Like dbg0, but also exit the program. Uses unsafePerformIO.

# Pretty tracing/logging in IO

dbg0IO :: (MonadIO m, Show a) => String -> a -> m () #

Like dbgN, but convenient to use in IO.

dbg1IO :: (MonadIO m, Show a) => String -> a -> m () #

dbg2IO :: (MonadIO m, Show a) => String -> a -> m () #

dbg3IO :: (MonadIO m, Show a) => String -> a -> m () #

dbg4IO :: (MonadIO m, Show a) => String -> a -> m () #

dbg5IO :: (MonadIO m, Show a) => String -> a -> m () #

dbg6IO :: (MonadIO m, Show a) => String -> a -> m () #

dbg7IO :: (MonadIO m, Show a) => String -> a -> m () #

dbg8IO :: (MonadIO m, Show a) => String -> a -> m () #

dbg9IO :: (MonadIO m, Show a) => String -> a -> m () #

# Tracing/logging with a show function

dbg0With :: (a -> String) -> a -> a #

Like dbgN, but taking a show function instead of a label.

dbg1With :: Show a => (a -> String) -> a -> a #

dbg2With :: Show a => (a -> String) -> a -> a #

dbg3With :: Show a => (a -> String) -> a -> a #

dbg4With :: Show a => (a -> String) -> a -> a #

dbg5With :: Show a => (a -> String) -> a -> a #

dbg6With :: Show a => (a -> String) -> a -> a #

dbg7With :: Show a => (a -> String) -> a -> a #

dbg8With :: Show a => (a -> String) -> a -> a #

dbg9With :: Show a => (a -> String) -> a -> a #

# Utilities

ghcDebugSupportedInLib :: Bool #

Is the hledger-lib package built with ghc-debug support ?

data GhcDebugMode #

Whether ghc-debug support is included in this build, and if so, how it will behave. When hledger is built with the `ghcdebug` cabal flag (off by default, because of extra deps), it can listen (on unix ?) for connections from ghc-debug clients like ghc-debug-brick, for pausing/resuming the program and inspecting memory usage and profile information.

With a ghc-debug-supporting build, ghc-debug can be enabled by running hledger with a negative --debug level. There are three different modes: --debug=-1 - run normally (can be paused/resumed by a ghc-debug client), --debug=-2 - pause and await client commands at program start (not useful currently), --debug=-3 - pause and await client commands at program end.

Constructors

GDNotSupported |
GDDisabled |
GDNoPause |
GDPauseAtStart |
GDPauseAtEnd |

#### Instances

Instances details

Show GhcDebugMode # |
Instance details Defined in Hledger.Utils.Debug Methods showsPrec :: Int -> GhcDebugMode -> ShowS # show :: GhcDebugMode -> String # showList :: [GhcDebugMode] -> ShowS #
Eq GhcDebugMode # |
Instance details Defined in Hledger.Utils.Debug Methods (==) :: GhcDebugMode -> GhcDebugMode -> Bool # (/=) :: GhcDebugMode -> GhcDebugMode -> Bool #
Ord GhcDebugMode # |
Instance details Defined in Hledger.Utils.Debug Methods compare :: GhcDebugMode -> GhcDebugMode -> Ordering # (<) :: GhcDebugMode -> GhcDebugMode -> Bool # (<=) :: GhcDebugMode -> GhcDebugMode -> Bool # (>) :: GhcDebugMode -> GhcDebugMode -> Bool # (>=) :: GhcDebugMode -> GhcDebugMode -> Bool # max :: GhcDebugMode -> GhcDebugMode -> GhcDebugMode # min :: GhcDebugMode -> GhcDebugMode -> GhcDebugMode #

ghcDebugMode :: GhcDebugMode #

Should the program open a socket allowing control by ghc-debug-brick or similar ghc-debug client ? See GhcDebugMode.

withGhcDebug' :: a -> a #

When ghc-debug support has been built into the program and enabled at runtime with --debug=-N, this calls ghc-debug's withGhcDebug; otherwise it's a no-op.

ghcDebugPause' :: IO () #

When ghc-debug support has been built into the program, this calls ghc-debug's pause, otherwise it's a no-op.

lbl_ :: String -> String -> String -> String #

Helper for producing debug messages: concatenates a name (eg a function name), short description of the value being logged, and string representation of the value.

progName :: String #

The progam name, with any ".log" suffix removed.

# Re-exports

trace :: String -> a -> a #

The `trace` function outputs the trace message given as its first argument, before returning the second argument as its result.

For example, this returns the value of `f x` and outputs the message to stderr. Depending on your terminal (settings), they may or may not be mixed.

    >>> let x = 123; f = show
    >>> trace ("calling f with x = " ++ show x) (f x)
    calling f with x = 123
    "123"

The `trace` function should only be used for debugging, or for monitoring execution. The function is not referentially transparent: its type indicates that it is a pure function but it has the side effect of outputting the trace message.

traceIO :: String -> IO () #

The `traceIO` function outputs the trace message from the IO monad. This sequences the output with respect to other IO actions.

@since base-4.5.0.0

traceShowId :: Show a => a -> a #

Like `traceShow` but returns the shown value instead of a third value.

    >>> traceShowId (1+2+3, "hello" ++ "world")
    (6,"helloworld")
    (6,"helloworld")

@since base-4.7.0.0