简体   繁体   English

如何判断java logging sockethandler是否仍在运行?

[英]How to tell if the java logging sockethandler is still running?

I have an app that creates a socket handler to my log server (on a different device) and uses it. 我有一个应用程序,它为我的日志服务器(在不同的设备上)创建一个套接字处理程序并使用它。 This works fine. 这很好用。

If the log sever is terminated and restarted the app does not know this. 如果日志服务器终止并重新启动,则应用程序不知道这一点。 The app should remove the old socket handler and add a new one. 该应用程序应删除旧的套接字处理程序并添加一个新的。

How can I tell if the java logging sockethandler is still running? 如何判断java logging sockethandler是否仍在运行?

Edit: I came up with the code below which seems to work: 编辑:我想出了下面的代码似乎工作:

    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;
}

Create a proxy handler to wrap the SocketHandler and install a custom java.util.logging.ErrorManager (as an inner class) to listen for exceptions and reconnect the internal handler on error. 创建一个代理处理程序来包装SocketHandler并安装一个自定义的java.util.logging.ErrorManager (作为内部类)来侦听异常并在出错时重新连接内部处理程序。

Here is some example code for you to improve and make sure you unit test it before you use it: 下面是一些示例代码供您改进,并确保在使用之前对其进行单元测试:

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;
        }
    }
}

This code will publish to the socket handler in the normal path. 此代码将发布到正常路径中的套接字处理程序。 On exception, it will close and recreate the socket handler. 在异常时,它将关闭并重新创建套接字处理程序。 If that fails, this code will store the current record up to the last 1000 records in a queue for delayed publishing. 如果失败,此代码将当前记录存储到队列中的最后1000条记录中以进行延迟发布。

Removing and adding the socket handler to the logger tree is a racy operation and could result losing log records or a flurry of reconnects. 删除套接字处理程序并将其添加到记录器树是一项非常简单的操作,可能会导致丢失日志记录或重新连接。 The proxy handler will allow you to properly control the number of reconnects and it allows you to re-publish errors that would otherwise be lost. 代理处理程序将允许您正确控制重新连接的数量,并允许您重新发布否则将丢失的错误。

How can I tell if the java logging sockethandler is still running? 如何判断java logging sockethandler是否仍在运行?

You can try to periodically call flush to detect a closed socket but that is overkill. 您可以尝试定期调用flush以检测已关闭的套接字,但这是过度的。 If the observer device is down and no errors occur in the source application it doesn't really matter if the socket is up or not. 如果观察器设备关闭且源应用程序中没有发生错误,则套接字是否启动并不重要。 Reacting at the time of failure is probably all you need to do. 失败时的反应可能就是你需要做的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM