Updated logs viewer component

- now by default last 50 lines are showed
- added copy to clipboard button
- added loading spinner to indicate to users when the logs are loading

app.get('/api/logs') is now app.post to allow for additional parameters (such as lines to retrieve)
This commit is contained in:
Isaac Grynsztein
2020-07-03 03:46:58 -04:00
parent 3732d13562
commit a9f197e46d
11 changed files with 45 additions and 15 deletions

View File

@@ -29,6 +29,7 @@ var config_api = require('./config.js');
var subscriptions_api = require('./subscriptions')
const CONSTS = require('./consts')
const { spawn } = require('child_process')
const read_last_lines = require('read-last-lines');
const is_windows = process.platform === 'win32';
@@ -1867,15 +1868,17 @@ app.get('/api/using-encryption', function(req, res) {
res.send(usingEncryption);
});
app.get('/api/logs', function(req, res) {
app.post('/api/logs', async function(req, res) {
let logs = null;
let lines = req.body.lines;
logs_path = path.join('appdata', 'logs', 'combined.log')
if (fs.existsSync(logs_path))
logs = fs.readFileSync(logs_path, 'utf8');
if (fs.existsSync(logs_path)) {
if (lines) logs = await read_last_lines.read(logs_path, lines);
else logs = fs.readFileSync(logs_path, 'utf8');
}
else
logger.error(`Failed to find logs file at the expected location: ${logs_path}`)
console.log(logs)
res.send({
logs: logs,
success: !!logs

View File

@@ -50,6 +50,7 @@
"passport-jwt": "^4.0.0",
"passport-local": "^1.0.0",
"progress": "^2.0.3",
"read-last-lines": "^1.7.2",
"shortid": "^2.2.15",
"unzipper": "^0.10.10",
"uuidv4": "^6.0.6",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -14,5 +14,5 @@
<link rel="stylesheet" href="styles.5112d6db78cf21541598.css"></head>
<body>
<app-root></app-root>
<script src="runtime-es2015.8f98e80442a6fc46f61d.js" type="module"></script><script src="runtime-es5.8f98e80442a6fc46f61d.js" nomodule defer></script><script src="polyfills-es5.7f923c8f5afda210edd3.js" nomodule defer></script><script src="polyfills-es2015.5b408f108bcea938a7e2.js" type="module"></script><script src="main-es2015.0cbc545a4a3bee376826.js" type="module"></script><script src="main-es5.0cbc545a4a3bee376826.js" nomodule defer></script></body>
<script src="runtime-es2015.1f02852de81190376ba1.js" type="module"></script><script src="runtime-es5.1f02852de81190376ba1.js" nomodule defer></script><script src="polyfills-es5.7f923c8f5afda210edd3.js" nomodule defer></script><script src="polyfills-es2015.5b408f108bcea938a7e2.js" type="module"></script><script src="main-es2015.0cbc545a4a3bee376826.js" type="module"></script><script src="main-es5.0cbc545a4a3bee376826.js" nomodule defer></script></body>
</html>

View File

@@ -1 +1 @@
!function(e){function r(r){for(var n,i,a=r[0],c=r[1],l=r[2],p=0,s=[];p<a.length;p++)i=a[p],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(r);s.length;)s.shift()();return u.push.apply(u,l||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,a=1;a<t.length;a++)0!==o[t[a]]&&(n=!1);n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={0:0},u=[];function i(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,i),t.l=!0,t.exports}i.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise((function(r,n){t=o[e]=[r,n]}));r.push(t[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+""+({}[e]||e)+"-es2015."+{1:"69c7d04ec9d3867ff817"}[e]+".js"}(e);var c=new Error;u=function(r){a.onerror=a.onload=null,clearTimeout(l);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:a})}),12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(r)},i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,(function(r){return e[r]}).bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="",i.oe=function(e){throw console.error(e),e};var a=window.webpackJsonp=window.webpackJsonp||[],c=a.push.bind(a);a.push=r,a=a.slice();for(var l=0;l<a.length;l++)r(a[l]);var f=c;t()}([]);
!function(e){function r(r){for(var n,i,a=r[0],c=r[1],l=r[2],p=0,s=[];p<a.length;p++)i=a[p],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(r);s.length;)s.shift()();return u.push.apply(u,l||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,a=1;a<t.length;a++)0!==o[t[a]]&&(n=!1);n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={0:0},u=[];function i(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,i),t.l=!0,t.exports}i.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise((function(r,n){t=o[e]=[r,n]}));r.push(t[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+""+({}[e]||e)+"-es2015."+{1:"6bc1f7cd24dfb6add92c"}[e]+".js"}(e);var c=new Error;u=function(r){a.onerror=a.onload=null,clearTimeout(l);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:a})}),12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(r)},i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,(function(r){return e[r]}).bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="",i.oe=function(e){throw console.error(e),e};var a=window.webpackJsonp=window.webpackJsonp||[],c=a.push.bind(a);a.push=r,a=a.slice();for(var l=0;l<a.length;l++)r(a[l]);var f=c;t()}([]);

