-
Notifications
You must be signed in to change notification settings - Fork 130
[JEP-210] Log handling rewrite #27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 69 commits
c229421
754ab9e
e3ccb7b
721bc75
30d64c7
78c5fbf
875b3ed
f2f1296
141d748
19530bd
4579f77
6f1ab49
e57d7c6
7db5d9d
e4968ef
e6a58e8
f46b98c
62ccf49
51fdc25
d34d03e
aa12940
08268a3
d2a39dd
89559d5
211bd14
72d29d0
2de9add
b0c6369
0f511fa
c88e980
a0e766b
c7b8610
33e9151
a8ea094
24266f8
59ba822
2ecc99f
1c75a1c
4c8c8ab
a01addc
a86881f
18d78f3
ab259f8
976c775
216223d
c2f2a8f
46bf528
39779fc
ae2b07e
5616213
d41f02f
9c48541
4c76b65
49c91cd
096aeab
d450172
8873326
acd07c0
3474475
17a0d2a
0a39b1c
6eac61d
6f5d227
2aa0348
ae21cee
5854f54
e830112
f9325b5
46f8333
9e07b63
5623f82
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/* | ||
* 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 hudson.Extension; | ||
import hudson.MarkupText; | ||
import hudson.Util; | ||
import hudson.console.ConsoleAnnotationDescriptor; | ||
import hudson.console.ConsoleAnnotator; | ||
import hudson.console.ConsoleNote; | ||
import hudson.model.TaskListener; | ||
import java.io.IOException; | ||
import java.io.PrintStream; | ||
import java.util.Iterator; | ||
import java.util.logging.Level; | ||
import java.util.logging.Logger; | ||
import javax.annotation.CheckForNull; | ||
import javax.annotation.Nonnull; | ||
import org.jenkinsci.plugins.workflow.actions.LabelAction; | ||
import org.jenkinsci.plugins.workflow.flow.FlowExecution; | ||
import org.jenkinsci.plugins.workflow.graph.BlockEndNode; | ||
import org.jenkinsci.plugins.workflow.graph.BlockStartNode; | ||
import org.jenkinsci.plugins.workflow.graph.FlowNode; | ||
import org.jenkinsci.plugins.workflow.job.WorkflowRun; | ||
import org.jenkinsci.plugins.workflow.log.LogStorage; | ||
import org.kohsuke.accmod.Restricted; | ||
import org.kohsuke.accmod.restrictions.NoExternalUse; | ||
|
||
/** | ||
* Console line with note printed when a new {@link FlowNode} is added to the graph. | ||
* Defines the {@code pipeline-new-node} CSS class and several attributes which may be used to control subsequent behavior: | ||
* <ul> | ||
* <li>{@code nodeId} for {@link FlowNode#getId} | ||
* <li>{@code startId} {@link FlowNode#getId} for {@link BlockStartNode}, else {@link BlockEndNode#getStartNode}, else absent | ||
* <li>{@code enclosingId} the immediately enclosing {@link BlockStartNode}, if any | ||
* <li>{@code label} for {@link LabelAction} if present | ||
* </ul> | ||
* @see LogStorage#startStep | ||
*/ | ||
@Restricted(NoExternalUse.class) | ||
public class NewNodeConsoleNote extends ConsoleNote<WorkflowRun> { | ||
|
||
private static final Logger LOGGER = Logger.getLogger(NewNodeConsoleNote.class.getName()); | ||
|
||
/** | ||
* Prefix used in metadata lines. | ||
*/ | ||
private static final String CONSOLE_NOTE_PREFIX = "[Pipeline] "; | ||
|
||
public static void print(FlowNode node, TaskListener listener) { | ||
PrintStream logger = listener.getLogger(); | ||
synchronized (logger) { | ||
try { | ||
listener.annotate(new NewNodeConsoleNote(node)); | ||
} catch (IOException x) { | ||
LOGGER.log(Level.WARNING, null, x); | ||
} | ||
logger.println(CONSOLE_NOTE_PREFIX + node.getDisplayFunctionName()); // note that StepAtomNode will never have a LabelAction at this point | ||
} | ||
} | ||
|
||
private final @Nonnull String id; | ||
private final @CheckForNull String enclosing; | ||
private final @CheckForNull String start; | ||
|
||
private NewNodeConsoleNote(FlowNode node) { | ||
id = node.getId(); | ||
if (node instanceof BlockEndNode) { | ||
enclosing = null; | ||
start = ((BlockEndNode) node).getStartNode().getId(); | ||
} else { | ||
Iterator<BlockStartNode> it = node.iterateEnclosingBlocks().iterator(); | ||
enclosing = it.hasNext() ? it.next().getId() : null; | ||
start = node instanceof BlockStartNode ? node.getId() : null; | ||
} | ||
} | ||
|
||
@Override | ||
public ConsoleAnnotator<?> annotate(WorkflowRun context, MarkupText text, int charPos) { | ||
StringBuilder startTag = new StringBuilder("<span class=\"pipeline-new-node\" nodeId=\"").append(id); | ||
dwnusbaum marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (start != null) { | ||
startTag.append("\" startId=\"").append(start); | ||
} | ||
if (enclosing != null) { | ||
startTag.append("\" enclosingId=\"").append(enclosing); | ||
} | ||
FlowExecution execution = context.getExecution(); | ||
if (execution != null) { | ||
try { | ||
FlowNode node = execution.getNode(id); | ||
if (node != null) { | ||
LabelAction a = node.getAction(LabelAction.class); | ||
if (a != null) { | ||
String displayName = a.getDisplayName(); | ||
assert displayName != null; | ||
startTag.append("\" label=\"").append(Util.escape(displayName)); // TODO is there some better way to escape for attribute values? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Noting here for future review/integration that this appears to be how we propose to deal with rendering of branch labels -- however it requires rich rendering of annotation content by the UI to be useful (i.e. not visible in plaintext logs). Is that the right decision? Not sure, the mechanism seems more straightforward in some ways. Edit: note that the other approach (prefixes) also required some rendering but didn't rely on the browser JS as much. I think this one seems somewhat more sane though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, this keeps the HTML leaner and does more of the fanciness on the client side. |
||
} | ||
} | ||
} catch (IOException x) { | ||
Logger.getLogger(NewNodeConsoleNote.class.getName()).log(Level.WARNING, null, x); | ||
} | ||
} | ||
startTag.append("\">"); | ||
text.addMarkup(0, text.length(), startTag.toString(), "</span>"); | ||
return null; | ||
} | ||
|
||
private static final long serialVersionUID = 1L; | ||
|
||
@Extension public static final class DescriptorImpl extends ConsoleAnnotationDescriptor {} | ||
|
||
} |
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,7 +31,17 @@ | |
<l:task icon="images/24x24/up.png" href="${rootURL}/${it.parent.url}" title="${%Back to Project}" contextMenu="false"/> | ||
<l:task icon="images/24x24/search.png" href="${buildUrl.baseUrl}/" title="${%Status}" contextMenu="false"/> | ||
<l:task icon="images/24x24/notepad.png" href="${buildUrl.baseUrl}/changes" title="${%Changes}"/> | ||
<p:console-link/> | ||
<j:choose> <!-- TODO <p:console-link/> may not currently be used as it calls getLogFile --> | ||
<j:when test="${it.logText.length() > 200000}"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps default int approximateLogLines(@Nonnull FlowExecutionOwner.Executable build) {
return overallLog(build, false).length() / 80;
} which could be overridden by external implementations to make an API call. Of course there is the broader goal of JENKINS-17406 to use paginated display. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Specifically:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ick, well okay, I'll let you deal with what that does to the fluentd-cloudwatch logging. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Needs to be revisited when resuming work on external log sinks. I am no longer working on that. |
||
<l:task href="${buildUrl.baseUrl}/console" icon="icon-terminal icon-md" title="${%Console Output}"/> | ||
<l:task href="${buildUrl.baseUrl}/consoleText" icon="icon-document icon-md" title="${%View as plain text}"/> | ||
</j:when> | ||
<j:otherwise> | ||
<l:task icon="images/24x24/terminal.png" href="${buildUrl.baseUrl}/console" title="${%Console Output}"> | ||
<l:task href="${buildUrl.baseUrl}/consoleText" icon="icon-document icon-md" title="${%View as plain text}"/> | ||
</l:task> | ||
</j:otherwise> | ||
</j:choose> | ||
<l:task icon="images/24x24/notepad.png" href="${buildUrl.baseUrl}/configure" title="${h.hasPermission(it,it.UPDATE)?'%Edit Build Information':'%View Build Information'}"/> | ||
<st:include page="delete.jelly"/> | ||
<j:if test="${it.hasAllowTerm()}"> | ||
|
Uh oh!
There was an error while loading. Please reload this page.