diff --git a/common/log.h b/common/log.h index 492f98ed8..7ea031d02 100644 --- a/common/log.h +++ b/common/log.h @@ -1,39 +1,57 @@ #pragma once +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + #include +#include +#include // Specifies a log target. -// default simply prints log to stderr +// default uses log_handler() with "llama.log" log file // this can be changed, by defining LOG_TARGET // like so: // // #define LOG_TARGET (a valid FILE*) // #include "log.h" // -// The log target can also be redirected to a function +// or it can be simply redirected to stdout or stderr // like so: // -// #define LOG_TARGET log_handler() +// #define LOG_TARGET stderr // #include "log.h" // -// FILE* log_handler() +// The log target can also be redirected to a diffrent function +// like so: +// +// #define LOG_TARGET log_handler_diffrent() +// #include "log.h" +// +// FILE* log_handler_diffrent() // { // return stderr; // } // // or: // -// #define LOG_TARGET log_handler("somelog.log") +// #define LOG_TARGET log_handler_another_one("somelog.log") // #include "log.h" // -// FILE* log_handler(char*filename) +// FILE* log_handler_another_one(char*filename) // { +// static FILE* logfile = nullptr; // (...) -// return fopen(...) +// if( !logfile ) +// { +// fopen(...) +// } +// (...) +// return logfile // } // #ifndef LOG_TARGET -#define LOG_TARGET stderr +#define LOG_TARGET log_handler() #endif // Allows disabling timestamps. @@ -75,4 +93,57 @@ // This us a trick to bypass the silly // "warning: ISO C++11 requires at least one argument for the "..." in a variadic macro" // so we xan gave a single macro which can be called just like printf. -#define LOG(...) _LOG(__VA_ARGS__, '\n') \ No newline at end of file +#define LOG(...) _LOG(__VA_ARGS__, '\n') + +inline FILE *log_handler(std::string s = "llama.log") +{ + static std::atomic_bool _initialized{false}; + static std::atomic_bool _logfileopened{false}; + + static FILE* logfile = nullptr; + + if (_initialized)[[likely]] + { + // with fallback in case something went wrong + return logfile ? logfile : stderr; + } + else + { + // Mutex-less threadsafe synchronisation. + // we need to make sure not more than one invocation of this function + // attempts to open a file at once. + // compare_exchange_strong checks and updates a flag + // in a single atomic operation. + bool expected{false}; + if( _logfileopened.compare_exchange_strong(expected,true) ) + { + // If the flag was previously false, and we managed to turn it true + // ew are now responsible for opening the log file + logfile = fopen( s.c_str(), "wa" ); + + if( !logfile ) + { + // Verify whether the file was opened, otherwise fallback to stderr + logfile = stderr; + + fprintf(stderr, "Failed to open logfile '%s' with error '%s'\n", s.c_str(), std::strerror(errno)); + fflush(stderr); + } + + _initialized.store(true); + } + else + { + // We are not first to open the log file + // + // TODO: Better thread-safe option, possibly std::condition_variable + + return stderr; + } + + // with fallback in case something went wrong + return logfile ? logfile : stderr; + } + + return stderr; +} \ No newline at end of file diff --git a/examples/main/main.cpp b/examples/main/main.cpp index 31d376985..4d504cd78 100644 --- a/examples/main/main.cpp +++ b/examples/main/main.cpp @@ -3,7 +3,7 @@ #define _GNU_SOURCE #endif -#define LOG_TARGET log_handler("asd") +//#define LOG_TARGET log_handler("asd") //#define LOG_NO_TIMESTAMPS #include "common.h" @@ -58,19 +58,6 @@ void sigint_handler(int signo) { } #endif -inline FILE *log_handler(std::string s) -{ - static bool initialized{false}; - - if (!initialized)[[unlikely]] - { - fprintf(stderr,"arg: %s", s.c_str()); - initialized=true; - } - - return stderr; -} - int main(int argc, char ** argv) { gpt_params params;