Add advanced webserver logging + settings
This commit is contained in:
parent
8f97b08eb5
commit
d570884def
|
@ -65,7 +65,7 @@ public class BlueMapConfigs implements BlueMapConfigProvider {
|
||||||
|
|
||||||
this.coreConfig = loadCoreConfig(defaultDataFolder);
|
this.coreConfig = loadCoreConfig(defaultDataFolder);
|
||||||
this.webappConfig = loadWebappConfig(defaultWebroot);
|
this.webappConfig = loadWebappConfig(defaultWebroot);
|
||||||
this.webserverConfig = loadWebserverConfig(webappConfig.getWebroot());
|
this.webserverConfig = loadWebserverConfig(webappConfig.getWebroot(), coreConfig.getData());
|
||||||
this.pluginConfig = usePluginConf ? loadPluginConfig() : new PluginConfig();
|
this.pluginConfig = usePluginConf ? loadPluginConfig() : new PluginConfig();
|
||||||
this.storageConfigs = Collections.unmodifiableMap(loadStorageConfigs(webappConfig.getWebroot()));
|
this.storageConfigs = Collections.unmodifiableMap(loadStorageConfigs(webappConfig.getWebroot()));
|
||||||
this.mapConfigs = Collections.unmodifiableMap(loadMapConfigs());
|
this.mapConfigs = Collections.unmodifiableMap(loadMapConfigs());
|
||||||
|
@ -144,7 +144,7 @@ public class BlueMapConfigs implements BlueMapConfigProvider {
|
||||||
return configManager.loadConfig(configFileRaw, CoreConfig.class);
|
return configManager.loadConfig(configFileRaw, CoreConfig.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized WebserverConfig loadWebserverConfig(Path defaultWebroot) throws ConfigurationException {
|
private synchronized WebserverConfig loadWebserverConfig(Path defaultWebroot, Path dataRoot) throws ConfigurationException {
|
||||||
Path configFileRaw = Path.of("webserver");
|
Path configFileRaw = Path.of("webserver");
|
||||||
Path configFile = configManager.findConfigPath(configFileRaw);
|
Path configFile = configManager.findConfigPath(configFileRaw);
|
||||||
Path configFolder = configFile.getParent();
|
Path configFolder = configFile.getParent();
|
||||||
|
@ -156,6 +156,8 @@ public class BlueMapConfigs implements BlueMapConfigProvider {
|
||||||
configFolder.resolve("webserver.conf"),
|
configFolder.resolve("webserver.conf"),
|
||||||
configManager.loadConfigTemplate("/de/bluecolored/bluemap/config/webserver.conf")
|
configManager.loadConfigTemplate("/de/bluecolored/bluemap/config/webserver.conf")
|
||||||
.setVariable("webroot", formatPath(defaultWebroot))
|
.setVariable("webroot", formatPath(defaultWebroot))
|
||||||
|
.setVariable("logfile", formatPath(dataRoot.resolve("logs").resolve("webapp.log")))
|
||||||
|
.setVariable("logfile-with-time", formatPath(dataRoot.resolve("logs").resolve("webapp_%1$tF_%1$tT.log")))
|
||||||
.build(),
|
.build(),
|
||||||
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING
|
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING
|
||||||
);
|
);
|
||||||
|
|
|
@ -38,13 +38,13 @@ import java.nio.file.Path;
|
||||||
public class WebserverConfig {
|
public class WebserverConfig {
|
||||||
|
|
||||||
private boolean enabled = true;
|
private boolean enabled = true;
|
||||||
|
|
||||||
private Path webroot = Path.of("bluemap", "web");
|
private Path webroot = Path.of("bluemap", "web");
|
||||||
|
|
||||||
private String ip = "0.0.0.0";
|
private String ip = "0.0.0.0";
|
||||||
|
|
||||||
private int port = 8100;
|
private int port = 8100;
|
||||||
|
|
||||||
|
private LogConfig log = new LogConfig();
|
||||||
|
|
||||||
public boolean isEnabled() {
|
public boolean isEnabled() {
|
||||||
return enabled;
|
return enabled;
|
||||||
}
|
}
|
||||||
|
@ -71,4 +71,30 @@ public class WebserverConfig {
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LogConfig getLog() {
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
@DebugDump
|
||||||
|
@ConfigSerializable
|
||||||
|
public static class LogConfig {
|
||||||
|
|
||||||
|
private String file = null;
|
||||||
|
private boolean append = true;
|
||||||
|
private String format = "%1$s \"%3$s %4$s %5$s\" %6$s %7$s";
|
||||||
|
|
||||||
|
public String getFile() {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAppend() {
|
||||||
|
return append;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFormat() {
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,9 @@ import java.net.BindException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
@ -185,8 +188,22 @@ public class Plugin implements ServerEventListener {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create web-logger
|
||||||
|
List<Logger> webLoggerList = new ArrayList<>();
|
||||||
|
if (webserverConfig.getLog().getFile() != null) {
|
||||||
|
ZonedDateTime zdt = ZonedDateTime.ofInstant(Instant.now(), ZoneId.systemDefault());
|
||||||
|
webLoggerList.add(Logger.file(
|
||||||
|
Path.of(String.format(webserverConfig.getLog().getFile(), zdt)),
|
||||||
|
webserverConfig.getLog().isAppend()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
webServer = new HttpServer(routingRequestHandler);
|
webServer = new HttpServer(new LoggingRequestHandler(
|
||||||
|
routingRequestHandler,
|
||||||
|
webserverConfig.getLog().getFormat(),
|
||||||
|
Logger.combine(webLoggerList)
|
||||||
|
));
|
||||||
webServer.bind(new InetSocketAddress(
|
webServer.bind(new InetSocketAddress(
|
||||||
webserverConfig.resolveIp(),
|
webserverConfig.resolveIp(),
|
||||||
webserverConfig.getPort()
|
webserverConfig.getPort()
|
||||||
|
|
|
@ -1,50 +1,74 @@
|
||||||
package de.bluecolored.bluemap.common.web;
|
package de.bluecolored.bluemap.common.web;
|
||||||
|
|
||||||
import de.bluecolored.bluemap.common.web.http.HttpHeader;
|
import de.bluecolored.bluemap.common.web.http.*;
|
||||||
import de.bluecolored.bluemap.common.web.http.HttpRequest;
|
|
||||||
import de.bluecolored.bluemap.common.web.http.HttpRequestHandler;
|
|
||||||
import de.bluecolored.bluemap.common.web.http.HttpResponse;
|
|
||||||
import de.bluecolored.bluemap.core.logger.Logger;
|
import de.bluecolored.bluemap.core.logger.Logger;
|
||||||
|
|
||||||
public class LoggingRequestHandler implements HttpRequestHandler {
|
public class LoggingRequestHandler implements HttpRequestHandler {
|
||||||
|
|
||||||
private final HttpRequestHandler delegate;
|
private final HttpRequestHandler delegate;
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
|
private final String format;
|
||||||
|
|
||||||
public LoggingRequestHandler(HttpRequestHandler delegate) {
|
public LoggingRequestHandler(HttpRequestHandler delegate) {
|
||||||
this(delegate, Logger.global);
|
this(delegate, Logger.global);
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoggingRequestHandler(HttpRequestHandler delegate, Logger logger) {
|
public LoggingRequestHandler(HttpRequestHandler delegate, Logger logger) {
|
||||||
|
this(delegate, "", logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoggingRequestHandler(HttpRequestHandler delegate, String format) {
|
||||||
|
this(delegate, format, Logger.global);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoggingRequestHandler(HttpRequestHandler delegate, String format, Logger logger) {
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
|
this.format = format;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HttpResponse handle(HttpRequest request) {
|
public HttpResponse handle(HttpRequest request) {
|
||||||
String source = request.getSource().toString();
|
|
||||||
|
|
||||||
|
// gather format parameters from request
|
||||||
|
String source = request.getSource().toString();
|
||||||
|
String xffSource = source;
|
||||||
HttpHeader xffHeader = request.getHeader("X-Forwarded-For");
|
HttpHeader xffHeader = request.getHeader("X-Forwarded-For");
|
||||||
if (xffHeader != null && !xffHeader.getValues().isEmpty()) {
|
if (xffHeader != null && !xffHeader.getValues().isEmpty()) {
|
||||||
source = xffHeader.getValues().get(0);
|
xffSource = xffHeader.getValues().get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder log = new StringBuilder()
|
String method = request.getMethod();
|
||||||
.append(source)
|
String address = request.getAddress();
|
||||||
.append(" \"").append(request.getMethod())
|
String version = request.getVersion();
|
||||||
.append(" ").append(request.getAddress())
|
|
||||||
.append(" ").append(request.getVersion())
|
|
||||||
.append("\" ");
|
|
||||||
|
|
||||||
|
// run request
|
||||||
HttpResponse response = delegate.handle(request);
|
HttpResponse response = delegate.handle(request);
|
||||||
|
|
||||||
log.append(response.getStatusCode());
|
// gather format parameters from response
|
||||||
if (response.getStatusCode().getCode() < 400) {
|
HttpStatusCode status = response.getStatusCode();
|
||||||
logger.logInfo(log.toString());
|
int statusCode = status.getCode();
|
||||||
|
String statusMessage = status.getMessage();
|
||||||
|
|
||||||
|
// format log message
|
||||||
|
String log = String.format(this.format,
|
||||||
|
source,
|
||||||
|
xffSource,
|
||||||
|
method,
|
||||||
|
address,
|
||||||
|
version,
|
||||||
|
statusCode,
|
||||||
|
statusMessage
|
||||||
|
);
|
||||||
|
|
||||||
|
// do the logging
|
||||||
|
if (statusCode < 500) {
|
||||||
|
logger.logInfo(log);
|
||||||
} else {
|
} else {
|
||||||
logger.logWarning(log.toString());
|
logger.logWarning(log);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return the response
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,3 +16,30 @@ webroot: "${webroot}"
|
||||||
# The port that the webserver listens to.
|
# The port that the webserver listens to.
|
||||||
# Default is 8100
|
# Default is 8100
|
||||||
port: 8100
|
port: 8100
|
||||||
|
|
||||||
|
# Config-section for webserver-activity logging
|
||||||
|
log: {
|
||||||
|
# The file where all the webserver-activity will be logged to.
|
||||||
|
# Comment out to disable the logging completely.
|
||||||
|
# Java String formatting syntax can be used to add time
|
||||||
|
# Default is no logging
|
||||||
|
file: "${logfile}"
|
||||||
|
#file: "${logfile-with-time}"
|
||||||
|
|
||||||
|
# Whether the logger should append to an existing file, or overwrite it
|
||||||
|
# Default is true
|
||||||
|
append: true
|
||||||
|
|
||||||
|
# The format of the webserver-acivity logs.
|
||||||
|
# The syntax is the java String formatting, see: https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html
|
||||||
|
# Possible Arguments:
|
||||||
|
# 1 - the source address (ignoring any xff headers)
|
||||||
|
# 2 - the source address (using the (leftmost) xff header if provided)
|
||||||
|
# 3 - the http-method of the request
|
||||||
|
# 4 - the full request-address
|
||||||
|
# 5 - the protocol version of the request
|
||||||
|
# 6 - the status-code of the response
|
||||||
|
# 7 - the status-message of the response
|
||||||
|
# Default is "%1$s \"%3$s %4$s %5$s\" %6$s %7$s"
|
||||||
|
format: "%1$s \"%3$s %4$s %5$s\" %6$s %7$s"
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package de.bluecolored.bluemap.core.logger;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class JavaLogger extends AbstractLogger {
|
||||||
|
|
||||||
|
private final Logger out;
|
||||||
|
|
||||||
|
public JavaLogger(Logger out) {
|
||||||
|
this.out = out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void logError(String message, Throwable throwable) {
|
||||||
|
out.log(Level.SEVERE, message, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void logWarning(String message) {
|
||||||
|
out.log(Level.WARNING, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void logInfo(String message) {
|
||||||
|
out.log(Level.INFO, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void logDebug(String message) {
|
||||||
|
if (out.isLoggable(Level.FINE)) out.log(Level.FINE, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void noFloodDebug(String message) {
|
||||||
|
if (out.isLoggable(Level.FINE)) super.noFloodDebug(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void noFloodDebug(String key, String message) {
|
||||||
|
if (out.isLoggable(Level.FINE)) super.noFloodDebug(key, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package de.bluecolored.bluemap.core.logger;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.logging.Formatter;
|
||||||
|
import java.util.logging.LogRecord;
|
||||||
|
|
||||||
|
public class LogFormatter extends Formatter {
|
||||||
|
|
||||||
|
private final String format;
|
||||||
|
|
||||||
|
public LogFormatter() {
|
||||||
|
this("[%1$tF %1$tT][%4$s] %5$s%6$s%n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public LogFormatter(String format) {
|
||||||
|
this.format = format;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Taken from {@link java.util.logging.SimpleFormatter} to be able to overwrite the format string.
|
||||||
|
* @param record the log record to be formatted.
|
||||||
|
* @return the formatted log
|
||||||
|
*/
|
||||||
|
public String format(LogRecord record) {
|
||||||
|
ZonedDateTime zdt = ZonedDateTime.ofInstant(
|
||||||
|
record.getInstant(), ZoneId.systemDefault());
|
||||||
|
String source;
|
||||||
|
if (record.getSourceClassName() != null) {
|
||||||
|
source = record.getSourceClassName();
|
||||||
|
if (record.getSourceMethodName() != null) {
|
||||||
|
source += " " + record.getSourceMethodName();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
source = record.getLoggerName();
|
||||||
|
}
|
||||||
|
String message = formatMessage(record);
|
||||||
|
String throwable = "";
|
||||||
|
if (record.getThrown() != null) {
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
PrintWriter pw = new PrintWriter(sw);
|
||||||
|
pw.println();
|
||||||
|
record.getThrown().printStackTrace(pw);
|
||||||
|
pw.close();
|
||||||
|
throwable = sw.toString();
|
||||||
|
}
|
||||||
|
return String.format(format,
|
||||||
|
zdt,
|
||||||
|
source,
|
||||||
|
record.getLoggerName(),
|
||||||
|
record.getLevel().getLocalizedName(),
|
||||||
|
message,
|
||||||
|
throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -24,6 +24,14 @@
|
||||||
*/
|
*/
|
||||||
package de.bluecolored.bluemap.core.logger;
|
package de.bluecolored.bluemap.core.logger;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.logging.FileHandler;
|
||||||
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
public abstract class Logger {
|
public abstract class Logger {
|
||||||
|
|
||||||
public static Logger global = stdOut();
|
public static Logger global = stdOut();
|
||||||
|
@ -107,4 +115,41 @@ public abstract class Logger {
|
||||||
return new PrintStreamLogger(System.out, System.err);
|
return new PrintStreamLogger(System.out, System.err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Logger file(Path path) throws IOException {
|
||||||
|
return file(path, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Logger file(Path path, boolean append) throws IOException {
|
||||||
|
return file(path, null, append);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Logger file(Path path, String format) throws IOException {
|
||||||
|
return file(path, format, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Logger file(Path path, @Nullable String format, boolean append) throws IOException {
|
||||||
|
Files.createDirectories(path.getParent());
|
||||||
|
|
||||||
|
FileHandler fileHandler = new FileHandler(path.toString(), append);
|
||||||
|
fileHandler.setFormatter(format == null ? new LogFormatter() : new LogFormatter(format));
|
||||||
|
|
||||||
|
java.util.logging.Logger javaLogger = java.util.logging.Logger.getAnonymousLogger();
|
||||||
|
javaLogger.setUseParentHandlers(false);
|
||||||
|
javaLogger.addHandler(fileHandler);
|
||||||
|
|
||||||
|
return new JavaLogger(javaLogger);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Logger combine(Iterable<Logger> logger) {
|
||||||
|
return combine(StreamSupport.stream(logger.spliterator(), false)
|
||||||
|
.toArray(Logger[]::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Logger combine(Logger... logger) {
|
||||||
|
if (logger.length == 0) return new VoidLogger();
|
||||||
|
if (logger.length == 1) return logger[0];
|
||||||
|
return new MultiLogger(logger);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package de.bluecolored.bluemap.core.logger;
|
||||||
|
|
||||||
|
@SuppressWarnings("ForLoopReplaceableByForEach")
|
||||||
|
public class MultiLogger extends AbstractLogger {
|
||||||
|
|
||||||
|
private final Logger[] logger;
|
||||||
|
|
||||||
|
public MultiLogger(Logger... logger) {
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void logError(String message, Throwable throwable) {
|
||||||
|
for (int i = 0; i < logger.length; i++)
|
||||||
|
logger[i].logError(message, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void logWarning(String message) {
|
||||||
|
for (int i = 0; i < logger.length; i++)
|
||||||
|
logger[i].logWarning(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void logInfo(String message) {
|
||||||
|
for (int i = 0; i < logger.length; i++)
|
||||||
|
logger[i].logInfo(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void logDebug(String message) {
|
||||||
|
for (int i = 0; i < logger.length; i++)
|
||||||
|
logger[i].logDebug(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -58,6 +58,9 @@ import java.net.BindException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
@ -203,10 +206,25 @@ public class BlueMapCLI implements ServerInterface {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<Logger> webLoggerList = new ArrayList<>();
|
||||||
|
if (verbose) webLoggerList.add(Logger.global);
|
||||||
|
if (config.getLog().getFile() != null) {
|
||||||
|
ZonedDateTime zdt = ZonedDateTime.ofInstant(Instant.now(), ZoneId.systemDefault());
|
||||||
|
webLoggerList.add(Logger.file(
|
||||||
|
Path.of(String.format(config.getLog().getFile(), zdt)),
|
||||||
|
config.getLog().isAppend()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
HttpRequestHandler handler = new BlueMapResponseModifier(routingRequestHandler);
|
HttpRequestHandler handler = new BlueMapResponseModifier(routingRequestHandler);
|
||||||
if (verbose) handler = new LoggingRequestHandler(handler);
|
handler = new LoggingRequestHandler(
|
||||||
|
handler,
|
||||||
|
config.getLog().getFormat(),
|
||||||
|
Logger.combine(webLoggerList)
|
||||||
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
//noinspection resource
|
||||||
HttpServer webServer = new HttpServer(handler);
|
HttpServer webServer = new HttpServer(handler);
|
||||||
webServer.bind(new InetSocketAddress(
|
webServer.bind(new InetSocketAddress(
|
||||||
config.resolveIp(),
|
config.resolveIp(),
|
||||||
|
|
Loading…
Reference in New Issue