Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 31 additions & 6 deletions src/main/java/org/jvnet/hudson/test/InboundAgentRule.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import hudson.model.Descriptor;
import hudson.model.Node;
import hudson.model.Slave;
import hudson.remoting.VirtualChannel;
import hudson.slaves.DumbSlave;
import hudson.slaves.JNLPLauncher;
import hudson.slaves.RetentionStrategy;
Expand All @@ -40,10 +41,13 @@
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.io.FileUtils;
import org.apache.tools.ant.util.JavaEnvUtils;
Expand Down Expand Up @@ -84,7 +88,7 @@ public static final class Options implements Serializable {
private boolean webSocket;
@CheckForNull private String tunnel;
private boolean start = true;

private final Map<String, Level> loggers = new LinkedHashMap<>();
private String label;
private final PrefixedOutputStream.Builder prefixedOutputStreamBuilder = PrefixedOutputStream.builder();

Expand Down Expand Up @@ -206,6 +210,20 @@ public Builder label(String label) {
return this;
}

public Builder withLogger(Class<?> clazz, Level level) {
return withLogger(clazz.getName(), level);
}

public Builder withPackageLogger(Class<?> clazz, Level level) {
return withLogger(clazz.getPackageName(), level);
}

public Builder withLogger(String logger, Level level) {
options.loggers.put(logger, level);
return this;
}


/**
* Build and return an {@link Options}.
*
Expand Down Expand Up @@ -270,7 +288,7 @@ public void start(@NonNull JenkinsRule r, Options options) throws Exception {
Objects.requireNonNull(name);
stop(r, name);
start(GetAgentArguments.get(r, name), options);
WaitForAgentOnline.wait(r, name);
WaitForAgentOnline.wait(r, name, options.loggers);
}

/**
Expand All @@ -281,7 +299,7 @@ public void start(@NonNull RealJenkinsRule r, Options options) throws Throwable
Objects.requireNonNull(name);
stop(r, name);
start(r.runRemotely(new GetAgentArguments(name)), options);
r.runRemotely(new WaitForAgentOnline(name));
r.runRemotely(new WaitForAgentOnline(name, options.loggers));
}

@SuppressFBWarnings(value = {"COMMAND_INJECTION", "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE"}, justification = "just for test code")
Expand Down Expand Up @@ -432,17 +450,19 @@ private static AgentArguments get(JenkinsRule r, String name) throws IOException

private static class WaitForAgentOnline implements RealJenkinsRule.Step {
private final String name;
private final Map<String, Level> loggers;

WaitForAgentOnline(String name) {
WaitForAgentOnline(String name, Map<String, Level> loggers) {
this.name = name;
this.loggers = loggers;
}

@Override
public void run(JenkinsRule r) throws Throwable {
wait(r, name);
wait(r, name, loggers);
}

static void wait(JenkinsRule r, String name) throws Exception {
static void wait(JenkinsRule r, String name, Map<String, Level> loggers) throws Exception {
Node node = r.jenkins.getNode(name);
if (node == null) {
throw new AssertionError("no such agent: " + name);
Expand All @@ -451,6 +471,11 @@ static void wait(JenkinsRule r, String name) throws Exception {
throw new AssertionError("agent is not a Slave: " + name);
}
r.waitOnline((Slave) node);
if (!loggers.isEmpty()) {
VirtualChannel channel = node.getChannel();
assert channel != null;
channel.call(new JenkinsRule.RemoteLogDumper(null, loggers, false));
}
}
}

Expand Down
23 changes: 15 additions & 8 deletions src/main/java/org/jvnet/hudson/test/JenkinsRule.java
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.UncheckedIOException;
import java.lang.annotation.Annotation;
import java.lang.management.ThreadInfo;
Expand Down Expand Up @@ -1193,27 +1194,29 @@ public void showAgentLogs(Slave s, LoggerRule loggerRule) throws Exception {
* @param loggers {@link Logger#getName} tied to log level
*/
public void showAgentLogs(Slave s, Map<String, Level> loggers) throws Exception {
s.getChannel().call(new RemoteLogDumper(s.getNodeName(), loggers));
s.getChannel().call(new RemoteLogDumper(s.getNodeName(), loggers, true));
}

private static final class RemoteLogDumper extends MasterToSlaveCallable<Void, RuntimeException> {
static final class RemoteLogDumper extends MasterToSlaveCallable<Void, RuntimeException> {
private final String name;
private final Map<String, Level> loggers;
private final TaskListener stderr = StreamTaskListener.fromStderr();
private final TaskListener stderr;
private final long start = DeltaSupportLogFormatter.start;
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
private static final List<Logger> loggerReferences = new LinkedList<>();
RemoteLogDumper(String name, Map<String, Level> loggers) {
RemoteLogDumper(String name, Map<String, Level> loggers, boolean forward) {
this.name = name;
this.loggers = loggers;
stderr = forward ? StreamTaskListener.fromStderr() : null;
}
@Override public Void call() throws RuntimeException {
PrintStream ps = stderr != null ? stderr.getLogger() : System.err;
Handler handler = new Handler() {
final Formatter formatter = new DeltaSupportLogFormatter();
@Override public void publish(LogRecord record) {
if (isLoggable(record)) {
stderr.getLogger().print(formatter.format(record).replaceAll("(?m)^([ 0-9.]*)", "$1[" + name + "] "));
stderr.getLogger().flush();
ps.print(formatter.format(record).replaceAll("(?m)^([ 0-9.]*)", name != null ? "$1[" + name + "] " : "$1 "));
ps.flush();
}
}
@Override public void flush() {}
Expand All @@ -1227,8 +1230,12 @@ private static final class RemoteLogDumper extends MasterToSlaveCallable<Void, R
loggerReferences.add(logger);
});
DeltaSupportLogFormatter.start = start; // match clock time on master
stderr.getLogger().println("Set up log dumper on " + name + ": " + loggers);
stderr.getLogger().flush();
if (name != null) {
ps.println("Set up log dumper on " + name + ": " + loggers);
} else {
ps.println("Set up log dumper: " + loggers);
}
ps.flush();
return null;
}
}
Expand Down