{"id":20516376,"url":"https://github.com/chloro-pn/pnlog","last_synced_at":"2026-06-06T19:30:59.671Z","repository":{"id":120001468,"uuid":"220363516","full_name":"chloro-pn/pnlog","owner":"chloro-pn","description":"a log library based on c++11 for linux and mac","archived":false,"fork":false,"pushed_at":"2020-03-15T12:39:09.000Z","size":432,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-05T23:27:55.602Z","etag":null,"topics":["cpp11","log-library"],"latest_commit_sha":null,"homepage":"","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/chloro-pn.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-11-08T01:41:57.000Z","updated_at":"2020-03-10T01:45:49.000Z","dependencies_parsed_at":null,"dependency_job_id":"fd5a6b7a-08d0-4e97-a0f9-4cb552325077","html_url":"https://github.com/chloro-pn/pnlog","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/chloro-pn/pnlog","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chloro-pn%2Fpnlog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chloro-pn%2Fpnlog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chloro-pn%2Fpnlog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chloro-pn%2Fpnlog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chloro-pn","download_url":"https://codeload.github.com/chloro-pn/pnlog/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chloro-pn%2Fpnlog/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33997732,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-06T02:00:07.033Z","response_time":107,"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":["cpp11","log-library"],"created_at":"2024-11-15T21:28:33.925Z","updated_at":"2026-06-06T19:30:59.638Z","avatar_url":"https://github.com/chloro-pn.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pnlog\na c++ log library based on c++11 for linux.\n\n# features\n* 支持多日志文件同时打开\n* 支持异步/同步模式\n* 支持日志等级调整（非线程安全）\n* 支持基于时间间隔的日志回滚（目前不会删除过期日志）\n* 支持日志文件运行时关闭\n* 支持输出重定向\n* 支持运行时打开/关闭时间戳 （非线程安全）\n* 通过使用log-buf的对象池，避免频繁的申请/释放动态内存。\n* 通过使用自旋锁而不是std::mutex，减少并发开销。\n\n# benchmark\n\u003cimg src=\"https://github.com/chloro-pn/pnlog/blob/master/pic/1.png\" width=\"450\" height=\"350\" /\u003e\n\n# build\npnlog uses cmake build tool to build the project.\n```console\nmkdir build \u0026\u0026 cd build\ncmake ..\nmake\n```\n\n# license\nMIT License\n\n# how to use\nyou can research example code in /examples dir to learn how to use pnlog.\n\n* write to stdout.\n* Global object backend's type is std::shared_ptr\u003cBackEnd\u003e, and you can only\nhave one object of the class BackEnd, which means the constructor of class BackEnd\nis privated.\n* Global object backend is in charge of opening, closing, and reopening various\nlog files, and each of log files managed by backend is identified by an index.\n* stdcout is opened by backend by default and it's index is 0.\n* You can call backend's get_capture method to create a std::shared\u003cCapTure\u003e obejct from backend.\nThe parameter is the index of log file, each log submitd by CapTure object will be appended to\nlog file identified by index.\n\n```c++\n#include \u003ciostream\u003e\n#include \"../include/pnlog.h\"\n#include \"../include/file_out_stream.h\"\n\nusing pnlog::backend;\n\nint main() {\n  auto capture = backend-\u003eget_capture(0);\n  for(int i = 0; i \u003c 10; ++i) {\n    if(i \u003e= 5) {\n      capture-\u003eenable_time();\n    }\n    if(i \u003e= 8) {\n      capture-\u003edisable_time();\n    }\n    if(i % 2 == 0) {\n      capture-\u003etrace(piece(\"hello world ! \", \" \", i));\n    }\n    else {\n      capture-\u003etrace(piece(\"hello world ! \", \" \", i), __FILE__, __LINE__);\n    }\n  }\n  return 0;\n}\n```\n\n* use enable_time() method and disable_time() method to choose timestamp or not.\n```c++ \n#include \"../include/pnlog.h\"\n\nusing pnlog::backend;\nint main() {\n  auto cap1 = backend-\u003eget_capture(0);\n  cap1-\u003eenable_time();\n  for(int i = 0; i \u003c 10; ++i) {\n    if(i \u003e 5) {\n      cap1-\u003esetLevel(pnlog::CapTure::Level::PN_WARNING);\n    }\n    cap1-\u003etrace(piece(\"example cap1 \", i));\n  }\n  return 0;\n}\n```\n\n* CapTure object can be constructed by invalid index(no log files correspond to it), under the condition ,the log will be abandoned.\n* More than one CapTure object can be constructed by the same index, and each object has its own log_level and format.\n```c++\n#include \"../include/pnlog.h\"\n\nusing pnlog::backend;\nint main() {\n  auto cap1 = backend-\u003eget_capture(0);\n  auto cap2 = backend-\u003eget_capture(0);\n  auto cap3 = backend-\u003eget_capture(1); // index 1 is invalid.\n  cap1-\u003eenable_time();\n  for(int i = 0; i \u003c 5; ++i) {\n    cap1-\u003etrace(piece(\"example cap1 \", i));\n    cap2-\u003etrace(piece(\"example cap2 \", i), __FILE__, __LINE__);\n    cap3-\u003etrace(piece(\"example cap3 \")); // do nothing.\n  }\n  return 0;\n}\n```\n* Use backend-\u003eopen() method to open a log file.\n* Log file can be opened by sync model (which means call out_stream_base-\u003e\nwrite() for each log)and async model (store a lot of logs in memory cache and\nwrite to log file once).\n```c++\n#include \"../include/pnlog.h\"\n#include \"../include/file_out_stream.h\"\n#include \u003ccstdio\u003e\n#include \u003ciostream\u003e\n\nusing pnlog::backend;\nint main() {\n  pnlog::BackEnd::options op;\n  op.asyn = false; // op.asyn = true by default.\n  backend-\u003eopen(op, 1, new pnlog::FileOutStream(\"example3log.txt\"));\n  auto cap1 = backend-\u003eget_capture(1);\n  cap1-\u003eenable_time();\n  for(int i = 0; i \u003c 5; ++i) {\n    cap1-\u003etrace(piece(\"example3 \", i));\n  }\n  cap1-\u003eclose();\n  std::cout \u003c\u003c \"syn model \\n\";\n  return 0;\n}\n```\n* capture's destructor would not close log file identified by index, and the log file would be closed by backend's destructor.However, you can call capture-\u003eclose() method to do it.\n```c++\n#include \"../include/pnlog.h\"\n#include \"../include/file_out_stream.h\"\n#include \u003ciostream\u003e\n#include \u003ccstdio\u003e\n\nusing pnlog::backend;\nint main() {\n  pnlog::BackEnd::options op;\n  backend-\u003eopen(op, 1, new pnlog::FileOutStream(\"example4log.txt\"));\n  auto cap1 = backend-\u003eget_capture(1);\n  cap1-\u003eenable_time();\n  for(int i = 0; i \u003c 5; ++i) {\n    cap1-\u003etrace(piece(\"example cap1 \", i));\n  }\n  cap1-\u003eclose();\n  std::cout \u003c\u003c \"the program is running now, but log file has been closed, try to \"\n               \"check it out.\\n\";\n  getchar();\n  return 0;\n}\n```\n\n* log rotate can be supported by set BackEnd::options object. Pnlog support duration-based rotate model.\n```c++\n#include \"../include/pnlog.h\"\n#include \"../include/file_out_stream.h\"\n#include \u003cunistd.h\u003e\n#include \u003ciostream\u003e\n\nusing pnlog::backend;\nint main() {\n  pnlog::BackEnd::options op;\n  //Rotate by duration, and each 3 seconds rotate the log file.\n  op.duration_rotating = true;\n  op.duration = std::chrono::seconds(3);\n  //set rotate file path and name.\n  op.path = \"example5\";\n  backend-\u003eopen(op, 1, new pnlog::FileOutStream(\"example5.txt\"));\n  auto cap1 = backend-\u003eget_capture(1);\n  cap1-\u003eenable_time();\n  for(int i = 0; i \u003c 10; ++i) {\n    cap1-\u003etrace(piece(\"example cap1 \", i));\n    sleep(1);\n    std::cout \u003c\u003c \"wait for 9 : \"\u003c\u003c i \u003c\u003c std::endl;\n  }\n  return 0;\n}\n```\n\n* thread-safe reopen method and close method.\n```c++\n#include \"../include/pnlog.h\"\n#include \"../include/file_out_stream.h\"\n#include \u003cthread\u003e\n#include \u003ciostream\u003e\n#include \u003cunistd.h\u003e\n\nusing namespace pnlog;\n\nint main() {\n  BackEnd::options op;\n  backend-\u003eopen(op, 1, new FileOutStream(\"example6log.txt\"));\n  backend-\u003eopen(op, 2, new FileOutStream(\"example6_closedlog.txt\"));\n  auto cap = backend-\u003eget_capture(1);\n  auto cap2 = backend-\u003eget_capture(2);\n  std::thread th([\u0026]()-\u003evoid {\n                   for(int i = 0; i \u003c 10000; ++i) {\n                     cap-\u003etrace(piece(\"writing in back thread. \", i));\n                     cap2-\u003etrace(piece(\"waiting for close.\", i));\n                   }\n                 });\n  backend-\u003eclose(2);\n  usleep(1e4);\n  backend-\u003ereopen(1, new FileOutStream(\"example6_reopenlog.txt\"));\n  th.join();\n  std::cout \u003c\u003c \"please check example6*.txt file \\n\";\n  return 0;\n}\n```\n\n* Configure log schedule for your class.\n```c++\n#include \"../include/pnlog.h\"\n#include \"../include/file_out_stream.h\"\n#include \u003cmemory\u003e\n\nusing pnlog::CapTure;\nusing pnlog::backend;\nusing pnlog::BackEnd;\n\nclass test {\nprivate:\n  int num_;//your data member.\n  std::shared_ptr\u003cCapTure\u003e logger;\n\npublic:\n  test():num_(0), logger(backend-\u003eget_capture(0)) {\n    logger-\u003eenable_time();\n    logger-\u003esetLevel(CapTure::Level::PN_DEBUG);\n  }\n\n  void add() {\n    ++num_;\n    logger-\u003etrace(piece(\"num change : \", num_), __FILE__, __LINE__);\n  }\n\n  void cut_down() {\n    if(num_ \u003c= 0) {\n      logger-\u003ewarning(piece(\"num now : \", num_), __FILE__, __LINE__);\n    }\n    --num_;\n    return;\n  }\n\n  ~test() = default;\n};\n\nint main() {\n  test t;\n  t.add();\n  t.cut_down();\n  t.cut_down();\n  return 0;\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchloro-pn%2Fpnlog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchloro-pn%2Fpnlog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchloro-pn%2Fpnlog/lists"}