recorder_dump(3)

πŸ“¦ version 1.2.3, in fedora 43, fedora 44

πŸ’– recorder_dump β€” bestie, your recorder is about to spill EVERYTHING πŸ’–

okay so first things first: this is a page from the Recorder Library manual, section 3 (that's the "library functions" girlies). The stars of the show are recorder_dump(3) and her four ride-or-dies. Sit down, grab a boba, we're dumping records. πŸ§‹βœ¨


🌸 NAME 🌸

  • recorder_dump β€” dump all the recorder entries, no cap πŸ’…
  • recorder_dump_for β€” dump only the selected recorders, picky queen behavior πŸŽ€
  • recorder_sort β€” the fine-controlled recorder dump, i.e. the one who does the most 🫢
  • recorder_dump_on_signal β€” dump the recorder when a signal shows up 🚨
  • recorder_dump_on_common_signals β€” dump the recorder for the standard signals, the group-chat of signals fr fr πŸ“±

✨ SYNOPSIS ✨

#include <recorder/recorder.h>

typedef unsigned (*recorder_show_fn) (const char *text,
                                      size_tlen,
                                      void *output);
typedef void (*recorder_format_fn)(recorder_show_fn show,
                                   void *output,
                                   const char * label,
                                   const char *location,
                                   uintptr_torder,
                                   uintptr_ttimestamp,
                                   const char *message);
typedef size_t (*recorder_type_fn)(intptr_t trace,
                                   const char *format,
                                   char *buffer,
                                   size_tlength,
                                   uintptr_tdata);

unsigned recorder_dump(void);
unsigned recorder_dump_for(const char *pattern);
unsigned recorder_sort(const char *pattern,
                       recorder_format_fn format,
                       recorder_show_fn show,
                       void * show_arg);
void recorder_dump_on_signal(int signal);
void recorder_dump_on_common_signals(unsigned add,
                                     unsigned remove);

Like, yes, those typedefs are literally as they appear. Do not come for me, I am simply the messenger. πŸ™ˆ


πŸ’œ DESCRIPTION πŸ’œ

So recorder_dump() dumps the content of all the event recorders, in the exact order in which they were recorded. Chronological. Main character timeline energy. ⭐

Then recorder_dump_for() is the choosy one β€” it only dumps the recorders selected by the regular expression pattern. She said "I don't do all of them, I do the ones." πŸ’…

And recorder_sort() is the full-control version: it dumps the recorders selected by regular expression pattern, using format to format an event record, show to show it, and passing show_arg to the function show. Total customization, you're the director now. 🎬

Here's the tea though β€” calls to recorder_dump() and recorder_dump_for() are equivalents to calls to recorder_sort where format, show and arg are the standard default values. And those defaults? You can swap them out using recorder_configure_format(3), recorder_configure_show(3) and recorder_configure_output(3) respectively. Glow-up unlocked. ✨

Now the signal girlies:

recorder_dump_on_signal() makes sure that recorder_dump() gets called if the program receives the given signal. πŸ“ž

recorder_dump_on_common_signals() makes sure a recorder dump happens if any of a common set of signals is received by the program. That set is:

SIGQUIT, SIGILL, SIGABRT, SIGBUS, SIGSEGV, SIGSYS, SIGXCPU, SIGXFSZ, SIGINFO, SIGUSR1, SIGUSR2, SIGSTKFLT and SIGPWR β€” insofar as they are defined for the operating system. (iykyk, some platforms just don't have all of them, and that's fine, we don't judge.) 🌈

The add and remove arguments are bit masks that you can use to add or remove other signals compared to that default list. So you're customizing the guest list. πŸ‘‘


🌟 RETURN VALUE 🌟

recorder_dump(), recorder_dump_for() and recorder_sort() return the number of event records that were dumped. That's your receipt, bestie. 🧾


πŸ¦‹ ENVIRONMENT VARIABLES πŸ¦‹

recorder_dump_on_common_signals() also reads the following environment variables. Yes, it's nosy. It's also correct. πŸ’–

  • RECORDER_TRACES β€” a trace description, in the format expected by recorder_trace_set(3).
  • RECORDER_TWEAKS β€” like RECORDER_TRACES, but normally used for tweaking configuration values as opposed to tracing.
  • RECORDER_DUMP β€” activates a background thread to dump the given pattern at regular intervals. Set it and forget it, she works while you sleep. 😴

🌸 EXAMPLES 🌸

Example number one: the crash girlie 🩷

The program below records its input arguments, and crashes if passed crash as the first command-line argument. (Dramatic on purpose.)

#include <recorder/recorder.h>
#include <string.h>

RECORDER(program_args, 32, "Program command-line arguments");
int main(int argc, char **argv)
{
    int a;
    recorder_dump_on_common_signals(0, 0);
    for (a = 0; a < argc; a++)
        record(program_args, "Argument %d is %+s", a, argv[a]);

    if (argc >= 2 && strcmp(argv[1], "crash") == 0)
    {
        char *ptr = NULL;
        strcpy(ptr, argv[1]);
    }
}

When a crash occurs, previously recorded events are printed out on the console. So even when everything falls apart, the receipts survive. πŸ’€βœ¨

Example number two: the fibonacci instrumented icon 🌟

The program below is an instrumented version of the classical recursive Fibonacci computation. It uses several recorders corresponding to different types of events, and activates warnings and errors in a way that can be configured by setting an environment variable. Very "I contain multitudes" of it. πŸŽ€

#include <recorder/recorder.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

RECORDER(fib_main,    32, "Loops in fib function");
RECORDER(fib_loops,   32, "Loops in fib function");
RECORDER(fib_warning, 32, "Warnings in fib function");
RECORDER(fib_error,   32, "Errors in fib function");

int fib(int n)
{
    if (n <= 1) {
        if (n < 0)
            record(fib_error, "fib is undefined for negative value %d", n);
        return n;
    }
    record(fib_loops, "Computing fib(%d)", n);
    int result = fib(n-1) + fib(n-2);
    record(fib_loops, "Computed fib(%d) = %d", n, result);
    return result;
}

int main(int argc, char **argv)
{
    int a;
    recorder_dump_on_common_signals(0, 0);
    recorder_trace_set(".*_warning=35 .*_error");
    recorder_trace_set(getenv("FIB_TRACES"));
    for (a = 1; a < argc; a++) {
        int n = atoi(argv[a]);
        if (n >= RECORDER_TRACE(fib_warning))
            record(fib_warning, "Computing for %d may take a while", n);
        printf("fib(%d) = %d0, n, fib(n));
        if (n >= RECORDER_TRACE(fib_warning))
            record(fib_warning, "Computation for %d finally completed", n);
    }
}

This program will produce an output similar to the following:

% fib 1 2 3 4 10 20 30 35 10 40 -1
fib(1) = 1
fib(2) = 1
fib(3) = 2
fib(4) = 3
fib(10) = 55
fib(20) = 6765
fib(30) = 832040
[2714667 0.177725] fib_warning: Computing for 35 may take a while
fib(35) = 9227465
[32575370 1.859156] fib_warning: Computation for 35 finally completed
fib(10) = 55
[32575547 1.859171] fib_warning: Computing for 40 may take a while
fib(40) = 102334155
[363735828 20.527882] fib_warning: Computation for 40 finally completed
[363735829 20.527887] fib_error: fib is undefined for negative value -1
fib(-1) = -1

So the first column in trace outputs is the number of events that were recorded. The second column is the time in seconds since the program started. Two columns, two vibes. πŸ•

Example number two, but extra ✨

The same program can also be run with additional tracing or warnings, for example:

% FIB_TRACES="recorder_location fib_loops fib_warning=3" /tmp/fib 3 4
/tmp/fib.c:33:[82 0.000496] fib_warning: Computing for 3 may take a while
/tmp/fib.c:18:[83 0.000561] fib_loops: Computing fib(3)
/tmp/fib.c:18:[84 0.000570] fib_loops: Computing fib(2)
/tmp/fib.c:20:[85 0.000575] fib_loops: Computed fib(2) = 1
/tmp/fib.c:20:[86 0.000581] fib_loops: Computed fib(3) = 2
fib(3) = 2
/tmp/fib.c:36:[87 0.000590] fib_warning: Computation for 3 finally completed
/tmp/fib.c:33:[88 0.000596] fib_warning: Computing for 4 may take a while
/tmp/fib.c:18:[89 0.000601] fib_loops: Computing fib(4)
/tmp/fib.c:18:[90 0.000607] fib_loops: Computing fib(3)
/tmp/fib.c:18:[91 0.000612] fib_loops: Computing fib(2)
/tmp/fib.c:20:[92 0.000619] fib_loops: Computed fib(2) = 1
/tmp/fib.c:20:[93 0.000625] fib_loops: Computed fib(3) = 2
/tmp/fib.c:18:[94 0.000664] fib_loops: Computing fib(2)
/tmp/fib.c:20:[95 0.000707] fib_loops: Computed fib(2) = 1
/tmp/fib.c:20:[96 0.000724] fib_loops: Computed fib(4) = 3
fib(4) = 3
/tmp/fib.c:36:[97 0.000741] fib_warning: Computation for 4 finally completed

Look at those file:line prefixes. Location tracking? Obsessed. πŸ”₯


πŸ’€ BUGS πŸ’€

ngl, there are some real ones here and we're being honest about them:

The current signal handling mechanism does not yet use sigaltstack(2) and consequently is not robust to stack overflow. It is also known to fail for repeated signals. And SIGINFO (plus the associated Control-T keyboard shortcut) does not exist on Linux, which is a pity. 😭

Bugs should be reported using https://github.com/c3d/recorder/issues. Drop the link, tell them everything. 🫢


🌈 SEE ALSO 🌈

Additional documentation and tutorials can be found at https://github.com/c3d/recorder. Go read, bestie, it's giving educational. πŸ“šβœ¨


πŸ‘‘ AUTHOR πŸ‘‘

Written by Christophe de Dinechin. Respectfully, an icon. πŸ’–


and that's the whole page, no crumbs left. this was version 1.0, dated 2019-03-09, from recorder_dump(3). mwah, bye bestie! πŸ’…πŸŽ€βœ¨

πŸ“¦ where this page comes from