Skip to content

Commit c6e9104

Browse files
authored
Added suppliers for loggers (Azure#20714)
Added suppliers for loggers
1 parent 8ac5a77 commit c6e9104

File tree

3 files changed

+309
-25
lines changed

3 files changed

+309
-25
lines changed

sdk/core/azure-core/src/main/java/com/azure/core/util/logging/ClientLogger.java

Lines changed: 126 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
import java.util.Arrays;
1414
import java.util.Objects;
15+
import java.util.function.Function;
16+
import java.util.function.Supplier;
1517
import java.util.regex.Pattern;
1618

1719
/**
@@ -37,6 +39,7 @@
3739
*/
3840
public class ClientLogger {
3941
private static final Pattern CRLF_PATTERN = Pattern.compile("[\r\n]");
42+
private static final String DEFAULT_MESSAGE_FORMAT = "{}";
4043
private final Logger logger;
4144

4245
/**
@@ -59,13 +62,50 @@ public ClientLogger(String className) {
5962
logger = initLogger instanceof NOPLogger ? new DefaultLogger(className) : initLogger;
6063
}
6164

65+
/**
66+
* Logs a formattable message that uses {@code {}} as the placeholder at the given {@code logLevel}.
67+
*
68+
* <p><strong>Code samples</strong></p>
69+
*
70+
* <p>Logging with a specific log level</p>
71+
* {@codesnippet com.azure.core.util.logging.clientlogger.log}
72+
*
73+
* @param logLevel Logging level for the log message.
74+
* @param message The formattable message to log.
75+
*/
76+
public void log(LogLevel logLevel, Supplier<String> message) {
77+
if (message != null) {
78+
performDeferredLogging(logLevel, false, DEFAULT_MESSAGE_FORMAT, message);
79+
}
80+
}
81+
82+
/**
83+
* Logs a formattable message that uses {@code {}} as the placeholder at {@code verbose} log level.
84+
*
85+
* <p><strong>Code samples</strong></p>
86+
*
87+
* <p>Logging with a specific log level and exception</p>
88+
* <p>
89+
* {@codesnippet com.azure.core.util.logging.clientlogger.log#throwable}
90+
*
91+
* @param logLevel Logging level for the log message.
92+
* @param message The formattable message to log.
93+
* @param throwable Throwable for the message.
94+
* {@link Throwable}.
95+
*/
96+
public void log(LogLevel logLevel, Supplier<String> message, Throwable throwable) {
97+
if (message != null) {
98+
performDeferredLogging(logLevel, true, DEFAULT_MESSAGE_FORMAT, message, throwable);
99+
}
100+
}
101+
62102
/**
63103
* Logs a message at {@code verbose} log level.
64104
*
65105
* <p><strong>Code samples</strong></p>
66106
*
67107
* <p>Logging a message at verbose log level.</p>
68-
*
108+
* <p>
69109
* {@codesnippet com.azure.core.util.logging.clientlogger.verbose}
70110
*
71111
* @param message The message to log.
@@ -82,12 +122,12 @@ public void verbose(String message) {
82122
* <p><strong>Code samples</strong></p>
83123
*
84124
* <p>Logging a message at verbose log level.</p>
85-
*
125+
* <p>
86126
* {@codesnippet com.azure.core.util.logging.clientlogger.verbose#string-object}
87127
*
88128
* @param format The formattable message to log.
89129
* @param args Arguments for the message. If an exception is being logged, the last argument should be the
90-
* {@link Throwable}.
130+
* {@link Throwable}.
91131
*/
92132
public void verbose(String format, Object... args) {
93133
if (logger.isDebugEnabled()) {
@@ -101,7 +141,7 @@ public void verbose(String format, Object... args) {
101141
* <p><strong>Code samples</strong></p>
102142
*
103143
* <p>Logging a message at verbose log level.</p>
104-
*
144+
* <p>
105145
* {@codesnippet com.azure.core.util.logging.clientlogger.info}
106146
*
107147
* @param message The message to log.
@@ -118,12 +158,12 @@ public void info(String message) {
118158
* <p><strong>Code samples</strong></p>
119159
*
120160
* <p>Logging a message at informational log level.</p>
121-
*
161+
* <p>
122162
* {@codesnippet com.azure.core.util.logging.clientlogger.info#string-object}
123163
*
124164
* @param format The formattable message to log
125165
* @param args Arguments for the message. If an exception is being logged, the last argument should be the
126-
* {@link Throwable}.
166+
* {@link Throwable}.
127167
*/
128168
public void info(String format, Object... args) {
129169
if (logger.isInfoEnabled()) {
@@ -136,8 +176,8 @@ public void info(String format, Object... args) {
136176
*
137177
* <p><strong>Code samples</strong></p>
138178
*
139-
* <p>Logging a message at verbose log level.</p>
140-
*
179+
* <p>Logging a message at warning log level.</p>
180+
* <p>
141181
* {@codesnippet com.azure.core.util.logging.clientlogger.warning}
142182
*
143183
* @param message The message to log.
@@ -154,12 +194,12 @@ public void warning(String message) {
154194
* <p><strong>Code samples</strong></p>
155195
*
156196
* <p>Logging a message at warning log level.</p>
157-
*
197+
* <p>
158198
* {@codesnippet com.azure.core.util.logging.clientlogger.warning#string-object}
159199
*
160200
* @param format The formattable message to log.
161201
* @param args Arguments for the message. If an exception is being logged, the last argument should be the
162-
* {@link Throwable}.
202+
* {@link Throwable}.
163203
*/
164204
public void warning(String format, Object... args) {
165205
if (logger.isWarnEnabled()) {
@@ -172,8 +212,8 @@ public void warning(String format, Object... args) {
172212
*
173213
* <p><strong>Code samples</strong></p>
174214
*
175-
* <p>Logging a message at verbose log level.</p>
176-
*
215+
* <p>Logging a message at error log level.</p>
216+
* <p>
177217
* {@codesnippet com.azure.core.util.logging.clientlogger.error}
178218
*
179219
* @param message The message to log.
@@ -190,12 +230,12 @@ public void error(String message) {
190230
* <p><strong>Code samples</strong></p>
191231
*
192232
* <p>Logging an error with stack trace.</p>
193-
*
233+
* <p>
194234
* {@codesnippet com.azure.core.util.logging.clientlogger.error#string-object}
195235
*
196236
* @param format The formattable message to log.
197237
* @param args Arguments for the message. If an exception is being logged, the last argument should be the
198-
* {@link Throwable}.
238+
* {@link Throwable}.
199239
*/
200240
public void error(String format, Object... args) {
201241
if (logger.isErrorEnabled()) {
@@ -330,30 +370,98 @@ private void performLogging(LogLevel logLevel, boolean isExceptionLogging, Strin
330370
}
331371

332372
sanitizeLogMessageInput(format);
373+
executeLogging(logLevel, format, throwableMessage, s -> s, args);
374+
}
375+
376+
/*
377+
* Performs the logging.
378+
*
379+
* @param logLevel sets the logging level
380+
* @isExceptionLogging sets exception logging
381+
* @param args Arguments for the message, if an exception is being logged last argument is the throwable.
382+
*/
383+
private void performDeferredLogging(LogLevel logLevel, boolean isExceptionLogging, String format, Object... args) {
384+
// If the logging level is less granular than verbose remove the potential throwable from the args.
385+
String throwableMessage = "";
386+
if (doesArgsHaveThrowable(args)) {
387+
// If we are logging an exception the format string is already the exception message, don't append it.
388+
if (!isExceptionLogging) {
389+
Object throwable = args[args.length - 1];
390+
391+
// This is true from before but is needed to appease SpotBugs.
392+
if (throwable instanceof Throwable) {
393+
throwableMessage = ((Throwable) throwable).getMessage();
394+
}
395+
}
396+
397+
/*
398+
* Environment is logging at a level higher than verbose, strip out the throwable as it would log its
399+
* stack trace which is only expected when logging at a verbose level.
400+
*/
401+
if (!logger.isDebugEnabled()) {
402+
args = removeThrowable(args);
403+
}
404+
}
405+
406+
sanitizeLogMessageInput(format);
407+
executeLogging(logLevel, format, throwableMessage, this::evaluateSupplierArgument, args);
408+
}
409+
410+
/*
411+
* Performs the logging.
412+
*
413+
* @param logLevel sets the logging level
414+
* @format sets exception logging
415+
* @throwableMessage the evaluated exception message which get value based on log level.
416+
* @loggingFunction sets how the logging message should be evaluated
417+
* @args Arguments for the message, if an exception is being logged last argument is the throwable.
418+
*/
419+
private void executeLogging(LogLevel logLevel, String format, String throwableMessage,
420+
Function<Object[], Object[]> loggingEvaluation, Object[] args) {
333421
switch (logLevel) {
334422
case VERBOSE:
335-
logger.debug(format, args);
423+
logger.debug(format, loggingEvaluation.apply(args));
336424
break;
337425
case INFORMATIONAL:
338-
logger.info(format, args);
426+
logger.info(format, loggingEvaluation.apply(args));
339427
break;
340428
case WARNING:
341429
if (!CoreUtils.isNullOrEmpty(throwableMessage)) {
342430
format += System.lineSeparator() + throwableMessage;
343431
}
344-
logger.warn(format, args);
432+
logger.warn(format, loggingEvaluation.apply(args));
345433
break;
346434
case ERROR:
347435
if (!CoreUtils.isNullOrEmpty(throwableMessage)) {
348436
format += System.lineSeparator() + throwableMessage;
349437
}
350-
logger.error(format, args);
438+
logger.error(format, loggingEvaluation.apply(args));
351439
break;
352440
default:
353441
// Don't do anything, this state shouldn't be possible.
354442
break;
355443
}
444+
}
445+
446+
/**
447+
* @param args The arguments passed to evaluate suppliers in args.
448+
* @return Return the argument with evaluated supplier
449+
*/
450+
451+
Object[] evaluateSupplierArgument(Object[] args) {
452+
if (isSupplierLogging(args)) {
453+
args[0] = ((Supplier<?>) args[0]).get();
454+
}
455+
return args;
456+
}
356457

458+
/**
459+
* @param args The arguments passed to determine supplier evaluation
460+
* @return Determines if it is supplier logging
461+
*/
462+
boolean isSupplierLogging(Object[] args) {
463+
return (args.length == 1 && args[0] instanceof Supplier)
464+
|| (args.length == 2 && args[0] instanceof Supplier && (args[1] instanceof Throwable || args[1] == null));
357465
}
358466

359467
/**

sdk/core/azure-core/src/samples/java/com/azure/core/util/logging/ClientLoggerJavaDocCodeSnippets.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@ public void loggingSnippets() {
3535
logger.info("A formattable message. Hello, {}", name);
3636
// END: com.azure.core.util.logging.clientlogger.info#string-object
3737

38+
// BEGIN: com.azure.core.util.logging.clientlogger.log
39+
logger.log(LogLevel.VERBOSE,
40+
() -> String.format("Param 1: %s, Param 2: %s, Param 3: %s", "param1", "param2", "param3"));
41+
// END: com.azure.core.util.logging.clientlogger.log
42+
43+
// BEGIN: com.azure.core.util.logging.clientlogger.log#throwable
44+
Throwable illegalArgumentException = new IllegalArgumentException("An invalid argument was encountered.");
45+
logger.log(LogLevel.VERBOSE,
46+
() -> String.format("Param 1: %s, Param 2: %s, Param 3: %s", "param1", "param2", "param3"),
47+
illegalArgumentException);
48+
// END: com.azure.core.util.logging.clientlogger.log#throwable
49+
3850
// BEGIN: com.azure.core.util.logging.clientlogger.warning
3951
Throwable detailedException = new IllegalArgumentException("A exception with a detailed message");
4052
logger.warning(detailedException.getMessage());
@@ -65,6 +77,7 @@ public void loggingSnippets() {
6577

6678
/**
6779
* Implementation not provided
80+
*
6881
* @return {@code null}
6982
*/
7083
private File getFile() {
@@ -73,6 +86,7 @@ private File getFile() {
7386

7487
/**
7588
* Implementation not provided
89+
*
7690
* @return {@code null}
7791
*/
7892
private String getName() {
@@ -81,6 +95,7 @@ private String getName() {
8195

8296
/**
8397
* Implementation not provided
98+
*
8499
* @param resource A file resource
85100
* @throws IOException if upload fails
86101
*/

0 commit comments

Comments
 (0)