Skip to content
This repository was archived by the owner on May 14, 2025. It is now read-only.

Commit 5694390

Browse files
oodamienilayaperumalg
authored andcommitted
Stream logs & Task Execution Logs
Stream Summary: add log section when the stream is running Task Execution: add log section after execution done Resolves #1230 #1231
1 parent 91de174 commit 5694390

File tree

11 files changed

+197
-26
lines changed

11 files changed

+197
-26
lines changed

ui/src/app/streams/stream/styles.scss

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,14 @@ table.table {
4545
width: auto;
4646
}
4747
}
48+
49+
.log-toolbar {
50+
padding-bottom: 10px;
51+
.dropdown {
52+
display: inline;
53+
margin-right: 4px;
54+
ul li a {
55+
cursor: pointer;
56+
}
57+
}
58+
}

ui/src/app/streams/stream/summary/stream-summary.component.html

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,36 @@
100100
</tbody>
101101
</table>
102102
</div>
103+
104+
<div class="row stream-summary-row">
105+
<div class="col-md-3">
106+
<strong>Logs:</strong>
107+
</div>
108+
<div class="col-md-21">
109+
<div class="log-toolbar">
110+
<div dropdown class="dropdown">
111+
<a class="btn btn-default btn-dropdown" dropdownToggle>
112+
<strong>{{ stream.logs[logSelectedIndex].id }}</strong>
113+
<span class="caret"></span>
114+
</a>
115+
<ul class="dropdown-menu" *dropdownMenu="">
116+
<ng-template ngFor let-runtimeApp [ngForOf]="stream.runtimes" let-i="index">
117+
<li [class.active]="stream.logs[logSelectedIndex].id === runtimeApp.id">
118+
<a (click)="changeLog(i)">{{ runtimeApp.id }}</a>
119+
</li>
120+
</ng-template>
121+
</ul>
122+
</div>
123+
<button type="button" class="btn btn-primary" (click)="refresh()">
124+
Refresh
125+
</button>
126+
</div>
127+
<div class="pui-log" *ngIf="stream.logs[logSelectedIndex].log">
128+
<pre><code>{{ stream.logs[logSelectedIndex].log }}</code></pre>
129+
</div>
130+
</div>
131+
</div>
132+
103133
</div>
104134

105135
</div>

ui/src/app/streams/stream/summary/stream-summary.component.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ export class StreamSummaryComponent implements OnInit {
3131
*/
3232
modal: BsModalRef;
3333

34+
/**
35+
* Log Selected
36+
*/
37+
logSelectedIndex = 0;
38+
3439
/**
3540
* Constructor
3641
*
@@ -77,12 +82,43 @@ export class StreamSummaryComponent implements OnInit {
7782
}
7883
}
7984
))
85+
.pipe(mergeMap(
86+
(val: any) => {
87+
if (val.runtimes.length > 0) {
88+
return this.streamsService.getLogs(val.streamDefinition)
89+
.pipe(map((logs) => {
90+
return {
91+
streamDefinition: val.streamDefinition,
92+
runtimes: val.runtimes,
93+
logs: val.runtimes.map(runtime => {
94+
let log = '';
95+
if (logs && logs.hasOwnProperty('logs')) {
96+
log = logs.logs[runtime.id] ? logs.logs[runtime.id] : '';
97+
}
98+
return {
99+
id: runtime.id,
100+
log: log
101+
};
102+
})
103+
};
104+
}));
105+
} else {
106+
return of({
107+
streamDefinition: val.streamDefinition,
108+
runtimes: val.runtimes,
109+
logs: []
110+
});
111+
}
112+
113+
}
114+
))
80115
.pipe(mergeMap(
81116
(val: any) => of(Parser.parse(val.streamDefinition.dslText as string, 'stream'))
82117
.pipe(map((val2) => {
83118
return {
84119
streamDefinition: val.streamDefinition,
85120
runtimes: val.runtimes,
121+
logs: val.logs,
86122
apps: val2.lines[0].nodes
87123
.map((node) => ({
88124
origin: node['name'],
@@ -95,6 +131,10 @@ export class StreamSummaryComponent implements OnInit {
95131
);
96132
}
97133

134+
changeLog(index) {
135+
this.logSelectedIndex = index;
136+
}
137+
98138
/**
99139
* Determine show deployment info
100140
*

ui/src/app/streams/streams.service.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,4 +313,18 @@ export class StreamsService {
313313
);
314314
}
315315

316+
/**
317+
* Get stream logs
318+
* @param {StreamDefinition} stream
319+
* @returns {Observable<HttpResponse<any>>}
320+
*/
321+
getLogs(stream: StreamDefinition): Observable<any> {
322+
const httpHeaders = HttpUtils.getDefaultHttpHeaders();
323+
return this.httpClient
324+
.get<any>(`/streams/logs/${stream.name}`, { headers: httpHeaders })
325+
.pipe(
326+
catchError(this.errorHandler.handleError)
327+
);
328+
}
329+
316330
}

