2012-12-11 23 views
6

Ho una classe di logger specializzata che utilizza la classe java.util.logging.Logger. Voglio essere in grado di utilizzare questo registratore nel gancio di arresto di un'altra classe. Tuttavia, sembra non accedere allo spegnimento. Da quello che ho letto, potrebbe esserci già un hook di spegnimento attivato per il logger stesso che sta causando il problema.Java: come far funzionare il logger nel gancio di arresto?

Come posso farlo funzionare? Idealmente, mi piacerebbe che fosse visto nel file di log che ho effettivamente eseguito il hook di shutdown quando il processo è terminato.

+0

Non sono sicuro che questo sia vero o meno ma non si ha alcun controllo sull'ordine in cui si verificano gli hook di arresto. –

+1

È vero, corrono [simultaneamente] (http://docs.oracle.com/javase/1.5.0/docs/guide/lang/hook-design.html) –

risposta

8

Sempre guardando la sorgente, la soluzione sembra essere quello di definire una proprietà sistema java.util.logging.manager che è una sottoclasse di LogManager che sostituisce il metodo reset(); modo i registratori continuano a lavorare alla chiusura.

import java.util.logging.LogManager; 
import java.util.logging.Logger; 

public class Main { 
    static { 
     // must be called before any Logger method is used. 
     System.setProperty("java.util.logging.manager", MyLogManager.class.getName()); 
    } 

    public static class MyLogManager extends LogManager { 
     static MyLogManager instance; 
     public MyLogManager() { instance = this; } 
     @Override public void reset() { /* don't reset yet. */ } 
     private void reset0() { super.reset(); } 
     public static void resetFinally() { instance.reset0(); } 
    } 

    public static void main(String... args) { 
     Logger logger1 = Logger.getLogger("Main1"); 
     logger1.info("Before shutdown"); 
     Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        Logger logger2 = Logger.getLogger("Main2"); 
        logger2.info("Shutting down 2"); 

       } finally { 
        MyLogManager.resetFinally(); 
       } 
      } 
     })); 
    } 
} 

stampe

Dec 11, 2012 5:56:55 PM Main main 
INFO: Before shutdown 
Dec 11, 2012 5:56:55 PM Main$1 run 
INFO: Shutting down 2 

Da questo codice per LogManager, si può vedere per vedere c'è un gancio di arresto che smonta i gestori e li chiude. Logger funziona solo in spegnimento se non è stato utilizzato prima, quindi questo codice non viene eseguito.

// This private class is used as a shutdown hook. 
// It does a "reset" to close all open handlers. 
private class Cleaner extends Thread { 

    private Cleaner() { 
     /* Set context class loader to null in order to avoid 
     * keeping a strong reference to an application classloader. 
     */ 
     this.setContextClassLoader(null); 
    } 

    public void run() { 
     // This is to ensure the LogManager.<clinit> is completed 
     // before synchronized block. Otherwise deadlocks are possible. 
     LogManager mgr = manager; 

     // If the global handlers haven't been initialized yet, we 
     // don't want to initialize them just so we can close them! 
     synchronized (LogManager.this) { 
      // Note that death is imminent. 
      deathImminent = true; 
      initializedGlobalHandlers = true; 
     } 

     // Do a reset to close all active handlers. 
     reset(); 
    } 
} 


/** 
* Protected constructor. This is protected so that container applications 
* (such as J2EE containers) can subclass the object. It is non-public as 
* it is intended that there only be one LogManager object, whose value is 
* retrieved by calling Logmanager.getLogManager. 
*/ 
protected LogManager() { 
    // Add a shutdown hook to close the global handlers. 
    try { 
     Runtime.getRuntime().addShutdownHook(new Cleaner()); 
    } catch (IllegalStateException e) { 
     // If the VM is already shutting down, 
     // We do not need to register shutdownHook. 
    } 
} 

Dal mio test

Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { 
    @Override 
    public void run() { 
     try { 
      Logger logger2 = Logger.getLogger("Main2"); 
      logger2.info("Shutting down 2"); 
     } catch (Throwable t) { 
      t.printStackTrace(); 
     } 
    } 
})); 

stampe

Dec 11, 2012 5:40:15 PM Main$1 run 
INFO: Shutting down 2 

ma se si aggiunge

Logger logger1 = Logger.getLogger("Main1"); 

di fuori di questo blocco si ottiene nulla.

+1

Anche usando 'Logger.getLogger (nome) Non vedo ancora stampato nulla sul mio log. Tuttavia, impostando la proprietà System e copiando il codice MyLogManager, sono riuscito a farlo funzionare.Bello grazie! – Marianna

1

Il gancio di arresto ha qualche vantaggio?

È meglio, aggiungere l'output del registro nell'ultima riga principale: Il blocco finally sarà eseguito in tutti i casi, eccetto quando poi saranno non eseguite il gancio di arresto si blocca VM ma, anche.

static void main(String[] argv) { 

    try { 
    startApp(); 
    } finally { 
    LOGGER.info("shudown"); 
    } 
} 
+0

Il mio processo è uno che è vivo tutto il giorno - seduto e in attesa che qualcosa accada. Non è una cosa fatta di tipo in cui posso semplicemente mettere quello che mi serve alla fine del codice. Credo che un hook di shutdown sia la soluzione giusta – Marianna

+1

Quindi sembra che tu non sappia dove si trova la tua fine del codice? Dovresti saperlo e scoprirlo. Questo non ha nulla a che fare con un solo colpo! Le nostre sw vengono eseguite per settimane senza arresto, ma sappiamo dove si trova la fine. Forse è un po 'difficile, usando la primavera o un'altra struttura. Ma dovresti sapere di ripulire, perché spesso è necessaria una chiusura ordinata! Il motivo per cui LOGGING ha bisogno di un gestore di shutdown è che è un lib e non può knwo la "fine del codice" – AlexWien

+0

Il processo non si chiude da solo, quindi in modo simile non c'è una fine logica. – Marianna

Problemi correlati