Logging handlers can now be adapted to special needs

This commit is contained in:
Uwe Oestermeier 2019-07-02 09:38:19 +02:00
parent 9042579518
commit 1480ad8145
4 changed files with 228 additions and 81 deletions

55
dist/iwmlib.js vendored
View File

@ -1545,14 +1545,34 @@
}
/* eslint-disable no-undef */
/* eslint-disable no-console */
/* eslint-disable no-unused-vars */
let ipc = null;
let logMessages = new Set();
let logHandlers = {
log: console.log,
warn: console.warn,
error: console.error
};
try {
ipc = require('electron').ipcRenderer;
} catch (e) {}
logHandlers.log = message => ipc.send('log', message);
logHandlers.warn = message => ipc.send('warn', message);
logHandlers.error = message => ipc.send('error', message);
} catch (e) {
console.log('Cannot use electron logging.');
}
/** Basic class for app specific logging requirements.
* Can be used to implement persistent logging in electron apps.
* Uses a logMessage cache to prevent error overflows. This is
* needed since errors may occur very frequently
* (e.g. display update loops at 60fps, programmatic loops, ...).
*
* The logging handlers can be overwritten by calling the static
* setup method.
*/
class Logging {
@ -1560,13 +1580,38 @@
* @param {*} message
*/
static log(message) {
logHandlers.log(message);
}
if (ipc) {
ipc.send('log', message);
} else {
console.log(message);
/**
* Static warn function.
* Emits each warning only once per session.
* @param {*} message
*/
static warn(message) {
if (!logMessages.has(message)) {
logMessages.add(message);
logHandlers.warn(message);
}
}
/**
* Static error function.
* Emits each error message only once per session.
* @param {*} message
*/
static error(message) {
if (!logMessages.has(message)) {
logMessages.add(message);
logHandlers.error(message);
}
}
static setup({log=console.log, warn=console.warn, error=console.error} = {}) {
logHandlers.log = log;
logHandlers.warn = warn;
logHandlers.error = error;
}
}
/* globals Hammer, propagating */

198
dist/iwmlib.pixi.js vendored
View File

@ -4709,28 +4709,73 @@
// }
}
/* eslint-disable no-undef */
/* eslint-disable no-console */
/* eslint-disable no-unused-vars */
let ipc = null;
let logMessages = new Set();
let logHandlers = {
log: console.log,
warn: console.warn,
error: console.error
};
try {
ipc = require('electron').ipcRenderer;
} catch (e) {}
logHandlers.log = message => ipc.send('log', message);
logHandlers.warn = message => ipc.send('warn', message);
logHandlers.error = message => ipc.send('error', message);
} catch (e) {
console.log('Cannot use electron logging.');
}
/** Basic class for app specific logging requirements.
* Can be used to implement persistent logging in electron apps.
* Uses a logMessage cache to prevent error overflows. This is
* needed since errors may occur very frequently
* (e.g. display update loops at 60fps, programmatic loops, ...).
*
* The logging handlers can be overwritten by calling the static
* setup method.
*/
class Logging {
class Logging$1 {
/** Static log function.
* @param {*} message
*/
static log(message) {
logHandlers.log(message);
}
if (ipc) {
ipc.send('log', message);
} else {
console.log(message);
/**
* Static warn function.
* Emits each warning only once per session.
* @param {*} message
*/
static warn(message) {
if (!logMessages.has(message)) {
logMessages.add(message);
logHandlers.warn(message);
}
}
/**
* Static error function.
* Emits each error message only once per session.
* @param {*} message
*/
static error(message) {
if (!logMessages.has(message)) {
logMessages.add(message);
logHandlers.error(message);
}
}
static setup({log=console.log, warn=console.warn, error=console.error} = {}) {
logHandlers.log = log;
logHandlers.warn = warn;
logHandlers.error = error;
}
}
/* globals Hammer, propagating */
@ -5676,7 +5721,7 @@
let size = this.interaction.current.size;
let limit = this.logInteractionsAbove;
if (size > limit) {
Logging.log(`Number of interactions ${size} exceeds ${limit}`);
Logging$1.log(`Number of interactions ${size} exceeds ${limit}`);
}
}
@ -7805,10 +7850,12 @@
/* globals PIXI, console*/
const registeredTiles = new Map();
// const pendingTiles = new Map()
/** Implements a baseTexture cache. The last textures are kept for reuse */
let keepTextures = 0;
const keptTextures = [];
const lateTextures = new Map();
let lastSweepTime = 0;
let sweepInterval = 2000.0;
/** The current Tile implementation simply uses PIXI.Sprites.
*
@ -7833,43 +7880,6 @@
keepTextures = value;
}
/**
* Marks the given url as pending. Pending tiles should not be destroyed
*
* @static
* @param {*} url
* @memberof Tile
*/
/* static schedule(url) {
let count = 0
if (pendingTiles.has(url)) {
count = pendingTiles.get(url)
}
pendingTiles.set(url, count + 1)
// console.log("Tile.scheduled", url, pendingTiles.size)
} */
/**
* Removes the given url from pending urls.
*
* @static
* @param {*} url
* @memberof Tile
*/
/* static unschedule(url) {
if (pendingTiles.has(url)) {
let count = pendingTiles.get(url)
if (count > 1) {
pendingTiles.set(url, count - 1)
}
else {
pendingTiles.clear(url)
}
}
// console.log("Tile.unscheduled", url, pendingTiles.size)
} */
/**
* Returns true iff the url is pending
*
@ -8001,14 +8011,60 @@
return null
}
/**
* Specialized renderWebGL to avoid freezing system
*
* @param {*} renderer
* @memberof Tile
*/
renderWebGL(renderer) {
try {
super.renderWebGL(renderer);
}
catch (e) {
// We want persistent logging here
Logging.error("Error in Tile.renderWebGL: " + e.message);
}
}
/**
* Removes lately arrived texture if they have not been touched in the meanwhile.
*
* @static
* @memberof Tile
*/
static sweepLateTextures() {
let now = performance.now();
if (now > lastSweepTime + sweepInterval) {
lastSweepTime = now;
let count = 0;
for (let [url, texture] of lateTextures.entries()) {
if (texture) {
let base = texture.baseTexture;
if (base != null && base.touched == 0) {
texture.destroy(true);
//console.info("Sweeping ", url)
count += 1;
lateTextures.delete(url);
}
}
}
if (count > 0)
console.log("Sweeping textures", count);
}
}
/**
* Texture received too late. We do not need it.
* @param {*} url
* @param {*} texture
*/
static lateTexture(url, texture) {
let destroyBase = !registeredTiles.has(url);
texture.destroy(destroyBase);
lateTextures.set(url, texture);
//console.warn("Tile.lateTexture")
// We cannot destroy the texture since we got errors in t.renderWebGL.
// Perhaps we can destroy unsed textures later on
Tile.sweepLateTextures();
}
static printInfos() {
@ -11811,6 +11867,10 @@
return ['decade', 'year', 'month', 'day', 'hour', 'minute', 'second']
}
static get largeTickSize() {
return 4.2
}
get minWidth() {
return 10
}
@ -11885,7 +11945,7 @@
return date.toLocaleDateString('de', format)
}
draw(timeline, range, width, height, available, format, nextFormat, level) {
draw(timeline, range, width, height, available, format, nextFormat, level, extraTicks=false) {
let first = null;
let last = null;
let keyedFormat = (format) ? format[this.formatKey] : null;
@ -11893,7 +11953,6 @@
let redundant = (nextFormat) ? this.formatKey in nextFormat : false;
let fullyRedundant = keyedFormat != null && keyedFormat == keyedNextFormat;
let y = timeline.getY();
for (let { start, end } of this.iterRanges(range)) {
let x = timeline.toX(start);
let xx = x;
@ -11902,11 +11961,10 @@
let key = this.dateKey(start);
let text = this.toLocaleString(start, format);
let align = 'center';
let downTick = false;
if (nextFormat) {
yy = y + timeline.tickLabelOffset(-1, 1);
align = 'left';
timeline.drawTick(x, 4.2);
timeline.drawTick(x, Ticks.largeTickSize);
let nextX = timeline.toX(end) - 100;
if (x < 0 && nextX > -100 && !redundant) {
xx = Math.min(4, nextX);
@ -11914,20 +11972,18 @@
else {
xx -= 2;
}
downTick = true;
}
else if (level > 0) {
xx = x + available / 2;
}
else {
downTick = true;
}
if (!fullyRedundant) {
timeline.ensureLabel(key, text,
{ x: xx, y: yy, align },
FontInfo.small);
}
if (downTick) timeline.drawTick(x, -1);
if (extraTicks)
timeline.drawTick(x, -level);
}
if (timeline.visibleRange(start, end)) {
if (first == null)
@ -11939,6 +11995,15 @@
return null
return { start: first, end: last }
}
drawExtra(timeline, range, size) {
for (let { start } of this.iterRanges(range)) {
if (timeline.visibleDate(start)) {
let x = timeline.toX(start);
timeline.drawTick(x, -size);
}
}
}
}
class DecadeTicks extends Ticks {
@ -12125,15 +12190,34 @@
visible.push(ticks);
}
let level = 0;
let ranges = [];
for (let ticks of visible) {
if (range == null)
return
continue
range = ticks.draw(timeline, range, width, height,
availables.get(ticks),
formats.get(ticks),
nextFormats.get(ticks), level);
if (range) {
ranges.push({ticks, range});
}
level += 1;
}
let extraLevel = ranges.length - 1;
let extraStart = extraLevel;
for(let {ticks, range} of ranges) {
ticks.drawExtra(timeline, range, extraLevel);
extraLevel -= 1;
if (extraLevel <= 0) {
continue
}
}
timeline.drawTick(start, Ticks.largeTickSize);
timeline.drawTick(start, -extraStart);
timeline.drawTick(end, Ticks.largeTickSize);
timeline.drawTick(end, -extraStart);
}
}

