simplify log filtering, while also adding depth based filtering

This commit is contained in:
Bruno Windels 2021-02-16 15:07:17 +01:00
parent 78805f0a65
commit 4defbe1322
4 changed files with 97 additions and 117 deletions

View file

@ -15,7 +15,7 @@ limitations under the License.
*/
import {LogItem} from "./LogItem.js";
import {LogLevel} from "./LogFilter.js";
import {LogLevel, LogFilter} from "./LogFilter.js";
export class BaseLogger {
constructor({platform}) {
@ -33,13 +33,19 @@ export class BaseLogger {
this._platform.settingsStorage.setBool("anonymize", this._anonymize);
}
run(labelOrValues, callback, logFilterDef) {
const item = new LogItem(labelOrValues, logFilterDef, this._platform, this._anonymize);
run(labelOrValues, callback, logLevel = LogLevel.Info, filterCreator = null) {
const item = new LogItem(labelOrValues, logLevel, null, this._platform, this._anonymize);
this._openItems.add(item);
const finishItem = () => {
const serialized = item.serialize(null);
console.log("serialized log item", item, serialized);
let filter = new LogFilter();
if (filterCreator) {
filter = filterCreator(filter, this);
} else {
// if not filter is specified, filter out anything lower than the initial log level
filter = filter.minLevel(logLevel);
}
const serialized = item.serialize(filter, 0);
if (serialized) {
this._persistItem(serialized);
}

View file

@ -24,74 +24,37 @@ export const LogLevel = {
Off: 7,
}
export function wrapLogFilterSource(logFilterDef) {
if (typeof logFilterDef === "function") {
return new DeferredFilterCreator(logFilterDef);
} else if (typeof logFilterDef === "number") {
return new SimpleFilterCreator(logFilterDef);
}
return null;
}
class LogFilter {
export class LogFilter {
constructor(parentFilter) {
this._default = parentFilter ? parentFilter._default : null;
this._min = parentFilter ? parentFilter._min : null;
this._parentFilter = parentFilter;
this._min = null;
this._maxDepth = null;
}
filter(item, children, depth) {
if (this._parentFilter) {
if (!this._parentFilter.filter(item, children, depth)) {
return false;
}
}
// neither our children or us have a loglevel high enough, filter out.
if (this._min !== null && children === null && item.logLevel < this._min) {
return false;
} if (this._maxDepth !== null && depth > this._maxDepth) {
return false;
} else {
return true;
}
}
/* methods to build the filter */
min(logLevel) {
minLevel(logLevel) {
this._min = logLevel;
if (this._default === null) {
this._default = logLevel;
}
return this;
}
default(logLevel) {
this._default = logLevel;
if (this._min === null) {
this._min = logLevel;
}
maxDepth(depth) {
this._maxDepth = depth;
return this;
}
/* methods to use the filter */
/** determine log level for item */
itemLevel(item) {
if (item._error) {
return LogLevel.Error;
}
return this._default;
}
/** determines whether an item should be persisted */
includeItem(item, logLevel, children) {
// neither our children or us have a loglevel high enough, bail out.
return logLevel >= this._min || children;
}
}
/**
* Allows to determine the log level of an item after it has finished.
* So we can set the log level on the item duration for example.
*/
class DeferredFilterCreator {
constructor(fn) {
this._fn = fn;
}
createFilter(item, parentFilter) {
return this._fn(new LogFilter(parentFilter), item);
}
}
class SimpleFilterCreator {
constructor(logLevel) {
this._logLevel = logLevel;
}
createFilter(item, parentFilter) {
return new LogFilter(parentFilter).default(this._logLevel);
}
}

View file

@ -14,29 +14,30 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {LogLevel, wrapLogFilterSource} from "./LogFilter.js";
import {LogLevel, LogFilter} from "./LogFilter.js";
export class LogItem {
constructor(labelOrValues, logFilterDef, platform, anonymize) {
constructor(labelOrValues, logLevel, filterCreator, platform, anonymize) {
this._platform = platform;
this._anonymize = anonymize;
this._start = platform.clock.now();
this._end = null;
this._values = typeof labelOrValues === "string" ? {label: labelOrValues} : labelOrValues;
this._error = null;
this._children = [];
this._logFilterSource = wrapLogFilterSource(logFilterDef);
this._values = typeof labelOrValues === "string" ? {l: labelOrValues} : labelOrValues;
this.error = null;
this.logLevel = logLevel;
this._children = null;
this._filterCreator = filterCreator;
}
/**
* Creates a new child item and runs it in `callback`.
*/
wrap(labelOrValues, callback, logFilterDef = null) {
const item = this.child(labelOrValues, logFilterDef);
wrap(labelOrValues, callback, logLevel = LogLevel.Info, filterCreator = null) {
const item = this.child(labelOrValues, logLevel, filterCreator);
return item.run(callback);
}
duration() {
get duration() {
if (this._end) {
return this._end - this._start;
} else {
@ -50,8 +51,8 @@ export class LogItem {
*
* Hence, the child item is not returned.
*/
log(labelOrValues, logFilterDef = null) {
const item = this.child(labelOrValues, logFilterDef);
log(labelOrValues, logLevel = LogLevel.Info) {
const item = this.child(labelOrValues, logLevel, null);
item.end = item.start;
}
@ -73,41 +74,45 @@ export class LogItem {
}
}
serialize(parentFilter) {
const filter = this._logFilterSource ? this._logFilterSource.createFilter(this, parentFilter) : parentFilter;
const logLevel = filter.itemLevel(this);
console.log("logLevel for item", logLevel);
const children = this._children.reduce((array, c) => {
const s = c.serialize(filter);
if (s) {
array = array || [];
array.push(s);
}
return array;
}, null);
if (!filter.includeItem(this, logLevel, children)) {
console.log("excluding log item", logLevel, children, this);
serialize(filter, depth) {
if (this._filterCreator) {
filter = this._filterCreator(new LogFilter(filter), this);
}
let children;
if (this._children !== null) {
children = this._children.reduce((array, c) => {
const s = c.serialize(filter, depth + 1);
if (s) {
if (array === null) {
array = [];
}
array.push(s);
}
return array;
}, null);
}
if (!filter.filter(this, children, depth)) {
return null;
}
let error = null;
if (this._error) {
error = {
stack: this._error.stack,
name: this._error.name
const item = {
// (s)tart
s: this._start,
// (d)uration
d: this.duration,
// (v)alues
v: this._values,
// (l)evel
l: this.logLevel
};
if (this.error) {
// (e)rror
item.e = {
stack: this.error.stack,
name: this.error.name
};
}
const item = {
s: this._start,
e: this._end,
v: this._values,
l: logLevel
};
if (error) {
item.err = error;
}
if (children) {
// (c)hildren
item.c = children;
}
return item;
@ -155,8 +160,10 @@ export class LogItem {
*/
finish() {
if (this._end === null) {
for(const c of this._children) {
c.finish();
if (this._children !== null) {
for(const c of this._children) {
c.finish();
}
}
this._end = this._platform.clock.now();
}
@ -168,16 +175,20 @@ export class LogItem {
}
catch(err) {
this._error = err;
this.error = err;
this.logLevel = LogLevel.Error;
this.finish();
return err;
}
child(labelOrValues, logFilterDef = null) {
child(labelOrValues, logLevel, filterCreator) {
if (this._end !== null) {
console.trace("log item is finished, additional logs will likely not be recorded");
}
const item = new LogItem(labelOrValues, logFilterDef, this._platform, this._anonymize);
const item = new LogItem(labelOrValues, logLevel, filterCreator, this._platform, this._anonymize);
if (this._children === null) {
this._children = [];
}
this._children.push(item);
return item;
}

View file

@ -111,13 +111,14 @@ export class Sync {
const timeout = this._status.get() === SyncStatus.Syncing ? INCREMENTAL_TIMEOUT : 0;
const syncResult = await this._logger.run("sync",
log => this._syncRequest(syncToken, timeout, log),
this._logger.level.Info,
(filter, log) => {
if (log.duration >= 2000) {
return filter.min(log.level.Info).default(log.level.Warn);
} if (this._status.get() === SyncStatus.CatchupSync) {
return filter.min(log.level.Info).default(log.level.Info);
if (log.duration >= 2000 || this._status.get() === SyncStatus.CatchupSync) {
return filter.minLevel(log.level.Info);
} else if (log.error) {
return filter.minLevel(log.level.Error);
} else {
return filter.min(log.level.Error);
return filter.maxDepth(0);
}
});
syncToken = syncResult.syncToken;
@ -192,7 +193,6 @@ export class Sync {
const isInitialSync = !syncToken;
syncToken = response.next_batch;
log.set("isInitialSync", isInitialSync);
log.set("syncToken", log.anonymize(syncToken));
log.set("status", this._status.get());