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
27namespace {
28
29// Default log level is error, which means that we'll log regular
30// errors and fatal errors.
31std::atomic<LogLevel> log_level(LogLevel::ERROR);
32std::mutex log_mutex;
33std::ofstream log_stream;
34std::ostream* log_ostream = &std::cerr;
35std::string log_filename;
36
37} // anonymous namespace
38
39void 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
56void base::set_log_level(const LogLevel level)
57{
58 log_level = level;
59}
60
61LogLevel base::get_log_level()
62{
63 return log_level;
64}
65
66static 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
91void 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
103void 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