1 /// \file LogRecords.d 2 3 module tagion.logger.LogRecords; 4 5 import tagion.hibon.HiBONRecord; 6 import tagion.logger.Logger : LogLevel, Topic; 7 8 /** @brief Definitions of auxiliary structs and types for working with logs 9 */ 10 11 /** 12 * \enum LogFiltersAction 13 * Defines type of action for list of log filters 14 */ 15 enum LogFiltersAction { 16 ADD, 17 REMOVE 18 } 19 20 /** 21 * \struct LogFilter 22 * Struct represents filter for receiving logs 23 */ 24 @safe struct LogFilter { 25 /** Task name to listen */ 26 @label("task") string task_name; 27 /** Log level. Applied for text logs */ 28 @label("level") LogLevel level; 29 /** Name of symbol to listen. Optional field */ 30 @label("symbol") string symbol_name; 31 32 mixin HiBONRecord!(q{ 33 /** Ctor for text logs 34 * @param task_name - task name 35 * @param level - log level 36 */ 37 this(string task_name, LogLevel level) nothrow { 38 this.task_name = task_name; 39 this.level = level; 40 this.symbol_name = ""; 41 } 42 43 /** Ctor for symbol logs 44 * @param task_name - task name 45 * @param symbol_name - symbol name 46 */ 47 this(string task_name, string symbol_name) nothrow { 48 this.task_name = task_name; 49 this.level = LogLevel.ALL; 50 this.symbol_name = symbol_name; 51 } 52 53 /** Ctor from \link LogInfo 54 * @param info - log info for creating filter 55 */ 56 this(in LogInfo info) nothrow 57 { 58 if (info.isTextLog) 59 { 60 this(info.task_name, info.level); 61 } 62 else 63 { 64 this(info.task_name, info.symbol_name); 65 } 66 } 67 }); 68 69 /** Method that check if given filter matches current filter 70 * @param filter - given filter to check for matching 71 * @return result of check 72 */ 73 @nogc bool match(in LogFilter filter) pure const nothrow { 74 return this.task_name == filter.task_name && this.level & filter.level && this.symbol_name == filter 75 .symbol_name; 76 } 77 78 /** Method that check if given log info matches current filter 79 * @param info - given log info to check for matching 80 * @return result of check 81 */ 82 @nogc bool match(in LogInfo info) pure const nothrow { 83 if (this.isTextLog != info.isTextLog) { 84 return false; 85 } 86 87 bool result; 88 if (info.isTextLog) { 89 result = this.task_name == info.task_name && this.level & info.level; 90 } 91 else { 92 result = this.task_name == info.task_name && this.symbol_name == info.symbol_name; 93 } 94 return result; 95 } 96 97 /** Method that check if current filter for text log 98 * @return result of check 99 */ 100 @nogc bool isTextLog() pure const nothrow { 101 import std.range; 102 103 return symbol_name.empty; 104 } 105 } 106 107 /** 108 * \struct LogFilterArray 109 * Struct stores array of \link LogFilter 110 */ 111 @safe struct LogFilterArray { 112 /** Array of filters */ 113 immutable(LogFilter[]) array; 114 115 /** Main ctor 116 * @param filters - array of filters 117 */ 118 this(immutable(LogFilter[]) filters) nothrow { 119 this.array = filters; 120 } 121 } 122 123 /** 124 * \struct TextLog 125 * Struct for wrapping text log into \link HiBONRecord 126 */ 127 @safe struct TextLog { 128 /** Text log message */ 129 @label("msg") string message; 130 131 mixin HiBONRecord!(q{ 132 /** Main ctor 133 * @param msg - text message 134 */ 135 this(string msg) nothrow { 136 this.message = msg; 137 } 138 }); 139 } 140 141 /** 142 * \struct LogInfo 143 * Struct stores info about passing log 144 */ 145 @safe struct LogInfo { 146 private { 147 /** Value that stores type of log */ 148 const bool _is_text_log; 149 } 150 151 /** Task name */ 152 const string task_name; 153 /** Log level */ 154 const LogLevel level; 155 156 /** Ctor for text logs 157 * @param task_name - task name 158 * @param level - log level 159 */ 160 this(string task_name, LogLevel level) nothrow pure { 161 this.task_name = task_name; 162 this.level = level; 163 164 _is_text_log = true; 165 } 166 167 const string topic_name; 168 /** Symbol name */ 169 const string symbol_name; 170 171 /** Ctor for symbol logs 172 * @param task_name - task name 173 * @param symbol_name - symbol name 174 */ 175 this(Topic topic, string task_name, string symbol_name) nothrow pure { 176 this.task_name = task_name; 177 this.topic_name = topic.name; 178 this.symbol_name = symbol_name; 179 180 _is_text_log = false; 181 } 182 183 /** Method that return whether current filter is text log 184 * @return result 185 */ 186 @nogc bool isTextLog() pure const nothrow { 187 return _is_text_log; 188 } 189 } 190 191 unittest { 192 enum task1 = "sometaskname"; 193 enum task2 = "anothertaskname"; 194 enum symbol1 = "some_symbol"; 195 enum symbol2 = "another_symbol"; 196 197 /// LogFilter_match_symmetrical 198 { 199 auto f1 = LogFilter(task1, LogLevel.STDERR); 200 auto f2 = LogFilter(task1, LogLevel.ERROR); 201 202 assert(f1.match(f2)); 203 assert(f2.match(f1)); 204 } 205 206 /// LogFilter_match_text_logs 207 { 208 assert(LogFilter(task1, LogLevel.ERROR).match(LogFilter(task1, LogLevel.STDERR))); 209 assert(LogFilter(task1, LogLevel.ALL).match(LogFilter(task1, LogLevel.INFO))); 210 assert(LogFilter(task2, LogLevel.ERROR).match(LogFilter(task2, LogLevel.ERROR))); 211 212 assert(!LogFilter(task1, LogLevel.STDERR).match(LogFilter(task1, LogLevel.INFO))); 213 assert(!LogFilter(task1, LogLevel.ERROR).match(LogFilter(task2, LogLevel.ERROR))); 214 assert(!LogFilter(task1, LogLevel.INFO).match(LogFilter("", LogLevel.INFO))); 215 216 assert(!LogFilter(task1, LogLevel.NONE).match(LogFilter(task1, LogLevel.NONE))); 217 } 218 219 /// LogFilter_match_text_log_info 220 { 221 assert(LogFilter(task1, LogLevel.STDERR).match(LogInfo(task1, LogLevel.ERROR))); 222 assert(LogFilter(task1, LogLevel.ALL).match(LogInfo(task1, LogLevel.INFO))); 223 224 assert(!LogFilter(task1, LogLevel.STDERR).match(LogInfo(task1, LogLevel.INFO))); 225 assert(!LogFilter(task1, LogLevel.INFO).match(LogInfo(task2, LogLevel.INFO))); 226 227 assert(!LogFilter(task1, LogLevel.NONE).match(LogInfo(task1, LogLevel.NONE))); 228 } 229 230 /// LogFilter_match_symbol_log 231 { 232 assert(LogFilter(task1, symbol1).match(LogFilter(task1, symbol1))); 233 assert(LogFilter(task2, symbol2).match(LogFilter(task2, symbol2))); 234 235 assert(!LogFilter(task1, symbol1).match(LogFilter(task1, LogLevel.ALL))); 236 assert(!LogFilter(task1, symbol1).match(LogFilter(task1, symbol2))); 237 assert(!LogFilter(task1, symbol1).match(LogFilter(task1, ""))); 238 } 239 240 /// LogFilter_match_symbol_log_info 241 { 242 assert(LogFilter(task1, symbol1).match(LogInfo(Topic(""), task1, symbol1))); 243 244 assert(!LogFilter(task1, symbol1).match(LogInfo(Topic(""), task1, symbol2))); 245 assert(!LogFilter(task1, symbol1).match(LogInfo(task1, LogLevel.ALL))); 246 } 247 248 /// LogFilter_isTextLog 249 { 250 assert(LogFilter(task1, LogLevel.ERROR).isTextLog); 251 assert(LogFilter(task1, LogLevel.NONE).isTextLog); 252 assert(LogFilter(task1, "").isTextLog); 253 254 assert(!LogFilter(task1, symbol1).isTextLog); 255 } 256 257 /// LogInfo_isTextLog 258 { 259 assert(LogInfo(task1, LogLevel.ERROR).isTextLog); 260 assert(LogInfo(task1, LogLevel.NONE).isTextLog); 261 262 assert(!LogInfo(Topic(), task1, symbol1).isTextLog); 263 assert(!LogInfo(Topic(), task1, "").isTextLog); 264 } 265 }