log.h 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  1. #pragma once
  2. #include <chrono>
  3. #include <cstring>
  4. #include <sstream>
  5. #include <iostream>
  6. #include <thread>
  7. #include <vector>
  8. #include <algorithm>
  9. #include <cinttypes>
  10. // --------------------------------
  11. //
  12. // Basic usage:
  13. //
  14. // --------
  15. //
  16. // The LOG() and LOG_TEE() macros are ready to go by default
  17. // they do not require any initialization.
  18. //
  19. // LOGLN() and LOG_TEELN() are variants which automatically
  20. // include \n character at the end of the log string.
  21. //
  22. // LOG() behaves exactly like printf, by default writing to a logfile.
  23. // LOG_TEE() additionally, prints to the screen too ( mimics Unix tee command ).
  24. //
  25. // Default logfile is named
  26. // "llama.<threadID>.log"
  27. // Default LOG_TEE() secondary output target is
  28. // stderr
  29. //
  30. // Logs can be dynamically disabled or enabled using functions:
  31. // log_disable()
  32. // and
  33. // log_enable()
  34. //
  35. // A log target can be changed with:
  36. // log_set_target( string )
  37. // creating and opening, or re-opening a file by string filename
  38. // or
  39. // log_set_target( FILE* )
  40. // allowing to point at stderr, stdout, or any valid FILE* file handler.
  41. //
  42. // --------
  43. //
  44. // End of Basic usage.
  45. //
  46. // --------------------------------
  47. // Specifies a log target.
  48. // default uses log_handler() with "llama.log" log file
  49. // this can be changed, by defining LOG_TARGET
  50. // like so:
  51. //
  52. // #define LOG_TARGET (a valid FILE*)
  53. // #include "log.h"
  54. //
  55. // or it can be simply redirected to stdout or stderr
  56. // like so:
  57. //
  58. // #define LOG_TARGET stderr
  59. // #include "log.h"
  60. //
  61. // The log target can also be redirected to a different function
  62. // like so:
  63. //
  64. // #define LOG_TARGET log_handler_different()
  65. // #include "log.h"
  66. //
  67. // FILE* log_handler_different()
  68. // {
  69. // return stderr;
  70. // }
  71. //
  72. // or:
  73. //
  74. // #define LOG_TARGET log_handler_another_one("somelog.log")
  75. // #include "log.h"
  76. //
  77. // FILE* log_handler_another_one(char*filename)
  78. // {
  79. // static FILE* logfile = nullptr;
  80. // (...)
  81. // if( !logfile )
  82. // {
  83. // fopen(...)
  84. // }
  85. // (...)
  86. // return logfile
  87. // }
  88. //
  89. #ifndef LOG_TARGET
  90. #define LOG_TARGET log_handler()
  91. #endif
  92. #ifndef LOG_TEE_TARGET
  93. #define LOG_TEE_TARGET stderr
  94. #endif
  95. // Utility for synchronizing log configuration state
  96. // since std::optional was introduced only in c++17
  97. enum LogTriState
  98. {
  99. LogTriStateSame,
  100. LogTriStateFalse,
  101. LogTriStateTrue
  102. };
  103. // Utility to obtain "pid" like unique process id and use it when creating log files.
  104. inline std::string log_get_pid()
  105. {
  106. static std::string pid;
  107. if (pid.empty())
  108. {
  109. // std::this_thread::get_id() is the most portable way of obtaining a "process id"
  110. // it's not the same as "pid" but is unique enough to solve multiple instances
  111. // trying to write to the same log.
  112. std::stringstream ss;
  113. ss << std::this_thread::get_id();
  114. pid = ss.str();
  115. }
  116. return pid;
  117. }
  118. // Utility function for generating log file names with unique id based on thread id.
  119. // invocation with log_filename_generator( "llama", "log" ) creates a string "llama.<number>.log"
  120. // where the number is a runtime id of the current thread.
  121. #define log_filename_generator(log_file_basename, log_file_extension) log_filename_generator_impl(LogTriStateSame, log_file_basename, log_file_extension)
  122. // INTERNAL, DO NOT USE
  123. inline std::string log_filename_generator_impl(LogTriState multilog, const std::string & log_file_basename, const std::string & log_file_extension)
  124. {
  125. static bool _multilog = false;
  126. if (multilog != LogTriStateSame)
  127. {
  128. _multilog = multilog == LogTriStateTrue;
  129. }
  130. std::stringstream buf;
  131. buf << log_file_basename;
  132. if (_multilog)
  133. {
  134. buf << ".";
  135. buf << log_get_pid();
  136. }
  137. buf << ".";
  138. buf << log_file_extension;
  139. return buf.str();
  140. }
  141. #ifndef LOG_DEFAULT_FILE_NAME
  142. #define LOG_DEFAULT_FILE_NAME log_filename_generator("llama", "log")
  143. #endif
  144. // Utility for turning #define values into string literals
  145. // so we can have a define for stderr and
  146. // we can print "stderr" instead of literal stderr, etc.
  147. #define LOG_STRINGIZE1(s) #s
  148. #define LOG_STRINGIZE(s) LOG_STRINGIZE1(s)
  149. #define LOG_TEE_TARGET_STRING LOG_STRINGIZE(LOG_TEE_TARGET)
  150. // Allows disabling timestamps.
  151. // in order to disable, define LOG_NO_TIMESTAMPS
  152. // like so:
  153. //
  154. // #define LOG_NO_TIMESTAMPS
  155. // #include "log.h"
  156. //
  157. #ifndef LOG_NO_TIMESTAMPS
  158. #ifndef _MSC_VER
  159. #define LOG_TIMESTAMP_FMT "[%" PRIu64 "] "
  160. #define LOG_TIMESTAMP_VAL , (std::chrono::duration_cast<std::chrono::duration<std::uint64_t>>(std::chrono::system_clock::now().time_since_epoch())).count()
  161. #else
  162. #define LOG_TIMESTAMP_FMT "[%" PRIu64 "] "
  163. #define LOG_TIMESTAMP_VAL , (std::chrono::duration_cast<std::chrono::duration<std::uint64_t>>(std::chrono::system_clock::now().time_since_epoch())).count()
  164. #endif
  165. #else
  166. #define LOG_TIMESTAMP_FMT "%s"
  167. #define LOG_TIMESTAMP_VAL ,""
  168. #endif
  169. #ifdef LOG_TEE_TIMESTAMPS
  170. #ifndef _MSC_VER
  171. #define LOG_TEE_TIMESTAMP_FMT "[%" PRIu64 "] "
  172. #define LOG_TEE_TIMESTAMP_VAL , (std::chrono::duration_cast<std::chrono::duration<std::uint64_t>>(std::chrono::system_clock::now().time_since_epoch())).count()
  173. #else
  174. #define LOG_TEE_TIMESTAMP_FMT "[%" PRIu64 "] "
  175. #define LOG_TEE_TIMESTAMP_VAL , (std::chrono::duration_cast<std::chrono::duration<std::uint64_t>>(std::chrono::system_clock::now().time_since_epoch())).count()
  176. #endif
  177. #else
  178. #define LOG_TEE_TIMESTAMP_FMT "%s"
  179. #define LOG_TEE_TIMESTAMP_VAL ,""
  180. #endif
  181. // Allows disabling file/line/function prefix
  182. // in order to disable, define LOG_NO_FILE_LINE_FUNCTION
  183. // like so:
  184. //
  185. // #define LOG_NO_FILE_LINE_FUNCTION
  186. // #include "log.h"
  187. //
  188. #ifndef LOG_NO_FILE_LINE_FUNCTION
  189. #ifndef _MSC_VER
  190. #define LOG_FLF_FMT "[%24s:%5d][%24s] "
  191. #define LOG_FLF_VAL , __FILE__, __LINE__, __FUNCTION__
  192. #else
  193. #define LOG_FLF_FMT "[%24s:%5ld][%24s] "
  194. #define LOG_FLF_VAL , __FILE__, __LINE__, __FUNCTION__
  195. #endif
  196. #else
  197. #define LOG_FLF_FMT "%s"
  198. #define LOG_FLF_VAL ,""
  199. #endif
  200. #ifdef LOG_TEE_FILE_LINE_FUNCTION
  201. #ifndef _MSC_VER
  202. #define LOG_TEE_FLF_FMT "[%24s:%5d][%24s] "
  203. #define LOG_TEE_FLF_VAL , __FILE__, __LINE__, __FUNCTION__
  204. #else
  205. #define LOG_TEE_FLF_FMT "[%24s:%5ld][%24s] "
  206. #define LOG_TEE_FLF_VAL , __FILE__, __LINE__, __FUNCTION__
  207. #endif
  208. #else
  209. #define LOG_TEE_FLF_FMT "%s"
  210. #define LOG_TEE_FLF_VAL ,""
  211. #endif
  212. // INTERNAL, DO NOT USE
  213. // USE LOG() INSTEAD
  214. //
  215. #ifndef _MSC_VER
  216. #define LOG_IMPL(str, ...) \
  217. do { \
  218. if (LOG_TARGET != nullptr) \
  219. { \
  220. fprintf(LOG_TARGET, LOG_TIMESTAMP_FMT LOG_FLF_FMT str "%s" LOG_TIMESTAMP_VAL LOG_FLF_VAL, __VA_ARGS__); \
  221. fflush(LOG_TARGET); \
  222. } \
  223. } while (0)
  224. #else
  225. #define LOG_IMPL(str, ...) \
  226. do { \
  227. if (LOG_TARGET != nullptr) \
  228. { \
  229. fprintf(LOG_TARGET, LOG_TIMESTAMP_FMT LOG_FLF_FMT str "%s" LOG_TIMESTAMP_VAL LOG_FLF_VAL "", ##__VA_ARGS__); \
  230. fflush(LOG_TARGET); \
  231. } \
  232. } while (0)
  233. #endif
  234. // INTERNAL, DO NOT USE
  235. // USE LOG_TEE() INSTEAD
  236. //
  237. #ifndef _MSC_VER
  238. #define LOG_TEE_IMPL(str, ...) \
  239. do { \
  240. if (LOG_TARGET != nullptr) \
  241. { \
  242. fprintf(LOG_TARGET, LOG_TIMESTAMP_FMT LOG_FLF_FMT str "%s" LOG_TIMESTAMP_VAL LOG_FLF_VAL, __VA_ARGS__); \
  243. fflush(LOG_TARGET); \
  244. } \
  245. if (LOG_TARGET != nullptr && LOG_TARGET != stdout && LOG_TARGET != stderr && LOG_TEE_TARGET != nullptr) \
  246. { \
  247. fprintf(LOG_TEE_TARGET, LOG_TEE_TIMESTAMP_FMT LOG_TEE_FLF_FMT str "%s" LOG_TEE_TIMESTAMP_VAL LOG_TEE_FLF_VAL, __VA_ARGS__); \
  248. fflush(LOG_TEE_TARGET); \
  249. } \
  250. } while (0)
  251. #else
  252. #define LOG_TEE_IMPL(str, ...) \
  253. do { \
  254. if (LOG_TARGET != nullptr) \
  255. { \
  256. fprintf(LOG_TARGET, LOG_TIMESTAMP_FMT LOG_FLF_FMT str "%s" LOG_TIMESTAMP_VAL LOG_FLF_VAL "", ##__VA_ARGS__); \
  257. fflush(LOG_TARGET); \
  258. } \
  259. if (LOG_TARGET != nullptr && LOG_TARGET != stdout && LOG_TARGET != stderr && LOG_TEE_TARGET != nullptr) \
  260. { \
  261. fprintf(LOG_TEE_TARGET, LOG_TEE_TIMESTAMP_FMT LOG_TEE_FLF_FMT str "%s" LOG_TEE_TIMESTAMP_VAL LOG_TEE_FLF_VAL "", ##__VA_ARGS__); \
  262. fflush(LOG_TEE_TARGET); \
  263. } \
  264. } while (0)
  265. #endif
  266. // The '\0' as a last argument, is a trick to bypass the silly
  267. // "warning: ISO C++11 requires at least one argument for the "..." in a variadic macro"
  268. // so we can have a single macro which can be called just like printf.
  269. // Main LOG macro.
  270. // behaves like printf, and supports arguments the exact same way.
  271. //
  272. #ifndef _MSC_VER
  273. #define LOG(...) LOG_IMPL(__VA_ARGS__, "")
  274. #else
  275. #define LOG(str, ...) LOG_IMPL("%s" str, "", __VA_ARGS__, "")
  276. #endif
  277. // Main TEE macro.
  278. // does the same as LOG
  279. // and
  280. // simultaneously writes stderr.
  281. //
  282. // Secondary target can be changed just like LOG_TARGET
  283. // by defining LOG_TEE_TARGET
  284. //
  285. #ifndef _MSC_VER
  286. #define LOG_TEE(...) LOG_TEE_IMPL(__VA_ARGS__, "")
  287. #else
  288. #define LOG_TEE(str, ...) LOG_TEE_IMPL("%s" str, "", __VA_ARGS__, "")
  289. #endif
  290. // LOG macro variants with auto endline.
  291. #ifndef _MSC_VER
  292. #define LOGLN(...) LOG_IMPL(__VA_ARGS__, "\n")
  293. #define LOG_TEELN(...) LOG_TEE_IMPL(__VA_ARGS__, "\n")
  294. #else
  295. #define LOGLN(str, ...) LOG_IMPL("%s" str, "", __VA_ARGS__, "\n")
  296. #define LOG_TEELN(str, ...) LOG_TEE_IMPL("%s" str, "", __VA_ARGS__, "\n")
  297. #endif
  298. // INTERNAL, DO NOT USE
  299. inline FILE *log_handler1_impl(bool change = false, LogTriState append = LogTriStateSame, LogTriState disable = LogTriStateSame, const std::string & filename = LOG_DEFAULT_FILE_NAME, FILE *target = nullptr)
  300. {
  301. static bool _initialized = false;
  302. static bool _append = false;
  303. static bool _disabled = filename.empty() && target == nullptr;
  304. static std::string log_current_filename{filename};
  305. static FILE *log_current_target{target};
  306. static FILE *logfile = nullptr;
  307. if (change)
  308. {
  309. if (append != LogTriStateSame)
  310. {
  311. _append = append == LogTriStateTrue;
  312. return logfile;
  313. }
  314. if (disable == LogTriStateTrue)
  315. {
  316. // Disable primary target
  317. _disabled = true;
  318. }
  319. // If previously disabled, only enable, and keep previous target
  320. else if (disable == LogTriStateFalse)
  321. {
  322. _disabled = false;
  323. }
  324. // Otherwise, process the arguments
  325. else if (log_current_filename != filename || log_current_target != target)
  326. {
  327. _initialized = false;
  328. }
  329. }
  330. if (_disabled)
  331. {
  332. // Log is disabled
  333. return nullptr;
  334. }
  335. if (_initialized)
  336. {
  337. // with fallback in case something went wrong
  338. return logfile ? logfile : stderr;
  339. }
  340. // do the (re)initialization
  341. if (target != nullptr)
  342. {
  343. if (logfile != nullptr && logfile != stdout && logfile != stderr)
  344. {
  345. fclose(logfile);
  346. }
  347. log_current_filename = LOG_DEFAULT_FILE_NAME;
  348. log_current_target = target;
  349. logfile = target;
  350. }
  351. else
  352. {
  353. if (log_current_filename != filename)
  354. {
  355. if (logfile != nullptr && logfile != stdout && logfile != stderr)
  356. {
  357. fclose(logfile);
  358. }
  359. }
  360. logfile = fopen(filename.c_str(), _append ? "a" : "w");
  361. }
  362. if (!logfile)
  363. {
  364. // Verify whether the file was opened, otherwise fallback to stderr
  365. logfile = stderr;
  366. fprintf(stderr, "Failed to open logfile '%s' with error '%s'\n", filename.c_str(), std::strerror(errno));
  367. fflush(stderr);
  368. // At this point we let the init flag be to true below, and let the target fallback to stderr
  369. // otherwise we would repeatedly fopen() which was already unsuccessful
  370. }
  371. _initialized = true;
  372. return logfile ? logfile : stderr;
  373. }
  374. // INTERNAL, DO NOT USE
  375. inline FILE *log_handler2_impl(bool change = false, LogTriState append = LogTriStateSame, LogTriState disable = LogTriStateSame, FILE *target = nullptr, const std::string & filename = LOG_DEFAULT_FILE_NAME)
  376. {
  377. return log_handler1_impl(change, append, disable, filename, target);
  378. }
  379. // Disables logs entirely at runtime.
  380. // Makes LOG() and LOG_TEE() produce no output,
  381. // until enabled back.
  382. #define log_disable() log_disable_impl()
  383. // INTERNAL, DO NOT USE
  384. inline FILE *log_disable_impl()
  385. {
  386. return log_handler1_impl(true, LogTriStateSame, LogTriStateTrue);
  387. }
  388. // Enables logs at runtime.
  389. #define log_enable() log_enable_impl()
  390. // INTERNAL, DO NOT USE
  391. inline FILE *log_enable_impl()
  392. {
  393. return log_handler1_impl(true, LogTriStateSame, LogTriStateFalse);
  394. }
  395. // Sets target fir logs, either by a file name or FILE* pointer (stdout, stderr, or any valid FILE*)
  396. #define log_set_target(target) log_set_target_impl(target)
  397. // INTERNAL, DO NOT USE
  398. inline FILE *log_set_target_impl(const std::string & filename) { return log_handler1_impl(true, LogTriStateSame, LogTriStateSame, filename); }
  399. inline FILE *log_set_target_impl(FILE *target) { return log_handler2_impl(true, LogTriStateSame, LogTriStateSame, target); }
  400. // INTERNAL, DO NOT USE
  401. inline FILE *log_handler() { return log_handler1_impl(); }
  402. // Enable or disable creating separate log files for each run.
  403. // can ONLY be invoked BEFORE first log use.
  404. #define log_multilog(enable) log_filename_generator_impl((enable) ? LogTriStateTrue : LogTriStateFalse, "", "")
  405. // Enable or disable append mode for log file.
  406. // can ONLY be invoked BEFORE first log use.
  407. #define log_append(enable) log_append_impl(enable)
  408. // INTERNAL, DO NOT USE
  409. inline FILE *log_append_impl(bool enable)
  410. {
  411. return log_handler1_impl(true, enable ? LogTriStateTrue : LogTriStateFalse, LogTriStateSame);
  412. }
  413. inline void log_test()
  414. {
  415. log_disable();
  416. LOG("01 Hello World to nobody, because logs are disabled!\n");
  417. log_enable();
  418. LOG("02 Hello World to default output, which is \"%s\" ( Yaaay, arguments! )!\n", LOG_STRINGIZE(LOG_TARGET));
  419. LOG_TEE("03 Hello World to **both** default output and " LOG_TEE_TARGET_STRING "!\n");
  420. log_set_target(stderr);
  421. LOG("04 Hello World to stderr!\n");
  422. LOG_TEE("05 Hello World TEE with double printing to stderr prevented!\n");
  423. log_set_target(LOG_DEFAULT_FILE_NAME);
  424. LOG("06 Hello World to default log file!\n");
  425. log_set_target(stdout);
  426. LOG("07 Hello World to stdout!\n");
  427. log_set_target(LOG_DEFAULT_FILE_NAME);
  428. LOG("08 Hello World to default log file again!\n");
  429. log_disable();
  430. LOG("09 Hello World _1_ into the void!\n");
  431. log_enable();
  432. LOG("10 Hello World back from the void ( you should not see _1_ in the log or the output )!\n");
  433. log_disable();
  434. log_set_target("llama.anotherlog.log");
  435. LOG("11 Hello World _2_ to nobody, new target was selected but logs are still disabled!\n");
  436. log_enable();
  437. LOG("12 Hello World this time in a new file ( you should not see _2_ in the log or the output )?\n");
  438. log_set_target("llama.yetanotherlog.log");
  439. LOG("13 Hello World this time in yet new file?\n");
  440. log_set_target(log_filename_generator("llama_autonamed", "log"));
  441. LOG("14 Hello World in log with generated filename!\n");
  442. #ifdef _MSC_VER
  443. LOG_TEE("15 Hello msvc TEE without arguments\n");
  444. LOG_TEE("16 Hello msvc TEE with (%d)(%s) arguments\n", 1, "test");
  445. LOG_TEELN("17 Hello msvc TEELN without arguments\n");
  446. LOG_TEELN("18 Hello msvc TEELN with (%d)(%s) arguments\n", 1, "test");
  447. LOG("19 Hello msvc LOG without arguments\n");
  448. LOG("20 Hello msvc LOG with (%d)(%s) arguments\n", 1, "test");
  449. LOGLN("21 Hello msvc LOGLN without arguments\n");
  450. LOGLN("22 Hello msvc LOGLN with (%d)(%s) arguments\n", 1, "test");
  451. #endif
  452. }
  453. inline bool log_param_single_parse(const std::string & param)
  454. {
  455. if ( param == "--log-test")
  456. {
  457. log_test();
  458. return true;
  459. }
  460. if ( param == "--log-disable")
  461. {
  462. log_disable();
  463. return true;
  464. }
  465. if ( param == "--log-enable")
  466. {
  467. log_enable();
  468. return true;
  469. }
  470. if (param == "--log-new")
  471. {
  472. log_multilog(true);
  473. return true;
  474. }
  475. if (param == "--log-append")
  476. {
  477. log_append(true);
  478. return true;
  479. }
  480. return false;
  481. }
  482. inline bool log_param_pair_parse(bool check_but_dont_parse, const std::string & param, const std::string & next = std::string())
  483. {
  484. if ( param == "--log-file")
  485. {
  486. if (!check_but_dont_parse)
  487. {
  488. log_set_target(log_filename_generator(next.empty() ? "unnamed" : next, "log"));
  489. }
  490. return true;
  491. }
  492. return false;
  493. }
  494. inline void log_print_usage()
  495. {
  496. printf("log options:\n");
  497. /* format
  498. printf(" -h, --help show this help message and exit\n");*/
  499. /* spacing
  500. printf("__-param----------------Description\n");*/
  501. printf(" --log-test Run simple logging test\n");
  502. printf(" --log-disable Disable trace logs\n");
  503. printf(" --log-enable Enable trace logs\n");
  504. printf(" --log-file Specify a log filename (without extension)\n");
  505. printf(" --log-new Create a separate new log file on start. "
  506. "Each log file will have unique name: \"<name>.<ID>.log\"\n");
  507. printf(" --log-append Don't truncate the old log file.\n");
  508. }
  509. #define log_dump_cmdline(argc, argv) log_dump_cmdline_impl(argc, argv)
  510. // INTERNAL, DO NOT USE
  511. inline void log_dump_cmdline_impl(int argc, char **argv)
  512. {
  513. std::stringstream buf;
  514. for (int i = 0; i < argc; ++i)
  515. {
  516. if (std::string(argv[i]).find(' ') != std::string::npos)
  517. {
  518. buf << " \"" << argv[i] <<"\"";
  519. }
  520. else
  521. {
  522. buf << " " << argv[i];
  523. }
  524. }
  525. LOGLN("Cmd:%s", buf.str().c_str());
  526. }
  527. #define log_tostr(var) log_var_to_string_impl(var).c_str()
  528. inline std::string log_var_to_string_impl(bool var)
  529. {
  530. return var ? "true" : "false";
  531. }
  532. inline std::string log_var_to_string_impl(std::string var)
  533. {
  534. return var;
  535. }
  536. inline std::string log_var_to_string_impl(const std::vector<int> & var)
  537. {
  538. std::stringstream buf;
  539. buf << "[ ";
  540. bool first = true;
  541. for (auto e : var)
  542. {
  543. if (first)
  544. {
  545. first = false;
  546. }
  547. else
  548. {
  549. buf << ", ";
  550. }
  551. buf << std::to_string(e);
  552. }
  553. buf << " ]";
  554. return buf.str();
  555. }
  556. template <typename C, typename T>
  557. inline std::string LOG_TOKENS_TOSTR_PRETTY(const C & ctx, const T & tokens)
  558. {
  559. std::stringstream buf;
  560. buf << "[ ";
  561. bool first = true;
  562. for (const auto &token : tokens)
  563. {
  564. if (!first) {
  565. buf << ", ";
  566. } else {
  567. first = false;
  568. }
  569. auto detokenized = llama_token_to_piece(ctx, token);
  570. detokenized.erase(
  571. std::remove_if(
  572. detokenized.begin(),
  573. detokenized.end(),
  574. [](const unsigned char c) { return !std::isprint(c); }),
  575. detokenized.end());
  576. buf
  577. << "'" << detokenized << "'"
  578. << ":" << std::to_string(token);
  579. }
  580. buf << " ]";
  581. return buf.str();
  582. }
  583. template <typename C, typename B>
  584. inline std::string LOG_BATCH_TOSTR_PRETTY(const C & ctx, const B & batch)
  585. {
  586. std::stringstream buf;
  587. buf << "[ ";
  588. bool first = true;
  589. for (int i = 0; i < batch.n_tokens; ++i)
  590. {
  591. if (!first) {
  592. buf << ", ";
  593. } else {
  594. first = false;
  595. }
  596. auto detokenized = llama_token_to_piece(ctx, batch.token[i]);
  597. detokenized.erase(
  598. std::remove_if(
  599. detokenized.begin(),
  600. detokenized.end(),
  601. [](const unsigned char c) { return !std::isprint(c); }),
  602. detokenized.end());
  603. buf
  604. << "\n" << std::to_string(i)
  605. << ":token '" << detokenized << "'"
  606. << ":pos " << std::to_string(batch.pos[i])
  607. << ":n_seq_id " << std::to_string(batch.n_seq_id[i])
  608. << ":seq_id " << std::to_string(batch.seq_id[i][0])
  609. << ":logits " << std::to_string(batch.logits[i]);
  610. }
  611. buf << " ]";
  612. return buf.str();
  613. }
  614. #ifdef LOG_DISABLE_LOGS
  615. #undef LOG
  616. #define LOG(...) // dummy stub
  617. #undef LOGLN
  618. #define LOGLN(...) // dummy stub
  619. #undef LOG_TEE
  620. #define LOG_TEE(...) fprintf(stderr, __VA_ARGS__) // convert to normal fprintf
  621. #undef LOG_TEELN
  622. #define LOG_TEELN(...) fprintf(stderr, __VA_ARGS__) // convert to normal fprintf
  623. #undef LOG_DISABLE
  624. #define LOG_DISABLE() // dummy stub
  625. #undef LOG_ENABLE
  626. #define LOG_ENABLE() // dummy stub
  627. #undef LOG_ENABLE
  628. #define LOG_ENABLE() // dummy stub
  629. #undef LOG_SET_TARGET
  630. #define LOG_SET_TARGET(...) // dummy stub
  631. #undef LOG_DUMP_CMDLINE
  632. #define LOG_DUMP_CMDLINE(...) // dummy stub
  633. #endif // LOG_DISABLE_LOGS