ui/src/app/tasks/model/task-execution.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export class TaskExecution {
1313
public jobExecutionIds: number[];
1414
public errorMessage: string;
1515
public externalExecutionId: string;
16+
public taskExecutionStatus: string;
1617

1718
constructor(executionId: number,
1819
exitCode: number,
@@ -23,7 +24,8 @@ export class TaskExecution {
2324
args: string[], // arguments would be restricted name
2425
jobExecutionIds: number[],
2526
errorMessage: string,
26-
externalExecutionId: string) {
27+
externalExecutionId: string,
28+
taskExecutionStatus: string) {
2729
this.executionId = executionId;
2830
this.exitCode = exitCode;
2931
this.taskName = taskName;
@@ -33,6 +35,7 @@ export class TaskExecution {
3335
this.arguments = args;
3436
this.jobExecutionIds = jobExecutionIds;
3537
this.errorMessage = errorMessage;
38+
this.taskExecutionStatus = taskExecutionStatus;
3639
this.externalExecutionId = externalExecutionId;
3740
}
3841

@@ -47,7 +50,8 @@ export class TaskExecution {
4750
jsonItem.arguments,
4851
jsonItem.jobExecutionIds,
4952
jsonItem.errorMessage,
50-
jsonItem.externalExecutionId);
53+
jsonItem.externalExecutionId,
54+
jsonItem.taskExecutionStatus);
5155
}
5256

5357
static pageFromJSON(input): Page<TaskExecution> {

ui/src/app/tasks/task-execution/task-execution.component.html

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
<app-page *ngIf="taskExecution$ | async as taskExecution; else loading">
1+
<app-page *ngIf="taskExecution$ | async as task; else loading">
22

33
<app-page-head>
44
<app-page-head-back [defaultUrl]="'/tasks/executions'"
55
[isNotRegex]="'^(\/tasks\/executions\/)'"></app-page-head-back>
66
<app-page-head-title>
7-
Task Execution Details - <strong>Execution ID: {{ taskExecution.executionId }}</strong>
7+
Task Execution Details - <strong>Execution ID: {{ task.task.executionId }}</strong>
88
</app-page-head-title>
99
<app-page-head-actions>
1010

1111
<button name="task-view" type="button" id="task-view"
12-
(click)="detailsTask(taskExecution.taskName)" class="btn btn-primary btn-fa" title="View details task">
12+
(click)="detailsTask(task.task.taskName)" class="btn btn-primary btn-fa" title="View details task">
1313
<span class="fa fa-info-circle"></span>
1414
View task details
1515
</button>
1616
<button name="task-launch" type="button" id="task-launch"
17-
(click)="launch(taskExecution.taskName)" class="btn btn-primary btn-fa" title="Relaunch the task"
17+
(click)="launch(task.task.taskName)" class="btn btn-primary btn-fa" title="Relaunch the task"
1818
[dataflowAppRoles]="['ROLE_CREATE']">
1919
<span class="fa fa-play"></span>
2020
Relaunch task
@@ -23,7 +23,7 @@
2323
</app-page-head>
2424

2525
<div dataflowLayoutType type="large">
26-
<table *ngIf="taskExecution" class="table table-hover">
26+
<table *ngIf="task.task" class="table table-hover">
2727
<thead>
2828
<tr>
2929
<th style="width: 200px">Property</th>
@@ -33,73 +33,81 @@
3333
<tbody>
3434
<tr>
3535
<td>Execution Id</td>
36-
<td>{{ taskExecution.executionId }}</td>
36+
<td>{{ task.task.executionId }}</td>
3737
</tr>
3838
<tr>
3939
<td>Task Name</td>
4040
<td>
41-
<a [routerLink]="'/tasks/definitions/' + taskExecution.taskName">{{ taskExecution.taskName }}</a>
41+
<a [routerLink]="'/tasks/definitions/' + task.task.taskName">{{ task.task.taskName }}</a>
4242
</td>
4343
</tr>
4444
<tr>
4545
<td>Arguments</td>
4646
<td>
47-
<div *ngIf="taskExecution.arguments">
48-
<div *ngFor="let arg of getArguments(taskExecution.arguments)">
47+
<div *ngIf="task.task.arguments">
48+
<div *ngFor="let arg of getArguments(task.task.arguments)">
4949
{{ arg[0] }}:
5050
<strong>{{ arg[1] }}</strong>
5151
</div>
5252
</div>
53-
<div *ngIf="!taskExecution.arguments">
53+
<div *ngIf="!task.task.arguments">
5454
N/A
5555
</div>
5656
</td>
5757
</tr>
5858
<tr>
5959
<td>External Execution Id</td>
60-
<td>{{ taskExecution.externalExecutionId || 'N/A' }}</td>
60+
<td>{{ task.task.externalExecutionId || 'N/A' }}</td>
6161
</tr>
6262
<tr>
6363
<td>Batch Job</td>
6464
<td>
65-
<span *ngIf="taskExecution.jobExecutionIds.length > 0" class="glyphicon glyphicon-ok text-info"></span>
66-
<span *ngIf="taskExecution.jobExecutionIds.length == 0" class="glyphicon glyphicon-remove text-danger"></span>
65+
<span *ngIf="task.task.jobExecutionIds.length > 0" class="glyphicon glyphicon-ok text-info"></span>
66+
<span *ngIf="task.task.jobExecutionIds.length == 0" class="glyphicon glyphicon-remove text-danger"></span>
6767
</td>
6868
</tr>
6969
<tr>
7070
<td>Job Execution Ids</td>
71-
<td *ngIf="taskExecution.jobExecutionIds.length > 0" id="jobExecutionIds">
71+
<td *ngIf="task.task.jobExecutionIds.length > 0" id="jobExecutionIds">
7272
<a [routerLink]="'/jobs/executions/' + jobExecutionId"
73-
*ngFor="let jobExecutionId of taskExecution.jobExecutionIds">
73+
*ngFor="let jobExecutionId of task.task.jobExecutionIds">
7474
{{ jobExecutionId }}
7575
</a>
7676
</td>
77-
<td *ngIf="taskExecution.jobExecutionIds.length == 0">
77+
<td *ngIf="task.task.jobExecutionIds.length == 0">
7878
N/A
7979
</td>
8080
</tr>
8181
<tr>
8282
<td>Start Time</td>
83-
<td>{{ taskExecution.startTime | dataflowDateTime }}</td>
83+
<td>{{ task.task.startTime | dataflowDateTime }}</td>
8484
</tr>
8585
<tr>
8686
<td>End Time</td>
87-
<td>{{ taskExecution.endTime | dataflowDateTime }}</td>
87+
<td>{{ task.task.endTime | dataflowDateTime }}</td>
8888
</tr>
8989
<tr>
9090
<td>Duration</td>
91-
<td>{{ taskExecution.startTime | dataflowDuration: taskExecution.endTime }}</td>
91+
<td>{{ task.task.startTime | dataflowDuration: task.task.endTime }}</td>
9292
</tr>
9393
<tr>
9494
<td>Exit Code</td>
95-
<td>{{ taskExecution.exitCode }}</td>
95+
<td>{{ task.task.exitCode }}</td>
9696
</tr>
9797
<tr>
9898
<td>Exit Message</td>
99-
<td>{{ taskExecution.exitMessage || 'N/A' }}</td>
99+
<td>{{ task.task.exitMessage || 'N/A' }}</td>
100100
</tr>
101101
</tbody>
102102
</table>
103+
104+
<div *ngIf="task.logs">
105+
<h2 style="padding-bottom: 12px;">Logs</h2>
106+
<div class="pui-log">
107+
<pre><code>{{ task.logs }}</code></pre>
108+
</div>
109+
</div>
110+
103111
</div>
104112
</app-page>
105113
<ng-template #loading>

ui/src/app/tasks/task-execution/task-execution.component.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { Component, OnInit } from '@angular/core';
22
import { TaskExecution } from '../model/task-execution';
33
import { ActivatedRoute, Router } from '@angular/router';
44
import { TasksService } from '../tasks.service';
5-
import { catchError, mergeMap } from 'rxjs/operators';
6-
import { Observable, EMPTY } from 'rxjs';
5+
import { catchError, map, mergeMap } from 'rxjs/operators';
6+
import { Observable, EMPTY, of } from 'rxjs';
77
import { RoutingStateService } from '../../shared/services/routing-state.service';
88
import { NotificationService } from '../../shared/services/notification.service';
99
import { AppError, HttpAppError } from '../../shared/model/error.model';
@@ -24,7 +24,7 @@ export class TaskExecutionComponent implements OnInit {
2424
/**
2525
* Observable of Task Execution
2626
*/
27-
taskExecution$: Observable<TaskExecution>;
27+
taskExecution$: Observable<any>;
2828

2929
/**
3030
* Constructor
@@ -52,6 +52,25 @@ export class TaskExecutionComponent implements OnInit {
5252
mergeMap(
5353
(val) => this.tasksService.getExecution(val.id)
5454
),
55+
mergeMap(
56+
(val) => {
57+
if (val.taskExecutionStatus === 'COMPLETE' || val.taskExecutionStatus === 'ERROR') {
58+
return this.tasksService.getTaskExecutionLogs(val).pipe(
59+
map(logs => {
60+
return {
61+
task: val,
62+
logs: logs
63+
};
64+
})
65+
);
66+
} else {
67+
return of({
68+
task: val,
69+
logs: null
70+
});
71+
}
72+
}
73+
),
5574
catchError(error => {
5675
if (HttpAppError.is404(error) || HttpAppError.is400(error)) {
5776
this.cancel();

ui/src/app/tasks/tasks.service.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
import { HttpResponse } from '@angular/common/http';
1717
import { Platform, PlatformTask } from '../shared/model/platform';
1818
import { DataflowEncoder } from '../shared/support/encoder.utils';
19+
import { StreamDefinition } from '../streams/model/stream-definition';
1920

2021
/**
2122
* Provides {@link TaskDefinition} related services.
@@ -375,4 +376,18 @@ export class TasksService {
375376
);
376377
}
377378

379+
/**
380+
* Get task execution logs
381+
* @param {TaskExecution} taskExecution
382+
* @returns {Observable<HttpResponse<any>>}
383+
*/
384+
getTaskExecutionLogs(taskExecution: TaskExecution): Observable<any> {
385+
const httpHeaders = HttpUtils.getDefaultHttpHeaders();
386+
return this.httpClient
387+
.get<any>(`/tasks/logs/${taskExecution.externalExecutionId}`, { headers: httpHeaders })
388+
.pipe(
389+
catchError(this.errorHandler.handleError)
390+
);
391+
}
392+
378393
}

ui/src/app/tests/mocks/streams.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,8 @@ export class MockStreamsService {
9595
return of([]);
9696
}
9797

98+
getLogs(stream: StreamDefinition): Observable<any> {
99+
return of([]);
100+
}
101+
98102
}

ui/src/app/tests/mocks/tasks.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,8 @@ export class MockTasksService {
122122
return of({});
123123
}
124124

125+
getTaskExecutionLogs(taskExecution: TaskExecution): Observable<any> {
126+
return of('');
127+
}
128+
125129
}

0 commit comments

Comments
 (0)