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 ipc = null;
let logMessages = new Set();
let logHandlers = {
log: console.log,
warn: console.warn,
error: console.error
};
try { try {
ipc = require('electron').ipcRenderer; 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. /** Basic class for app specific logging requirements.
* Can be used to implement persistent logging in electron apps. * 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 {
@ -1560,13 +1580,38 @@
* @param {*} message * @param {*} message
*/ */
static log(message) { static log(message) {
logHandlers.log(message);
}
if (ipc) { /**
ipc.send('log', message); * Static warn function.
} else { * Emits each warning only once per session.
console.log(message); * @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 */ /* 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 ipc = null;
let logMessages = new Set();
let logHandlers = {
log: console.log,
warn: console.warn,
error: console.error
};
try { try {
ipc = require('electron').ipcRenderer; 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. /** Basic class for app specific logging requirements.
* Can be used to implement persistent logging in electron apps. * 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. /** Static log function.
* @param {*} message * @param {*} message
*/ */
static log(message) { static log(message) {
logHandlers.log(message);
}
if (ipc) { /**
ipc.send('log', message); * Static warn function.
} else { * Emits each warning only once per session.
console.log(message); * @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 */ /* globals Hammer, propagating */
@ -5676,7 +5721,7 @@
let size = this.interaction.current.size; let size = this.interaction.current.size;
let limit = this.logInteractionsAbove; let limit = this.logInteractionsAbove;
if (size > limit) { 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*/ /* globals PIXI, console*/
const registeredTiles = new Map(); const registeredTiles = new Map();
// const pendingTiles = new Map()
/** Implements a baseTexture cache. The last textures are kept for reuse */ /** Implements a baseTexture cache. The last textures are kept for reuse */
let keepTextures = 0; let keepTextures = 0;
const keptTextures = []; const keptTextures = [];
const lateTextures = new Map();
let lastSweepTime = 0;
let sweepInterval = 2000.0;
/** The current Tile implementation simply uses PIXI.Sprites. /** The current Tile implementation simply uses PIXI.Sprites.
* *
@ -7833,43 +7880,6 @@
keepTextures = value; 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 * Returns true iff the url is pending
* *
@ -8001,14 +8011,60 @@
return null 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. * Texture received too late. We do not need it.
* @param {*} url * @param {*} url
* @param {*} texture * @param {*} texture
*/ */
static lateTexture(url, texture) { static lateTexture(url, texture) {
let destroyBase = !registeredTiles.has(url); lateTextures.set(url, texture);
texture.destroy(destroyBase); //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() { static printInfos() {
@ -11811,6 +11867,10 @@
return ['decade', 'year', 'month', 'day', 'hour', 'minute', 'second'] return ['decade', 'year', 'month', 'day', 'hour', 'minute', 'second']
} }
static get largeTickSize() {
return 4.2
}
get minWidth() { get minWidth() {
return 10 return 10
} }
@ -11885,7 +11945,7 @@
return date.toLocaleDateString('de', format) 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 first = null;
let last = null; let last = null;
let keyedFormat = (format) ? format[this.formatKey] : null; let keyedFormat = (format) ? format[this.formatKey] : null;
@ -11893,7 +11953,6 @@
let redundant = (nextFormat) ? this.formatKey in nextFormat : false; let redundant = (nextFormat) ? this.formatKey in nextFormat : false;
let fullyRedundant = keyedFormat != null && keyedFormat == keyedNextFormat; let fullyRedundant = keyedFormat != null && keyedFormat == keyedNextFormat;
let y = timeline.getY(); let y = timeline.getY();
for (let { start, end } of this.iterRanges(range)) { for (let { start, end } of this.iterRanges(range)) {
let x = timeline.toX(start); let x = timeline.toX(start);
let xx = x; let xx = x;
@ -11902,11 +11961,10 @@
let key = this.dateKey(start); let key = this.dateKey(start);
let text = this.toLocaleString(start, format); let text = this.toLocaleString(start, format);
let align = 'center'; let align = 'center';
let downTick = false;
if (nextFormat) { if (nextFormat) {
yy = y + timeline.tickLabelOffset(-1, 1); yy = y + timeline.tickLabelOffset(-1, 1);
align = 'left'; align = 'left';
timeline.drawTick(x, 4.2); timeline.drawTick(x, Ticks.largeTickSize);
let nextX = timeline.toX(end) - 100; let nextX = timeline.toX(end) - 100;
if (x < 0 && nextX > -100 && !redundant) { if (x < 0 && nextX > -100 && !redundant) {
xx = Math.min(4, nextX); xx = Math.min(4, nextX);
@ -11914,20 +11972,18 @@
else { else {
xx -= 2; xx -= 2;
} }
downTick = true;
} }
else if (level > 0) { else if (level > 0) {
xx = x + available / 2; xx = x + available / 2;
} }
else {
downTick = true;
}
if (!fullyRedundant) { if (!fullyRedundant) {
timeline.ensureLabel(key, text, timeline.ensureLabel(key, text,
{ x: xx, y: yy, align }, { x: xx, y: yy, align },
FontInfo.small); FontInfo.small);
} }
if (downTick) timeline.drawTick(x, -1); if (extraTicks)
timeline.drawTick(x, -level);
} }
if (timeline.visibleRange(start, end)) { if (timeline.visibleRange(start, end)) {
if (first == null) if (first == null)
@ -11939,6 +11995,15 @@
return null return null
return { start: first, end: last } 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 { class DecadeTicks extends Ticks {
@ -12125,15 +12190,34 @@
visible.push(ticks); visible.push(ticks);
} }
let level = 0; let level = 0;
let ranges = [];
for (let ticks of visible) { for (let ticks of visible) {
if (range == null) if (range == null)
return continue
range = ticks.draw(timeline, range, width, height, range = ticks.draw(timeline, range, width, height,
availables.get(ticks), availables.get(ticks),
formats.get(ticks), formats.get(ticks),
nextFormats.get(ticks), level); nextFormats.get(ticks), level);
if (range) {
ranges.push({ticks, range});
}
level += 1; 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"> <link rel="stylesheet" href="../css/doctest.css">
<script src="./3rdparty/highlight/highlight.pack.js"></script> <script src="./3rdparty/highlight/highlight.pack.js"></script>
<script src="../dist/iwmlib.3rdparty.js"></script> <script src="../dist/iwmlib.3rdparty.js"></script>
<script src="../dist/iwmlib.js"></script> <script src="../dist/iwmlib.js"></script>
</head> </head>
<body id="page" onload="Doctest.run()"> <body id="page" onload="Doctest.run()">
<h1> <h1>
Logging Logging
</h1> </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"> <script class="doctest">
Logging.log('app started') 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> </script>
</body> </body>

View File

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