Skip to content

Commit

Permalink
User Pluggable Connection Time Trace Logger (#1077)
Browse files Browse the repository at this point in the history
  • Loading branch information
scottf authored Feb 28, 2024
1 parent 8d0885e commit 39d651b
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 65 deletions.
67 changes: 57 additions & 10 deletions src/main/java/io/nats/client/Options.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,14 @@
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

import static io.nats.client.support.Encoding.uriDecode;
import static io.nats.client.support.NatsConstants.*;
import static io.nats.client.support.NatsUri.DEFAULT_NATS_URI;
import static io.nats.client.support.SSLUtils.DEFAULT_TLS_ALGORITHM;
import static io.nats.client.support.Validator.*;

Expand Down Expand Up @@ -235,6 +236,11 @@ public class Options {
* {@link Builder#errorListener(ErrorListener) errorListener}.
*/
public static final String PROP_ERROR_LISTENER = PFX + "callback.error";
/**
* Property used to configure a builder from a Properties object. {@value}, see
* {@link Builder#timeTraceLogger(TimeTraceLogger) timeTraceLogger}.
*/
public static final String PROP_TIME_TRACE_LOGGER = PFX + "time.trace";
/**
* Property used to configure a builder from a Properties object. {@value}, see
* {@link Builder#statisticsCollector(StatisticsCollector) statisticsCollector}.
Expand Down Expand Up @@ -597,6 +603,7 @@ public class Options {
private final ReconnectDelayHandler reconnectDelayHandler;

private final ErrorListener errorListener;
private final TimeTraceLogger timeTraceLogger;
private final ConnectionListener connectionListener;
private final StatisticsCollector statisticsCollector;
private final String dataPortType;
Expand Down Expand Up @@ -710,6 +717,7 @@ public static class Builder {
private ReconnectDelayHandler reconnectDelayHandler;

private ErrorListener errorListener = null;
private TimeTraceLogger timeTraceLogger = null;
private ConnectionListener connectionListener = null;
private StatisticsCollector statisticsCollector = null;
private String dataPortType = DEFAULT_DATA_PORT_TYPE;
Expand Down Expand Up @@ -819,6 +827,7 @@ public Builder properties(Properties props) {
booleanProperty(props, PROP_USE_OLD_REQUEST_STYLE, b -> this.useOldRequestStyle = b);

classnameProperty(props, PROP_ERROR_LISTENER, o -> this.errorListener = (ErrorListener) o);
classnameProperty(props, PROP_TIME_TRACE_LOGGER, o -> this.timeTraceLogger = (TimeTraceLogger) o);
classnameProperty(props, PROP_CONNECTION_CB, o -> this.connectionListener = (ConnectionListener) o);
classnameProperty(props, PROP_STATISTICS_COLLECTOR, o -> this.statisticsCollector = (StatisticsCollector) o);

Expand Down Expand Up @@ -1400,6 +1409,16 @@ public Builder errorListener(ErrorListener listener) {
return this;
}

/**
* Set the {@link TimeTraceLogger TimeTraceLogger} to receive trace events related to this connection.
* @param logger The new TimeTraceLogger for this connection.
* @return the Builder for chaining
*/
public Builder timeTraceLogger(TimeTraceLogger logger) {
this.timeTraceLogger = logger;
return this;
}

/**
* Set the {@link ConnectionListener ConnectionListener} to receive asynchronous notifications of disconnect
* events.
Expand Down Expand Up @@ -1674,6 +1693,26 @@ else if (useDefaultTls) {
socketWriteTimeout = null;
}

if (errorListener == null) {
errorListener = new ErrorListenerLoggerImpl();
}

if (timeTraceLogger == null) {
if (traceConnection) {
timeTraceLogger = (format, args) -> {
String timeStr = DateTimeFormatter.ISO_TIME.format(LocalDateTime.now());
System.out.println("[" + timeStr + "] connect trace: " + String.format(format, args));
};
}
else {
timeTraceLogger = (f, a) -> {};
}
}
else {
// if the dev provided an impl, we assume they meant to time trace the connection
traceConnection = true;
}

return new Options(this);
}

Expand Down Expand Up @@ -1723,6 +1762,7 @@ public Builder(Options o) {
this.reconnectDelayHandler = o.reconnectDelayHandler;

this.errorListener = o.errorListener;
this.timeTraceLogger = o.timeTraceLogger;
this.connectionListener = o.connectionListener;
this.statisticsCollector = o.statisticsCollector;
this.dataPortType = o.dataPortType;
Expand All @@ -1745,13 +1785,8 @@ public Builder(Options o) {
// CONSTRUCTOR
// ----------------------------------------------------------------------------------------------------
private Options(Builder b) {
if (b.natsServerUris.isEmpty()) {
this.natsServerUris = Collections.singletonList(DEFAULT_NATS_URI);
}
else {
this.natsServerUris = Collections.unmodifiableList(b.natsServerUris);
}
this.unprocessedServers = b.unprocessedServers; // exactly how the user gave them
this.natsServerUris = Collections.unmodifiableList(b.natsServerUris);
this.unprocessedServers = Collections.unmodifiableList(b.unprocessedServers); // exactly how the user gave them
this.noRandomize = b.noRandomize;
this.noResolveHostnames = b.noResolveHostnames;
this.reportNoResponders = b.reportNoResponders;
Expand Down Expand Up @@ -1787,7 +1822,8 @@ private Options(Builder b) {
this.authHandler = b.authHandler;
this.reconnectDelayHandler = b.reconnectDelayHandler;

this.errorListener = b.errorListener == null ? new ErrorListenerLoggerImpl() : b.errorListener;
this.errorListener = b.errorListener;
this.timeTraceLogger = b.timeTraceLogger;
this.connectionListener = b.connectionListener;
this.statisticsCollector = b.statisticsCollector;
this.dataPortType = b.dataPortType;
Expand Down Expand Up @@ -1838,6 +1874,16 @@ public ErrorListener getErrorListener() {
return this.errorListener;
}

/**
* If the user provided a TimeTraceLogger, it's returned here.
* If the user set traceConnection but did not supply their own, the original time trace logging will occur
* If the user did not provide a TimeTraceLogger and did not set traceConnection, this will be a no-op implementation.
* @return the time trace logger
*/
public TimeTraceLogger getTimeTraceLogger() {
return this.timeTraceLogger;
}

/**
* @return the connection listener, or null, see {@link Builder#connectionListener(ConnectionListener) connectionListener()} in the builder doc
*/
Expand Down Expand Up @@ -2005,7 +2051,8 @@ public boolean isTrackAdvancedStats() {
}

/**
* @return should we trace the connection process to system.out
* If isTraceConnection is true, the user provided a TimeTraceLogger or manually called traceConnection in the builder
* @return should we trace the connection?
*/
public boolean isTraceConnection() {
return traceConnection;
Expand Down
18 changes: 18 additions & 0 deletions src/main/java/io/nats/client/TimeTraceLogger.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2024 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package io.nats.client;

public interface TimeTraceLogger {
void trace(String format, Object... args);
}
Loading

0 comments on commit 39d651b

Please sign in to comment.