diff --git a/packages/common-server/src/logger.ts b/packages/common-server/src/logger.ts index 0579fba6a7..b1e8c84ed3 100644 --- a/packages/common-server/src/logger.ts +++ b/packages/common-server/src/logger.ts @@ -1,7 +1,6 @@ // import pino from "pino"; import { env } from "@dendronhq/common-all"; -import path from "path"; import pino from "pino"; export class Logger { @@ -19,6 +18,9 @@ export class Logger { // eslint-disable-next-line no-console console.log(this.name, ctx, msg); } + debug = (msg: any) => { + this._log(msg); + }; info = (msg: any) => { this._log(msg); }; @@ -27,7 +29,7 @@ export class Logger { }; } -function createLogger(name?: string) { +function createLogger(name?: string): pino.Logger { const level = env("LOG_LEVEL", { shouldThrow: false }) || "debug"; const nameClean = name || env("LOG_NAME"); @@ -41,7 +43,14 @@ function createLogger(name?: string) { } } -export { createLogger }; +export type DLogger = { + debug: (msg: any) => void; + info: (msg: any) => void; + error: (msg: any) => void; + //fatal: (msg: any) => void; +} + +export { createLogger, pino }; export function logAndThrow(logger: Logger, msg: any): never { logger.error(msg); diff --git a/packages/engine-server/src/drivers/file/parser.ts b/packages/engine-server/src/drivers/file/parser.ts index c560a8e2fb..9835342aff 100644 --- a/packages/engine-server/src/drivers/file/parser.ts +++ b/packages/engine-server/src/drivers/file/parser.ts @@ -13,15 +13,14 @@ import { createLogger, globMatch, mdFile2NodeProps, + pino, + DLogger, } from "@dendronhq/common-server"; import fs from "fs-extra"; import _ from "lodash"; import path from "path"; import YAML from "yamljs"; -// @ts-ignore -const logger = createLogger("FileParser"); - export type FileMeta = { // file name: eg. foo.md, name = foo prefix: string; @@ -46,6 +45,7 @@ function getFileMeta(fpaths: string[]): FileMetaDict { type FileParserOpts = { errorOnEmpty?: boolean; errorOnBadParse?: boolean; + logger?: pino.Logger; }; type FileParserProps = Required; @@ -58,13 +58,17 @@ export class FileParser { public store: DEngineStore; + public logger: DLogger; + constructor(store: DEngineStore, opts?: FileParserOpts) { this.errors = []; this.missing = new Set(); this.opts = _.defaults(opts, { errorOnEmpty: true, errorOnBadParse: true, + logger: createLogger("FileParser"), }); + this.logger = this.opts.logger; this.store = store; } @@ -89,7 +93,7 @@ export class FileParser { try { noteProps = mdFile2NodeProps(path.join(store.opts.root, ent.fpath)); } catch (err) { - logger.error({ ctx: "toNode", ent, opts, err }); + this.logger.error({ ctx: "toNode", ent, opts, err }); if (opts.errorOnBadParse) { throw err; } else { diff --git a/packages/engine-server/src/drivers/file/store.ts b/packages/engine-server/src/drivers/file/store.ts index 1e0c734fba..d458927e69 100644 --- a/packages/engine-server/src/drivers/file/store.ts +++ b/packages/engine-server/src/drivers/file/store.ts @@ -26,16 +26,16 @@ import { mdFile2NodeProps, node2MdFile, schema2YMLFile, + DLogger, } from "@dendronhq/common-server"; import { FileParser } from "./parser"; import _ from "lodash"; import path from "path"; -const logger = createLogger("FileStore"); - interface FileStorageOpts { root: string; + logger?: DLogger; } export function fileNameToTitle(name: string): string { @@ -54,10 +54,13 @@ export abstract class FileStorageBase { public rootId: string; + public logger: DLogger; + constructor(opts: FileStorageOpts) { this.opts = opts; this.idToPath = {}; this.rootId = ""; + this.logger = opts.logger || createLogger("FileStore"); } abstract doGetFile(id: string): DNodeRawProps; @@ -67,19 +70,19 @@ export abstract class FileStorageBase { } async getRoot() { - logger.debug({ ctx: "getRoot", rootId: this.rootId }); + this.logger.debug({ ctx: "getRoot", rootId: this.rootId }); return this.doGetFile(this.rootId); } async get(id: string, _opts?: QueryOpts): Promise { let resp: DNodeRawProps; - logger.debug({ ctx: "get:presGetFile", id }); + this.logger.debug({ ctx: "get:presGetFile", id }); if (this.isRoot(id)) { resp = await this.getRoot(); } else { resp = this.doGetFile(id); } - logger.debug({ ctx: "get:postGetFile", resp }); + this.logger.debug({ ctx: "get:postGetFile", resp }); return { data: resp, }; @@ -163,7 +166,7 @@ export class FileStorage extends FileStorageBase implements DEngineStore { const data = new NodeBuilder().buildSchemaFromProps(schemaProps); // TODO // this.refreshIdToPath(data) - logger.debug({ ctx: "query:exit:pre" }); + this.logger.debug({ ctx: "query:exit:pre" }); return makeResponse({ data, error: null }); } throw Error(`unsupported ${queryString}`); @@ -175,7 +178,7 @@ export class FileStorage extends FileStorageBase implements DEngineStore { const data = new NodeBuilder().buildNoteFromProps(noteProps, { schemas }); this.refreshIdToPath(data); - logger.debug({ ctx: "query:exit:pre" }); + this.logger.debug({ ctx: "query:exit:pre" }); return makeResponse({ data, error: null }); } throw Error(`unsupported ${queryString}`); @@ -186,7 +189,7 @@ export class FileStorage extends FileStorageBase implements DEngineStore { } refreshIdToPath(nodes: IDNode[]) { - logger.debug({ + this.logger.debug({ ctx: "refreshIdToPaths", nodes: nodes.map((n) => n.toRawProps()), }); diff --git a/packages/engine-server/src/engine.ts b/packages/engine-server/src/engine.ts index 641f775df7..56dca5b93c 100644 --- a/packages/engine-server/src/engine.ts +++ b/packages/engine-server/src/engine.ts @@ -30,7 +30,7 @@ import { SchemaRawProps, UpdateNodesOpts, } from "@dendronhq/common-all"; -import { createLogger } from "@dendronhq/common-server"; +import { createLogger, DLogger, Logger } from "@dendronhq/common-server"; import fs from "fs-extra"; import Fuse from "fuse.js"; import _ from "lodash"; @@ -38,7 +38,6 @@ import FileStorage from "./drivers/file/store"; import { BodyParser } from "./drivers/raw/BodyParser"; let _DENDRON_ENGINE: DendronEngine; -const logger = createLogger("DEngine"); function isAllQuery(qs: string): boolean { return qs === "**/*"; @@ -73,6 +72,7 @@ type DendronEngineOpts = { forceNew?: boolean; store?: DEngineStore; mode?: DEngineMode; + logger?: DLogger; }; type DendronEngineProps = Required; @@ -94,21 +94,26 @@ export class DendronEngine implements DEngine { public store: DEngineStore; + public logger: Logger; + static getOrCreateEngine(opts?: DendronEngineOpts): DEngine { + const ctx = "getOrCreateEngine"; if (opts) { const root = opts.root; const optsClean: DendronEngineProps = _.defaults(opts || {}, { forceNew: false, - store: new FileStorage({ root }), + store: new FileStorage({ root, logger: opts?.logger }), root, // TODO: remove cacheDir: "/tmp/dendronCache", mode: "fuzzy", + logger: createLogger("DEngine"), }); if (!_DENDRON_ENGINE || optsClean.forceNew) { if (_.isUndefined(optsClean.root)) { throw Error(`root must be defined`); } + optsClean.logger.info({ ctx, msg: "create new engine" }); // TODO _DENDRON_ENGINE = new DendronEngine(optsClean.store, optsClean); } @@ -132,6 +137,8 @@ export class DendronEngine implements DEngine { }); this.fullNodes = new Set(); this.queries = new Set(); + // @ts-ignore + this.logger = props.logger; // setup schemas this.schemas = {}; @@ -214,7 +221,7 @@ export class DendronEngine implements DEngine { this.notes[id] = node; } else { // exists, merge it - logger.debug({ + this.logger.debug({ ctx: "refreshNodes:existingNode", node: node.toRawProps(), }); @@ -231,7 +238,7 @@ export class DendronEngine implements DEngine { title: n.title, id: n.id, })); - logger.debug({ + this.logger.debug({ ctx: "refreshNodes", newNodes, allNodes, @@ -276,7 +283,7 @@ export class DendronEngine implements DEngine { const tmp = _.find(this.notes, { fname }); if (_.isUndefined(tmp)) { const msg = `node ${idOrFname} not found`; - logger.error({ ctx, msg }); + this.logger.error({ ctx, msg }); throw Error(msg); } noteToDelete = tmp; @@ -305,7 +312,7 @@ export class DendronEngine implements DEngine { async get(id: string, mode: QueryMode, opts?: QueryOpts) { opts = _.defaults(opts || {}, { fullNode: true, createIfNew: true }); let nodeDict; - logger.debug({ ctx: "get", id, opts }); + this.logger.debug({ ctx: "get", id, opts }); if (mode === "schema") { nodeDict = this.schemas; @@ -318,14 +325,14 @@ export class DendronEngine implements DEngine { // a full node has a body and is fully resolved if (opts?.fullNode && !this.fullNodes.has(id)) { - logger.debug({ ctx: "get:fetchFromStore:pre", id }); + this.logger.debug({ ctx: "get:fetchFromStore:pre", id }); const fnResp = await this.store.get(id, { ...opts, webClient: true, }); - logger.debug({ ctx: "get:fetchFromStore:post", id, opts, fnResp }); + this.logger.debug({ ctx: "get:fetchFromStore:post", id, opts, fnResp }); const fullNode = await this.resolveIds(fnResp.data, this.notes); - logger.debug({ ctx: "get:resolve:post", fnResp }); + this.logger.debug({ ctx: "get:resolve:post", fnResp }); // TODO: this.refreshNodes([fullNode], opts); return { data: fullNode }; @@ -349,7 +356,7 @@ export class DendronEngine implements DEngine { // handle all query case if (isAllQuery(queryString)) { - logger.debug({ ctx: "query:queryAll:pre", mode }); + this.logger.debug({ ctx: "query:queryAll:pre", mode }); try { data = await this.store.query("**/*", mode, { ...opts, @@ -357,10 +364,10 @@ export class DendronEngine implements DEngine { }); } catch (err) { if (err instanceof DendronError) { - logger.info({ ctx, msg: "no root found", mode }); + this.logger.info({ ctx, msg: "no root found", mode }); const root = this._createRoot(mode); await this.store.write(root); - logger.info({ ctx, msg: "post:store.write", mode }); + this.logger.info({ ctx, msg: "post:store.write", mode }); return this.query(queryString, mode, opts); } else { throw err; @@ -383,7 +390,7 @@ export class DendronEngine implements DEngine { } else { items = _.map(results, (resp) => resp.item); } - logger.debug({ ctx: "query:exit:schema", items }); + this.logger.debug({ ctx: "query:exit:schema", items }); return makeResponse({ data: _.map(items, (item) => nodes[item.id]), error: null, @@ -408,7 +415,7 @@ export class DendronEngine implements DEngine { items[0]?.path !== queryString && opts.createIfNew ) { - logger.debug({ + this.logger.debug({ ctx: "query:write:pre", queryString, item: items[0], @@ -432,7 +439,7 @@ export class DendronEngine implements DEngine { const fetchedFullNodes = await Promise.all( _.map>(items, async (ent) => { if (!this.fullNodes.has(ent.id)) { - logger.debug({ + this.logger.debug({ ctx: "query:fuse.search:post", status: "fetch full node from store", }); @@ -440,7 +447,7 @@ export class DendronEngine implements DEngine { const fn = await this.get(ent.id, mode); return fn.data; } - logger.debug({ + this.logger.debug({ ctx: "query:fuse.search:post", status: "fetch full node from cache", }); @@ -451,12 +458,12 @@ export class DendronEngine implements DEngine { _.filter(fetchedFullNodes, (ent) => !_.isNull(ent)) as IDNode[], { fullNode: true } ); - logger.debug({ + this.logger.debug({ ctx: "query:fetchedFullNodes:exit", fetchedFullNodes, }); } - logger.debug({ ctx: "query:exit:note", items }); + this.logger.debug({ ctx: "query:exit:note", items }); return makeResponse({ data: _.map(items, (item) => this.notes[item.id]), error: null, diff --git a/packages/plugin-core/.vscode/launch.json b/packages/plugin-core/.vscode/launch.json index 2c0297cc99..68ef5ac6de 100644 --- a/packages/plugin-core/.vscode/launch.json +++ b/packages/plugin-core/.vscode/launch.json @@ -14,12 +14,11 @@ // "--disable-extensions", "--extensionDevelopmentPath=${workspaceFolder}" ], - "outFiles": ["${workspaceFolder}/out/**/*.js"], + "outFiles": ["${workspaceFolder:plugin-core}/out/**/*.js"], "env": { "STAGE": "dev", "VSCODE_DEBUGGING_EXTENSION": "dendron" } - //"preLaunchTask": "npm: watch no }, { "name": "Extension Tests", diff --git a/packages/plugin-core/package.json b/packages/plugin-core/package.json index 916cc75785..942b633d0f 100644 --- a/packages/plugin-core/package.json +++ b/packages/plugin-core/package.json @@ -82,6 +82,10 @@ "command": "dendron.dev.resetConfig", "title": "Dev:Dendron: ResetConfig" }, + { + "command": "dendron.dev.openLogs", + "title": "Dev:Dendron: Open Logs" + }, { "command": "dendron.openLink", "title": "Dendron: Open Link" diff --git a/packages/plugin-core/src/commands/OpenLogs.ts b/packages/plugin-core/src/commands/OpenLogs.ts new file mode 100644 index 0000000000..de22912241 --- /dev/null +++ b/packages/plugin-core/src/commands/OpenLogs.ts @@ -0,0 +1,21 @@ +import { Uri, workspace, window } from "vscode"; +import { Logger } from "../logger"; +import { BaseCommand } from "./base"; +const L = Logger; + +type OpenLogsCommandOpts = { +}; + +export class OpenLogsCommand extends BaseCommand { + async execute(opts: OpenLogsCommandOpts) { + const ctx = "execute"; + L.info({ ctx, opts }); + const logPath = Logger.logPath; + if (!logPath) { + throw Error("logPath not defined"); + } + const doc= await workspace.openTextDocument(Uri.file(logPath)); + window.showTextDocument(doc); + return; + } +} diff --git a/packages/plugin-core/src/commands/ReloadIndex.ts b/packages/plugin-core/src/commands/ReloadIndex.ts index b4199b42c1..bc753c5a34 100644 --- a/packages/plugin-core/src/commands/ReloadIndex.ts +++ b/packages/plugin-core/src/commands/ReloadIndex.ts @@ -2,6 +2,7 @@ import { createLogger } from "@dendronhq/common-server"; import { BaseCommand } from "./base"; import { DendronEngine } from "@dendronhq/engine-server"; import { DEngine } from "@dendronhq/common-all/src"; +import { DendronWorkspace } from "../workspace"; const L = createLogger("ReloadIndexCommand"); @@ -13,9 +14,11 @@ export class ReloadIndexCommand extends BaseCommand | undefined; + static logPath?: string static configure(context: ExtensionContext, level: TraceLevel) { fs.ensureDirSync(context.logPath); - setEnv("LOG_DST", posix.join(context.logPath, "dendron.log")); + const logPath = path.join(context.logPath, "dendron.log"); + setEnv("LOG_DST", logPath); + Logger.logPath = logPath; this.logger = createLogger("dendron"); this.level = level; } @@ -73,10 +76,10 @@ export class Logger { this.output?.appendLine(JSON.stringify(msg)); } - static log(msg: any, lvl: TraceLevel, _opts?: { show?: boolean }) { + static log = (msg: any, lvl: TraceLevel, _opts?: { show?: boolean }) => { if (Logger.cmpLevel(lvl)) { Logger.logger && Logger.logger[lvl](msg); - this.output?.appendLine(lvl + ": " + JSON.stringify(msg)); + Logger.output?.appendLine(lvl + ": " + JSON.stringify(msg)); // FIXME: disable for now const shouldShow = false; // getStage() === "dev" && cleanOpts.show; if (shouldShow || Logger.cmpLevels(lvl, "error")) { diff --git a/packages/plugin-core/src/workspace.ts b/packages/plugin-core/src/workspace.ts index a8bb88380e..96d85801b1 100644 --- a/packages/plugin-core/src/workspace.ts +++ b/packages/plugin-core/src/workspace.ts @@ -36,6 +36,7 @@ import { VSCodeUtils } from "./utils"; import { isAnythingSelected } from "./utils/editor"; +import { OpenLogsCommand } from "./commands/OpenLogs"; let _DendronWorkspace: DendronWorkspace | null; @@ -445,6 +446,19 @@ export class DendronWorkspace { ) ); + this.context.subscriptions.push( + vscode.commands.registerCommand( + DENDRON_COMMANDS.OPEN_LOGS, + async () => { + try { + await new OpenLogsCommand().execute({}); + } catch(err) { + Logger.error(JSON.stringify(err)); + } + } + ) + ); + this.context.subscriptions.push( vscode.commands.registerCommand( DENDRON_COMMANDS.UPGRADE_SETTINGS,