Added new Logs component and created a cluster->logs menu item. Moved the logs from the dashboard home page to the dedicated logs page.Additional comments resolved.Dropped Logs from health component.
Fixes: https://tracker.ceph.com/issues/24571
Signed-off-by: Diksha Godbole <diksha.godbole@gmail.com>
import { ConfigurationComponent } from './ceph/cluster/configuration/configuration.component';
import { CrushmapComponent } from './ceph/cluster/crushmap/crushmap.component';
import { HostsComponent } from './ceph/cluster/hosts/hosts.component';
+import { LogsComponent } from './ceph/cluster/logs/logs.component';
import { MonitorComponent } from './ceph/cluster/monitor/monitor.component';
import { OsdListComponent } from './ceph/cluster/osd/osd-list/osd-list.component';
import { DashboardComponent } from './ceph/dashboard/dashboard/dashboard.component';
canActivate: [AuthGuardService],
data: { breadcrumbs: 'Cluster/CRUSH map' }
},
+ {
+ path: 'logs',
+ component: LogsComponent,
+ canActivate: [AuthGuardService],
+ data: { breadcrumbs: 'Cluster/Logs' }
+ },
{
path: 'perf_counters/:type/:id',
component: PerformanceCounterComponent,
import { CrushmapComponent } from './crushmap/crushmap.component';
import { HostDetailsComponent } from './hosts/host-details/host-details.component';
import { HostsComponent } from './hosts/hosts.component';
+import { LogsComponent } from './logs/logs.component';
import { MonitorComponent } from './monitor/monitor.component';
import { OsdDetailsComponent } from './osd/osd-details/osd-details.component';
import { OsdFlagsModalComponent } from './osd/osd-flags-modal/osd-flags-modal.component';
ConfigurationDetailsComponent,
ConfigurationFormComponent,
OsdReweightModalComponent,
- CrushmapComponent
+ CrushmapComponent,
+ LogsComponent
]
})
export class ClusterModule {}
--- /dev/null
+<div *ngIf="contentData">
+<tabset>
+ <tab i18n-heading
+ heading="Cluster Logs">
+ <div class="well">
+ <div *ngIf="contentData.clog">
+ <p *ngFor="let line of contentData.clog">
+ {{ line.stamp }} {{ line.priority }}
+ <span [ngStyle]="line">
+ {{ line.message }}
+ <br>
+ </span>
+ </p>
+ </div>
+ </div>
+ </tab>
+
+ <tab i18n-heading
+ heading="Audit Logs">
+ <div class="well">
+ <div *ngIf="contentData.audit_log">
+ <p *ngFor="let line of contentData.audit_log">
+ {{ line.stamp }} {{ line.priority }}
+ <span [ngStyle]="line">
+ <span style="font-weight: bold;">
+ {{ line.message }}
+ </span>
+ <br>
+ </span>
+ </p>
+ </div>
+ </div>
+ </tab>
+</tabset>
+</div>
--- /dev/null
+p {
+ font-family: monospace;
+ color: black;
+}
--- /dev/null
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { TabsModule } from 'ngx-bootstrap/tabs';
+
+import { configureTestBed } from '../../../../testing/unit-test-helper';
+import { SharedModule } from '../../../shared/shared.module';
+import { LogsComponent } from './logs.component';
+
+describe('LogsComponent', () => {
+ let component: LogsComponent;
+ let fixture: ComponentFixture<LogsComponent>;
+
+ configureTestBed({
+ imports: [HttpClientTestingModule, TabsModule.forRoot(), SharedModule],
+ declarations: [LogsComponent]
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(LogsComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
--- /dev/null
+import { Component, OnDestroy, OnInit } from '@angular/core';
+
+import { DashboardService } from '../../../shared/api/dashboard.service';
+
+@Component({
+ selector: 'cd-logs',
+ templateUrl: './logs.component.html',
+ styleUrls: ['./logs.component.scss']
+})
+export class LogsComponent implements OnInit, OnDestroy {
+ contentData: any;
+ interval: number;
+
+ constructor(private dashboardService: DashboardService) {}
+
+ ngOnInit() {
+ this.getInfo();
+ this.interval = window.setInterval(() => {
+ this.getInfo();
+ }, 5000);
+ }
+
+ ngOnDestroy() {
+ clearInterval(this.interval);
+ }
+
+ getInfo() {
+ this.dashboardService.getHealth().subscribe((data: any) => {
+ this.contentData = data;
+ });
+ }
+}
<ng-container *ngIf="contentData.health?.checks?.length > 0">
<ng-template #healthChecks>
<p class="logs-link"
- i18n>→ See <a (click)="viewportScroller.scrollToAnchor('logs')">Logs</a> for more details.</p>
+ i18n>→ See <a routerLink="/logs">Logs</a> for more details.</p>
<ul>
<li *ngFor="let check of contentData.health.checks">
<span [ngStyle]="check.severity | healthColor">{{ check.type }}</span>: {{ check.summary.message }}
*ngIf="contentData.pg_info">
<ng-template #pgStatus>
<p class="logs-link"
- i18n>→ See <a (click)="viewportScroller.scrollToAnchor('logs')">Logs</a> for more details.</p>
+ i18n>→ See <a routerLink="/logs">Logs</a> for more details.</p>
<ul>
<li *ngFor="let pgStatesText of contentData.pg_info.statuses | keyvalue">
{{ pgStatesText.key }}: {{ pgStatesText.value }}
</cd-info-card>
</div>
</cd-info-group>
-
- <cd-info-group groupTitle="Logs"
- i18n-groupTitle
- class="row info-group"
- id="logs"
- *ngIf="contentData.clog || contentData.audit_log">
-
- <cd-info-card cardTitle="Cluster"
- i18n-cardTitle
- class="col-md-12 col-lg-6"
- cardClass="card-medium"
- contentClass="no-center scroll text-monospace"
- *ngIf="contentData.clog">
- <p *ngFor="let line of contentData.clog">
- {{ line.stamp }} {{ line.priority }}
- <span [ngStyle]="line | logColor">
- {{ line.message }}
- <br>
- </span>
- </p>
- </cd-info-card>
- <cd-info-card cardTitle="Audit"
- i18n-cardTitle
- class="col-md-12 col-lg-6"
- cardClass="card-medium"
- contentClass="no-center scroll text-monospace"
- *ngIf="contentData.audit_log">
- <p *ngFor="let line of contentData.audit_log">
- {{ line.stamp }} {{ line.priority }}
- <span [ngStyle]="line | logColor">
- <span style="font-weight: bold;">
- {{ line.message }}
- </span>
- <br>
- </span>
- </p>
- </cd-info-card>
- </cd-info-group>
</div>
expect(infoGroup.querySelectorAll('cd-info-card').length).toBe(1);
});
});
-
- // @TODO: remove this test when logs are no longer in landing page
- // See https://tracker.ceph.com/issues/24571 & https://github.com/ceph/ceph/pull/23834
- it('should render Logs group & cards in addition to the other ones', () => {
- const payload = _.cloneDeep(healthPayload);
- payload['clog'] = [];
- payload['audit_log'] = [];
-
- getHealthSpy.and.returnValue(of(payload));
- fixture.detectChanges();
-
- const infoGroups = fixture.debugElement.nativeElement.querySelectorAll('cd-info-group');
- expect(infoGroups.length).toBe(4);
-
- const infoCards = fixture.debugElement.nativeElement.querySelectorAll('cd-info-card');
- expect(infoCards.length).toBe(20);
- });
});
-import { ViewportScroller } from '@angular/common';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { I18n } from '@ngx-translate/i18n-polyfill';
contentData: any;
interval: number;
- constructor(
- private dashboardService: DashboardService,
- public viewportScroller: ViewportScroller,
- private i18n: I18n
- ) {}
+ constructor(private dashboardService: DashboardService, private i18n: I18n) {}
ngOnInit() {
this.getInfo();
class="dropdown-item"
routerLink="/crush-map">CRUSH map</a>
</li>
+ <li routerLinkActive="active"
+ class="tc_submenuitem tc_submenuitem_log"
+ *ngIf="permissions.log.read">
+ <a i18n
+ class="dropdown-item"
+ routerLink="/logs">Logs
+ </a>
+ </li>
</ul>
</li>