@@ -27,6 +27,8 @@ public class PipelineConsoleViewAction extends AbstractPipelineViewAction {
27
27
private final WorkflowRun target ;
28
28
private final PipelineStepApi stepApi ;
29
29
30
+ private static final ObjectMapper MAPPER = new ObjectMapper ();
31
+
30
32
public PipelineConsoleViewAction (WorkflowRun target ) {
31
33
super (target );
32
34
this .target = target ;
@@ -55,35 +57,41 @@ public String getIconClassName() {
55
57
public HttpResponse getSteps (StaplerRequest req ) throws IOException {
56
58
String nodeId = req .getParameter ("nodeId" );
57
59
if (nodeId != null ) {
58
- logger .debug ("getSteps was passed nodeId '" + nodeId + "'." );
59
- ObjectMapper mapper = new ObjectMapper ();
60
- PipelineStepList steps = stepApi .getSteps (nodeId );
61
- String stepsJson = mapper .writeValueAsString (steps );
62
- if (logger .isDebugEnabled ()) {
63
- logger .debug ("Steps: '" + stepsJson + "'." );
64
- }
65
- return HttpResponses .okJSON (JSONObject .fromObject (stepsJson ));
60
+ return HttpResponses .okJSON (getSteps (nodeId ));
66
61
} else {
67
62
return HttpResponses .errorJSON ("Error getting console text" );
68
63
}
69
64
}
70
65
66
+ private JSONObject getSteps (String nodeId ) throws IOException {
67
+ logger .debug ("getSteps was passed nodeId '" + nodeId + "'." );
68
+ PipelineStepList steps = stepApi .getSteps (nodeId );
69
+ String stepsJson = MAPPER .writeValueAsString (steps );
70
+ if (logger .isDebugEnabled ()) {
71
+ logger .debug ("Steps: '" + stepsJson + "'." );
72
+ }
73
+ return JSONObject .fromObject (stepsJson );
74
+ }
71
75
// Return all steps to:
72
76
// - reduce number of API calls
73
77
// - remove dependency of getting list of stages in frontend.
74
78
@ GET
75
79
@ WebMethod (name = "allSteps" )
76
80
public HttpResponse getAllSteps (StaplerRequest req ) throws IOException {
77
- ObjectMapper mapper = new ObjectMapper ();
81
+ return HttpResponses .okJSON (getAllSteps ());
82
+ }
83
+
84
+ // Private method for testing.
85
+ protected JSONObject getAllSteps () throws IOException {
78
86
PipelineStepList steps = stepApi .getAllSteps ();
79
- String stepsJson = mapper .writeValueAsString (steps );
87
+ String stepsJson = MAPPER .writeValueAsString (steps );
80
88
if (logger .isDebugEnabled ()) {
81
89
logger .debug ("Steps: '" + stepsJson + "'." );
82
90
}
83
- return HttpResponses . okJSON ( JSONObject .fromObject (stepsJson ) );
91
+ return JSONObject .fromObject (stepsJson );
84
92
}
85
93
86
- /* Get pre-parsed console output in json format.
94
+ /*
87
95
* The default behavior of this functions differs from 'getConsoleOutput' in that it will use LOG_THRESHOLD from the end of the string.
88
96
* Note: if 'startByte' is negative and falls outside of the console text then we will start from byte 0.
89
97
* Example:
@@ -102,10 +110,22 @@ public HttpResponse getConsoleOutput(StaplerRequest req) throws IOException {
102
110
return HttpResponses .errorJSON ("Error getting console json" );
103
111
}
104
112
logger .debug ("getConsoleOutput was passed node id '" + nodeId + "'." );
113
+ // This will be a step, so return it's log output.
114
+ // startByte to start getting data from. If negative will startByte from end of string with
115
+ // LOG_THRESHOLD.
116
+ Long startByte = parseIntWithDefault (req .getParameter ("startByte" ), -LOG_THRESHOLD );
117
+ JSONObject data = getConsoleOutputJson (nodeId , startByte );
118
+ if (data == null ) {
119
+ return HttpResponses .errorJSON ("Something went wrong - check Jenkins logs." );
120
+ }
121
+ return HttpResponses .okJSON (data );
122
+ }
105
123
124
+ protected JSONObject getConsoleOutputJson (String nodeId , Long requestStartByte )
125
+ throws IOException {
106
126
Long startByte = 0L ;
107
127
long endByte = 0L ;
108
- long textLength = 0L ;
128
+ long textLength ;
109
129
String text = "" ;
110
130
// If this is an exception, return the exception text (inc. stacktrace).
111
131
if (isUnhandledException (nodeId )) {
@@ -114,57 +134,47 @@ public HttpResponse getConsoleOutput(StaplerRequest req) throws IOException {
114
134
text = getNodeExceptionText (nodeId );
115
135
endByte = text .length ();
116
136
} else {
117
- // This will be a step, so return it's log output.
118
- // startByte to start getting data from. If negative will startByte from end of string with
119
- // LOG_THRESHOLD.
120
- startByte = parseIntWithDefault (req .getParameter ("startByte" ), -LOG_THRESHOLD );
121
-
122
137
AnnotatedLargeText <? extends FlowNode > logText = getLogForNode (nodeId );
123
138
124
139
if (logText != null ) {
125
140
textLength = logText .length ();
126
141
// postitive startByte
127
- if (startByte > textLength ) {
142
+ if (requestStartByte > textLength ) {
128
143
// Avoid resource leak.
129
144
logger .error ("consoleJson - user requested startByte larger than console output." );
130
- return HttpResponses . errorJSON ( "startByte too large." ) ;
145
+ return null ;
131
146
}
132
147
// if startByte is negative make sure we don't try and get a byte before 0.
133
- if (startByte < 0 ) {
134
- logger .debug (
135
- "consoleJson - requested negative startByte '" + Long .toString (startByte ) + "'." );
136
- startByte = textLength + startByte ;
137
- if (startByte < 0 ) {
148
+ if (requestStartByte < 0L ) {
149
+ logger .debug ("consoleJson - requested negative startByte '" + requestStartByte + "'." );
150
+ startByte = textLength + requestStartByte ;
151
+ if (startByte < 0L ) {
138
152
logger .debug (
139
153
"consoleJson - requested negative startByte '"
140
- + Long . toString ( startByte )
141
- + "' out of bounds, setting to 0." );
154
+ + requestStartByte
155
+ + "' out of bounds, starting at 0." );
142
156
startByte = 0L ;
143
157
}
158
+ } else {
159
+ startByte = requestStartByte ;
144
160
}
145
-
146
- logger .debug (
147
- "Returning '"
148
- + Long .toString (textLength - startByte )
149
- + "' bytes from 'getConsoleOutput'." );
150
- } else {
151
- // If there is no text then set set startByte to 0 - as we have read from the start, there
152
- // is just nothing there.
153
- startByte = 0L ;
161
+ logger .debug ("Returning '" + (textLength - startByte ) + "' bytes from 'getConsoleOutput'." );
162
+ text = PipelineNodeUtil .convertLogToString (logText , startByte );
163
+ endByte = textLength ;
154
164
}
155
165
}
156
- HashMap <String , Object > response = new HashMap <String , Object >();
166
+ HashMap <String , Object > response = new HashMap <>();
157
167
response .put ("text" , text );
158
168
response .put ("startByte" , startByte );
159
169
response .put ("endByte" , endByte );
160
- return HttpResponses . okJSON ( JSONObject .fromObject (response ) );
170
+ return JSONObject .fromObject (response );
161
171
}
162
172
163
173
private AnnotatedLargeText <? extends FlowNode > getLogForNode (String nodeId ) throws IOException {
164
174
FlowExecution execution = target .getExecution ();
165
175
if (execution != null ) {
166
176
logger .debug ("getLogForNode found execution." );
167
- PipelineNodeUtil .getLogText (execution .getNode (nodeId ));
177
+ return PipelineNodeUtil .getLogText (execution .getNode (nodeId ));
168
178
}
169
179
return null ;
170
180
}
@@ -186,13 +196,13 @@ private boolean isUnhandledException(String nodeId) throws IOException {
186
196
return false ;
187
197
}
188
198
189
- private static long parseIntWithDefault (String s , long default_value ) {
199
+ private static long parseIntWithDefault (String s , long defaultValue ) {
190
200
try {
191
201
logger .debug ("Parsing user provided value of '" + s + "'" );
192
202
return Long .parseLong (s );
193
203
} catch (NumberFormatException e ) {
194
- logger .debug ("Using default value of '" + default_value + "'" );
195
- return default_value ;
204
+ logger .debug ("Using default value of '" + defaultValue + "'" );
205
+ return defaultValue ;
196
206
}
197
207
}
198
208
}
0 commit comments