{"id":17724794,"url":"https://github.com/jibsen/blog","last_synced_at":"2025-07-25T06:03:04.141Z","repository":{"id":72894952,"uuid":"168009353","full_name":"jibsen/blog","owner":"jibsen","description":"Basic logging","archived":false,"fork":false,"pushed_at":"2019-01-29T20:33:21.000Z","size":10,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2023-08-03T12:20:55.885Z","etag":null,"topics":["c","logging"],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jibsen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2019-01-28T17:59:45.000Z","updated_at":"2023-08-03T12:20:55.886Z","dependencies_parsed_at":"2023-09-18T12:17:21.754Z","dependency_job_id":null,"html_url":"https://github.com/jibsen/blog","commit_stats":null,"previous_names":[],"tags_count":0,"template":null,"template_full_name":null,"purl":"pkg:github/jibsen/blog","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jibsen%2Fblog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jibsen%2Fblog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jibsen%2Fblog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jibsen%2Fblog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jibsen","download_url":"https://codeload.github.com/jibsen/blog/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jibsen%2Fblog/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266963279,"owners_count":24013020,"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-07-25T02:00:09.625Z","response_time":70,"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":"2024-10-25T15:48:47.047Z","updated_at":"2025-07-25T06:03:04.095Z","avatar_url":"https://github.com/jibsen.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# blog - basic logging\n\n\n## About\n\nblog provides basic logging functionality aimed at developers.\n\nMost programmers are familiar with print(f) debugging, where you sprinkle\nprint statements around the code while trying to figure out what is happening.\n\n`blog()` is a macro which you can use to insert such statements in your code.\nThe benefit is more structured output, and making it is easy to disable some\n(based on level) or all of them.\n\nIf you need more functionality, please see the section on related projects.\n\n\n## Usage\n\nblog assigns a level to each message. The supported levels are:\n\n  - `BLOG_ERROR` (0) - unrecoverable error\n  - `BLOG_WARN` (1) - recoverable error\n  - `BLOG_INFO` (2) - normal significant event\n  - `BLOG_DEBUG` (3) - normal insignificant event\n  - `BLOG_TRACE` (4) - implementation detail\n\nHere is an example of a C function with some logging calls:\n\n~~~c\n#include \"blog.h\"\n\n/* Merge sorted linked lists p and q into p (not stable) */\nvoid merge(struct node **p, struct node **q)\n{\n    blog(BLOG_INFO, \"merging lists\");\n\n    if (!*q) {\n        blog(BLOG_DEBUG, \"q is empty\");\n\n        return;\n    }\n\n    while (*p) {\n        blog(BLOG_TRACE, \"comparing %d to %d\", (*p)-\u003eval, (*q)-\u003eval);\n\n        if ((*p)-\u003eval \u003e (*q)-\u003eval) {\n            blog(BLOG_TRACE, \"swapping tails\");\n\n            struct node *tmp = *p;\n            *p = *q;\n            *q = tmp;\n        }\n        p = \u0026(*p)-\u003enext;\n    }\n\n    blog(BLOG_TRACE, \"moving tail of larger elements\");\n\n    *p = *q;\n    *q = NULL;\n}\n~~~\n\nAs you can see, `blog()` works like printf with the addition of the level as\nthe first parameter. With the default logging level of `BLOG_INFO`, the output\non stderr from calling this function would be something like:\n\n    [info] llist.c:114: merging lists\n\n\n### Controlling output\n\nblog uses two global variables:\n\n  - `blog_stream` - FILE pointer to write messages to (defaults to stderr if\n    `NULL`)\n  - `blog_level` - dynamic logging level, messages above this are ignored\n    (defaults to `BLOG_INFO`)\n\nSay we create a file for logging and set the level to `BLOG_TRACE`, either\nmanually, or using the `blog_init()` convenience function:\n\n~~~c\nFILE *log_file = fopen(\"log.txt\", \"w\");\n\nif (!log_file) {\n    perror(\"cannot open log.txt for writing\");\n    exit(EXIT_FAILURE);\n}\n\nblog_init(log_file, BLOG_TRACE);\n~~~\n\nThe output in `log.txt` from the above example might now be something like:\n\n    [info] blog.c:84: blog initialized (level 4 - trace)\n    [info] llist.c:114: merging lists\n    [trace] llist.c:123: comparing 3 to 5\n    [trace] llist.c:123: comparing 11 to 5\n    [trace] llist.c:126: swapping tails\n    [trace] llist.c:123: comparing 7 to 11\n    [trace] llist.c:123: comparing 19 to 11\n    [trace] llist.c:126: swapping tails\n    [trace] llist.c:123: comparing 13 to 19\n    [trace] llist.c:135: moving tail of larger elements\n\n\n### Disabling output\n\nIf you define `NBLOG` before including `blog.h`, then `blog()` becomes a\nno-op. This works like `NDEBUG` for `assert.h` in that you can include\n`blog.h` multiple times and `blog()` will be redefined based on `NBLOG`.\n\nSimilarly, `BLOG_MAX_LEVEL` can be used to set a compile time logging level\nbefore including `blog.h`. Any `blog()` above this level do nothing. With\noptimization turned on, most compilers will remove such calls entirely.\n\n\n### Options when compiling blog\n\nIf blog is compiled with `BLOG_TIMESTAMP` defined, each line will be prefixed\nwith a timestamp in square brackets.\n\n    [2019-01-28 13:08:10] [info] llist.c:114: merging lists\n\nBy default blog locks the output file while writing to it. This can be\ndisabled with `BLOG_NO_LOCKING`.\n\n`BLOG_FLUSH_LEVEL` can be used to set the level up to which blog flushes\nafter each write. It defaults to `BLOG_ERROR`.\n\n\n## Notes\n\n  - blog uses C99 variadic macros and POSIX or Windows file locking.\n\n\n## Related Projects\n\nThis is a random sample of logging libraries from a quick web search:\n\n  - [Boost.Log](https://github.com/boostorg/log)\n  - [glog](https://github.com/google/glog)\n  - [log.c](https://github.com/rxi/log.c)\n  - [log4c](http://log4c.sourceforge.net/)\n  - [Macro-Logger](https://github.com/dmcrodrigues/macro-logger)\n  - [slog](https://github.com/kala13x/slog)\n  - [spdlog](https://github.com/gabime/spdlog)\n  - [zf_log](https://github.com/wonder-mice/zf_log)\n  - [zlog](https://github.com/zma/zlog/)\n\nI haven't tried all of them, so I cannot comment on the quality. Think of it\nas a starting point if you want to look further.\n\n\n## License\n\nThis projected is licensed under the [MIT License](LICENSE) (MIT).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjibsen%2Fblog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjibsen%2Fblog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjibsen%2Fblog/lists"}