New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pluggable resource leak detector #5392
Conversation
static final ResourceLeakDetector<ByteBuf> leakDetector = loadResourceLeakDetector(); | ||
|
||
private static ResourceLeakDetector<ByteBuf> loadResourceLeakDetector() { | ||
String customLeakDetector = SystemPropertyUtil.get("io.netty.customResourceLeakDetector"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use PrivilegedAction
to try loading this.
@artgon This looks awesome! Just a few comments. Please also sign the ICLA: And adjust the commit message to match our template: |
@artgon Also I wonder if it would be good to add something like: public abstract class ResourceLeakDetectorFactory {
private static volatile ResourceLeakDetectorFactory INSTANCE = new ResourceLeakDetectorFactory() {....};
protected ResourceLeakDetectorFactory() { .... }
public static ResourceLeakDetectorFactory instance() {
return INSTANCE;
}
public static void setResourceLeakDetectorFactory(ResourceLeakDetectorFactory factory) {
INSTANCE = factory;
}
public ResourceLeakDetector(Class<?> clazz) {
....
}
} Then add all the static loading stuff in this implementation and also provide a setter to do it program and use the factory to obtain the instances. This way the code of loading is in one place and will work even if somewhere else a ResourceLeakDetector is needed. |
Great, thanks for the feedback. I've signed the agreement and I'll make the changes you suggested. Looks like I followed that commit message template on the comment instead of the commit. Do you want me to just copy it over? |
Yes please :)
|
@normanmaurer Yeah, I think that's a good idea. Let me go back to the drawing board and elaborate on this a bit. |
Cool :) Let me know if you have questions
|
Just ping me when you are ready for another review! |
logger.error("Class {} does not inherit from ResourceLeakDetector.", customLeakDetector); | ||
} | ||
} | ||
} catch (Exception e) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
catch a Throwable
instead of Exception
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
ab9cbe0
to
33a1c3d
Compare
@normanmaurer I've taken another run at it, let me know what you think. |
Let me check
|
INSTANCE = factory; | ||
} | ||
|
||
public abstract <T> ResourceLeakDetector<T> loadResourceLeakDetector(final Class<T> resource); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please rename to newResourceLeakDetector
to be more inline with the rest of netty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also javadocs please :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, yes of course. Will do :)
What about the general approach? Is that what you had in mind with the factory?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep
* | ||
* @param records - the trace of the leak | ||
*/ | ||
protected void reportTracedLeak(String records, String resourceType) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just a nit but could you swap both of these.
try { | ||
if (customLeakDetector != null) { | ||
Class<?> detectorClass = Class.forName(customLeakDetector, true, | ||
PlatformDependent.getSystemClassLoader()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can be done just one time in a static block. There is no need to load the class multiple times.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it can but it'll be slightly ugly because it will have to handle the ClassNotFoundException
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whats the problem ? Just catch Throwable
log it and always use the default impl later on. We do this in several places in netty.
@artgon just four comments. Rest looks awesome! |
} | ||
|
||
ResourceLeakDetector<T> resourceLeakDetector = new ResourceLeakDetector<T>(resource); | ||
logger.debug("Loaded default ResourceLeakDetector: {}", resourceLeakDetector); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we remove the log message for loading above please also remove this one
@artgon you rock! Will pull this in shortly. Thanks again for this awesome contribution. |
@artgon Could you also update |
Allow users of Netty to plug in their own leak detector for the purpose of instrumentation. Motivation: We are rolling out a large Netty deployment and want to be able to track the amount of leaks we're seeing in production via custom instrumentation. In order to achieve this today, I had to plug in a custom `ByteBufAllocator` into the bootstrap and have it initialize a custom `ResourceLeakDetector`. Due to these classes mostly being marked `final` or having private or static methods, a lot of the code had to be copy-pasted and it's quite ugly. Modifications: * I've added a static loader method for the `ResourceLeakDetector` in `AbstractByteBuf` that tries to instantiate the class passed in via the `-Dio.netty.customResourceLeakDetector`, otherwise falling back to the default one. * I've modified `ResourceLeakDetector` to be non-final and to have the reporting broken out in to methods that can be overridden. Result: You can instrument leaks in your application by just adding something like the following: ```java public class InstrumentedResourceLeakDetector<T> extends ResourceLeakDetector<T> { @monitor("InstanceLeakCounter") private final AtomicInteger instancesLeakCounter; @monitor("LeakCounter") private final AtomicInteger leakCounter; public InstrumentedResourceLeakDetector(Class<T> resource) { super(resource); this.instancesLeakCounter = new AtomicInteger(); this.leakCounter = new AtomicInteger(); } @OverRide protected void reportTracedLeak(String records) { super.reportTracedLeak(records); leakCounter.incrementAndGet(); } @OverRide protected void reportUntracedLeak() { super.reportUntracedLeak(); leakCounter.incrementAndGet(); } @OverRide protected void reportInstancesLeak() { super.reportInstancesLeak(); instancesLeakCounter.incrementAndGet(); } } ```
Okay, I've made the changes. |
@artgon ❤️... will pull in once the CI runs finishes |
@artgon thanks again! |
Allow users of Netty to plug in their own leak detector for the purpose of instrumentation.
Motivation:
We are rolling out a large Netty deployment and want to be able to track the amount of leaks we're seeing in production via custom instrumentation. In order to achieve this today, I had to plug in a custom
ByteBufAllocator
into the bootstrap and have it initialize a customResourceLeakDetector
. Due to these classes mostly being markedfinal
or having private or static methods, a lot of the code had to be copy-pasted and it's quite ugly.Modifications:
ResourceLeakDetector
inAbstractByteBuf
that tries to instantiate the class passed in via the-Dio.netty.customResourceLeakDetector
, otherwise falling back to the default one.ResourceLeakDetector
to be non-final and to have the reporting broken out in to methods that can be overridden.Result:
You can instrument leaks in your application by just adding something like the following: