Line data Source code
1 : /**
2 : Copyright (c) 2016-2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #include "SPLog.h"
25 :
26 : #if MODULE_STAPPLER_THREADS
27 : #include "SPThread.h"
28 : #endif
29 :
30 : #if ANDROID
31 : #include <android/log.h>
32 : #endif
33 :
34 : namespace STAPPLER_VERSIONIZED stappler::log {
35 :
36 : static const constexpr int MAX_LOG_FUNC = 16;
37 :
38 : #if DEBUG
39 : static std::bitset<6> s_logMask;
40 : #else
41 : static std::bitset<6> s_logMask = (1 | 2 | 4 | 8);
42 : #endif
43 :
44 3864 : static void DefaultLog2(LogType type, const StringView &tag, const StringView &text) {
45 3864 : std::stringstream stream;
46 :
47 : #if !ANDROID
48 3864 : switch (type) {
49 1275 : case LogType::Verbose: stream << "Verbose: "; break;
50 1400 : case LogType::Debug: break;
51 25 : case LogType::Info: stream << "Info: "; break;
52 180 : case LogType::Warn: stream << "Warn: "; break;
53 884 : case LogType::Error: stream << "Error: "; break;
54 100 : case LogType::Fatal: stream << "Fatal: "; break;
55 : }
56 : #endif
57 :
58 : #if MODULE_STAPPLER_THREADS
59 3864 : if (auto local = thread::ThreadInfo::getThreadLocal()) {
60 400 : if (!local->managed) {
61 0 : stream << "[Thread:" << std::this_thread::get_id() << "] ";
62 400 : } else if (local->threadId == thread::ThreadInfo::mainThreadId) {
63 0 : stream << "[MainThread] ";
64 400 : } else if (local->detouched) {
65 400 : stream << "[" << local->name << "] ";
66 : } else {
67 0 : stream << "[" << local->name << ":" << local->threadId << ":" << local->workerId << "] ";
68 : }
69 : } else {
70 3464 : stream << "[Log] ";
71 : }
72 : #endif
73 :
74 : #if !ANDROID
75 3864 : stream << tag << ": ";
76 : #endif
77 3864 : stream << text;
78 : #ifndef __apple__
79 3864 : stream << "\n";
80 : #endif
81 :
82 3864 : auto str = stream.str();
83 :
84 : #if ANDROID
85 : switch (type) {
86 : case LogType::Verbose: __android_log_print(ANDROID_LOG_VERBOSE, tag.data(), "%s", str.c_str()); break;
87 : case LogType::Debug: __android_log_print(ANDROID_LOG_DEBUG, tag.data(), "%s", str.c_str()); break;
88 : case LogType::Info: __android_log_print(ANDROID_LOG_INFO, tag.data(), "%s", str.c_str()); break;
89 : case LogType::Warn: __android_log_print(ANDROID_LOG_WARN, tag.data(), "%s", str.c_str()); break;
90 : case LogType::Error: __android_log_print(ANDROID_LOG_ERROR, tag.data(), "%s", str.c_str()); break;
91 : case LogType::Fatal: __android_log_print(ANDROID_LOG_FATAL, tag.data(), "%s", str.c_str()); break;
92 : }
93 : #else
94 3864 : fwrite(str.c_str(), str.length(), 1, stdout);
95 3864 : fflush(stdout);
96 : #endif // platform switch
97 3864 : }
98 :
99 3864 : static void DefaultLog(LogType type, const StringView &tag, CustomLog::Type t, CustomLog::VA &va) {
100 3864 : if (t == CustomLog::Text) {
101 3814 : DefaultLog2(type, tag, va.text);
102 : } else {
103 : char stackBuf[1_KiB];
104 : va_list tmpList;
105 50 : va_copy(tmpList, va.format.args);
106 50 : int size = vsnprintf(stackBuf, size_t(1_KiB - 1), va.format.format, tmpList);
107 50 : va_end(tmpList);
108 50 : if (size > int(1_KiB - 1)) {
109 25 : char *buf = new char[size + 1];
110 25 : size = vsnprintf(buf, size_t(size), va.format.format, va.format.args);
111 25 : DefaultLog2(type, tag, StringView(buf, size));
112 25 : delete [] buf;
113 25 : } else if (size >= 0) {
114 25 : DefaultLog2(type, tag, StringView(stackBuf, size));
115 : } else {
116 0 : DefaultLog2(type, tag, "Log error");
117 : }
118 : }
119 3864 : }
120 :
121 : struct CustomLogManager : RefBase<memory::StandartInterface> {
122 : CustomLog::log_fn logFuncArr[MAX_LOG_FUNC] = { 0 };
123 : std::atomic<int> logFuncCount;
124 : std::mutex logFuncMutex;
125 :
126 4014 : static Rc<CustomLogManager> get() {
127 : static std::mutex s_mutex;
128 4014 : static Rc<CustomLogManager> ptr;
129 :
130 4014 : std::unique_lock<std::mutex> lock(s_mutex);
131 4014 : if (!ptr) {
132 25 : ptr = Rc<CustomLogManager>::alloc();
133 : }
134 8028 : return ptr;
135 4014 : }
136 :
137 100 : void insert(CustomLog::log_fn fn) {
138 100 : logFuncMutex.lock();
139 200 : if (logFuncCount.load() < MAX_LOG_FUNC) {
140 100 : logFuncArr[logFuncCount] = fn;
141 100 : ++ logFuncCount;
142 : }
143 100 : logFuncMutex.unlock();
144 100 : }
145 :
146 100 : void remove(CustomLog::log_fn fn) {
147 100 : logFuncMutex.lock();
148 100 : int count = logFuncCount.load();
149 150 : for (int i = 0; i < count; i++) {
150 150 : if (logFuncArr[i] == fn) {
151 100 : if (i != count - 1) {
152 0 : memmove(&logFuncArr[i], &logFuncArr[i + 1], (count - i - 1) * sizeof(CustomLog::log_fn));
153 : }
154 100 : -- logFuncCount;
155 100 : break;
156 : }
157 : }
158 100 : logFuncMutex.unlock();
159 100 : }
160 :
161 3864 : void log(LogType type, const StringView tag, CustomLog::Type t, CustomLog::VA &va) {
162 3864 : if (s_logMask.test(toInt(type))) {
163 0 : return;
164 : }
165 :
166 3864 : int count = logFuncCount.load();
167 3864 : if (count == 0) {
168 3764 : DefaultLog(type, tag, t, va);
169 : } else {
170 100 : bool success = true;
171 100 : logFuncMutex.lock();
172 100 : count = logFuncCount.load();
173 250 : for (int i = 0; i < count; i++) {
174 150 : success = logFuncArr[i](type, tag, t, va);
175 150 : if (!success) {
176 0 : break;
177 : }
178 : }
179 100 : logFuncMutex.unlock();
180 100 : if (success) {
181 100 : DefaultLog(type, tag, t, va);
182 : }
183 : }
184 : }
185 : };
186 :
187 100 : CustomLog::CustomLog(log_fn logfn) : fn(logfn) {
188 100 : manager = CustomLogManager::get();
189 100 : if (fn) {
190 100 : static_cast<CustomLogManager *>(manager.get())->insert(fn);
191 : }
192 100 : }
193 :
194 125 : CustomLog::~CustomLog() {
195 125 : if (fn) {
196 75 : static_cast<CustomLogManager *>(manager.get())->remove(fn);
197 : }
198 125 : }
199 :
200 25 : CustomLog::CustomLog(CustomLog && other) : fn(other.fn) {
201 25 : manager = CustomLogManager::get();
202 25 : other.fn = nullptr;
203 25 : }
204 :
205 25 : CustomLog& CustomLog::operator=(CustomLog && other) {
206 25 : manager = CustomLogManager::get();
207 25 : if (fn && fn != other.fn) {
208 25 : static_cast<CustomLogManager *>(manager.get())->remove(fn);
209 : }
210 25 : fn = other.fn;
211 25 : other.fn = nullptr;
212 25 : return *this;
213 : }
214 :
215 25 : void setLogFilterMask(std::bitset<6> &&mask) {
216 25 : s_logMask = move(mask);
217 25 : }
218 :
219 25 : std::bitset<6> getlogFilterMask() {
220 25 : return s_logMask;
221 : }
222 :
223 50 : void format(LogType type, const StringView &tag, const char *fmt, ...) {
224 50 : CustomLog::VA va;
225 50 : va_start(va.format.args, fmt);
226 50 : va.format.format = fmt;
227 :
228 50 : auto m = CustomLogManager::get();
229 50 : m->log(type, tag, CustomLog::Format, va);
230 :
231 50 : va_end(va.format.args);
232 50 : }
233 :
234 3814 : void text(LogType type, const StringView &tag, const StringView &text) {
235 3814 : CustomLog::VA va;
236 3814 : va.text = text;
237 3814 : auto m = CustomLogManager::get();
238 3814 : m->log(type, tag, CustomLog::Text, va);
239 3814 : }
240 :
241 : }
|