/logs

Personal C buffered logging library. No C runtime, no C standard library.

Primary LanguageC

Logs

Personal C buffered logging library. Example (available in example.c):

#include "logs.h"

void mainCRTStartup()
{
  const char* logs_file_name = "logs.txt";
  
  // Open outputs
  logs_open_console_output();
  logs_open_file_output(logs_file_name);

  u32 bits = 0x3C000000;
  for (u32 bit_pos = 24; bit_pos > 15; bit_pos--)
  {
    bits |= (1 << bit_pos);
    f32 value = *(f32*)&bits;

    // Format logs
    log_min_hex_u32(bits);
    log_literal(" (");
    log_u32(bits);
    log_literal(") as a f32 is ");
    log_f32(value);
    log_char('\n');

    // When deemed ready, write buffered logs to enabled outputs
    logs_flush();
  }

  // Write to specific outputs
  logs_disable_output(LOGS_OUTPUT_CONSOLE);
  log_literal("========== Logging session end ==========\n\n");
  logs_flush();
  
  logs_enable_output(LOGS_OUTPUT_CONSOLE);
  logs_disable_output(LOGS_OUTPUT_FILE);
  log_literal("\nLogs written to file ");
  log_cstr(logs_file_name);

  // Close outputs, implicitly flushing logs buffer to enabled outputs
  logs_close_file_output();
  logs_close_console_output();

  ExitProcess(0);
}

You can compile this example yourself by running build.bat (requires Visual Studio Build Tools or the Native Desktop workload).

Features

  • For Windows XP and above
  • Support for x86 64-bit and 32-bit architectures
  • Compiles with MSVC (GCC and Clang not tested)
  • No C runtime, no C standard library
  • Provides control over output streams (open, close, disable, enable, flush, ANSI escape sequences toggling)
    • Provides 1 console output, with ANSI escape sequences, which is either created or reused
    • Provides 1 named file output, which is either created or reused
  • Custom formatting of some basic types:
    • Signed and unsigned integers up to 64-bit, in decimal, hexadecimal and binary format
    • Floating-point values up to -/+ 2,147,483,648 with 6 fractional digits. NaN and infinities are represented as -/+ 2,147,483,648, depending on the sign bit
  • Buffered logging of the above types, literal constant strings, C strings, and single characters
  • Logs are turned off by default to prevent any accidental performance hit, and are enabled by defining the compile-time macro ENABLE_LOGS (setting it to 0 disables logs)

The code in this repository is inspired from Christopher "skeeto" Wellons's excellent article "Let's implement buffered, formatted output"

Repository files

  • logs.h / logs.c: logs output management, logs appending functions
  • num_to_str.h / num_to_str.c: number to string formatting functions
  • types.h: custom typedefs, for personal convience
  • example.c: simple example usage of this library
  • build.bat: sample script to compile the example provided, and to show how to include and compile this library into another codebase

Rational

Why support Windows only?

Most computers games are targeted at Windows. Nowadays, Proton handles running Windows games on Linux very well, so Windows is my first choice as well. It is also the OS I work with. Nonetheless, I'm interested in adding some cross-OS/ISA/platform support.

s32? u64?

See types.h.
s is for signed.
u is for unsigned.
f is for "floating-point number".
The number following is the type's width in bits.
This is purely for convenience.

Why not use printf, or the C runtime and standard library?

  • I like experimenting and understanding what it takes to build even the most mundane things
  • I'm only using a small subset of features of the printf's family of functions in my day-to-day work
  • I can manage how logs are buffered, with my own straightforward alternative
  • Compiling this library (example.c included) creates an 5.6 KB executable. By including the C runtime, it grows to 115 KB. I appreciate eliminating that big of a dependency: in theory, the program could fit in the L1 cache of a 20+-years-old CPU

Why is there no double/f64-to-string formatting function?

I almost never use double. If I ever need it, then I'll implement something.

Possible improvements

  • Support Unicode characters for logs and log file names
  • Add a variadic, printf-like log function or macro (e.g. logs_append("%s is %u", "Albert", 23))
  • Implement a macro to stringify compile-time constants passed to log functions (e.g. logs_append_float(123.456f) would compile to an equivalent of logs_append_literal(str))
  • Prevent ANSI escape sequences from appearing in the log file (might require changing code architecture)
  • Would mapping the log file to the process' virtual memory and using a view to edit it be better than writing to it with WriteFile? See CreateFileMapping and MapViewOfFile
  • Add some native support for other OS (Linux?) and other CPU architectures (ARM?)

License

The code in this repository is released in the public domain. You can use it with no constraint.