| 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 |  | 
|---|