I was reading the new features of Log4j2 and there's a feature that enables
"Java 8 lambda support for lazy logging"
And it gives two examples
The first one is the bad practice
// pre-Java 8 style optimization: explicitly check the log level
// to make sure the expensiveOperation() method is only called if necessary
if (logger.isTraceEnabled()) {
logger.trace("Some long-running operation returned {}", expensiveOperation());
}
And the second one is the good practice
// Java-8 style optimization: no need to explicitly check the log level:
// the lambda expression is not evaluated if the TRACE level is not enabled
logger.trace("Some long-running operation returned {}", () -> expensiveOperation());
Where is being made the checking if the requested log level is enabled ?
"logger.isTraceEnabled()" ?
Where is being made the checking if the requested log level is enabled ?
Inside the logger.trace() method.
The trick here however is in the way you pass the argument. Pre-java8 style computed the value at the time of calling logger.trace.
logger.trace(..., expensiveOperation());
Java 8 style uses a Supplier
logger.trace( ..., () -> expensiveOperation());
So the expensiveOperation() is called only when requested - inside the trace method.
Have a look at implementation of java.util.logging.Logger.log():
public void log(Level level, Supplier<String> msgSupplier) {
if (!isLoggable(level)) {
return;
}
LogRecord lr = new LogRecord(level, msgSupplier.get()); // <-- here is the expensive computation
doLog(lr);
}
The trace method (or any other logging method for that sake) already checks logging level internally. Checking it in the caller too is an optimization to avoid calculating expensiveOperation(). With Java 8's new syntax, we don't pass the calculated value of expensiveOperation(), but a lambda that invokes it only if needed.
Note that although log4j didn't implement it, you could, in theory, have the same behavior without the fancy Java 8 syntax by defining an interface for a value provider, and have the logging method call it:
// Interface definition
public interface ValueProvider {
String getValue();
}
// Calling it from the main code with an anonymous implementation:
logger.trace("Some long-running operation returned {}",
new ValueProvider() {
public String getValue() {
return expensiveOperation();
}
});
Related
Is there a way to detect usages of java method reference (double colon) operator inside the code?
I need to discover all instance/static method references used in a given class in order to be able to detect some errors (must verify that the target method has a particular annotation - #Good in the below example) during build time. As by convention a method reference should be used only to some of the methods when it is passed to a constructor of some helper class (Info in the below example).
class X {
Info init() {
return new Info(X::beta); // good code: target method has #Good annotation
return new Info(X::alpha); // bad code: target method has no #Good annotation
}
void alpha() {
}
#Good
void beta() {
}
}
The intention is to be able to click on the method reference as this makes it easy to follow as otherwise if just passing Method instance or just method name it would lack this ability.
(The example is not very good but I'm now allowed to share more details, sorry about that!)
I can see IntelliJ IDEA "knows" about them - when you ctrl+click on them it navigates to the target method so there should be some form of a static analysis used there.
I'm already using ObjectWeb ASM to detect invocations to certain methods but it seems it lacks the ability to detect method references (::)
EDIT:
Just a note that you can also pass new Info(x -> x.alpha()) as #Thomas below mentioned in the comments but this would not pass our review process but I guess the additional ability to detect it would not hurt.
EDIT2: What exactly are you trying to achieve with these checks? What makes beta worthy of receiving the annotation?
Answer:
When the init() method is called we obtain the Info instance and from it obtain the lambda which must be a method reference. Then we use javassist ProxyFactory and create a sub-class of class X then instantiate it and intercept all its methods via setting a method handler. So now it is safe to execute the lambda without allowing it to make any side effects - the method body is skipped and the only thing we do is to capture which is the X method that the lambda actually is calling - in the example this will lead to a java.lang.Method instance pointing to X.beta or X.alpha method. Then we can check if it has the #Good annotation and proceed accordingly - which is to call the lambda without any proxying, but that call might happen later, like a millisecond later or an hour later. If there is no #Good annotation we cannot proceed - it is a bug.
So the problem is that this will happen at runtime later and there might be a bug not caught early enough and that is the reason I would like to inspect the X class at build time and catch all the bugs :)
This is a bit of a shot in the dark, as I'm neither very proficient with ASM nor sure if this approach addresses your problem. Having said that, I found that, in a similar setting, asm.MethodVisitor calls MethodVisitor.visitInvokeDynamicInsn(...) for (some? all?) method references.
E.g., if I compile this variant of your class X along with an Info:
class Info {
public Info(Runnable alpha) {}
}
class X {
Info init() { return new Info(this::alpha); }
void alpha() {}
}
... and I then feed the resulting X.class into a mini ClassVisitor + printing MethodVisitor (Groovy for brevity):
class MyMethodVisitor extends MethodVisitor {
MyMethodVisitor(MethodVisitor parent) { super(Opcodes.ASM8, parent) }
#Override
void visitInvokeDynamicInsn(String name, String descriptor, Handle bootstrapMethodHandle, Object... bootstrapMethodArguments) {
println "visitInvokeDynamicInsn($name, $descriptor, $bootstrapMethodHandle, $bootstrapMethodArguments)"
super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments)
}
}
class MyClassVisitor extends ClassVisitor {
MyClassVisitor() { super(Opcodes.ASM8) }
#Override
MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
println "Starting method '$name'"
new MyMethodVisitor(super.visitMethod(access, name, descriptor, signature, exceptions))
}
}
def clr = new ClassReader(new File("./X.class").bytes)
clr.accept(new MyClassVisitor(), ClassReader.SKIP_FRAMES)
Then the method visitor prints, amongst other details, a call to visitInvokeDynamicInsn from within the method visitation of X::init with the desired X::alpha among the arguments (the xyz being my local package):
Visiting method '<init>'
Visiting method 'init'
visitInvokeDynamicInsn(run, (xyz/X;)Ljava/lang/Runnable;,
java/lang/invoke/LambdaMetafactory.metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; (6),
[()V, xyz/X.alpha()V (5), ()V])
Visiting method 'alpha'
So it would seem possible to peel the method out of those arguments. I am not sure if this reliable (e.g., whether this bytecode is guaranteed by specification, or whether it can depend on compilation/optimization details).
This question already has answers here:
Lazy evaluation for logging in Java 8
(6 answers)
Closed 2 years ago.
I have a debug log statement in my code to which I am passing a result of costly method call.
log.debug("Data - {}", obj.costlyMethodCall());
Now, even if debug logging is disabled, obj.costlyMethodCall() will always be evaluated to be passed as method argument.
One way to mitigate this is to have a explicit check if debug logging is enabled
if (log.isDebugEnabled()) {
log.debug("Data - {}", obj.costlyMethodCall());
}
But this reduces code readability.
Is there any better way to make invocation of obj.costlyMethodCall() lazy or conditional here?
Usually this is solved by having a method accepting something similar to a Supplier instead of a concrete Object so that you can pass in something like
log.debug("Data - {}", () -> obj.costlyMethodCall());
where log.debug is something like
public void debug(String message, Supplier<Object> supplier) {
Object value = supplier.get(); // costlyMethodCall is only called here
// ...
}
If you are already extensively bought into a logging framework, defining your own methods, as suggested by Smutje, may not be a practical option.
Instead, define a static method something like:
static <T> Supplier<T> lazy(Supplier<? extends T> delegate) {
return new Supplier<T>() {
#Override public T get() { return delegate.get(); }
#Override public String toString() { return Objects.toString(get()); }
};
}
Then provide this as an argument to your call:
log.debug("Data - {}", lazy(() -> obj.costlyMethodCall()));
If you don't provide a Supplier which overrides toString(), the logging library can't (necessarily) know that it needs to evaluate the supplier to build the toString(). Ideone example.
Yes, you could use lamdba expression to delay that. New versions of logger use this approach, like log4j 2.4. You don't need to provide new methods, just use newer logging API if you can.
You can do the following:
log.debug("Data - {}", () -> obj.costlyMethodCall());
They added this in recent logger where you need to delay String usage, without polluting your code with the if(log.isDebugEnabled())...
You pass a Supplier that will return the Strings, only once called.
You can check this link if you need to: https://garygregory.wordpress.com/2015/09/16/a-gentle-introduction-to-the-log4j-api-and-lambda-basics/
I'm trying to write a AsyncLoadingCache that accepts a CacheWriter and I'm getting an IllegalStateException.
Here's my code:
CacheWriter<String, UUID> cacheWriter = new CacheWriter<String, UUID>() {
#Override
public void write(String key, UUID value) {
}
#Override
public void delete(String key, UUID value, RemovalCause cause) {
}
};
AsyncLoadingCache<String, UUID> asyncCache = Caffeine.newBuilder()
.expireAfterWrite(60, TimeUnit.SECONDS)
.writer(cacheWriter)
.maximumSize(100L)
.buildAsync((String s) -> { /* <== line 41, exception occurs here */
return UUID.randomUUID();
});
And I'm getting this trace
Exception in thread "main" java.lang.IllegalStateException
at com.github.benmanes.caffeine.cache.Caffeine.requireState(Caffeine.java:174)
at com.github.benmanes.caffeine.cache.Caffeine.buildAsync(Caffeine.java:854)
at com.mycompany.caffeinetest.Main.main(Main.java:41)
If I'll change the cache to a LoadingCache or remove .writer(cacheWriter) the code will run properly. What am I doing wrong? it seems I'm providing the right types to both objects.
Unfortunately these two features are incompatible. While the documentation states this, I have updated the exception to communicate this better. In Caffeine.writer it states,
This feature cannot be used in conjunction with {#link #weakKeys()} or {#link #buildAsync}.
A CacheWriter is a synchronous interceptor for a mutation of an entry. For example, it might be used to evict into a disk cache as a secondary layer, whereas a RemovalListener is asynchronous and using it would leave a race where the entry is not present in either caches. The mechanism is to use ConcurrentHashMap's compute methods to perform the write or removal, and call into the CacheWriter within that block.
In AsyncLoadingCache, the value materializes later when the CompletableFuture is successful, or is automatically removed if null or an error. When the entry is modified within the hash table, this future may be in-flight. This would mean that the CacheWriter would often be called without the materialized value and likely cannot do very intelligent things.
From an API perspective, unfortunately telescoping builders (which use the type system to disallow incompatible chains) become more confusing than using runtime exceptions. Sorry for not making the error clear, which should now be fixed.
I am kind of new to Observers, and I am still trying to figure them out. I have the following piece of code:
observableKafka.getRealTimeEvents()
.filter(this::isTrackedAccount)
.filter(e -> LedgerMapper.isDepositOrClosedTrade((Transaction) e.getPayload()))
.map(ledgerMapper::mapLedgerTransaction)
.map(offerCache::addTransaction)
.filter(offer -> offer != null) // Offer may have been removed from cache since last check
.filter(Offer::isReady)
.doOnError(throwable -> {
LOG.info("Exception thrown on realtime events");
})
.forEach(awardChecker::awardFailOrIgnore);
getRealTimeEvents() returns an Observable<Event>.
Does the location of .doOnError matters? Also, what is the effect of adding more than one call to it in this piece of code? I have realised I can do it and all of them get invoked, but I am not sure of what could be its purpose.
Yes, it does. doOnError acts when an error is passing through the stream at that specific point, so if the operator(s) before doOnError throw(s), your action will be called. However, if you place the doOnError further up, it may or may not be called depending on what downstream operators are in the chain.
Given
Observer<Object> ignore = new Observer<Object>() {
#Override public void onCompleted() {
}
#Override public void onError(Throwable e) {
}
#Override public void onNext(Object t) {
}
};
For example, the following code will always call doOnError:
Observable.<Object>error(new Exception()).doOnError(e -> log(e)).subscribe(ignore);
However, this code won't:
Observable.just(1).doOnError(e -> log(e))
.flatMap(v -> Observable.<Integer>error(new Exception())).subscribe(ignore);
Most operators will bounce back exceptions that originate downstream.
Adding multipe doOnError is viable if you transform an exception via onErrorResumeNext or onExceptionResumeNext:
Observable.<Object>error(new RuntimeException())
.doOnError(e -> log(e))
.onErrorResumeNext(Observable.<Object>error(new IllegalStateException()))
.doOnError(e -> log(e)).subscribe(ignore);
otherwise, you'd log the same exception at multiple locations of the chain.
the doOn??? methods are there for side-effects, processing that doesn't really is your core business value let's say. Logging is a perfectly fine use for that.
That said, sometimes you want to do something more meaningful with an error, like retrying, or displaying a message to a user, etc... For these cases, the "rx" way would be to process the error in a subscribe call.
doOnError (and the other doOn methods) wraps the original Observable into a new one and adds behavior to it (around its onError method, obviously). That's why you can call it many times. Also one benefit of being able to call it anywhere in the chain is that you can access errors that would otherwise be hidden from the consumer of the stream (the Subscriber), for instance because there's a retry down in the chain...
What is the difference between Futures.addCallBack() and Futures.transform() in Google Guava Concurrency.
As per the documentation:
Futures.addCallBack():
addCallback(ListenableFuture<V> future, FutureCallback<? super V> callback) Registers separate success and failure callbacks to be run when the Future's computation is complete or, if the computation is already complete, immediately.
Futures.transform():
transform(ListenableFuture<I> input, AsyncFunction<? super I,? extends O> function) Returns a new ListenableFuture whose result is asynchronously derived from the result of the given Future.
As per my understanding addCallback() will register success or failure callback when asynchronous processing is completed. In this case we can handle the out put based on success or failure conditions (example: logging, flow control..etc). and transform() only return the Asynchronous object back. So difference is only Callback?.
whether my understanding is correct?
Which is the best one to use with asynchronous processing?
If I need to call multiple asynchronous methods in a sequence, is there any best practice for that?
What is the difference between using AsyncFunction and Function in transform(ListenableFuture<I> input, Function/AsyncFunction <? super I,? extends O> function)? (AsyncFunction only used for nested Futures.transform()?)
What I tried:
I try to write code like below, whether this is a good practice or not.
public ListenableFuture<MyObject> doSomething() {
logger.info( "Entered in dosomething() Method." );
ListeningExecutorService executor =
MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(50));
ListenableFuture<MyObject> myAsyncObject =
calculator.calculateSomething(input);
//internally calculator.calculateSomething() have multiple asynchronous
// calls and I am using Futures.transform(), without callback.
Futures.addCallback(myAsyncObject, new FutureCallback<MyObject>() {
public void onSuccess(MyObject result) {
logger.info( "Calculation Completed successfully." );
//TODO: check for success and log it.
}
public void onFailure(Throwable thrown) {
logErrorDetails(thrown);
}
}, executor);
executor.shutdown();
return myAsyncObject;
}
Well you didn't write the full method signature in your question
addCallback returns nothing
transform returns a future that holds result of the function (if the input succeeded) or the original input's failure (if not). This allows to chain transformations, with a fluent syntax.
I've not used AsyncFunction, but I understand they add one level of asynchronicity, ie the result of the Future is another Future.