micrometer-metrics / micrometer

An application observability facade for the most popular observability tools. Think SLF4J, but for observability.
https://micrometer.io
Apache License 2.0
4.45k stars 980 forks source link

Native image config for netty in statsd module is not relocated during shading #3212

Open edudar opened 2 years ago

edudar commented 2 years ago

statsd module uses a shaded netty that makes its packages io.micrometer.shaded.io.netty, and none of the standard native hints apply.

So far, I had to add (using spring-native) the following to get the app to start at least:

@NativeHint( // Micrometer
        types = @TypeHint(
                access = {TypeAccess.DECLARED_CLASSES, TypeAccess.DECLARED_CONSTRUCTORS, TypeAccess.DECLARED_METHODS},
                typeNames = "io.micrometer.shaded.io.netty.buffer.AbstractByteBufAllocator"
        )
)
@NativeHint(
        types = {
                @TypeHint(
                        typeNames = "io.micrometer.shaded.io.netty.util.internal.shaded.org.jctools.queues.BaseMpscLinkedArrayQueueColdProducerFields",
                        fields = @FieldHint(name = "producerLimit", allowUnsafeAccess = true)
                ),
                @TypeHint(
                        typeNames = "io.micrometer.shaded.io.netty.util.internal.shaded.org.jctools.queues.BaseMpscLinkedArrayQueueConsumerFields",
                        fields = @FieldHint(name = "consumerIndex", allowUnsafeAccess = true)
                ),
                @TypeHint(
                        typeNames = "io.micrometer.shaded.io.netty.util.internal.shaded.org.jctools.queues.BaseMpscLinkedArrayQueueProducerFields",
                        fields = @FieldHint(name = "producerIndex", allowUnsafeAccess = true)
                ),
                @TypeHint(
                        typeNames = "io.micrometer.shaded.io.netty.util.ReferenceCountUtil",
                        methods = @MethodHint(name = "touch", parameterTypes = {Object.class})
                )
        }
)

But I might have to add more as I keep testing it.

shakuzen commented 2 years ago

I suspect we could add some build configuration to rename things in the netty native-image.properties that are in the published micrometer-registry-statsd JAR. I tried a few things with the shadow plugin but I haven't been successful so far. I don't know if that would be sufficient or not, but it seems like a good starting point. Pull request welcome.

shakuzen commented 2 years ago

I'm told the latest native-image config for netty 4 is located at https://github.com/oracle/graalvm-reachability-metadata/tree/master/metadata/io.netty. I'm still not sure the most maintainable way to use that and ensure it is up-to-date given our shading (and repackaging) of netty. We essentially need a copy of that config using our io.micrometer.shaded.io.netty package. Though we may only need a small subset in reality, given the parts of netty that we use (via reactor-netty) in the statsd module.

eye-dee commented 1 year ago

Hello

I think I have the similar issue. I try to use spring boot 3 native support.

And get the following issue:

Caused by: java.lang.IllegalArgumentException: Can't find '[toLeakAwareBuffer]' in io.micrometer.shaded.io.netty.buffer.AbstractByteBufAllocator
        at io.micrometer.shaded.io.netty.util.ResourceLeakDetector.addExclusions(ResourceLeakDetector.java:596) ~[na:na]
        at io.micrometer.shaded.io.netty.buffer.AbstractByteBufAllocator.<clinit>(AbstractByteBufAllocator.java:37) ~[service:1.10.2]  

not sure how to fix it with RuntimeHintsRegistrar

AlexeiZenin commented 1 year ago

+1, I am on SB 3.0 and can't see an easy path from these NativeHint annotations in OP to the new method of adding the "hints" as @eye-dee mentions

edudar commented 9 months ago

Just for the record, it's fairly similar to annotations from spring-native. This is the registrar class I ended up creating to support SB3, statsd, and native image:

public class MicrometerHints implements RuntimeHintsRegistrar {

    public static final String NETTY_PKG = "io.micrometer.shaded.io.netty.";
    public static final String JC_TOOLS_PKG = "util.internal.shaded.org.jctools.";

    @Override
    public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
        hints.reflection()
                .registerType(AbstractByteBufAllocator.class,
                        builtWith(DECLARED_CLASSES, INVOKE_PUBLIC_CONSTRUCTORS, INVOKE_DECLARED_METHODS))
                .registerType(ReferenceCountUtil.class,
                        hint -> hint.withMethod("touch", List.of(TypeReference.of(Object.class)), INVOKE))
                .registerTypeIfPresent(classLoader,
                        NETTY_PKG + JC_TOOLS_PKG + "queues.BaseMpscLinkedArrayQueueColdProducerFields",
                        hint -> hint.withField("producerLimit"))
                .registerTypeIfPresent(classLoader,
                        NETTY_PKG + JC_TOOLS_PKG + "queues.BaseMpscLinkedArrayQueueConsumerFields",
                        hint -> hint.withField("consumerIndex"))
                .registerTypeIfPresent(classLoader,
                        NETTY_PKG + JC_TOOLS_PKG + "queues.BaseMpscLinkedArrayQueueProducerFields",
                        hint -> hint.withField("producerIndex"))
                .registerTypeIfPresent(classLoader,
                        NETTY_PKG + JC_TOOLS_PKG + "queues.MpscArrayQueueConsumerIndexField",
                        hint -> hint.withField("consumerIndex"))
                .registerTypeIfPresent(classLoader,
                        NETTY_PKG + JC_TOOLS_PKG + "queues.MpscArrayQueueProducerIndexField",
                        hint -> hint.withField("producerIndex"))
                .registerTypeIfPresent(classLoader,
                        NETTY_PKG + JC_TOOLS_PKG + "queues.MpscArrayQueueProducerLimitField",
                        hint -> hint.withField("producerLimit"));
    }
}
marcingrzejszczak commented 8 months ago

@edudar where is this class coming from? Do you have a reproducer for this issue?

edudar commented 8 months ago

Which class? MicrometerRuntimeHints? That’s the result of trial and error trying to compile and run a service using micrometer with statsd in a native image. I don’t have a minimal reproducer, but this is a common problem with aot/native and shaded packages as classes move and are missing reachability metadata, unless one provides it.