{"id":26925255,"url":"https://github.com/badsami/logs","last_synced_at":"2025-10-13T04:06:21.862Z","repository":{"id":210663845,"uuid":"714067329","full_name":"badsami/logs","owner":"badsami","description":"C buffered logging library. No C runtime, no C standard library, no dynamic allocation. Get your data formatted into a stack-allocated buffer of pre-determined size, then write it all at once to a console and/or a file to minimise writes to persistent storage.","archived":false,"fork":false,"pushed_at":"2025-07-22T19:12:01.000Z","size":108,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-22T21:10:52.380Z","etag":null,"topics":["c","logging"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/badsami.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-11-03T21:02:40.000Z","updated_at":"2025-07-22T19:12:04.000Z","dependencies_parsed_at":"2023-12-04T10:24:19.740Z","dependency_job_id":"e715952e-f06e-44d3-bbc2-4fccd8563052","html_url":"https://github.com/badsami/logs","commit_stats":null,"previous_names":["bad-sam/logs","badsami/logs"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/badsami/logs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/badsami%2Flogs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/badsami%2Flogs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/badsami%2Flogs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/badsami%2Flogs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/badsami","download_url":"https://codeload.github.com/badsami/logs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/badsami%2Flogs/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270235764,"owners_count":24550187,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-13T02:00:09.904Z","response_time":66,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","logging"],"created_at":"2025-04-02T02:33:54.846Z","updated_at":"2025-10-13T04:06:16.842Z","avatar_url":"https://github.com/badsami.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Logs\nC buffered logging library. No C runtime, no C standard library, no dynamic allocation. Get your data formatted into a stack-allocated buffer of pre-determined size, then write it all at once to a console and/or a file to minimise writes to persistent storage.\nExample (available in [`example.c`](example.c)):\n```C\n#include \"logs.h\"\n\nvoid mainCRTStartup()\n{\n  const WCHAR* logs_file_name = u\"Fluß_¼½¾_Öçé_ǅ.txt\";\n  \n  // Open outputs\n  logs_open_console_output();\n  logs_open_file_output(logs_file_name);\n\n  union { u32 bits; f32 val; } num = {.bits = 0x3C000000};\n  for (u32 bit_pos = 24; bit_pos \u003e 15; bit_pos--)\n  {\n    num.bits |= (1 \u003c\u003c bit_pos);\n\n    // Format logs\n    log_literal_str(\"0x\");\n    log_hex_num(num.bits);\n    log_literal_str(u\" (\");\n    log_dec_num(num.bits);\n    log_literal_str(u8\") as a f32 is \");\n    log_dec_num(num.val);\n    log_character('\\n');\n  }\n\n  // Then write buffered logs to enabled outputs\n  logs_flush();\n\n  // Write to specific outputs\n  logs_disable_output(LOGS_CONSOLE_OUTPUT);\n  log_literal_str(\"========== Logging session end ==========\\n\\n\");\n  logs_flush();\n  \n  logs_enable_output(LOGS_CONSOLE_OUTPUT);\n  logs_disable_output(LOGS_FILE_OUTPUT);\n  log_literal_str(u8\"\\nLogs written to file \");\n  log_null_terminated_str(logs_file_name);\n\n  // Close outputs, implicitly flushing logs buffer to enabled outputs\n  logs_close_file_output();\n  logs_close_console_output();\n\n  ExitProcess(0);\n}\n```\n\nYou can compile this example yourself by running [`build.bat`](build.bat), or from a x64 Native Tools Command Prompt for VS by running `cl.exe /DLOGS_ENABLED /std:c11 /utf-8 to_str_utilities.c logs.c example.c /link /subsystem:console /entry:mainCRTStartup /nodefaultlib /out:example.exe kernel32.lib`  \n(requires Visual Studio Build Tools or the Native Desktop workload).  \n\nThe code in this repository is inspired from\n[Christopher \"skeeto\" Wellons](https://github.com/skeeto)'s excellent article\n\"[Let's implement buffered, formatted output](https://nullprogram.com/blog/2023/02/13/)\"\n\n## Features\n- Targets Windows XP and above\n- Supports x86_64\n- Compiles with MSVC (GCC and Clang not supported)\n- Doesn't use the C runtime, nor the C standard library\n- No dynamic allocations, the logs buffer is allocated on the stack\n- Offers output streams control (open, close, disable, enable, write)\n  - Provides 1 console output which is either created or reused from the calling process, and set to display UTF-8-encoded characters\n  - Provides 1 ASCII- or UTF-16-named file output, which is either created or opened, then appended to\n- Logging of fundamental types\n  - Signed and unsigned integers up to 64-bit, in binary, decimal and hexadecimal format, with or without a pre-determined size in bits, digits or nibbles\n  - 32-bit floating point numbers in binary, decimal and hexadecimal format, with or without a pre-determined size in bits or nibbles, or a pre-determined decimal fractional part size, with a few particularities:\n    - Values outside of [-2^32 + 1, 2^32 - 1] are output as `-big` or `big`, depending on their sign (see rational in [log_dec_f32_number() comments in log.c](https://github.com/badsami/logs/blob/main/logs.c#L520-L583))\n    - `-qnan`, `qnan`, `-snan`, `snan`, `-inf` or `inf` may be output for matching non-number values\n    - `-0` will be converted to `0`\n    - Without a predetermined size, 6 digits past the period are written to the output. This can be increased up to 9 (see `F32_DEC_FRAC_DEFAULT_STR_SIZE` and `F32_DEC_FRAC_MULT` in [types_max_str_size.h](types_max_str_size.h))\n    - When passing a fixed fractional part size in digits that exceeds 9, the fractional part will be truncated to 9 digits (see `F32_DEC_FRAC_MAX_STR_SIZE` in [types_max_str_size.h](types_max_str_size.h))\n    - Values are written in full. Scientific notation and other notations are not used\n  - ASCII, UTF-8 and UTF-16 characters, null-terminated, sized and literal compile-time strings\n- Compile-time defined logs buffer size through macro definition `/DLOGS_BUFFER_SIZE`, which defaults to 4 KB\n- Helpers to manage logs buffer memory, with [types_max_str_size.h](types_max_str_size.h) to estimate the maximum number of characters a fundamental type may be represented with, and with [logs_buffer_remaining_bytes()](https://github.com/badsami/logs/blob/main/logs.c#L184-#L190)\n- Logs are turned off by default to prevent any accidental performance hit, and are enabled by defining the compile-time macro `LOGS_ENABLED` (setting it to `0` disables logs)\n\n\u003e [!NOTE]\n\u003e Because this library gives control over the logs buffer size and when it should be written to enabled outputs, all functions, once called, assume there is enough space left in the logs buffer to append the content they are passed. You are in charge of choosing a log buffer size that is appropriate to your needs, and of calling `logs_flush()` before the buffer becomes over-saturated.  \n\n\u003e [!NOTE]\n\u003e It is important to compile with [/utf-8](https://learn.microsoft.com/en-us/cpp/build/reference/utf-8-set-source-and-executable-character-sets-to-utf-8?view=msvc-170) if you are passing UTF-8 encoded characters and strings to the functions of this library.\n\n\n## Repository files\n- [`logs.h`](logs.h) / [`logs.c`](logs.c): logs output management, fundamental types formatting and buffering, logs buffer consumption helper\n- [`to_str_utilities.h`](to_str_utilities.h) / [`to_str_utilities.c`](to_str_utilities.c): helpers to categorise and efficiently convert numbers to characters\n- [`types.h`](types.h): custom typedefs, for convenience\n- [`example.c`](example.c): example usage of this library\n- [`build.bat`](build.bat): sample script to compile the example provided, and to show how to include and compile this library into another codebase\n\n\n## Rational\n### Why not use printf, or the C runtime and standard library?\n- I like experimenting and understanding what it takes to build even the most simple things\n- I'm usually using only a small subset of features from the `printf`'s family of functions\n- This small library provides me with clearer, more explicit control over logs and their outputs\n- I avoid using the C standard library and Windows C runtime, which often incur hidden performance hits or perform operations I don't need, and increase executable size significantly for small tools/libraries. Using the C runtime, compiling this library (`example.c` included) with `build.bat` results in a 106.5 KB executable. Without the C runtime, the executable shrinks down to 5.5 KB. The former can't fit into the L1 cache of an [Intel's Lion Cove](https://en.wikipedia.org/wiki/Lion_Cove#L0) CPU nor in that of an [AMD's Zen 5](https://en.wikipedia.org/wiki/Zen_5#L1) CPU, both from 2024. The latter could fit in the L1 cache of an [Intel's i486](https://en.wikipedia.org/wiki/I486#Differences_between_i386_and_i486) CPU from 1989 or in that of an [AMD's K6](https://en.wikipedia.org/wiki/AMD_K6#Models) CPU from 1997. Isn't that incredible?\n\n### Why support Windows only?\nThis is the operating system I'm most familiar with, and Wine makes it easy to run code targeted at Windows on Linux.\n\n### `s32`? `u64`?\nSee [`types.h`](types.h).  \n- `s` is for `signed`\n- `u` is for `unsigned`\n- `f` is for \"floating-point number\"\n- The number following is the type's width in bits  \n\nThis is purely for convenience.\n\n## License\nThe code in this repository is released in the public domain. You are allowed to use the code in this repository freely.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbadsami%2Flogs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbadsami%2Flogs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbadsami%2Flogs/lists"}