Skip to content

Commit

Permalink
Logs UI (#1528)
Browse files Browse the repository at this point in the history
  • Loading branch information
Senyoret1 authored Apr 15, 2023
1 parent 20bf07e commit 0106d9e
Show file tree
Hide file tree
Showing 11 changed files with 664 additions and 2 deletions.
2 changes: 2 additions & 0 deletions static/skywire-manager-src/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ import { VpnDnsConfigComponent } from './components/vpn/layout/vpn-dns-config/vp
import { RewardsAddressComponent } from './components/pages/node/node-info/node-info-content/rewards-address-config/rewards-address-config.component';
import { BulkRewardAddressChangerComponent } from './components/layout/bulk-reward-address-changer/bulk-reward-address-changer.component';
import { UserAppSettingsComponent } from './components/pages/node/apps/node-apps/user-app-settings/user-app-settings.component';
import { NodeLogsComponent } from './components/pages/node/actions/node-logs/node-logs.component';

const globalRippleConfig: RippleGlobalOptions = {
disabled: true,
Expand Down Expand Up @@ -176,6 +177,7 @@ const globalRippleConfig: RippleGlobalOptions = {
RewardsAddressComponent,
BulkRewardAddressChangerComponent,
UserAppSettingsComponent,
NodeLogsComponent,
],
imports: [
BrowserModule,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { processServiceError } from 'src/app/utils/errors';
import { SelectableOption, SelectOptionComponent } from 'src/app/components/layout/select-option/select-option.component';
import { MenuOptionData } from 'src/app/components/layout/top-bar/top-bar.component';
import { StorageService } from 'src/app/services/storage.service';
import { NodeLogsComponent } from './node-logs/node-logs.component';

/**
* Helper object for managing the options shown in the menu while in the node details page.
Expand Down Expand Up @@ -134,7 +135,7 @@ export class NodeActionsHelper {
} else if (actionName === 'update') {
this.update();
} else if (actionName === 'logs') {
window.open(window.location.origin + '/api/visors/' + nodePk + '/runtime-logs', '_blank');
this.runtimeLogs();
} else if (actionName === 'reboot') {
this.reboot();
} else if (actionName === null) {
Expand Down Expand Up @@ -220,6 +221,13 @@ export class NodeActionsHelper {
window.open(protocol + '//' + hostname + '/pty/' + this.currentNodeKey, '_blank', 'noopener noreferrer');
}

/**
* Opens the modal window for checking the runtime logs of a node.
*/
runtimeLogs() {
NodeLogsComponent.openDialog(this.dialog);
}

back() {
if (!this.showingFullList) {
this.router.navigate(['nodes']);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<app-dialog [headline]="'node.logs.title' | translate" [includeVerticalMargins]="false" [includeScrollableArea]="false" [dialog]="dialogRef">
<!-- Filter button. -->
<div *ngIf="!loading && logEntries && logEntries.length > 0" class="filter-area" (click)="showFilters()">
<div class="filter-content">
<div>
<span>{{ 'node.logs.selected-filter' | translate }} </span>
<span class="actual-value">{{ ('node.logs.' + levelDetails.get(currentMinimumLevel).levelFilterName) | translate }}</span>
</div>
<div *ngIf="logEntries.length > filteredLogEntries.length" class="small">
{{ 'node.logs.filter-ignored' | translate:{number: logEntries.length - filteredLogEntries.length} }}
</div>
</div>
<div class="filter-margin"></div>
</div>

<mat-dialog-content #content>
<!-- Link for opening all the logs, if there are too much for the modal window. -->
<div *ngIf="!loading && hasMoreLogMessages" class="log-entry">
<a [href]="getFullLogsUrl()" target="_blank" class="view-raw-link">
{{ 'node.logs.view-rest' | translate:{number: totalLogs} }}
</a>
</div>

<!-- All entries. -->
<ng-container *ngIf="!loading">
<div *ngFor="let entry of filteredLogEntries" class="log-entry">
<!-- Basic fields. -->
<span class="transparent">
{{ entry.time }}
</span>
<span [class]="levelDetails.get(entry.level).colorClass">
{{ levelDetails.get(entry.level).name }}
</span>
[
<span class="transparent">
{{ entry.func }}
</span>
<span class="module-color">
{{ entry._module }}
</span>
]<ng-container *ngIf="entry.msg">:</ng-container>
<span *ngIf="entry.msg">
{{ entry.msg }}
</span>

<!-- Extra fields. -->
<ng-container *ngFor="let extra of entry.extra">
<span class="extra-data-color">
{{ extra.name }}
</span>
<span>
="{{ extra.value }}"
</span>
</ng-container>
</div>
</ng-container>

<!-- Link for opening all the logs. -->
<div *ngIf="!loading && logEntries && logEntries.length > 0" class="log-entry">
<a [href]="getFullLogsUrl()" target="_blank" class="view-raw-link">
<ng-container *ngIf="!hasMoreLogMessages">
{{ 'node.logs.view-all' | translate }}
</ng-container>
<ng-container *ngIf="hasMoreLogMessages">
{{ 'node.logs.view-rest' | translate:{number: totalLogs} }}
</ng-container>
</a>
</div>

<!-- Msg if there are no logs. -->
<div class="log-empty-msg" *ngIf="!loading && (!logEntries || logEntries.length === 0)">
{{ 'node.logs.no-logs' | translate }}
</div>
<!-- Msg if there are no logs with the current filter. -->
<div class="log-empty-msg" *ngIf="!loading && logEntries && logEntries.length > 0 && filteredLogEntries.length < 1">
{{ 'node.logs.no-logs-for-filter' | translate }}
</div>
<!-- Loading animation. -->
<app-loading-indicator [showWhite]="false" *ngIf="loading"></app-loading-indicator>

<!-- Update button. -->
<div class="update-button subtle-transparent-button" (click)="loadData(0)">
<div *ngIf="!loading" class="update-time">
<mat-icon *ngIf="!showAlert" class="icon" [inline]="true">refresh</mat-icon>
<span>{{ ('refresh-button.' + elapsedTime.translationVarName) | translate:{time: elapsedTime.elapsedTime} }}</span>
</div>
</div>
</mat-dialog-content>
</app-dialog>

Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
@import "variables";

.filter-area {
margin-left: -$mat-dialog-padding;
margin-right: -$mat-dialog-padding;
font-size: $font-size-smaller;
color: $light-gray;
background-color: #d9deeb;
cursor: pointer;

&:hover {
background-color: darken(#d9deeb, 3%);
}

.filter-content {
padding: 10px $mat-dialog-padding;
text-align: center;

.actual-value {
color: $black;
}

.small {
font-size: $font-size-mini-plus;
}
}

.filter-margin {
height: 1px;
background-color: $modal-separator;
margin: 0 12px;
}
}

.log-entry {
margin-top: 15px;
word-break: break-word;

.transparent {
color: $lighter-gray;
}
}

.log-entry:first-of-type {
margin-top: 0px;
}

.log-entry:last-of-type {
margin-bottom: $mat-dialog-padding;
}

.log-empty-msg {
text-align: center;
}

.view-raw-link {
color: $blue-medium;
}

.update-button {
display: flex;
justify-content: center;
cursor: pointer;

mat-icon {
position: relative;
top: 5px;
margin-right: 5px;
}

.update-time {
text-align: center;
font-size: $font-size-mini;
color: $black;
margin: 0 5px;
}
}

.panic-level-color {
color: #ff0000;
}

.fatal-level-color {
color: #ff0000;
}

.error-level-color {
color: #d10000;
}

.warning-level-color {
color: #e27505;
}

.info-level-color {
color: #0d9519;
}

.debug-level-color {
color: #0065ff;
}

.trace-level-color {
color: #468cf5;
}

.unknown-level-color {
color: #e27505;
}

.module-color {
color: #a119fc;
}

.extra-data-color {
color: #ad8021;
}
Loading

0 comments on commit 0106d9e

Please sign in to comment.