Browse Source

system log browser

pull/1/head
Rob Colbert 3 years ago
parent
commit
8291251b3f
  1. 11
      app/controllers/admin.js
  2. 57
      app/controllers/admin/log.js
  3. 17
      app/models/link-category.js
  4. 2
      app/models/link.js
  5. 44
      app/services/log.js
  6. 5
      app/views/admin/components/menu.pug
  7. 3
      app/views/admin/layouts/main.pug
  8. 46
      app/views/admin/log/index.pug
  9. 3
      lib/site-platform.js

11
app/controllers/admin.js

@ -44,11 +44,12 @@ class AdminController extends SiteController {
}),
);
router.use('/host',await this.loadChild(path.join(__dirname, 'admin', 'host')));
router.use('/job-queue',await this.loadChild(path.join(__dirname, 'admin', 'job-queue')));
router.use('/link',await this.loadChild(path.join(__dirname, 'admin', 'link')));
router.use('/newsletter',await this.loadChild(path.join(__dirname, 'admin', 'newsletter')));
router.use('/settings',await this.loadChild(path.join(__dirname, 'admin', 'settings')));
router.use('/host', await this.loadChild(path.join(__dirname, 'admin', 'host')));
router.use('/job-queue', await this.loadChild(path.join(__dirname, 'admin', 'job-queue')));
router.use('/link', await this.loadChild(path.join(__dirname, 'admin', 'link')));
router.use('/log', await this.loadChild(path.join(__dirname, 'admin', 'log')));
router.use('/newsletter', await this.loadChild(path.join(__dirname, 'admin', 'newsletter')));
router.use('/settings', await this.loadChild(path.join(__dirname, 'admin', 'settings')));
router.use('/user', await this.loadChild(path.join(__dirname, 'admin', 'user')));
router.get('/diagnostics', this.getDiagnostics.bind(this));

57
app/controllers/admin/log.js

@ -0,0 +1,57 @@
// admin/log.js
// Copyright (C) 2021 Digital Telepresence, LLC
// License: Apache-2.0
'use strict';
const DTP_COMPONENT_NAME = 'admin:log';
const express = require('express');
const { SiteController } = require('../../../lib/site-lib');
class LogController extends SiteController {
constructor (dtp) {
super(dtp, DTP_COMPONENT_NAME);
}
async start ( ) {
const router = express.Router();
router.use(async (req, res, next) => {
res.locals.currentView = 'admin';
res.locals.adminView = 'log';
return next();
});
router.get('/', this.getIndex.bind(this));
return router;
}
async getIndex (req, res, next) {
const { log: logService } = this.dtp.services;
try {
res.locals.query = req.query;
res.locals.components = await logService.getComponentNames();
res.locals.pagination = this.getPaginationParameters(req, 25);
const search = { };
if (req.query.component) {
search.componentName = req.query.component;
}
res.locals.logs = await logService.getRecords(search, res.locals.pagination);
res.locals.totalLogCount = await logService.getTotalCount();
res.render('admin/log/index');
} catch (error) {
return next(error);
}
}
}
module.exports = async (dtp) => {
let controller = new LogController(dtp);
return controller;
};

17
app/models/link-category.js

@ -0,0 +1,17 @@
// link-category.js
// Copyright (C) 2021 Digital Telepresence, LLC
// License: Apache-2.0
'use strict';
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const LinkCategorySchema = new Schema({
user: { type: Schema.ObjectId, required: true, index: 1, ref: 'User' },
name: { type: String, required: true },
order: { type: Number, default: 0, required: true },
});
module.exports = mongoose.model('LinkCategory', LinkCategorySchema);

2
app/models/link.js

