001package io.cui.tools.logging; 002 003import static io.cui.tools.string.MoreStrings.nullToEmpty; 004import static java.util.Objects.requireNonNull; 005 006import java.util.function.Supplier; 007import java.util.logging.Logger; 008import java.util.regex.Pattern; 009 010import io.cui.tools.string.MoreStrings; 011 012/** 013 * <p> 014 * Wrapper around java-util {@link Logger} that simplifies its usage. In 015 * addition it provides a similar api like slf4j. It is not meant to act as logging-facade like 016 * slf4j or jakarta-commons-logging. It only provides a little syntactic sugar for the built-in 017 * logger. 018 * </p> 019 * <h2>Obtaining a logger</h2> 020 * <p> 021 * {@code private static final CuiLogger log = new CuiLogger(SomeClass.class);} 022 * </p> 023 * <p> 024 * {@code private static final CuiLogger log = new CuiLogger("SomeLoggerName");} 025 * </p> 026 * <p> 027 * {@code private static final CuiLogger log = CuiLoggerFactory.getLogger();} 028 * </p> 029 * <h2>Logging</h2> 030 * <p> 031 * {@link CuiLogger} provides an implicit code guard, if used correctly. Used correctly hereby means 032 * to either use formatting with parameter or incorporating {@link Supplier} for generating the 033 * actual log-message. For other means of creating a message you still can use code guards. 034 * </p> 035 * <p> 036 * {@code log.trace("Parameter-type matches exactly '%s'", assignableSource);} 037 * </p> 038 * <p> 039 * {@code log.debug("Adding found method '%s' on class '%s'", name, clazz);} 040 * </p> 041 * <p> 042 * {@code log.info("Starting up application");} 043 * </p> 044 * <p> 045 * {@code // In order not to mess up with the ellipsis parameter} 046 * </p> 047 * <p> 048 * {@code // exceptions must be the first parameter} 049 * </p> 050 * <p> 051 * {@code log.warn(e, "Exception during lenientFormat for '%s'", objectToString); } 052 * </p> 053 * <p> 054 * {@code log.error(e, "Caught an exception"); } 055 * </p> 056 * <p> 057 * {@code log.info(() -> "Supplier can be used as well");} 058 * </p> 059 * <p> 060 * {@code log.error(e, () -> "Even with exceptions");} 061 * </p> 062 * <p> 063 * {@code log.trace(() -> "I will only be evaluated if the trace-level for is enabled");} 064 * </p> 065 * <h2>Formatting</h2> 066 * <p> 067 * Like slf4j there is a simple way of formatting log-messages. In addition to '{}' the 068 * formatting supports '%s' as well. At runtime it replaces the '{}' tokens with 069 * '%s' and passes the data to {@link MoreStrings#lenientFormat(String, Object...)} for 070 * creating the actual log-message. As a variant providing a {@link Supplier} works as well. 071 * </p> 072 * 073 * @author Oliver Wolff 074 * 075 */ 076public class CuiLogger { 077 078 private final Logger delegate; 079 080 static final Pattern SLF4J_PATTERN = Pattern.compile(Pattern.quote("{}")); 081 082 /** 083 * @param clazz to be used for acquiring a concrete {@link Logger} instance. 084 * Must not be null 085 */ 086 public CuiLogger(Class<?> clazz) { 087 requireNonNull(clazz); 088 delegate = Logger.getLogger(clazz.getName()); 089 } 090 091 /** 092 * @param name to be used for acquiring a concrete {@link Logger} instance. 093 * Must not be null 094 */ 095 public CuiLogger(String name) { 096 requireNonNull(nullToEmpty(name)); 097 delegate = Logger.getLogger(name); 098 } 099 100 /** 101 * Is the logger instance enabled for the trace level? 102 * 103 * @return {@code true} if this CuiLogger is enabled for the trace level, 104 * false otherwise. 105 * 106 */ 107 public boolean isTraceEnabled() { 108 return LogLevel.TRACE.isEnabled(delegate); 109 } 110 111 /** 112 * Log a message at the trace level. 113 * 114 * @param msg the message string to be logged 115 * 116 */ 117 public void trace(String msg) { 118 LogLevel.TRACE.handleActualLog(delegate, msg, null); 119 } 120 121 /** 122 * Log a message at the trace level. 123 * 124 * @param msg the message string to be logged 125 * 126 */ 127 public void trace(Supplier<String> msg) { 128 LogLevel.TRACE.log(delegate, msg, null); 129 } 130 131 /** 132 * Log a message at the trace level. 133 * 134 * @param throwable to be logged 135 * @param msg the message string to be logged 136 * 137 */ 138 public void trace(Throwable throwable, Supplier<String> msg) { 139 LogLevel.TRACE.log(delegate, msg, throwable); 140 } 141 142 /** 143 * Log a message at the trace level. 144 * 145 * @param msg the message string to be logged 146 * @param throwable to be logged 147 * 148 */ 149 public void trace(String msg, Throwable throwable) { 150 LogLevel.TRACE.handleActualLog(delegate, msg, throwable); 151 } 152 153 /** 154 * Log a message at the trace level. 155 * 156 * @param throwable to be logged 157 * @param template to be used for formatting, see class-documentation for details on formatting 158 * @param parameter to be used for replacing the placeholder 159 * 160 */ 161 public void trace(Throwable throwable, String template, Object... parameter) { 162 LogLevel.TRACE.log(delegate, throwable, template, parameter); 163 } 164 165 /** 166 * Log a message at the trace level. 167 * 168 * @param template to be used for formatting, see class-documentation for details on formatting 169 * @param parameter to be used for replacing the placeholder 170 * 171 */ 172 public void trace(String template, Object... parameter) { 173 LogLevel.TRACE.log(delegate, template, parameter); 174 } 175 176 /** 177 * Is the logger instance enabled for the debug level? 178 * 179 * @return {@code true} if this CuiLogger is enabled for the debug level, 180 * false otherwise. 181 * 182 */ 183 public boolean isDebugEnabled() { 184 return LogLevel.DEBUG.isEnabled(delegate); 185 } 186 187 /** 188 * Log a message at the debug level. 189 * 190 * @param msg the message string to be logged 191 */ 192 public void debug(String msg) { 193 LogLevel.DEBUG.handleActualLog(delegate, msg, null); 194 } 195 196 /** 197 * Log a message at the debug level. 198 * 199 * @param msg the message string to be logged 200 * @param throwable to be logged 201 * 202 */ 203 public void debug(String msg, Throwable throwable) { 204 LogLevel.DEBUG.handleActualLog(delegate, msg, throwable); 205 } 206 207 /** 208 * Log a message at the debug level. 209 * 210 * @param msg the message string to be logged 211 * 212 */ 213 public void debug(Supplier<String> msg) { 214 LogLevel.DEBUG.log(delegate, msg, null); 215 } 216 217 /** 218 * Log a message at the debug level. 219 * 220 * @param throwable to be logged 221 * @param msg the message string to be logged 222 * 223 */ 224 public void debug(Throwable throwable, Supplier<String> msg) { 225 LogLevel.DEBUG.log(delegate, msg, throwable); 226 } 227 228 /** 229 * Log a message at the debug level. 230 * 231 * @param throwable to be logged 232 * @param template to be used for formatting, see class-documentation for details on formatting 233 * @param parameter to be used for replacing the placeholder 234 * 235 */ 236 public void debug(Throwable throwable, String template, Object... parameter) { 237 LogLevel.DEBUG.log(delegate, throwable, template, parameter); 238 } 239 240 /** 241 * Log a message at the debug level. 242 * 243 * @param template to be used for formatting, see class-documentation for details on formatting 244 * @param parameter to be used for replacing the placeholder 245 * 246 */ 247 public void debug(String template, Object... parameter) { 248 LogLevel.DEBUG.log(delegate, template, parameter); 249 } 250 251 /** 252 * Is the logger instance enabled for the info level? 253 * 254 * @return {@code true} if this CuiLogger is enabled for the info level, 255 * false otherwise. 256 * 257 */ 258 public boolean isInfoEnabled() { 259 return LogLevel.INFO.isEnabled(delegate); 260 } 261 262 /** 263 * Log a message at the info level. 264 * 265 * @param msg the message string to be logged 266 */ 267 public void info(String msg) { 268 LogLevel.INFO.handleActualLog(delegate, msg, null); 269 } 270 271 /** 272 * Log a message at the info level. 273 * 274 * @param msg the message string to be logged 275 * @param throwable to be logged 276 * 277 */ 278 public void info(String msg, Throwable throwable) { 279 LogLevel.INFO.handleActualLog(delegate, msg, throwable); 280 } 281 282 /** 283 * Log a message at the info level. 284 * 285 * @param msg the message string to be logged 286 * 287 */ 288 public void info(Supplier<String> msg) { 289 LogLevel.INFO.log(delegate, msg, null); 290 } 291 292 /** 293 * Log a message at the info level. 294 * 295 * @param throwable to be logged 296 * @param msg the message string to be logged 297 * 298 */ 299 public void info(Throwable throwable, Supplier<String> msg) { 300 LogLevel.INFO.log(delegate, msg, throwable); 301 } 302 303 /** 304 * Log a message at the info level. 305 * 306 * @param throwable to be logged 307 * @param template to be used for formatting, see class-documentation for details on formatting 308 * @param parameter to be used for replacing the placeholder 309 * 310 */ 311 public void info(Throwable throwable, String template, Object... parameter) { 312 LogLevel.INFO.log(delegate, throwable, template, parameter); 313 } 314 315 /** 316 * Log a message at the info level. 317 * 318 * @param template to be used for formatting, see class-documentation for details on formatting 319 * @param parameter to be used for replacing the placeholder 320 * 321 */ 322 public void info(String template, Object... parameter) { 323 LogLevel.INFO.log(delegate, template, parameter); 324 } 325 326 /** 327 * Is the logger instance enabled for the warn level? 328 * 329 * @return {@code true} if this CuiLogger is enabled for the warn level, 330 * false otherwise. 331 * 332 */ 333 public boolean isWarnEnabled() { 334 return LogLevel.WARN.isEnabled(delegate); 335 } 336 337 /** 338 * Log a message at the warn level. 339 * 340 * @param msg the message string to be logged 341 */ 342 public void warn(String msg) { 343 LogLevel.WARN.handleActualLog(delegate, msg, null); 344 } 345 346 /** 347 * Log a message at the warn level. 348 * 349 * @param msg the message string to be logged 350 * @param throwable to be logged 351 * 352 */ 353 public void warn(String msg, Throwable throwable) { 354 LogLevel.WARN.handleActualLog(delegate, msg, throwable); 355 } 356 357 /** 358 * Log a message at the warn level. 359 * 360 * @param msg the message string to be logged 361 * 362 */ 363 public void warn(Supplier<String> msg) { 364 LogLevel.WARN.log(delegate, msg, null); 365 } 366 367 /** 368 * Log a message at the warn level. 369 * 370 * @param throwable to be logged 371 * @param msg the message string to be logged 372 * 373 */ 374 public void warn(Throwable throwable, Supplier<String> msg) { 375 LogLevel.WARN.log(delegate, msg, throwable); 376 } 377 378 /** 379 * Log a message at the warn level. 380 * 381 * @param throwable to be logged 382 * @param template to be used for formatting, see class-documentation for details on formatting 383 * @param parameter to be used for replacing the placeholder 384 * 385 */ 386 public void warn(Throwable throwable, String template, Object... parameter) { 387 LogLevel.WARN.log(delegate, throwable, template, parameter); 388 } 389 390 /** 391 * Log a message at the warn level. 392 * 393 * @param template to be used for formatting, see class-documentation for details on formatting 394 * @param parameter to be used for replacing the placeholder 395 * 396 */ 397 public void warn(String template, Object... parameter) { 398 LogLevel.WARN.log(delegate, template, parameter); 399 } 400 401 /** 402 * Is the logger instance enabled for the error level? 403 * 404 * @return {@code true} if this CuiLogger is enabled for the error level, 405 * false otherwise. 406 * 407 */ 408 public boolean isErrorEnabled() { 409 return LogLevel.ERROR.isEnabled(delegate); 410 } 411 412 /** 413 * Log a message at the error level. 414 * 415 * @param msg the message string to be logged 416 */ 417 public void error(String msg) { 418 LogLevel.ERROR.handleActualLog(delegate, msg, null); 419 } 420 421 /** 422 * Log a message at the error level. 423 * 424 * @param msg the message string to be logged 425 * @param throwable to be logged 426 * 427 */ 428 public void error(String msg, Throwable throwable) { 429 LogLevel.ERROR.handleActualLog(delegate, msg, throwable); 430 } 431 432 /** 433 * Log a message at the error level. 434 * 435 * @param msg the message string to be logged 436 * 437 */ 438 public void error(Supplier<String> msg) { 439 LogLevel.ERROR.log(delegate, msg, null); 440 } 441 442 /** 443 * Log a message at the error level. 444 * 445 * @param throwable to be logged 446 * @param msg the message string to be logged 447 * 448 */ 449 public void error(Throwable throwable, Supplier<String> msg) { 450 LogLevel.ERROR.log(delegate, msg, throwable); 451 } 452 453 /** 454 * Log a message at the error level. 455 * 456 * @param throwable to be logged 457 * @param template to be used for formatting, see class-documentation for details on formatting 458 * @param parameter to be used for replacing the placeholder 459 * 460 */ 461 public void error(Throwable throwable, String template, Object... parameter) { 462 LogLevel.ERROR.log(delegate, throwable, template, parameter); 463 } 464 465 /** 466 * Log a message at the error level. 467 * 468 * @param template to be used for formatting, see class-documentation for details on formatting 469 * @param parameter to be used for replacing the placeholder 470 * 471 */ 472 public void error(String template, Object... parameter) { 473 LogLevel.ERROR.log(delegate, template, parameter); 474 } 475 476 Logger getWrapped() { 477 return delegate; 478 } 479 480 /** 481 * @return the name / class of the underlying logger 482 */ 483 public String getName() { 484 return delegate.getName(); 485 } 486 487 /** 488 * @return CUI log level derived from JUL log level. 489 * E.g. FINEST(300) matches TRACE(400), CONFIG(700) matches DEBUG(500), ALL matches 490 * TRACE. 491 */ 492 public LogLevel getLogLevel() { 493 return LogLevel.from(delegate.getLevel()); 494 } 495 496}