2017-05-05 50 views
3

我有一個應用程序創建一個套接字處理程序到我的日誌服務器(在不同的設備上)並使用它。這工作正常。如何判斷java日誌sockethandler是否仍在運行?

如果日誌服務器終止並重新啓動,應用程序不知道這一點。該應用程序應該刪除舊的套接字處理程序並添加一個新的套接字處

如何判斷java日誌sockethandler是否仍在運行?

編輯:我想出了下面的代碼,這似乎工作:

public static class MySocketHandler extends SocketHandler { 
     public MySocketHandler(String host,int port, Logger logger) throws IOException { 
      super(host,port); 
      this.logger=logger; 
      setErrorManager(new ErrorManager() { 
       @Override public synchronized void error(String msg,Exception ex,int code) { 
        super.error(msg,ex,code); 
        System.out.println("error: "+msg+", "+ex+", "+code); 
        removeHandler(); 
        failed=true; 
       } 
      }); 
     } 
     void removeHandler() { 
      logger.removeHandler(MySocketHandler.this); 
      System.out.println("removed my socket handler"); 
     } 
     final Logger logger; 
     Boolean failed=false; 
} 

回答

0

創建一個代理處理程序來包裝SocketHandler 和安裝自定義java.util.logging.ErrorManager(作爲內部類)來監聽異常和錯誤時重新連接內部處理程序。

下面是一些示例代碼爲您提高並確保您單元測試它在使用它之前:

import java.io.IOException; 
import java.io.UnsupportedEncodingException; 
import java.util.ArrayDeque; 
import java.util.logging.ErrorManager; 
import java.util.logging.Filter; 
import java.util.logging.Formatter; 
import java.util.logging.Handler; 
import java.util.logging.Level; 
import java.util.logging.LogRecord; 
import java.util.logging.SocketHandler; 

public class ReconnectingSocketHandler extends Handler { 

    private SocketHandler target; 
    private boolean active; 
    private final Watcher listener = new Watcher(); 
    private final ArrayDeque<LogRecord> pending = new ArrayDeque<>(1); 

    public ReconnectingSocketHandler() { 
     //@todo Read properties from LogManager. 
    } 

    @Override 
    public synchronized void publish(LogRecord record) { 
     if (!active) { //Prevent reentrance. 
      active = true; 
      try { 
       if (record != null && isLoggable(record)) { 
        pending.add(record); 
       } 

       //Store only the last few records only on error. 
       if (pending.size() > 1000) { 
        pending.pollFirst(); 
       } 

       //While we have retries and records. 
       for (int r = 0; r < 2 && !pending.isEmpty(); ++r) { 
        if (target == null) { 
         //@todo implement time based backoff. 
         target = new SocketHandler(); 
         target.setLevel(super.getLevel()); 
         target.setEncoding(super.getEncoding()); 
         target.setFilter(super.getFilter()); 
         target.setFormatter(super.getFormatter()); 
         target.setErrorManager(listener); 
        } 

        //Write the queue to the socket handler. 
        for (LogRecord lr; (lr = pending.poll()) != null;) { 
         target.publish(lr); 
         //On error, close and retry. 
         if (listener.last != null) { 
          pending.addFirst(lr); 
          reportError(null, listener.last, 
            ErrorManager.WRITE_FAILURE); 
          listener.last = null; 
          target.close(); 
          target = null; 
          break; 
         } 
        } 
       } 
      } catch (IOException ioe) { 
       target = null; //Try again later. 
       reportError(null, ioe, ErrorManager.WRITE_FAILURE); 
      } finally { 
       active = false; 
      } 
     } 
    } 

    @Override 
    public synchronized void flush() { 
     publish((LogRecord) null); 
     if (target != null) { 
      target.flush(); 
     } 
    } 

    @Override 
    public synchronized void close() { 
     super.setLevel(Level.OFF); 
     flush(); 
     if (target != null) { 
      target.close(); 
      target = null; 
     } 
    } 

    @Override 
    public synchronized void setLevel(Level newLevel) { 
     super.setLevel(newLevel); 
     if (target != null) { 
      target.setLevel(newLevel); 
     } 
    } 

    @Override 
    public synchronized void setFilter(Filter newFilter) { 
     super.setFilter(newFilter); 
     if (target != null) { 
      target.setFilter(newFilter); 
     } 
    } 

    @Override 
    public synchronized void setEncoding(String encoding) throws UnsupportedEncodingException { 
     super.setEncoding(encoding); 
     if (target != null) { 
      target.setEncoding(encoding); 
     } 
    } 

    @Override 
    public synchronized void setFormatter(Formatter newFormatter) { 
     super.setFormatter(newFormatter); 
     if (target != null) { 
      target.setFormatter(newFormatter); 
     } 
    } 

    private class Watcher extends ErrorManager { 

     Exception last; 

     Watcher() { 
     } 

     @Override 
     public void error(String msg, Exception ex, int code) { 
      last = ex; 
     } 
    } 
} 

此代碼將發佈到插座處理器的正常路徑。在例外情況下,它將關閉並重新創建套接字處理程序。如果失敗,此代碼會將當前記錄存儲到隊列中的最後1000條記錄中以用於延遲發佈。

刪除套接字處理程序並將其添加到記錄器樹是一項繁瑣的操作,可能會導致丟失日誌記錄或重新連接。代理處理程序將允許您正確控制重新連接的數量,並允許您重新發布可能會丟失的錯誤。

如何判斷java日誌sockethandler是否仍在運行?

您可以嘗試定期呼叫flush來檢測封閉的套接字,但這是過度殺傷。如果觀察器設備關閉並且源應用程序中沒有發生錯誤,則套接字是否啓動並不重要。在失敗時作出反應可能是你需要做的。

+0

請參閱我的編輯 –

+0

看起來像您試圖保存儘可能多的消息。在我的情況下,這些是在現場登錄到每臺設備上的文件適配器的一堆專用平板電腦。插入電纜並不總是可行的,因爲平板電腦可能被安裝在盒子中。有時一臺筆記本電腦可能出現在WiFi網絡上以捕獲日誌。所以我希望套接字處理程序在電源週期和其他事情出錯時正常退出並重新啓動。 –

+0

@RayTayek示例代碼僅在連接斷開時存儲記錄。每次發佈都會嘗試重新連接套接字處理程序併發布任何記錄的積壓。 – jmehrens

相關問題