View File

@@ -1 +1 @@
!function(e){function r(r){for(var n,i,a=r[0],c=r[1],l=r[2],p=0,s=[];p<a.length;p++)i=a[p],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(r);s.length;)s.shift()();return u.push.apply(u,l||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,a=1;a<t.length;a++)0!==o[t[a]]&&(n=!1);n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={0:0},u=[];function i(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,i),t.l=!0,t.exports}i.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise((function(r,n){t=o[e]=[r,n]}));r.push(t[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+""+({}[e]||e)+"-es5."+{1:"69c7d04ec9d3867ff817"}[e]+".js"}(e);var c=new Error;u=function(r){a.onerror=a.onload=null,clearTimeout(l);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:a})}),12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(r)},i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,(function(r){return e[r]}).bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="",i.oe=function(e){throw console.error(e),e};var a=window.webpackJsonp=window.webpackJsonp||[],c=a.push.bind(a);a.push=r,a=a.slice();for(var l=0;l<a.length;l++)r(a[l]);var f=c;t()}([]);
!function(e){function r(r){for(var n,i,a=r[0],c=r[1],l=r[2],p=0,s=[];p<a.length;p++)i=a[p],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(r);s.length;)s.shift()();return u.push.apply(u,l||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,a=1;a<t.length;a++)0!==o[t[a]]&&(n=!1);n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={0:0},u=[];function i(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,i),t.l=!0,t.exports}i.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise((function(r,n){t=o[e]=[r,n]}));r.push(t[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+""+({}[e]||e)+"-es5."+{1:"6bc1f7cd24dfb6add92c"}[e]+".js"}(e);var c=new Error;u=function(r){a.onerror=a.onload=null,clearTimeout(l);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:a})}),12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(r)},i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,(function(r){return e[r]}).bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="",i.oe=function(e){throw console.error(e),e};var a=window.webpackJsonp=window.webpackJsonp||[],c=a.push.bind(a);a.push=r,a=a.slice();for(var l=0;l<a.length;l++)r(a[l]);var f=c;t()}([]);

View File

@@ -1,3 +1,21 @@
<div style="height: 100%">
<textarea style="height: 100%" matInput readonly [(ngModel)]="logs" placeholder="Logs will appear here" i18n-placeholder="Logs placeholder"></textarea>
<div *ngIf="logs_loading" style="position: absolute; top: 40%; left: 50%">
<mat-spinner [diameter]="32"></mat-spinner>
</div>
<textarea style="height: 275px" matInput readonly [(ngModel)]="logs" placeholder="Logs will appear here" i18n-placeholder="Logs placeholder"></textarea>
<div>
<button style="margin-top: 12px;" [cdkCopyToClipboard]="logs" (click)="copiedLogsToClipboard()" mat-flat-button color="primary"><ng-container i18n="Copy to clipboard button text">Copy to clipboard</ng-container></button>
<div style="float: right">
<ng-container i18n="Label for lines select in logger view">Lines:</ng-container>&nbsp;
<mat-form-field style="width: 75px;">
<mat-select (selectionChange)="getLogs()" [(ngModel)]="requested_lines">
<mat-option [value]="10">10</mat-option>
<mat-option [value]="25">25</mat-option>
<mat-option [value]="50">50</mat-option>
<mat-option [value]="100">100</mat-option>
<mat-option [value]="0">All</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
</div>

View File

@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, AfterViewInit } from '@angular/core';
import { PostsService } from '../../posts.services';
@Component({
@@ -9,7 +9,8 @@ import { PostsService } from '../../posts.services';
export class LogsViewerComponent implements OnInit {
logs: string = null;
requested_lines = 50;
logs_loading = false;
constructor(private postsService: PostsService) { }
ngOnInit(): void {
@@ -17,16 +18,23 @@ export class LogsViewerComponent implements OnInit {
}
getLogs() {
this.postsService.getLogs().subscribe(res => {
if (!this.logs) { this.logs_loading = true; } // only show loading spinner at the first load
this.postsService.getLogs(this.requested_lines !== 0 ? this.requested_lines : null).subscribe(res => {
this.logs_loading = false;
if (res['logs']) {
this.logs = res['logs'];
} else {
this.postsService.openSnackBar('Failed to retrieve logs!');
}
}, err => {
this.logs_loading = false;
console.error(err);
this.postsService.openSnackBar('Failed to retrieve logs!');
});
}
copiedLogsToClipboard() {
this.postsService.openSnackBar('Logs copied to clipboard!');
}
}

View File

@@ -234,8 +234,8 @@ export class PostsService implements CanActivate {
return this.http.post(this.path + 'getVideoInfos', {fileNames: fileNames, type: type, urlMode: urlMode}, this.httpOptions);
}
getLogs() {
return this.http.get(this.path + 'logs', this.httpOptions);
getLogs(lines = 50) {
return this.http.post(this.path + 'logs', {lines: lines}, this.httpOptions);
}
isPinSet() {