diff --git a/src/serializer.js b/src/serializer.js index 8b52e95..9d35018 100644 --- a/src/serializer.js +++ b/src/serializer.js @@ -1,5 +1,15 @@ const Transform = require('readable-stream').Transform +// A malformed stream can make the same packet fail to parse for every frame it sends -- thousands +// of identical stacks a minute. Log the first occurrence of each in full, then only at 1, 2, 4, 8, +// ... so a persistent fault stays O(log n) instead of unbounded. Keyed per parser instance. +function logThrottled (counts, key, full) { + const n = (counts.get(key) || 0) + 1 + counts.set(key, n) + if (n === 1) console.log(full) + else if ((n & (n - 1)) === 0) console.log(`${key} (repeated ${n} times)`) +} + class Serializer extends Transform { constructor (proto, mainType) { super({ writableObjectMode: true }) @@ -62,6 +72,7 @@ class FullPacketParser extends Transform { this.proto = proto this.mainType = mainType this.noErrorLogging = noErrorLogging + this.errorCounts = new Map() } parsePacketBuffer (buffer) { @@ -73,13 +84,14 @@ class FullPacketParser extends Transform { try { packet = this.parsePacketBuffer(chunk) if (packet.metadata.size !== chunk.length && !this.noErrorLogging) { - console.log('Chunk size is ' + chunk.length + ' but only ' + packet.metadata.size + ' was read ; partial packet : ' + + logThrottled(this.errorCounts, 'chunk size mismatch', + 'Chunk size is ' + chunk.length + ' but only ' + packet.metadata.size + ' was read ; partial packet : ' + JSON.stringify(packet.data) + '; buffer :' + chunk.toString('hex')) } } catch (e) { if (e.partialReadError) { if (!this.noErrorLogging) { - console.log(e.stack) + logThrottled(this.errorCounts, e.stack.split('\n')[0], e.stack) } return cb() } else {