Skip to content

Commit c9a0f5c

Browse files
authored
Merge pull request #87 from cljohnso/memoryMonitor
Add memory monitor
2 parents 5946c33 + db6bafb commit c9a0f5c

File tree

5 files changed

+1814
-55
lines changed

5 files changed

+1814
-55
lines changed

port-chooser/src/main/java/org/terracotta/utilities/test/net/NetStat.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,10 @@ private static BusyPort parseWindowsCsv(String line) {
498498
builder.localEndpoint(BusyPort.IPVersion.IPV4, fields.get(1), fields.get(2));
499499
builder.remoteEndpoint(BusyPort.IPVersion.IPV4, fields.get(3), fields.get(4));
500500
builder.state(BusyPort.TcpState.fromMicrosoftString(fields.get(5)));
501-
builder.shortCommand(fields.get(6));
501+
// The short command may be missing
502+
if (fields.size() >= 7) {
503+
builder.shortCommand(fields.get(6));
504+
}
502505
// The full command line may be missing ...
503506
if (fields.size() >= 8) {
504507
builder.commandLine(fields.get(7));

port-chooser/src/test/java/org/terracotta/utilities/test/net/PortManagerTest.java

Lines changed: 4 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,11 @@
1717
package org.terracotta.utilities.test.net;
1818

1919
import ch.qos.logback.classic.Level;
20-
import ch.qos.logback.classic.LoggerContext;
21-
import ch.qos.logback.classic.filter.ThresholdFilter;
22-
import ch.qos.logback.classic.spi.ILoggingEvent;
2320

2421
import org.junit.Ignore;
2522
import org.junit.Test;
26-
import org.slf4j.Logger;
2723
import org.slf4j.LoggerFactory;
24+
import org.terracotta.utilities.test.logging.ConnectedListAppender;
2825

2926
import java.io.IOException;
3027
import java.lang.ref.WeakReference;
@@ -40,7 +37,6 @@
4037
import java.util.concurrent.TimeUnit;
4138
import java.util.concurrent.atomic.AtomicReference;
4239

43-
import static java.util.Objects.requireNonNull;
4440
import static org.hamcrest.Matchers.allOf;
4541
import static org.hamcrest.Matchers.equalTo;
4642
import static org.hamcrest.Matchers.hasItem;
@@ -323,7 +319,7 @@ public void testReleaseCheckEnabled() throws IOException {
323319
assertFalse(PortManager.DISABLE_PORT_RELEASE_CHECK_ENV_VARIABLE + " environment variable must be false or not specified",
324320
Boolean.parseBoolean(System.getenv(PortManager.DISABLE_PORT_RELEASE_CHECK_ENV_VARIABLE)));
325321

326-
try (ListAppender appender = new ListAppender(LoggerFactory.getLogger(PortManager.class), "WARN")) {
322+
try (ConnectedListAppender appender = ConnectedListAppender.newInstance(LoggerFactory.getLogger(PortManager.class), "WARN")) {
327323
PortManager.PortRef portRef = portManager.reservePort();
328324
int port = portRef.port();
329325
try (ServerSocket ignored = new ServerSocket(port)) {
@@ -351,7 +347,7 @@ public void testReleaseCheckDisabled() throws IOException {
351347
assertFalse(PortManager.DISABLE_PORT_RELEASE_CHECK_ENV_VARIABLE + " environment variable must be false or not specified",
352348
Boolean.parseBoolean(System.getenv(PortManager.DISABLE_PORT_RELEASE_CHECK_ENV_VARIABLE)));
353349

354-
try (ListAppender appender = new ListAppender(LoggerFactory.getLogger(PortManager.class), "WARN")) {
350+
try (ConnectedListAppender appender = ConnectedListAppender.newInstance(LoggerFactory.getLogger(PortManager.class), "WARN")) {
355351
PortManager.PortRef portRef = portManager.reservePort();
356352
int port = portRef.port();
357353
try (ServerSocket ignored = new ServerSocket(port)) {
@@ -380,7 +376,7 @@ public void testReleaseCheckDisabledEnvironment() throws IOException {
380376
assumeTrue("Skipped unless " + PortManager.DISABLE_PORT_RELEASE_CHECK_ENV_VARIABLE + " environment variable is true",
381377
Boolean.parseBoolean(System.getenv(PortManager.DISABLE_PORT_RELEASE_CHECK_ENV_VARIABLE)));
382378

383-
try (ListAppender appender = new ListAppender(LoggerFactory.getLogger(PortManager.class), "WARN")) {
379+
try (ConnectedListAppender appender = ConnectedListAppender.newInstance(LoggerFactory.getLogger(PortManager.class), "WARN")) {
384380
PortManager.PortRef portRef = portManager.reservePort();
385381
int port = portRef.port();
386382
try (ServerSocket ignored = new ServerSocket(port)) {
@@ -439,50 +435,4 @@ public void testSequentialAllocation() {
439435
ports.clear();
440436
}
441437
}
442-
443-
/**
444-
* A {@link ch.qos.logback.core.read.ListAppender} implementation that auto-connects
445-
* itself to a designated {@link Logger}. The {@link #close()} or {@link #stop()} method
446-
* should be called after use of the appender is completed to have the appender removed
447-
* from the designated {@code Logger}.
448-
*/
449-
private static class ListAppender extends ch.qos.logback.core.read.ListAppender<ILoggingEvent>
450-
implements AutoCloseable {
451-
private final ch.qos.logback.classic.Logger logbackLogger;
452-
453-
public ListAppender(Logger logger, String minimumLevel) {
454-
super();
455-
requireNonNull(logger, "logger");
456-
Level minLevel = Level.toLevel(requireNonNull(minimumLevel, "minimumLevel"), Level.DEBUG);
457-
458-
this.setContext((LoggerContext)LoggerFactory.getILoggerFactory());
459-
ThresholdFilter filter = new ThresholdFilter();
460-
filter.setLevel(minLevel.levelStr);
461-
this.addFilter(filter);
462-
this.start();
463-
464-
this.logbackLogger = (ch.qos.logback.classic.Logger)logger;
465-
logbackLogger.addAppender(this);
466-
}
467-
468-
@Override
469-
public void stop() {
470-
logbackLogger.detachAppender(this);
471-
super.stop();
472-
}
473-
474-
@Override
475-
public void close() {
476-
this.stop();
477-
}
478-
479-
/**
480-
* Gets a reference to the {@code List} holding the recorded {@link ILoggingEvent} instances.
481-
* This list may be altered, for example, cleared.
482-
* @return the mutable list of recorded {@code ILoggingEvent} instances
483-
*/
484-
public List<ILoggingEvent> events() {
485-
return this.list;
486-
}
487-
}
488438
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/*
2+
* Copyright IBM Corp. 2025
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.terracotta.utilities.test.logging;
17+
18+
import ch.qos.logback.classic.Level;
19+
import ch.qos.logback.classic.LoggerContext;
20+
import ch.qos.logback.classic.filter.ThresholdFilter;
21+
import ch.qos.logback.classic.spi.ILoggingEvent;
22+
import org.slf4j.Logger;
23+
import org.slf4j.LoggerFactory;
24+
25+
import java.util.List;
26+
27+
import static java.util.Objects.requireNonNull;
28+
29+
/**
30+
* A {@link ch.qos.logback.core.read.ListAppender} implementation that auto-connects
31+
* itself to a designated {@link Logger}. The {@link #close()} or {@link #stop()} method
32+
* should be called after use of the appender is completed to have the appender removed
33+
* from the designated {@code Logger}.
34+
*
35+
* <h3>Usage</h3>
36+
* The following demonstrates a typical usage pattern:
37+
* <pre>{@code
38+
* try (ConnectedListAppender appender = ConnectedListAppender.newInstance(LoggerFactory.getLogger(ObservedLoggerClass.class), "WARN")) {
39+
* ...
40+
* // activity logging against ObservedLoggerClass
41+
* ...
42+
* assertThat(appender.events(), hasItem(allOf(
43+
* hasProperty("level", equalTo(Level.ERROR)),
44+
* hasProperty("formattedMessage", is(stringContainsInOrder("first string ", "second string")))
45+
* )));
46+
* }}</pre>
47+
*/
48+
public class ConnectedListAppender extends ch.qos.logback.core.read.ListAppender<ILoggingEvent>
49+
implements AutoCloseable {
50+
private final ch.qos.logback.classic.Logger logbackLogger;
51+
52+
/**
53+
* Create a new {@code ConnectedListAppender} connected to the specified {@code Logger}.
54+
* @param logger the {@code Logger} to which the new appender is added
55+
* @param minimumLevel the <i>minimum</i> level of logging events to capture;
56+
* "ERROR" &gt; "WARN" &gt; "INFO" &gt; "DEBUG" &gt; "TRACE" &gt; "ALL";
57+
* if the value supplied is not recognized by Logback, "DEBUG" is used
58+
* @return a new {@code ConnectedListAppender} instance
59+
*/
60+
public static ConnectedListAppender newInstance(Logger logger, String minimumLevel) {
61+
ConnectedListAppender appender = new ConnectedListAppender(logger);
62+
appender.setContext((LoggerContext)LoggerFactory.getILoggerFactory());
63+
64+
Level minLevel = Level.toLevel(requireNonNull(minimumLevel, "minimumLevel"), Level.DEBUG);
65+
ThresholdFilter filter = new ThresholdFilter();
66+
filter.setLevel(minLevel.levelStr);
67+
appender.addFilter(filter);
68+
69+
appender.start();
70+
71+
((ch.qos.logback.classic.Logger)logger).addAppender(appender);
72+
73+
return appender;
74+
}
75+
76+
/**
77+
* Create a new {@code ConnectedListAppender}.
78+
* @param logger the {@code Logger} to which the new appender is added
79+
*/
80+
private ConnectedListAppender(Logger logger) {
81+
super();
82+
this.logbackLogger = (ch.qos.logback.classic.Logger)requireNonNull(logger, "logger");
83+
}
84+
85+
/**
86+
* Detaches this appender from the logger and stops this appender.
87+
*/
88+
@Override
89+
public void stop() {
90+
logbackLogger.detachAppender(this);
91+
super.stop();
92+
}
93+
94+
/**
95+
* Detaches this appender from the logger and stops this appender.
96+
* This method calls {@link #stop()}.
97+
*/
98+
@Override
99+
public void close() {
100+
this.stop();
101+
}
102+
103+
/**
104+
* Gets a reference to the {@code List} holding the recorded {@link ILoggingEvent} instances.
105+
* This list may be altered, for example, cleared.
106+
* <p>
107+
* The returned list is <i>live</i> -- it is the list to which logging events are appended.
108+
* Accesses to the returned list while this appender is "active" should synchronize against
109+
* this appender.
110+
*
111+
* @return the mutable list of recorded {@code ILoggingEvent} instances
112+
*/
113+
public List<ILoggingEvent> events() {
114+
return this.list;
115+
}
116+
}

0 commit comments

Comments
 (0)