Permalink
Browse files

feat(logs): system logs

  • Loading branch information...
jkuri authored and Izak88 committed Sep 4, 2017
1 parent 5f3ed0a commit 32af36a7d05903fc59d916d69d705c2991dcbe19
@@ -15,11 +15,11 @@ export function insertLog(data: LogType): Promise<any> {
export function getLogs(
limit: number,
offset: number,
type?: 'info' | 'warning' | 'error'
type?: 'all' | 'info' | 'warning' | 'error'
): Promise<any[]> {
return new Promise((resolve, reject) => {
new Log().query(q => {
if (type) {
if (type !== 'all') {
q.where('type', type);
}

@@ -36,6 +36,7 @@ import {
getUserJobPermissions
} from './db/permission';
import { insertEnvironmentVariable, removeEnvironmentVariable } from './db/environment-variable';
import { getLogs } from './db/log';
import { imageExists } from './docker';
import { checkApiRequestAuth } from './security';
import * as multer from 'multer';
@@ -448,6 +449,18 @@ export function environmentVariableRoutes(): express.Router {
return router;
}

export function logsRoutes(): express.Router {
const router = express.Router();

router.get(`/:limit/:offset/:type`, (req: express.Request, res: express.Response) => {
getLogs(req.params.limit, req.params.offset, req.params.type)
.then(logs => res.status(200).json({ data: logs }))
.catch(err => res.status(200).json({ status: false }));
});

return router;
}

function index(req: express.Request, res: express.Response): void {
return res.status(200).sendFile(resolve(__dirname, '../app/index.html'));
}
@@ -45,6 +45,7 @@ export class ExpressServer implements IExpressServer {
app.use('/api/jobs', routes.jobRoutes());
app.use('/api/permissions', routes.permissionRoutes());
app.use('/api/variables', routes.environmentVariableRoutes());
app.use('/api/logs', routes.logsRoutes());
app.use('/badge', routes.badgeRoutes());
app.use(routes.webRoutes());

@@ -55,7 +56,7 @@ export class ExpressServer implements IExpressServer {
cyan('http'),
yellow(']'),
' --- ',
`server running on port ${this.config.port}`
`server running on port ${yellow(this.config.port.toString())}`
].join('');
observer.next(msg);
});
@@ -76,7 +76,7 @@ export class SocketServer {
green('socket'),
yellow(']'),
' --- ',
`session cleared after user ${session.userId}`
`session cleared after user ${yellow(session.userId)}`
].join('');
logger.info(msg);
}
@@ -184,7 +184,7 @@ export class SocketServer {
green('socket'),
yellow(']'),
' --- ',
`socket server running at port ${options.port}`
`socket server running at port ${yellow(options.port.toString())}`
].join('');
logger.info(msg);

@@ -197,7 +197,7 @@ export class SocketServer {
green('socket'),
yellow(']'),
' --- ',
`updating session for user ${id} (${ip})`
`updating session for user ${yellow(id)} (${yellow(ip)})`
].join('');
logger.info(msg);

@@ -218,7 +218,7 @@ export class SocketServer {
green('socket'),
yellow(']'),
' --- ',
`socket connection established ${req.session.userId}`
`socket connection established ${yellow(req.session.userId)}`
].join('');
logger.info(msg);
});
@@ -31,6 +31,7 @@ import { AppJobComponent } from './components/app-job';
import { AppUserComponent } from './components/app-user';
import { AppSettingsComponent } from './components/app-settings';
import { AppTeamComponent } from './components/app-team';
import { AppLogsComponent } from './components/app-logs';


@NgModule({
@@ -49,6 +50,7 @@ import { AppTeamComponent } from './components/app-team';
AppSettingsComponent,
AppTeamComponent,
AppUserComponent,
AppLogsComponent,
EqualValidator,
SafeHtmlPipe,
TimeDurationPipe,
@@ -101,11 +103,19 @@ import { AppTeamComponent } from './components/app-team';
component: AppUserComponent,
canActivate: [AuthGuard]
},
{
path: 'logs',
component: AppLogsComponent,
canActivate: [AuthGuard]
},
{
path: 'login',
component: AppLoginComponent
},
{ path: 'setup', component: AppSetupComponent }
{
path: 'setup',
component: AppSetupComponent
}
]),
HttpModule,
FormsModule,
@@ -20,6 +20,9 @@
<a class="nav-dropdown-item" routerLink="/settings">
Settings
</a>
<a class="nav-dropdown-item" routerLink="/logs">
System Logs
</a>
<a class="nav-dropdown-item" (click)="logout()">
Logout
</a>
@@ -0,0 +1,61 @@
<app-header></app-header>

<nav class="nav sub-nav">
<div class="container">
<div class="nav-left">
<span class="nav-item">
<h1>System Logs</h1>
</span>
</div>
<div class="nav-center">

</div>
<div class="nav-right">
<div class="group-buttons">
<button class="group-button" [ngClass]="{ 'is-active': show === 'all' }" (click)="showAllBuilds()">All Logs</button>
<button class="group-button" [ngClass]="{ 'is-active': show === 'info' }" (click)="showCommits()">Info</button>
<button class="group-button" [ngClass]="{ 'is-active': show === 'warning' }" (click)="showPullRequests()">Warnings</button>
<button class="group-button" [ngClass]="{ 'is-active': show === 'error' }" (click)="showPullRequests()">Errors</button>
</div>
</div>
</div>
</nav>

<div class="container">
<div class="columns">
<div class="column is-12">
<div class="content">
<div class="container" *ngIf="loading">
<img src="images/icons/flickr.svg" class="main-loader">
</div>

<div class="columns is-multiline" *ngIf="!loading">
<div class="column is-12">
<div class="log-lines dracula-ansi-theme">
<div class="columns log-line" *ngFor="let line of logs; let i = index;">
<div class="column is-2 data-label-container">
<span class="data-label" [ngClass]="{ green: line.type === 'info', red: line.type === 'error', yellow: line.type === 'warning' }">
{{ line.type }}
</span>
</div>
<div class="column is-9">
<span [innerHTML]="line.message"></span>
</div>
<div class="column is-1">
<span class="time">{{ line.created_at | date:'shortTime' }}</span>
</div>
</div>
</div>
<div layout-align="center" *ngIf="logs?.length" align="center" class="more-button-container">
<button type="button" class="button dark" name="btn-loadmore" (click)="fetch($event)" [class.is-loading]="fetching" [class.is-hidden]="hideMoreButton">
<img src="images/icons/more.svg">
Load more
</button>
</div>
</div>
</div>

</div>
</div>
</div>
</div>
@@ -0,0 +1,69 @@
import { Component, OnInit } from '@angular/core';
import { SocketService } from '../../services/socket.service';
import { ApiService } from '../../services/api.service';
import * as AnsiUp from 'ansi_up';

export interface LogType {
message: string;
type: 'info' | 'warning' | 'error';
created_at: Date;
updated_at: Date;
}

@Component({
selector: 'app-logs',
templateUrl: 'app-logs.component.html'
})
export class AppLogsComponent implements OnInit {
loading: boolean;
show: 'all' | 'info' | 'warnings' | 'errors';
limit: number;
offset: number;
logs: LogType[];
au: any;
fetching: boolean;
hideMoreButton: boolean;

constructor(
private socketService: SocketService,
private apiService: ApiService
) {
this.loading = true;
this.show = 'all';
this.limit = 20;
this.offset = 0;
this.logs = [];
}

ngOnInit() {
this.au = new AnsiUp.default();
this.au.use_classes = true;
this.fetch();
}

fetch(e?: MouseEvent): void {
if (e && e.preventDefault) {
e.preventDefault();
e.stopPropagation();
}

this.fetching = true;
this.apiService.getLogs(this.limit, this.offset, this.show)
.subscribe(logs => {
this.logs = this.logs.concat(logs.map(log => {
log.message = this.au.ansi_to_html(log.message);
return log;
}));

this.fetching = false;
this.loading = false;

if (logs.length === this.limit) {
this.offset += 20;
this.hideMoreButton = false;
} else {
this.hideMoreButton = true;
}
});
}
}
@@ -0,0 +1 @@
export * from './app-logs.component';
@@ -20,6 +20,10 @@ export class ApiService {
return this.http.get(`${this.loc.protocol}//${this.loc.hostname}${this.port}/badge/${id}`);
}

getLogs(limit: number, offset: number, type: string): Observable<any> {
return this.get(`${this.url}/logs/${limit}/${offset}/${type}`, null, true);
}

getBuilds(limit: number, offset: number, buildTypes: string, userId?: string): Observable<any> {
if (userId) {
return this.get(
@@ -20,6 +20,7 @@
@import 'build-details'
@import 'job'
@import 'settings'
@import 'logs'
@import 'disconnected'

html, body, .hero
@@ -0,0 +1,22 @@
.log-lines
display: inline-block
width: 100%
margin: 30px 0 0
padding: 10px
background: darken($background, 5)
border-radius: 6px
box-shadow: 1px 2px 10px rgba($background, 0.7)

.log-line
display: flex
align-items: center
margin: 0
line-height: 1
font-size: 14px
height: 28px
font-weight: $weight-semibold

.data-label-container
display: flex
align-items: center
justify-content: center
@@ -5,7 +5,7 @@
}

.ansi-red-fg, .ansi-red-bg {
color: #ff5555;
color: #ED1C24;
}

.ansi-green-fg, .ansi-green-bg {
@@ -17,7 +17,7 @@
}

.ansi-blue-fg, .ansi-blue-bg {
color: #134eb2;
color: #54a4f3;
}

.ansi-magenta-fg, .ansi-magenta-bg {
@@ -37,7 +37,7 @@
}

.ansi-bright-red-fg, .ansi-bright-red-bg {
color: #ff5555;
color: #ED1C24;
}

.ansi-bright-green-fg, .ansi-bright-green-bg {

0 comments on commit 32af36a

Please sign in to comment.