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