@ -11,7 +11,7 @@ const Schema = mongoose.Schema;
const { ResourceStats, ResourceStatsDefaults } = require('./lib/resource-stats');
const LinkSchema = new Schema({
created: { type: Date, required: true, default: Date.now, index: -1, expires: '7d' },
created: { type: Date, required: true, default: Date.now, index: -1 },
user: { type: Schema.ObjectId, required: true, index: 1, ref: 'User' },
label: { type: String, required: true, maxlength: 100 },
href: { type: String, required: true, maxlength: 255 },

44
app/services/log.js

@ -0,0 +1,44 @@
// log.js
// Copyright (C) 2021 Digital Telepresence, LLC
// License: Apache-2.0
'use strict';
const mongoose = require('mongoose');
const Log = mongoose.model('Log');
const { SiteService } = require('../../lib/site-lib');
class SystemLogService extends SiteService {
constructor (dtp) {
super(dtp, module.exports);
}
async getRecords (search, pagination) {
const logs = await Log
.find(search)
.sort({ created: -1 })
.skip(pagination.skip)
.limit(pagination.cpp)
.lean();
return logs;
}
async getComponentNames ( ) {
return await Log.distinct('componentName');
}
async getTotalCount ( ) {
const count = await Log.estimatedDocumentCount();
this.log.debug('log message total count', { count });
return count;
}
}
module.exports = {
slug: 'log',
name: 'log',
create: (dtp) => { return new SystemLogService(dtp); },
};

5
app/views/admin/components/menu.pug

@ -36,6 +36,11 @@ ul.uk-nav.uk-nav-default
span.nav-item-icon
i.fas.fa-microchip
span.uk-margin-small-left Jobs
li(class={ 'uk-active': (adminView === 'log') })
a(href="/admin/log")
span.nav-item-icon
i.fas.fa-clipboard-list
span.uk-margin-small-left Logs
li.uk-nav-divider

3
app/views/admin/layouts/main.pug

@ -1,4 +1,7 @@
extends ../../layouts/main
block vendorcss
link(rel="stylesheet", href="/highlight.js/styles/default.css")
block content-container
block page-header

46
app/views/admin/log/index.pug

@ -0,0 +1,46 @@
extends ../layouts/main
block content
include ../../components/pagination-bar
.uk-margin
form(method="GET", action="/admin/log").uk-form
div(uk-grid).uk-grid-small.uk-flex-middle
.uk-width-expand
h1 Log #[span.uk-text-small.uk-text-muted #{numeral(totalLogCount).format('0,0')} records]
.uk-width-auto
-
var urlParams = '';
if (query.component) {
urlParams += `&component=${query.component}`;
}
+renderPaginationBar(`/admin/log`, totalLogCount, urlParams)
.uk-width-auto
select(id="component", name="component").uk-select
each componentName in components
option(value= componentName, selected= (query.component === componentName))= componentName
.uk-width-auto
button(type="submit").uk-button.dtp-button-primary Filter
if Array.isArray(logs) && (logs.length > 0)
table.uk-table.uk-table-small.uk-table-divider
thead
tr
th Timestamp
th Level
th Component
th Message
tbody
each log in logs
tr
td= moment(log.created).format('YYYY-MM-DD hh:mm:ss.SSS')
td= log.level
td= log.componentName
td
div= log.message
if log.metadata
.uk-text-small(style="font-family: Courier New;")!= hljs.highlightAuto(JSON.stringify(log.metadata, null, 1)).value
else
div There are no logs.

3
lib/site-platform.js

@ -210,11 +210,13 @@ module.exports.startWebServer = async (dtp) => {
* Expose useful modules and information
*/
module.app.locals.DTP_SCRIPT_DEBUG = (process.env.NODE_ENV === 'local');
module.app.locals.dtp = dtp;
module.app.locals.pkg = require(path.join(dtp.config.root, 'package.json'));
module.app.locals.moment = require('moment');
module.app.locals.numeral = require('numeral');
module.app.locals.phoneNumberJS = require('libphonenumber-js');
module.app.locals.anchorme = require('anchorme').default;
module.app.locals.hljs = require('highlight.js');
/*
* Set up the protected markdown renderer that will refuse to process links and images
@ -262,6 +264,7 @@ module.exports.startWebServer = async (dtp) => {
module.app.use('/mpegts', cacheOneDay, express.static(path.join(dtp.config.root, 'node_modules', 'mpegts.js', 'dist')));
module.app.use('/numeral', cacheOneDay, express.static(path.join(dtp.config.root, 'node_modules', 'numeral', 'min')));
module.app.use('/tinymce', cacheOneDay, express.static(path.join(dtp.config.root, 'node_modules', 'tinymce')));
module.app.use('/highlight.js', cacheOneDay, express.static(path.join(dtp.config.root, 'node_modules', 'highlight.js')));
/*
* ExpressJS middleware

Loading…
Cancel
Save