package ppx_minidebug

  1. Overview
  2. Docs

ppx_minidebug usage

ppx_minidebug traces selected code if it has type annotations. ppx_minidebug offers three ways of instrumenting the code: %debug_pp and %debug_show based on deriving.show, and %debug_sexp based on sexplib0 and ppx_sexp_conv. The syntax extension expects a module Debug_runtime in the scope. The ppx_minidebug.runtime library offers three ways of logging the traces, as functors generating Debug_runtime modules given an output channel (e.g. for a file).

Take a look at ppx_debug which is significantly more powerful!

See Minidebug_runtime for the provided loggers.

Usage

Try opam install ppx_minidebug to install from the opam repository. To install `ppx_minidebug` from sources, download it with e.g. gh repo clone lukstafi/ppx_minidebug; cd ppx_minidebug and then either dune install or opam install ..

To use ppx_minidebug in a Dune project, add/modify these stanzas: (preprocess (pps ... ppx_minidebug)), and (libraries ... ppx_minidebug.runtime).

To trace a function, you have to type-annotate the function result. To trace an argument of a traced function, or a let-binding, you need to type-annotate it. You can control how much gets logged by adding or removing type annotations.

Tracing only happens in explicitly marked scopes, using the extension points: %debug_pp, %debug_this_pp, %debug_show, %debug_this_show (based on printing functionality provided by deriving.show), %debug_sexp, %debug_this_sexp (using functionality provided by sexplib0 and ppx_sexp_conv). See examples in the test directory.

The %debug_this variants are intended only for let-bindings: let%debug_this v: t = compute value in body will trace v and the type-annotated bindings and functions inside compute value, but it will not trace body.

Example setting up a logger printing to the screen:

module Debug_runtime =
  Minidebug_runtime.Flushing(struct let debug_ch = stdout let time_tagged = true end)
let%debug_show test_logging: string = "Hello World"

Example setting up a logger printing to a file:

module Debug_runtime =
  Minidebug_runtime.Flushing(
    Minidebug_runtime.Debug_ch(struct let filename = "debugger_flushing.log" end))
let%debug_show test_logging: string = "Hello World"

VS Code suggestions

Add / remove type annotations and visit files using VOCaml

VOCaml helpers for coding in OCaml provide commands to add and remove annotations on selected bindings. They can be used to introduce logging, tune it, and cleanup afterward. It also has a command to populate the _Quick Open_ dialog with a file name and location from a line under cursor. It can be used to jump to the source code from a log file.

Note that you can add and remove type annotations using VSCode OCaml Platform's code actions, and the Find and Transform suggestion below is a more flexible go-to-file solution -- so VOCaml is somewhat redundant. But, it is still valuable: (1) it annotates multiple let-bindings at once in a selection, and (2) it annotates the argument types and the return type of a function (as required by ppx_debug) when invoked on a function definition.

Visualize the flame graph using Log Inspector

Log Inspector (sub-millisecond)'s main feature is visualizing timestamped logs as flame graphs. To invoke it in VS Code, go to the Minidebug_runtime.Flushing-style logs file, press crtl+shift+P, and execute the command Log Inspector: Draw.

The sub-millisecond functionality is now upstreamed to Log Inspector.

Go to file location using Find and Transform

This will expand your general-purpose VS Code toolbox!

Find and Transform is a powerful VS Code extension. I put the following in my `keybindings.json` file (command: Open Keyboard Shortcuts (JSON)):

{
  "key": "alt+q",
  "command": "findInCurrentFile",
  "args": {
    "description": "Open file at cursor",
    "find": "\"([^\"]+)\":([0-9]+)",
    "run": [
      "$${",
        "const pos = new vscode.Position($2, 0);",
        "const range = new vscode.Range(pos, pos);",
        "const options = {selection: range};",
        "const wsFolderUri = vscode.workspace.workspaceFolders[0].uri;",
        "const uri = await vscode.Uri.joinPath(wsFolderUri, '$1');",
        "await vscode.commands.executeCommand('vscode.open', uri, options);",
        
        // "await vscode.commands.executeCommand('workbench.action.quickOpen', `$1:$2`);",
      "}$$",
    ],
    "isRegex": true,
    "restrictFind": "line",
  }
}

Then, pressing `alt+q` will open a pre-populated dialog, and `enter` will get me to the file location. The file-and-location detection above matches the default one from the Flushing module, you can adjust the find pattern to match other formats.

OCaml

Innovation. Community. Security.