| 1 | // LAF Base Library |
| 2 | // Copyright (C) 2019-2022 Igara Studio S.A. |
| 3 | // Copyright (C) 2001-2017 David Capello |
| 4 | // |
| 5 | // This file is released under the terms of the MIT license. |
| 6 | // Read LICENSE.txt for more information. |
| 7 | |
| 8 | #ifdef HAVE_CONFIG_H |
| 9 | #include "config.h" |
| 10 | #endif |
| 11 | |
| 12 | #include "base/log.h" |
| 13 | |
| 14 | #include "base/debug.h" |
| 15 | #include "base/fstream_path.h" |
| 16 | |
| 17 | #include <atomic> |
| 18 | #include <cstdarg> |
| 19 | #include <cstdio> |
| 20 | #include <cstring> |
| 21 | #include <fstream> |
| 22 | #include <iostream> |
| 23 | #include <mutex> |
| 24 | #include <string> |
| 25 | #include <vector> |
| 26 | |
| 27 | namespace { |
| 28 | |
| 29 | // Default log level is error, which means that we'll log regular |
| 30 | // errors and fatal errors. |
| 31 | std::atomic<LogLevel> log_level(LogLevel::ERROR); |
| 32 | std::mutex log_mutex; |
| 33 | std::ofstream log_stream; |
| 34 | std::ostream* log_ostream = &std::cerr; |
| 35 | std::string log_filename; |
| 36 | |
| 37 | } // anonymous namespace |
| 38 | |
| 39 | void base::set_log_filename(const char* filename) |
| 40 | { |
| 41 | if (log_stream.is_open()) { |
| 42 | log_stream.close(); |
| 43 | log_ostream = &std::cerr; |
| 44 | } |
| 45 | |
| 46 | if (filename) { |
| 47 | log_filename = filename; |
| 48 | log_stream.open(FSTREAM_PATH(log_filename)); |
| 49 | log_ostream = &log_stream; |
| 50 | } |
| 51 | else { |
| 52 | log_filename = std::string(); |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | void base::set_log_level(const LogLevel level) |
| 57 | { |
| 58 | log_level = level; |
| 59 | } |
| 60 | |
| 61 | LogLevel base::get_log_level() |
| 62 | { |
| 63 | return log_level; |
| 64 | } |
| 65 | |
| 66 | static void LOGva(const char* format, va_list ap) |
| 67 | { |
| 68 | va_list apTmp; |
| 69 | va_copy(apTmp, ap); |
| 70 | int size = std::vsnprintf(nullptr, 0, format, apTmp); |
| 71 | va_end(apTmp); |
| 72 | if (size < 1) |
| 73 | return; // Nothing to log |
| 74 | |
| 75 | std::vector<char> buf(size+1); |
| 76 | std::vsnprintf(&buf[0], buf.size(), format, ap); |
| 77 | |
| 78 | { |
| 79 | std::lock_guard lock(log_mutex); |
| 80 | ASSERT(log_ostream); |
| 81 | log_ostream->write(&buf[0], size); |
| 82 | log_ostream->flush(); |
| 83 | } |
| 84 | |
| 85 | #ifdef _DEBUG |
| 86 | fputs(&buf[0], stderr); |
| 87 | fflush(stderr); |
| 88 | #endif |
| 89 | } |
| 90 | |
| 91 | void LOG(const char* format, ...) |
| 92 | { |
| 93 | ASSERT(format); |
| 94 | if (!format || log_level < INFO) |
| 95 | return; |
| 96 | |
| 97 | va_list ap; |
| 98 | va_start(ap, format); |
| 99 | LOGva(format, ap); |
| 100 | va_end(ap); |
| 101 | } |
| 102 | |
| 103 | void LOG(const LogLevel level, const char* format, ...) |
| 104 | { |
| 105 | ASSERT(format); |
| 106 | if (!format || log_level < level) |
| 107 | return; |
| 108 | |
| 109 | va_list ap; |
| 110 | va_start(ap, format); |
| 111 | LOGva(format, ap); |
| 112 | va_end(ap); |
| 113 | } |
| 114 | |