Skip to content

Commit

Permalink
[JENKINS-30088] Annotate workflow metadata logs
Browse files Browse the repository at this point in the history
Originally-Committed-As: 7e2c3a0f52684f989b5c398a9ffd99739a8f7b14
  • Loading branch information
amuniz committed Sep 28, 2015
1 parent d10e6ae commit 99afbdb
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 16 deletions.
Expand Up @@ -88,6 +88,7 @@
import org.jenkinsci.plugins.workflow.graph.BlockEndNode;
import org.jenkinsci.plugins.workflow.graph.FlowEndNode;
import org.jenkinsci.plugins.workflow.graph.FlowNode;
import org.jenkinsci.plugins.workflow.job.console.WorkflowConsoleLogger;
import org.jenkinsci.plugins.workflow.steps.FlowInterruptedException;
import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.stapler.HttpResponses;
Expand Down Expand Up @@ -656,7 +657,7 @@ private final class GraphL implements GraphListener {
}
node.addAction(new TimingAction());

logNodeMessage(node, "Running: " + node.getDisplayFunctionName());
logNodeMessage(node);
if (node instanceof FlowEndNode) {
finish(((FlowEndNode) node).getResult(), execution.getCauseOfFailure());
} else {
Expand All @@ -669,19 +670,19 @@ private final class GraphL implements GraphListener {
}
}

private void logNodeMessage(FlowNode node, String message) {
PrintStream logger = listener.getLogger();
private void logNodeMessage(FlowNode node) {
WorkflowConsoleLogger wfLogger = new WorkflowConsoleLogger(listener);
String prefix = getLogPrefix(node);
if (prefix != null) {
logger.printf("[%s] %s%n", prefix, message);
wfLogger.log(String.format("[%s] %s", prefix, node.getDisplayFunctionName()));
} else {
logger.println(message);
wfLogger.log(node.getDisplayFunctionName());
}
// Flushing to keep logs printed in order as much as possible. The copyLogs method uses
// LargeText and possibly LogLinePrefixOutputFilter. Both of these buffer and flush, causing strange
// out of sequence writes to the underlying log stream (and => things being printed out of sequence)
// if we don't flush the logger here.
logger.flush();
wfLogger.getLogger().flush();
}

static void alias() {
Expand Down
@@ -0,0 +1,75 @@
/*
* The MIT License
*
* Copyright (c) 2015, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package org.jenkinsci.plugins.workflow.job.console;

import java.io.IOException;
import java.io.PrintStream;
import java.nio.charset.Charset;

import hudson.model.BuildListener;

/**
* Console logger used to write workflow related metadata in console text.
*
* It wraps the regular {@link BuildListener} to add a filter that annotates any text line sent to the console through
* this logger. It also adds a prefix to the line ([Workflow]).
*
* Annotated lines will be rendered in a lighter color so they do not interefere with the important part of the log.
*/
public class WorkflowConsoleLogger {

private final BuildListener listener;
private final WorkflowMetadataConsoleFilter annotator;

public WorkflowConsoleLogger(BuildListener listener) {
this.listener = listener;
this.annotator = new WorkflowMetadataConsoleFilter(listener.getLogger());
}

/**
* Provides access to the wrapped listener logger.
* @return the logger print stream
*/
public PrintStream getLogger() {
return listener.getLogger();
}

/**
* Sends an annotated log message to the console after adding the prefix [Workflow].
* @param message the message to wrap and annotate.
*/
public void log(String message) {
logAnnot(WorkflowRunConsoleNote.CONSOLE_NOTE_PREFIX, message);
}

private void logAnnot(String prefix, String message) {
byte[] msg = String.format("%s%s%n", prefix, message).getBytes(Charset.defaultCharset());
try {
annotator.eol(msg, msg.length);
} catch (IOException e) {
listener.getLogger().println("Problem with writing into console log: " + e.getMessage());
}
}
}
@@ -0,0 +1,55 @@
/*
* The MIT License
*
* Copyright (c) 2015, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package org.jenkinsci.plugins.workflow.job.console;

import java.io.IOException;
import java.io.OutputStream;

import hudson.console.LineTransformationOutputStream;

/**
* It transforms workflow metadata log messages through {@link WorkflowRunConsoleNote}.
*/
public class WorkflowMetadataConsoleFilter extends LineTransformationOutputStream {

private final OutputStream out;

public WorkflowMetadataConsoleFilter(OutputStream out) {
this.out = out;
}

@Override
protected void eol(byte[] b, int len) throws IOException {
new WorkflowRunConsoleNote().encodeTo(out);
out.write(b, 0, len);
}

@Override
public void close() throws IOException {
super.close();
out.close();
}

}
@@ -1,31 +1,62 @@
/*
* The MIT License
*
* Copyright (c) 2015, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package org.jenkinsci.plugins.workflow.job.console;

import org.jenkinsci.plugins.workflow.job.WorkflowRun;

import hudson.Extension;
import hudson.MarkupText;
import hudson.console.ConsoleAnnotationDescriptor;
import hudson.console.ConsoleAnnotator;
import hudson.console.ConsoleNote;
import hudson.model.Run;

/**
* Console note for Workflow metadata specific messages.
* See {@link WorkflowConsoleLogger} for more information.
*/
public class WorkflowRunConsoleNote extends ConsoleNote<Run<?, ?>> {

/**
* Prefix used in metadata lines.
*/
public static final String CONSOLE_NOTE_PREFIX = "[Workflow] ";

/**
* CSS color selector.
*/
private static final String TEXT_COLOR = "9A9999";

@Override
public ConsoleAnnotator<Run<?,?>> annotate(Run<?, ?> context, MarkupText text, int charPos) {
if (context instanceof WorkflowRun) {
// TODO
if (text.getText().startsWith(CONSOLE_NOTE_PREFIX)) {
text.addMarkup(0, text.length(), "<span style=\"color:#"+ TEXT_COLOR +"\">", "</span>");
}
}
return null;
}

@Extension
public static final class DescriptorImpl extends ConsoleAnnotationDescriptor {
public String getDisplayName() {
return "Workflow Console Note";
}
}

private static final long serialVersionUID = 1L;

}

0 comments on commit 99afbdb

Please sign in to comment.