logtodb
This commit is contained in:
parent
b39544b43b
commit
b3c107ce58
@ -84,6 +84,7 @@ export interface RemotelySavePluginSettings {
|
|||||||
syncConfigDir?: boolean;
|
syncConfigDir?: boolean;
|
||||||
syncUnderscoreItems?: boolean;
|
syncUnderscoreItems?: boolean;
|
||||||
lang?: LangTypeAndAuto;
|
lang?: LangTypeAndAuto;
|
||||||
|
logToDB?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated
|
* @deprecated
|
||||||
@ -156,3 +157,8 @@ export const API_VER_STAT_FOLDER = "0.13.27";
|
|||||||
export const API_VER_REQURL = "0.13.26";
|
export const API_VER_REQURL = "0.13.26";
|
||||||
export const VALID_REQURL =
|
export const VALID_REQURL =
|
||||||
requireApiVersion(API_VER_REQURL) && !Platform.isAndroidApp;
|
requireApiVersion(API_VER_REQURL) && !Platform.isAndroidApp;
|
||||||
|
|
||||||
|
export const DEFAULT_DEBUG_FOLDER = "_debug_remotely_save/";
|
||||||
|
export const DEFAULT_SYNC_PLANS_HISTORY_FILE_PREFIX =
|
||||||
|
"sync_plans_hist_exported_on_";
|
||||||
|
export const DEFAULT_LOG_HISTORY_FILE_PREFIX = "log_hist_exported_on_";
|
||||||
|
|||||||
@ -3,8 +3,7 @@ import { reverseString } from "./misc";
|
|||||||
|
|
||||||
import type { RemotelySavePluginSettings } from "./baseTypes";
|
import type { RemotelySavePluginSettings } from "./baseTypes";
|
||||||
|
|
||||||
import * as origLog from "loglevel";
|
import { log } from "./moreOnLog";
|
||||||
const log = origLog.getLogger("rs-default");
|
|
||||||
|
|
||||||
const DEFAULT_README: string =
|
const DEFAULT_README: string =
|
||||||
"The file contains sensitive info, so DO NOT take screenshot of, copy, or share it to anyone! It's also generated automatically, so do not edit it manually.";
|
"The file contains sensitive info, so DO NOT take screenshot of, copy, or share it to anyone! It's also generated automatically, so do not edit it manually.";
|
||||||
|
|||||||
@ -1,15 +1,19 @@
|
|||||||
import { TAbstractFile, TFolder, TFile, Vault } from "obsidian";
|
import { TAbstractFile, TFolder, TFile, Vault } from "obsidian";
|
||||||
|
|
||||||
import type { SyncPlanType } from "./sync";
|
import type { SyncPlanType } from "./sync";
|
||||||
import { readAllSyncPlanRecordTextsByVault } from "./localdb";
|
import {
|
||||||
|
readAllSyncPlanRecordTextsByVault,
|
||||||
|
readAllLogRecordTextsByVault,
|
||||||
|
} from "./localdb";
|
||||||
import type { InternalDBs } from "./localdb";
|
import type { InternalDBs } from "./localdb";
|
||||||
import { mkdirpInVault } from "./misc";
|
import { mkdirpInVault } from "./misc";
|
||||||
|
import {
|
||||||
|
DEFAULT_DEBUG_FOLDER,
|
||||||
|
DEFAULT_LOG_HISTORY_FILE_PREFIX,
|
||||||
|
DEFAULT_SYNC_PLANS_HISTORY_FILE_PREFIX,
|
||||||
|
} from "./baseTypes";
|
||||||
|
|
||||||
import * as origLog from "loglevel";
|
import { log } from "./moreOnLog";
|
||||||
const log = origLog.getLogger("rs-default");
|
|
||||||
|
|
||||||
const DEFAULT_DEBUG_FOLDER = "_debug_remotely_save/";
|
|
||||||
const DEFAULT_SYNC_PLANS_HISTORY_FILE_PREFIX = "sync_plans_hist_exported_on_";
|
|
||||||
|
|
||||||
export const exportVaultSyncPlansToFiles = async (
|
export const exportVaultSyncPlansToFiles = async (
|
||||||
db: InternalDBs,
|
db: InternalDBs,
|
||||||
@ -34,3 +38,27 @@ export const exportVaultSyncPlansToFiles = async (
|
|||||||
});
|
});
|
||||||
log.info("finish exporting");
|
log.info("finish exporting");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const exportVaultLoggerOutputToFiles = async (
|
||||||
|
db: InternalDBs,
|
||||||
|
vault: Vault,
|
||||||
|
vaultRandomID: string
|
||||||
|
) => {
|
||||||
|
await mkdirpInVault(DEFAULT_DEBUG_FOLDER, vault);
|
||||||
|
const records = await readAllLogRecordTextsByVault(db, vaultRandomID);
|
||||||
|
let md = "";
|
||||||
|
if (records.length === 0) {
|
||||||
|
md = "No logger history found.";
|
||||||
|
} else {
|
||||||
|
md =
|
||||||
|
"Logger history found:\n\n" +
|
||||||
|
"```text\n" +
|
||||||
|
records.join("\n") +
|
||||||
|
"\n```\n";
|
||||||
|
}
|
||||||
|
const ts = Date.now();
|
||||||
|
const filePath = `${DEFAULT_DEBUG_FOLDER}${DEFAULT_LOG_HISTORY_FILE_PREFIX}${ts}.md`;
|
||||||
|
await vault.create(filePath, md, {
|
||||||
|
mtime: ts,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import { base32, base64url } from "rfc4648";
|
import { base32, base64url } from "rfc4648";
|
||||||
import { bufferToArrayBuffer, hexStringToTypedArray } from "./misc";
|
import { bufferToArrayBuffer, hexStringToTypedArray } from "./misc";
|
||||||
|
|
||||||
import * as origLog from "loglevel";
|
import { log } from "./moreOnLog";
|
||||||
const log = origLog.getLogger("rs-default");
|
|
||||||
|
|
||||||
const DEFAULT_ITER = 20000;
|
const DEFAULT_ITER = 20000;
|
||||||
|
|
||||||
|
|||||||
@ -7,8 +7,7 @@ import {
|
|||||||
RemotelySavePluginSettings,
|
RemotelySavePluginSettings,
|
||||||
} from "./baseTypes";
|
} from "./baseTypes";
|
||||||
|
|
||||||
import * as origLog from "loglevel";
|
import { log } from "./moreOnLog";
|
||||||
const log = origLog.getLogger("rs-default");
|
|
||||||
|
|
||||||
export const exportQrCodeUri = async (
|
export const exportQrCodeUri = async (
|
||||||
settings: RemotelySavePluginSettings,
|
settings: RemotelySavePluginSettings,
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
Subproject commit 75a3b2a830c5e3286fa26a0c13178505f7ff5cac
|
Subproject commit 2afc10b080356dc8d25e77105838fcfc91f072c6
|
||||||
103
src/localdb.ts
103
src/localdb.ts
@ -1,14 +1,13 @@
|
|||||||
import localforage from "localforage";
|
import localforage from "localforage";
|
||||||
|
export type LocalForage = typeof localforage;
|
||||||
|
import { nanoid } from "nanoid";
|
||||||
import { requireApiVersion, TAbstractFile, TFile, TFolder } from "obsidian";
|
import { requireApiVersion, TAbstractFile, TFile, TFolder } from "obsidian";
|
||||||
|
|
||||||
import { API_VER_STAT_FOLDER, SUPPORTED_SERVICES_TYPE } from "./baseTypes";
|
import { API_VER_STAT_FOLDER, SUPPORTED_SERVICES_TYPE } from "./baseTypes";
|
||||||
import type { SyncPlanType } from "./sync";
|
import type { SyncPlanType } from "./sync";
|
||||||
|
import { toText, unixTimeToStr } from "./misc";
|
||||||
|
|
||||||
export type LocalForage = typeof localforage;
|
import { log } from "./moreOnLog";
|
||||||
|
|
||||||
import * as origLog from "loglevel";
|
|
||||||
import { nanoid } from "nanoid";
|
|
||||||
const log = origLog.getLogger("rs-default");
|
|
||||||
|
|
||||||
const DB_VERSION_NUMBER_IN_HISTORY = [20211114, 20220108, 20220326];
|
const DB_VERSION_NUMBER_IN_HISTORY = [20211114, 20220108, 20220326];
|
||||||
export const DEFAULT_DB_VERSION_NUMBER: number = 20220326;
|
export const DEFAULT_DB_VERSION_NUMBER: number = 20220326;
|
||||||
@ -18,6 +17,7 @@ export const DEFAULT_TBL_FILE_HISTORY = "filefolderoperationhistory";
|
|||||||
export const DEFAULT_TBL_SYNC_MAPPING = "syncmetadatahistory";
|
export const DEFAULT_TBL_SYNC_MAPPING = "syncmetadatahistory";
|
||||||
export const DEFAULT_SYNC_PLANS_HISTORY = "syncplanshistory";
|
export const DEFAULT_SYNC_PLANS_HISTORY = "syncplanshistory";
|
||||||
export const DEFAULT_TBL_VAULT_RANDOM_ID_MAPPING = "vaultrandomidmapping";
|
export const DEFAULT_TBL_VAULT_RANDOM_ID_MAPPING = "vaultrandomidmapping";
|
||||||
|
export const DEFAULT_TBL_LOGGER_OUTPUT = "loggeroutput";
|
||||||
|
|
||||||
export interface FileFolderHistoryRecord {
|
export interface FileFolderHistoryRecord {
|
||||||
key: string;
|
key: string;
|
||||||
@ -57,6 +57,7 @@ export interface InternalDBs {
|
|||||||
syncMappingTbl: LocalForage;
|
syncMappingTbl: LocalForage;
|
||||||
syncPlansTbl: LocalForage;
|
syncPlansTbl: LocalForage;
|
||||||
vaultRandomIDMappingTbl: LocalForage;
|
vaultRandomIDMappingTbl: LocalForage;
|
||||||
|
loggerOutputTbl: LocalForage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -211,6 +212,10 @@ export const prepareDBs = async (
|
|||||||
name: DEFAULT_DB_NAME,
|
name: DEFAULT_DB_NAME,
|
||||||
storeName: DEFAULT_TBL_VAULT_RANDOM_ID_MAPPING,
|
storeName: DEFAULT_TBL_VAULT_RANDOM_ID_MAPPING,
|
||||||
}),
|
}),
|
||||||
|
loggerOutputTbl: localforage.createInstance({
|
||||||
|
name: DEFAULT_DB_NAME,
|
||||||
|
storeName: DEFAULT_TBL_LOGGER_OUTPUT,
|
||||||
|
}),
|
||||||
} as InternalDBs;
|
} as InternalDBs;
|
||||||
|
|
||||||
// try to get vaultRandomID firstly
|
// try to get vaultRandomID firstly
|
||||||
@ -546,3 +551,91 @@ export const readAllSyncPlanRecordTextsByVault = async (
|
|||||||
return records.map((x) => x.syncPlan);
|
return records.map((x) => x.syncPlan);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const readAllLogRecordTextsByVault = async (
|
||||||
|
db: InternalDBs,
|
||||||
|
vaultRandomID: string
|
||||||
|
) => {
|
||||||
|
const records = [] as { ts: number; r: string }[];
|
||||||
|
await db.loggerOutputTbl.iterate((value, key, iterationNumber) => {
|
||||||
|
if (key.startsWith(`${vaultRandomID}\t`)) {
|
||||||
|
const item = {
|
||||||
|
ts: parseInt(key.split("\t")[1]),
|
||||||
|
r: value as string,
|
||||||
|
};
|
||||||
|
records.push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// while reading the logs, we want it to be ascending
|
||||||
|
records.sort((a, b) => a.ts - b.ts);
|
||||||
|
|
||||||
|
if (records === undefined) {
|
||||||
|
return [] as string[];
|
||||||
|
} else {
|
||||||
|
return records.map((x) => x.r);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const insertLoggerOutputByVault = async (
|
||||||
|
db: InternalDBs,
|
||||||
|
vaultRandomID: string,
|
||||||
|
...msg: any[]
|
||||||
|
) => {
|
||||||
|
const ts = Date.now();
|
||||||
|
const tsFmt = unixTimeToStr(ts);
|
||||||
|
const key = `${vaultRandomID}\t${ts}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const val = [`[${tsFmt}]`, ...msg.map((x) => toText(x))].join(" ");
|
||||||
|
db.loggerOutputTbl.setItem(key, val);
|
||||||
|
} catch (err) {
|
||||||
|
// give up, and let it pass
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const clearAllLoggerOutputRecords = async (db: InternalDBs) => {
|
||||||
|
await db.loggerOutputTbl.clear();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We remove records that are older than 7 days or 10000 records.
|
||||||
|
* It's a heavy operation, so we shall not place it in the start up.
|
||||||
|
* @param db
|
||||||
|
*/
|
||||||
|
export const clearExpiredLoggerOutputRecords = async (db: InternalDBs) => {
|
||||||
|
const MILLISECONDS_OLD = 1000 * 60 * 60 * 24 * 7; // 7 days
|
||||||
|
const COUNT_TO_MANY = 10000;
|
||||||
|
|
||||||
|
const currTs = Date.now();
|
||||||
|
const expiredTs = currTs - MILLISECONDS_OLD;
|
||||||
|
|
||||||
|
let records = (await db.loggerOutputTbl.keys()).map((key) => {
|
||||||
|
const ts = parseInt(key.split("\t")[1]);
|
||||||
|
const expired = ts <= expiredTs;
|
||||||
|
return {
|
||||||
|
ts: ts,
|
||||||
|
key: key,
|
||||||
|
expired: expired,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const keysToRemove = new Set(
|
||||||
|
records.filter((x) => x.expired).map((x) => x.key)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (records.length - keysToRemove.size > COUNT_TO_MANY) {
|
||||||
|
// we need to find out records beyond 10000 records
|
||||||
|
records = records.filter((x) => !x.expired); // shrink the array
|
||||||
|
records.sort((a, b) => -(a.ts - b.ts)); // descending
|
||||||
|
records.slice(COUNT_TO_MANY).forEach((element) => {
|
||||||
|
keysToRemove.add(element.key);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const ps = [] as Promise<void>[];
|
||||||
|
keysToRemove.forEach((element) => {
|
||||||
|
ps.push(db.loggerOutputTbl.removeItem(element));
|
||||||
|
});
|
||||||
|
await Promise.all(ps);
|
||||||
|
};
|
||||||
|
|||||||
45
src/main.ts
45
src/main.ts
@ -24,6 +24,8 @@ import {
|
|||||||
loadFileHistoryTableByVault,
|
loadFileHistoryTableByVault,
|
||||||
prepareDBs,
|
prepareDBs,
|
||||||
InternalDBs,
|
InternalDBs,
|
||||||
|
insertLoggerOutputByVault,
|
||||||
|
clearExpiredLoggerOutputRecords,
|
||||||
} from "./localdb";
|
} from "./localdb";
|
||||||
import { RemoteClient } from "./remote";
|
import { RemoteClient } from "./remote";
|
||||||
import {
|
import {
|
||||||
@ -48,11 +50,11 @@ import { ObsConfigDirFileType, listFilesInObsFolder } from "./obsFolderLister";
|
|||||||
import { I18n } from "./i18n";
|
import { I18n } from "./i18n";
|
||||||
import type { LangType, LangTypeAndAuto, TransItemType } from "./i18n";
|
import type { LangType, LangTypeAndAuto, TransItemType } from "./i18n";
|
||||||
|
|
||||||
import * as origLog from "loglevel";
|
|
||||||
import { DeletionOnRemote, MetadataOnRemote } from "./metadataOnRemote";
|
import { DeletionOnRemote, MetadataOnRemote } from "./metadataOnRemote";
|
||||||
import { SyncAlgoV2Modal } from "./syncAlgoV2Notice";
|
import { SyncAlgoV2Modal } from "./syncAlgoV2Notice";
|
||||||
import { applyPresetRulesInplace } from "./presetRules";
|
import { applyPresetRulesInplace } from "./presetRules";
|
||||||
const log = origLog.getLogger("rs-default");
|
|
||||||
|
import { applyLogWriterInplace, log } from "./moreOnLog";
|
||||||
|
|
||||||
const DEFAULT_SETTINGS: RemotelySavePluginSettings = {
|
const DEFAULT_SETTINGS: RemotelySavePluginSettings = {
|
||||||
s3: DEFAULT_S3_CONFIG,
|
s3: DEFAULT_S3_CONFIG,
|
||||||
@ -70,6 +72,7 @@ const DEFAULT_SETTINGS: RemotelySavePluginSettings = {
|
|||||||
syncConfigDir: false,
|
syncConfigDir: false,
|
||||||
syncUnderscoreItems: false,
|
syncUnderscoreItems: false,
|
||||||
lang: "auto",
|
lang: "auto",
|
||||||
|
logToDB: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
interface OAuth2Info {
|
interface OAuth2Info {
|
||||||
@ -343,8 +346,8 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
triggerSource: triggerSource,
|
triggerSource: triggerSource,
|
||||||
syncStatus: this.syncStatus,
|
syncStatus: this.syncStatus,
|
||||||
});
|
});
|
||||||
log.info(msg);
|
log.error(msg);
|
||||||
log.info(error);
|
log.error(error);
|
||||||
getNotice(msg, 10 * 1000);
|
getNotice(msg, 10 * 1000);
|
||||||
getNotice(error.message, 10 * 1000);
|
getNotice(error.message, 10 * 1000);
|
||||||
this.syncStatus = "idle";
|
this.syncStatus = "idle";
|
||||||
@ -412,6 +415,10 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// must AFTER preparing DB
|
||||||
|
this.addOutputToDBIfSet();
|
||||||
|
this.enableAutoClearOutputToDBHistIfSet();
|
||||||
|
|
||||||
this.syncStatus = "idle";
|
this.syncStatus = "idle";
|
||||||
|
|
||||||
this.registerEvent(
|
this.registerEvent(
|
||||||
@ -911,4 +918,34 @@ export default class RemotelySavePlugin extends Plugin {
|
|||||||
// just skip
|
// just skip
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addOutputToDBIfSet() {
|
||||||
|
if (this.settings.logToDB) {
|
||||||
|
applyLogWriterInplace((...msg: any[]) => {
|
||||||
|
insertLoggerOutputByVault(this.db, this.vaultRandomID, ...msg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enableAutoClearOutputToDBHistIfSet() {
|
||||||
|
const initClearOutputToDBHistAfterMilliseconds = 1000 * 45;
|
||||||
|
const autoClearOutputToDBHistAfterMilliseconds = 1000 * 60 * 5;
|
||||||
|
|
||||||
|
this.app.workspace.onLayoutReady(() => {
|
||||||
|
// init run
|
||||||
|
window.setTimeout(() => {
|
||||||
|
if (this.settings.logToDB) {
|
||||||
|
clearExpiredLoggerOutputRecords(this.db);
|
||||||
|
}
|
||||||
|
}, initClearOutputToDBHistAfterMilliseconds);
|
||||||
|
|
||||||
|
// scheduled run
|
||||||
|
const intervalID = window.setInterval(() => {
|
||||||
|
if (this.settings.logToDB) {
|
||||||
|
clearExpiredLoggerOutputRecords(this.db);
|
||||||
|
}
|
||||||
|
}, autoClearOutputToDBHistAfterMilliseconds);
|
||||||
|
this.registerInterval(intervalID);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
64
src/misc.ts
64
src/misc.ts
@ -4,8 +4,7 @@ import * as path from "path";
|
|||||||
import { base32, base64url } from "rfc4648";
|
import { base32, base64url } from "rfc4648";
|
||||||
import XRegExp from "xregexp";
|
import XRegExp from "xregexp";
|
||||||
|
|
||||||
import * as origLog from "loglevel";
|
import { log } from "./moreOnLog";
|
||||||
const log = origLog.getLogger("rs-default");
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
@ -319,3 +318,64 @@ export const unixTimeToStr = (x: number | undefined | null) => {
|
|||||||
}
|
}
|
||||||
return window.moment(x).format() as string;
|
return window.moment(x).format() as string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value#examples
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const getCircularReplacer = () => {
|
||||||
|
const seen = new WeakSet();
|
||||||
|
return (key: any, value: any) => {
|
||||||
|
if (typeof value === "object" && value !== null) {
|
||||||
|
if (seen.has(value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
seen.add(value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert "any" value to string.
|
||||||
|
* @param x
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const toText = (x: any) => {
|
||||||
|
if (x === undefined || x === null) {
|
||||||
|
return `${x}`;
|
||||||
|
}
|
||||||
|
if (typeof x === "string") {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
x instanceof String ||
|
||||||
|
x instanceof Date ||
|
||||||
|
typeof x === "number" ||
|
||||||
|
typeof x === "bigint" ||
|
||||||
|
typeof x === "boolean"
|
||||||
|
) {
|
||||||
|
return `${x}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
x instanceof Error ||
|
||||||
|
(x &&
|
||||||
|
x.stack &&
|
||||||
|
x.message &&
|
||||||
|
typeof x.stack === "string" &&
|
||||||
|
typeof x.message === "string")
|
||||||
|
) {
|
||||||
|
return (x.stack || x.message) as string;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const y = JSON.stringify(x, getCircularReplacer(), 2);
|
||||||
|
if (y !== undefined) {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
throw new Error("not jsonable");
|
||||||
|
} catch {
|
||||||
|
return `${x}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
34
src/moreOnLog.ts
Normal file
34
src/moreOnLog.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// It's very dangerous for this file to depend on other files in the same project.
|
||||||
|
// We should avoid this situation as much as possible.
|
||||||
|
|
||||||
|
import { TAbstractFile, TFolder, TFile, Vault } from "obsidian";
|
||||||
|
|
||||||
|
import * as origLog from "loglevel";
|
||||||
|
import type { LogLevelNumbers, Logger, LogLevel, LogLevelDesc } from "loglevel";
|
||||||
|
const log2 = origLog.getLogger("rs-default");
|
||||||
|
|
||||||
|
const originalFactory = log2.methodFactory;
|
||||||
|
|
||||||
|
export const applyLogWriterInplace = function (writer: (...msg: any[]) => any) {
|
||||||
|
log2.methodFactory = function (
|
||||||
|
methodName: string,
|
||||||
|
logLevel: LogLevelNumbers,
|
||||||
|
loggerName: string | symbol
|
||||||
|
) {
|
||||||
|
const rawMethod = originalFactory(methodName, logLevel, loggerName);
|
||||||
|
|
||||||
|
return function (...msg: any[]) {
|
||||||
|
rawMethod.apply(undefined, msg);
|
||||||
|
writer(...msg);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
log2.setLevel(log2.getLevel());
|
||||||
|
};
|
||||||
|
|
||||||
|
export const restoreLogWritterInplace = () => {
|
||||||
|
log2.methodFactory = originalFactory;
|
||||||
|
log2.setLevel(log2.getLevel());
|
||||||
|
};
|
||||||
|
|
||||||
|
export const log = log2;
|
||||||
@ -3,9 +3,6 @@ import { Queue } from "@fyears/tsqueue";
|
|||||||
import chunk from "lodash/chunk";
|
import chunk from "lodash/chunk";
|
||||||
import flatten from "lodash/flatten";
|
import flatten from "lodash/flatten";
|
||||||
|
|
||||||
import * as origLog from "loglevel";
|
|
||||||
const log = origLog.getLogger("rs-default");
|
|
||||||
|
|
||||||
export interface ObsConfigDirFileType {
|
export interface ObsConfigDirFileType {
|
||||||
key: string;
|
key: string;
|
||||||
ctime: number;
|
ctime: number;
|
||||||
|
|||||||
@ -11,8 +11,7 @@ import * as onedrive from "./remoteForOnedrive";
|
|||||||
import * as s3 from "./remoteForS3";
|
import * as s3 from "./remoteForS3";
|
||||||
import * as webdav from "./remoteForWebdav";
|
import * as webdav from "./remoteForWebdav";
|
||||||
|
|
||||||
import * as origLog from "loglevel";
|
import { log } from "./moreOnLog";
|
||||||
const log = origLog.getLogger("rs-default");
|
|
||||||
|
|
||||||
export class RemoteClient {
|
export class RemoteClient {
|
||||||
readonly serviceType: SUPPORTED_SERVICES_TYPE;
|
readonly serviceType: SUPPORTED_SERVICES_TYPE;
|
||||||
|
|||||||
@ -12,8 +12,7 @@ import { bufferToArrayBuffer, getFolderLevels, mkdirpInVault } from "./misc";
|
|||||||
|
|
||||||
export { Dropbox } from "dropbox";
|
export { Dropbox } from "dropbox";
|
||||||
|
|
||||||
import * as origLog from "loglevel";
|
import { log } from "./moreOnLog";
|
||||||
const log = origLog.getLogger("rs-default");
|
|
||||||
|
|
||||||
export const DEFAULT_DROPBOX_CONFIG: DropboxConfig = {
|
export const DEFAULT_DROPBOX_CONFIG: DropboxConfig = {
|
||||||
accessToken: "",
|
accessToken: "",
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import type {
|
|||||||
User,
|
User,
|
||||||
} from "@microsoft/microsoft-graph-types";
|
} from "@microsoft/microsoft-graph-types";
|
||||||
import cloneDeep from "lodash/cloneDeep";
|
import cloneDeep from "lodash/cloneDeep";
|
||||||
import * as origLog from "loglevel";
|
|
||||||
import { request, requestUrl, requireApiVersion, Vault } from "obsidian";
|
import { request, requestUrl, requireApiVersion, Vault } from "obsidian";
|
||||||
import {
|
import {
|
||||||
API_VER_REQURL,
|
API_VER_REQURL,
|
||||||
@ -24,7 +23,7 @@ import {
|
|||||||
mkdirpInVault,
|
mkdirpInVault,
|
||||||
} from "./misc";
|
} from "./misc";
|
||||||
|
|
||||||
const log = origLog.getLogger("rs-default");
|
import { log } from "./moreOnLog";
|
||||||
|
|
||||||
const SCOPES = ["User.Read", "Files.ReadWrite.AppFolder", "offline_access"];
|
const SCOPES = ["User.Read", "Files.ReadWrite.AppFolder", "offline_access"];
|
||||||
const REDIRECT_URI = `obsidian://${COMMAND_CALLBACK_ONEDRIVE}`;
|
const REDIRECT_URI = `obsidian://${COMMAND_CALLBACK_ONEDRIVE}`;
|
||||||
|
|||||||
@ -39,8 +39,7 @@ import {
|
|||||||
|
|
||||||
export { S3Client } from "@aws-sdk/client-s3";
|
export { S3Client } from "@aws-sdk/client-s3";
|
||||||
|
|
||||||
import * as origLog from "loglevel";
|
import { log } from "./moreOnLog";
|
||||||
const log = origLog.getLogger("rs-default");
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// special handler using Obsidian requestUrl
|
// special handler using Obsidian requestUrl
|
||||||
|
|||||||
@ -9,8 +9,7 @@ import { RemoteItem, VALID_REQURL, WebdavConfig } from "./baseTypes";
|
|||||||
import { decryptArrayBuffer, encryptArrayBuffer } from "./encrypt";
|
import { decryptArrayBuffer, encryptArrayBuffer } from "./encrypt";
|
||||||
import { bufferToArrayBuffer, getPathFolder, mkdirpInVault } from "./misc";
|
import { bufferToArrayBuffer, getPathFolder, mkdirpInVault } from "./misc";
|
||||||
|
|
||||||
import * as origLog from "loglevel";
|
import { log } from "./moreOnLog";
|
||||||
const log = origLog.getLogger("rs-default");
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
FileStat,
|
FileStat,
|
||||||
|
|||||||
@ -9,18 +9,25 @@ import {
|
|||||||
} from "obsidian";
|
} from "obsidian";
|
||||||
import {
|
import {
|
||||||
API_VER_REQURL,
|
API_VER_REQURL,
|
||||||
|
DEFAULT_DEBUG_FOLDER,
|
||||||
SUPPORTED_SERVICES_TYPE,
|
SUPPORTED_SERVICES_TYPE,
|
||||||
SUPPORTED_SERVICES_TYPE_WITH_REMOTE_BASE_DIR,
|
SUPPORTED_SERVICES_TYPE_WITH_REMOTE_BASE_DIR,
|
||||||
VALID_REQURL,
|
VALID_REQURL,
|
||||||
WebdavAuthType,
|
WebdavAuthType,
|
||||||
WebdavDepthType,
|
WebdavDepthType,
|
||||||
} from "./baseTypes";
|
} from "./baseTypes";
|
||||||
import { exportVaultSyncPlansToFiles } from "./debugMode";
|
import {
|
||||||
|
exportVaultSyncPlansToFiles,
|
||||||
|
exportVaultLoggerOutputToFiles,
|
||||||
|
} from "./debugMode";
|
||||||
import { exportQrCodeUri } from "./importExport";
|
import { exportQrCodeUri } from "./importExport";
|
||||||
import {
|
import {
|
||||||
clearAllSyncMetaMapping,
|
clearAllSyncMetaMapping,
|
||||||
clearAllSyncPlanRecords,
|
clearAllSyncPlanRecords,
|
||||||
destroyDBs,
|
destroyDBs,
|
||||||
|
clearAllLoggerOutputRecords,
|
||||||
|
insertLoggerOutputByVault,
|
||||||
|
clearExpiredLoggerOutputRecords,
|
||||||
} from "./localdb";
|
} from "./localdb";
|
||||||
import type RemotelySavePlugin from "./main"; // unavoidable
|
import type RemotelySavePlugin from "./main"; // unavoidable
|
||||||
import { RemoteClient } from "./remote";
|
import { RemoteClient } from "./remote";
|
||||||
@ -36,11 +43,14 @@ import {
|
|||||||
} from "./remoteForOnedrive";
|
} from "./remoteForOnedrive";
|
||||||
import { messyConfigToNormal } from "./configPersist";
|
import { messyConfigToNormal } from "./configPersist";
|
||||||
import type { TransItemType } from "./i18n";
|
import type { TransItemType } from "./i18n";
|
||||||
|
|
||||||
import * as origLog from "loglevel";
|
|
||||||
import { checkHasSpecialCharForDir } from "./misc";
|
import { checkHasSpecialCharForDir } from "./misc";
|
||||||
import { applyWebdavPresetRulesInplace } from "./presetRules";
|
import { applyWebdavPresetRulesInplace } from "./presetRules";
|
||||||
const log = origLog.getLogger("rs-default");
|
|
||||||
|
import {
|
||||||
|
applyLogWriterInplace,
|
||||||
|
log,
|
||||||
|
restoreLogWritterInplace,
|
||||||
|
} from "./moreOnLog";
|
||||||
|
|
||||||
class PasswordModal extends Modal {
|
class PasswordModal extends Modal {
|
||||||
plugin: RemotelySavePlugin;
|
plugin: RemotelySavePlugin;
|
||||||
@ -1702,6 +1712,64 @@ export class RemotelySaveSettingTab extends PluginSettingTab {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const logToDBDiv = debugDiv.createEl("div");
|
||||||
|
new Setting(logToDBDiv)
|
||||||
|
.setName(t("settings_logtodb"))
|
||||||
|
.setDesc(t("settings_logtodb_desc"))
|
||||||
|
.addDropdown(async (dropdown) => {
|
||||||
|
dropdown.addOption("enable", t("enable"));
|
||||||
|
dropdown.addOption("disable", t("disable"));
|
||||||
|
dropdown
|
||||||
|
.setValue(this.plugin.settings.logToDB ? "enable" : "disable")
|
||||||
|
.onChange(async (val: string) => {
|
||||||
|
const logToDB = val === "enable";
|
||||||
|
if (logToDB) {
|
||||||
|
applyLogWriterInplace((...msg: any[]) => {
|
||||||
|
insertLoggerOutputByVault(
|
||||||
|
this.plugin.db,
|
||||||
|
this.plugin.vaultRandomID,
|
||||||
|
...msg
|
||||||
|
);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
restoreLogWritterInplace();
|
||||||
|
}
|
||||||
|
clearExpiredLoggerOutputRecords(this.plugin.db);
|
||||||
|
this.plugin.settings.logToDB = logToDB;
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
new Setting(logToDBDiv)
|
||||||
|
.setName(t("settings_logtodbexport"))
|
||||||
|
.setDesc(
|
||||||
|
t("settings_logtodbexport_desc", {
|
||||||
|
debugFolder: DEFAULT_DEBUG_FOLDER,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.addButton(async (button) => {
|
||||||
|
button.setButtonText(t("settings_logtodbexport_button"));
|
||||||
|
button.onClick(async () => {
|
||||||
|
await exportVaultLoggerOutputToFiles(
|
||||||
|
this.plugin.db,
|
||||||
|
this.app.vault,
|
||||||
|
this.plugin.vaultRandomID
|
||||||
|
);
|
||||||
|
new Notice(t("settings_logtodbexport_notice"));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
new Setting(logToDBDiv)
|
||||||
|
.setName(t("settings_logtodbclear"))
|
||||||
|
.setDesc(t("settings_logtodbclear_desc"))
|
||||||
|
.addButton(async (button) => {
|
||||||
|
button.setButtonText(t("settings_logtodbclear_button"));
|
||||||
|
button.onClick(async () => {
|
||||||
|
await clearAllLoggerOutputRecords(this.plugin.db);
|
||||||
|
new Notice(t("settings_logtodbclear_notice"));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const syncMappingDiv = debugDiv.createEl("div");
|
const syncMappingDiv = debugDiv.createEl("div");
|
||||||
new Setting(syncMappingDiv)
|
new Setting(syncMappingDiv)
|
||||||
.setName(t("settings_delsyncmap"))
|
.setName(t("settings_delsyncmap"))
|
||||||
|
|||||||
@ -47,8 +47,7 @@ import {
|
|||||||
} from "./metadataOnRemote";
|
} from "./metadataOnRemote";
|
||||||
import { isInsideObsFolder, ObsConfigDirFileType } from "./obsFolderLister";
|
import { isInsideObsFolder, ObsConfigDirFileType } from "./obsFolderLister";
|
||||||
|
|
||||||
import * as origLog from "loglevel";
|
import { log } from "./moreOnLog";
|
||||||
const log = origLog.getLogger("rs-default");
|
|
||||||
|
|
||||||
export type SyncStatusType =
|
export type SyncStatusType =
|
||||||
| "idle"
|
| "idle"
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { App, Modal, Notice, PluginSettingTab, Setting } from "obsidian";
|
import { App, Modal, Notice, PluginSettingTab, Setting } from "obsidian";
|
||||||
import type RemotelySavePlugin from "./main"; // unavoidable
|
import type RemotelySavePlugin from "./main"; // unavoidable
|
||||||
import type { TransItemType } from "./i18n";
|
import type { TransItemType } from "./i18n";
|
||||||
import * as origLog from "loglevel";
|
|
||||||
const log = origLog.getLogger("rs-default");
|
import { log } from "./moreOnLog";
|
||||||
|
|
||||||
export class SyncAlgoV2Modal extends Modal {
|
export class SyncAlgoV2Modal extends Modal {
|
||||||
agree: boolean;
|
agree: boolean;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user