| 1 | // This file is a part of Framsticks SDK. http://www.framsticks.com/ |
|---|
| 2 | // Copyright (C) 1999-2019 Maciej Komosinski and Szymon Ulatowski. |
|---|
| 3 | // See LICENSE.txt for details. |
|---|
| 4 | |
|---|
| 5 | #include "loggers.h" |
|---|
| 6 | #include <common/util-string.h> |
|---|
| 7 | #include <string.h> |
|---|
| 8 | |
|---|
| 9 | void logMessage(const char *obj, const char *method, int level, const char *msg) |
|---|
| 10 | { |
|---|
| 11 | tlsGetRef(message_handler_manager_instance).send(obj, method, level, msg); |
|---|
| 12 | } |
|---|
| 13 | |
|---|
| 14 | THREAD_LOCAL_DEF(LoggerManager, message_handler_manager_instance); |
|---|
| 15 | |
|---|
| 16 | void LoggerManager::send(int position, const char *obj, const char *method, int level, const char *msg) |
|---|
| 17 | { |
|---|
| 18 | if (position >= int(loggers.size())) position = int(loggers.size()) - 1; |
|---|
| 19 | bool blocked = false; |
|---|
| 20 | for (int i = position; i >= 0; i--) |
|---|
| 21 | { |
|---|
| 22 | LoggerBase *logger = loggers[i]; |
|---|
| 23 | if ((!(logger->options & LoggerBase::Paused)) && |
|---|
| 24 | ((!blocked) || (logger->options & LoggerBase::CannotBeBlocked))) |
|---|
| 25 | { |
|---|
| 26 | logger->handle(obj, method, level, msg); |
|---|
| 27 | if (!(logger->options & LoggerBase::DontBlock)) blocked = true; |
|---|
| 28 | } |
|---|
| 29 | } |
|---|
| 30 | } |
|---|
| 31 | |
|---|
| 32 | int LoggerManager::add(LoggerBase *logger) |
|---|
| 33 | { |
|---|
| 34 | logger->manager = this; |
|---|
| 35 | loggers.push_back(logger); |
|---|
| 36 | return int(loggers.size()) - 1; |
|---|
| 37 | } |
|---|
| 38 | |
|---|
| 39 | void LoggerManager::remove(int i) |
|---|
| 40 | { |
|---|
| 41 | LoggerBase *h = loggers[i]; |
|---|
| 42 | h->manager = NULL; |
|---|
| 43 | loggers.erase(loggers.begin() + i); |
|---|
| 44 | } |
|---|
| 45 | |
|---|
| 46 | void LoggerManager::remove(LoggerBase *logger) |
|---|
| 47 | { |
|---|
| 48 | int index = find(logger); |
|---|
| 49 | if (index >= 0) |
|---|
| 50 | remove(index); |
|---|
| 51 | } |
|---|
| 52 | |
|---|
| 53 | void LoggerManager::removeAll() |
|---|
| 54 | { |
|---|
| 55 | while (loggers.size() > 0) |
|---|
| 56 | remove(int(loggers.size()) - 1); |
|---|
| 57 | } |
|---|
| 58 | |
|---|
| 59 | ////////////////////////////////// |
|---|
| 60 | |
|---|
| 61 | void LoggerBase::send(const char *obj, const char *method, int level, const char *msg) |
|---|
| 62 | { |
|---|
| 63 | if (!isEnabled()) return; |
|---|
| 64 | int position = manager->find(this); |
|---|
| 65 | if (position >= 0) manager->send(position - 1, obj, method, level, msg); |
|---|
| 66 | } |
|---|
| 67 | |
|---|
| 68 | void LoggerBase::logPrintf(const char *obj, const char *method, int level, const char *msg, ...) |
|---|
| 69 | { |
|---|
| 70 | if (!isEnabled()) return; |
|---|
| 71 | string buf; |
|---|
| 72 | va_list argptr; |
|---|
| 73 | va_start(argptr, msg); |
|---|
| 74 | buf = ssprintf_va(msg, argptr); |
|---|
| 75 | va_end(argptr); |
|---|
| 76 | send(obj, method, level, buf.c_str()); |
|---|
| 77 | } |
|---|
| 78 | |
|---|
| 79 | |
|---|
| 80 | void LoggerBase::enable() |
|---|
| 81 | { |
|---|
| 82 | if (isEnabled()) return; |
|---|
| 83 | tlsGetRef(message_handler_manager_instance).add(this); |
|---|
| 84 | } |
|---|
| 85 | |
|---|
| 86 | void LoggerBase::disable() |
|---|
| 87 | { |
|---|
| 88 | if (!isEnabled()) return; |
|---|
| 89 | tlsGetRef(message_handler_manager_instance).remove(this); |
|---|
| 90 | } |
|---|
| 91 | |
|---|
| 92 | void LoggerBase::pause() |
|---|
| 93 | { |
|---|
| 94 | if (isPaused()) return; |
|---|
| 95 | options |= Paused; |
|---|
| 96 | } |
|---|
| 97 | |
|---|
| 98 | void LoggerBase::resume() |
|---|
| 99 | { |
|---|
| 100 | if (!isPaused()) return; |
|---|
| 101 | options &= ~Paused; |
|---|
| 102 | } |
|---|
| 103 | |
|---|
| 104 | void LoggerBase::handle(const char *obj, const char *method, int level, const char *msg) |
|---|
| 105 | { |
|---|
| 106 | int line = 0; //all lines except the first one get the "..." prefix |
|---|
| 107 | const char* nextsep; |
|---|
| 108 | do |
|---|
| 109 | { |
|---|
| 110 | nextsep = strchr(msg, '\n'); |
|---|
| 111 | if (nextsep == NULL) //last chunk, until the end |
|---|
| 112 | nextsep = strchr(msg, '\0'); |
|---|
| 113 | if ((nextsep > msg) && (nextsep[-1] == '\r')) |
|---|
| 114 | nextsep--; |
|---|
| 115 | if (line == 0) |
|---|
| 116 | { |
|---|
| 117 | if (*nextsep == 0) //there was only one line! no need to modify it in any way. |
|---|
| 118 | handleSingleLine(obj, method, level, msg); |
|---|
| 119 | else //first line from multi-line |
|---|
| 120 | handleSingleLine(obj, method, level, string(msg, nextsep - msg).c_str()); |
|---|
| 121 | } |
|---|
| 122 | else //consecutive lines from multi-line |
|---|
| 123 | handleSingleLine(obj, method, level, (LOG_MULTILINE_CONTINUATION + string(msg, nextsep - msg)).c_str()); //could also add line numbers like ...(3)... but let's keep the prefix short and simple |
|---|
| 124 | line++; |
|---|
| 125 | if ((options & Paused) != 0) break; //seemingly pointless test (it was already checked), but 'options' can change inside handleSingleLine(). |
|---|
| 126 | if ((nextsep[0] == '\r') && (nextsep[1] == '\n')) |
|---|
| 127 | msg = nextsep + 2; |
|---|
| 128 | else if (*nextsep) |
|---|
| 129 | msg = nextsep + 1; |
|---|
| 130 | } while (*nextsep); |
|---|
| 131 | } |
|---|
| 132 | |
|---|
| 133 | ///////////////////////////////// |
|---|
| 134 | |
|---|
| 135 | void LoggerToMemory::handle(const char *obj, const char *method, int level, const char *msg) |
|---|
| 136 | { |
|---|
| 137 | if (level > maxlevel) maxlevel = level; |
|---|
| 138 | if (level >= LOG_INFO) infocount++; |
|---|
| 139 | if (level >= LOG_WARN) warncount++; |
|---|
| 140 | if (level >= LOG_ERROR) errcount++; |
|---|
| 141 | |
|---|
| 142 | if (level >= minleveltostore) |
|---|
| 143 | { |
|---|
| 144 | storedcount++; |
|---|
| 145 | if (options & (StoreFirstMessage | StoreAllMessages)) |
|---|
| 146 | { |
|---|
| 147 | if (!((options&StoreFirstMessage) && (msgs.length() > 0))) |
|---|
| 148 | { |
|---|
| 149 | if (msgs.length() > 0) msgs += '\n'; |
|---|
| 150 | msgs += ssprintf(LOG_FORMAT, logLevelName(level), obj, method, msg); |
|---|
| 151 | } |
|---|
| 152 | } |
|---|
| 153 | } |
|---|
| 154 | } |
|---|
| 155 | |
|---|
| 156 | string LoggerToMemory::getCountSummary() const |
|---|
| 157 | { |
|---|
| 158 | if (getErrorWarningInfoCount()) |
|---|
| 159 | { |
|---|
| 160 | string msg; |
|---|
| 161 | if (getErrorCount()) |
|---|
| 162 | msg = ssprintf("%d error(s)", getErrorCount()); |
|---|
| 163 | int w; |
|---|
| 164 | if ((w = getWarningCount())) |
|---|
| 165 | msg += ssprintf("%s%d warning(s)", (msg.size()>0 ? ", " : ""), w); |
|---|
| 166 | if ((w = getInfoCount())) |
|---|
| 167 | msg += ssprintf("%s%d message(s)", (msg.size()>0 ? ", " : ""), w); |
|---|
| 168 | return msg; |
|---|
| 169 | } |
|---|
| 170 | return string(""); |
|---|
| 171 | } |
|---|