View File

@ -8,15 +8,26 @@
<link rel="stylesheet" href="../css/doctest.css">
<script src="./3rdparty/highlight/highlight.pack.js"></script>
<script src="../dist/iwmlib.3rdparty.js"></script>
<script src="../dist/iwmlib.js"></script>
<script src="../dist/iwmlib.js"></script>
</head>
<body id="page" onload="Doctest.run()">
<h1>
Logging
</h1>
<p>Store informations of your app permanently.</p>
<p>Store informations of your app permanently or use app specific logging functions.</p>
<script class="doctest">
Logging.log('app started')
Logging.warn("shouldn't happen")
Logging.error('restart')
Logging.setup({ log: message => console.log("app specific" + message) })
Logging.log("now app related")
</script>
<p>You can overwrite the log, warn, and error handler by using Logging.setup with
app specific functions.</p>
<script class="doctest">
Logging.setup({ log: message => console.log("app specific" + message) })
Logging.log("now app related")
</script>
</body>

View File

@ -1,10 +1,21 @@
/* eslint-disable no-undef */
/* eslint-disable no-console */
/* eslint-disable no-unused-vars */
let ipc = null
let logMessages = new Set()
let logHandlers = {
log: console.log,
warn: console.warn,
error: console.error
}
try {
ipc = require('electron').ipcRenderer
logHandlers.log = message => ipc.send('log', message)
logHandlers.warn = message => ipc.send('warn', message)
logHandlers.error = message => ipc.send('error', message)
} catch (e) {
console.log("Cannot use electron logging.")
console.log('Cannot use electron logging.')
}
/** Basic class for app specific logging requirements.
@ -12,6 +23,9 @@ try {
* Uses a logMessage cache to prevent error overflows. This is
* needed since errors may occur very frequently
* (e.g. display update loops at 60fps, programmatic loops, ...).
*
* The logging handlers can be overwritten by calling the static
* setup method.
*/
export default class Logging {
@ -19,12 +33,7 @@ export default class Logging {
* @param {*} message
*/
static log(message) {
if (ipc) {
ipc.send('log', message)
} else {
console.log(message)
}
logHandlers.log(message)
}
/**
@ -35,11 +44,7 @@ export default class Logging {
static warn(message) {
if (!logMessages.has(message)) {
logMessages.add(message)
if (ipc) {
ipc.send('warn', message)
} else {
console.warn(message)
}
logHandlers.warn(message)
}
}
@ -51,11 +56,13 @@ export default class Logging {
static error(message) {
if (!logMessages.has(message)) {
logMessages.add(message)
if (ipc) {
ipc.send('error', message)
} else {
console.error(message)
}
logHandlers.error(message)
}
}
static setup({log=console.log, warn=console.warn, error=console.error} = {}) {
logHandlers.log = log
logHandlers.warn = warn
logHandlers.error = error
}
}