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