diff --git a/pom.xml b/pom.xml
index fc3b9c635..0b6947bf6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -172,6 +172,12 @@ THE SOFTWARE.
3.0.1
jar
+
+ org.kohsuke
+ access-modifier-annotation
+ 1.7
+ jar
+
diff --git a/src/main/java/hudson/remoting/Channel.java b/src/main/java/hudson/remoting/Channel.java
index 4aafdcfe6..b785c7e01 100644
--- a/src/main/java/hudson/remoting/Channel.java
+++ b/src/main/java/hudson/remoting/Channel.java
@@ -60,6 +60,8 @@
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
+import org.kohsuke.accmod.Restricted;
+import org.kohsuke.accmod.restrictions.NoExternalUse;
/**
* Represents a communication channel to the remote peer.
@@ -210,7 +212,7 @@ public class Channel implements VirtualChannel, IChannel, Closeable {
/**
* Number of {@link Command} objects sent to the other side.
*/
- private int commandsSent;
+ private volatile long commandsSent;
/**
* Number of {@link Command} objects received from the other side.
@@ -218,7 +220,7 @@ public class Channel implements VirtualChannel, IChannel, Closeable {
* When a transport is functioning correctly, {@link #commandsSent} of one side
* and {@link #commandsReceived} of the other side should closely match.
*/
- private int commandsReceived;
+ private volatile long commandsReceived;
/**
* Timestamp of the last {@link Command} object sent/received, in
@@ -1172,6 +1174,7 @@ public void dumpPerformanceCounters(PrintWriter w) throws IOException {
w.printf(Locale.ENGLISH, "Resource loading time=%,dms%n", resourceLoadingTime.get() / (1000 * 1000));
}
+ //TODO: Make public after merge into the master branch
/**
* Print the diagnostic information.
*
@@ -1226,17 +1229,24 @@ public void dumpPerformanceCounters(PrintWriter w) throws IOException {
* Number of RPC calls (e.g., method call through a {@linkplain RemoteInvocationHandler proxy})
* that the other side has made to us but not yet returned yet.
*
- * @since 2.26.3
+ * @param w Output destination
+ * @throws IOException Error while creating or writing the channel information
+ *
+ * @since 2.62.3 - stable 2.x (restricted)
+ * @since TODO 3.x - public version
*/
- public void dumpDiagnostics(PrintWriter w) throws IOException {
+ @Restricted(NoExternalUse.class)
+ public void dumpDiagnostics(@Nonnull PrintWriter w) throws IOException {
w.printf("Channel %s%n",name);
w.printf(" Created=%s%n", new Date(createdAt));
w.printf(" Commands sent=%d%n", commandsSent);
w.printf(" Commands received=%d%n", commandsReceived);
w.printf(" Last command sent=%s%n", new Date(lastCommandSentAt));
w.printf(" Last command received=%s%n", new Date(lastCommandReceivedAt));
- w.printf(" Pending outgoing calls=%d%n", pendingCalls.size());
- w.printf(" Pending incoming calls=%d%n", pendingCalls.size());
+
+ // TODO: Update after the merge to 3.x branch, where the Hashtable is going to be replaced as a part of
+ // https://github.com/jenkinsci/remoting/pull/109
+ w.printf(" Pending calls=%d%n", pendingCalls.size());
}
/**
@@ -1584,17 +1594,48 @@ public static Channel current() {
return CURRENT.get();
}
+ // TODO: Unrestrict after the merge into the master.
+ // By now one may use it via the reflection logic only
/**
* Calls {@link #dumpDiagnostics(PrintWriter)} across all the active channels in this system.
* Used for diagnostics.
*
- * @since 2.26.3
- */
- public static void dumpDiagnosticsForAll(PrintWriter w) throws IOException {
- for (Ref ref : ACTIVE_CHANNELS.values().toArray(new Ref[0])) {
- Channel ch = ref.channel();
- if (ch!=null)
- ch.dumpDiagnostics(w);
+ * @param w Output destination
+ *
+ * @since 2.62.3 - stable 2.x (restricted)
+ * @since TODO 3.x - public version
+ */
+ @Restricted(NoExternalUse.class)
+ public static void dumpDiagnosticsForAll(@Nonnull PrintWriter w) {
+ final Ref[] channels = ACTIVE_CHANNELS.values().toArray(new Ref[0]);
+ int processedCount = 0;
+ for (Ref ref : channels) {
+ // Check if we can still write the output
+ if (w.checkError()) {
+ logger.log(Level.WARNING,
+ String.format("Cannot dump diagnostics for all channels, because output stream encountered an error. "
+ + "Processed %d of %d channels, first unprocessed channel reference is %s.",
+ processedCount, channels.length, ref
+ ));
+ break;
+ }
+
+ // Dump channel info if the reference still points to it
+ final Channel ch = ref.channel();
+ if (ch != null) {
+ try {
+ ch.dumpDiagnostics(w);
+ } catch (Throwable ex) {
+ if (ex instanceof Error) {
+ throw (Error)ex;
+ }
+ w.printf("Cannot dump diagnostics for the channel %s. %s. See Error stacktrace in system logs",
+ ch.getName(), ex.getMessage());
+ logger.log(Level.WARNING,
+ String.format("Cannot dump diagnostics for the channel %s", ch.getName()), ex);
+ }
+ }
+ processedCount++;
}
}