[ 
https://issues.apache.org/jira/browse/LOG4J2-658?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14105017#comment-14105017
 ] 

Matt Sicker commented on LOG4J2-658:
------------------------------------

Just to spice things up, apparently the version of the JDK I'm using 
(1.8.0_05-b13) has YET ANOTHER different signature for Shutdown.add. Thus, to 
address this, I've implemented this using more generic parameter injection that 
makes certain assumptions about the various types and what parameter they're 
supposed to be. I also have this working with a predictable shutdown hook order 
thanks to using an ArrayList instead of a Set of some sort.

To accomplish this, I've introduced a {{ShutdownRegistrationStrategy}} 
interface along with two implementations: a default one that just uses 
{{Runtime.getRuntime().addShutdownHook()}}, and another one for OpenJDK that 
attempts to register shutdown hooks using the very last possible system 
shutdown hook slot. Since this is still a work in progress, here's a preview of 
how I abused reflection (once again!) to dig deep into OpenJDK:

{code}
public class OpenJdkShutdownRegistrationStrategy implements 
ShutdownRegistrationStrategy {

    private static final Collection<Thread> HOOKS = new ArrayList<Thread>();
    private static final Object LOCK = new Object();

    static {
        try {
            final Class<?> shutdown = 
Loader.loadSystemClass("java.lang.Shutdown");
            final int hookIndex = calculateHookIndex(shutdown);
            registerMainShutdownHook(shutdown, hookIndex);
        } catch (final Exception e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    // this method is only relevant for JDK7+ where the system shutdown hooks 
field is a fixed-size array
    private static int calculateHookIndex(final Class<?> shutdown) {
        try {
            final Field maxSystemHooks = 
shutdown.getDeclaredField("MAX_SYSTEM_HOOKS");
            maxSystemHooks.setAccessible(true);
            final int maxHooks = maxSystemHooks.getInt(null);
            return maxHooks > 0 ? maxHooks - 1 : 0;
        } catch (NoSuchFieldException e) {
            return 0;
        } catch (IllegalAccessException e) {
            return 0;
        }
    }

    private static void registerMainShutdownHook(final Class<?> shutdown, final 
int hookIndex)
        throws NoSuchMethodException, InvocationTargetException, 
IllegalAccessException {
        final Method add = getAddMethod(shutdown);
        final Class<?>[] paramTypes = add.getParameterTypes();
        final Object[] params = new Object[paramTypes.length];
        for (int i = 0; i < paramTypes.length; i++) {
            final Class<?> type = paramTypes[i];
            if (type.equals(int.class)) {
                params[i] = hookIndex;
            } else if (type.equals(boolean.class)) {
                params[i] = false;
            } else if (type.equals(Runnable.class)) {
                params[i] = new MainShutdownHook();
            } else {
                params[i] = type.cast(null);
            }
        }
        add.invoke(null, params);
    }

    private static Method getAddMethod(final Class<?> shutdown) {
        final Method[] methods = shutdown.getDeclaredMethods();
        for (final Method method : methods) {
            if (method.getName().equals("add")) {
                method.setAccessible(true);
                return method;
            }
        }
        throw new NoSuchMethodError("No Shutdown.add() method could be found!");
    }

    @Override
    public void registerShutdownHook(final Thread hook) {
        synchronized (LOCK) {
            HOOKS.add(hook);
        }
    }

    @Override
    public void unregisterShutdownHook(final Thread hook) {
        synchronized (LOCK) {
            HOOKS.remove(hook);
        }
    }

    private static class MainShutdownHook implements Runnable {
        @Override
        public void run() {
            synchronized (LOCK) {
                for (final Thread hook : HOOKS) {
                    try {
                        hook.run();
                    } catch (final Throwable t) {
                        if (t instanceof ThreadDeath) {
                            throw (ThreadDeath) t;
                        }
                    }
                }
            }
        }
    }
}
{code}

> shutdown hook called too early
> ------------------------------
>
>                 Key: LOG4J2-658
>                 URL: https://issues.apache.org/jira/browse/LOG4J2-658
>             Project: Log4j 2
>          Issue Type: Bug
>    Affects Versions: 2.0-rc1, 2.0-rc2, 2.0.2
>            Reporter: Romain Manni-Bucau
>
> Hi
> this issue follow few mail exchanges from the commons list. Here the 
> interesting part for log4j2:
> {quote}
> Here what I do (we can move it to another thread since that's 100% log4j2 
> related): unzip apache-tomee-1.7.0-SNAPSHOT-webprofile.zip && cd 
> apache-tomee-webprofile-1.7.0-SNAPSHOT/ && rm conf/logging.properties  && 
> echo 'openejb.log.factory=log4j'>conf/system.properties && cp ~/log4j2.xml 
> conf/log4j2.xml && cp 
> ~/.m2/repository/org/apache/logging/log4j/log4j-api/2.0-rc2-SNAPSHOT/log4j-api-2.0-rc2-SNAPSHOT.jar
>  lib/ && cp 
> ~/.m2/repository/org/apache/logging/log4j/log4j-core/2.0-rc2-SNAPSHOT/log4j-core-2.0-rc2-SNAPSHOT.jar
>  lib/ && cp 
> ~/.m2/repository/org/apache/logging/log4j/log4j-1.2-api/2.0-rc2-SNAPSHOT/log4j-1.2-api-2.0-rc2-SNAPSHOT.jar
>  lib/ && ./bin/catalina.sh
> it makes server starting with log4j2 logs, if you ctrl+c logs are not 
> printed. Sure it is cause context is closed too early and then loggers have 
> NullConfiguration. (If I debug in java.lang.ApplicationShutdownHooks#runHooks 
> to wait all hooks exec it works)
> {quote}
> Basically the issue is that when shutting down with ctrl+C some logs are 
> swallowed.



--
This message was sent by Atlassian JIRA
(v6.2#6252)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to