diff --git a/src/locales/en.json b/src/locales/en.json index 8ccb9aba0e..7a665f49ac 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -222,9 +222,6 @@ "Comfy_Locale": { "name": "Language" }, - "Comfy_Logging_Enabled": { - "name": "Enable logging" - }, "Comfy_MaskEditor_BrushAdjustmentSpeed": { "name": "Brush adjustment speed multiplier", "tooltip": "Controls how quickly the brush size and hardness change when adjusting. Higher values mean faster changes." diff --git a/src/locales/ja.json b/src/locales/ja.json index cfb9857c83..f4dc0fd824 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -323,9 +323,6 @@ "Comfy_Locale": { "name": "言語" }, - "Comfy_Logging_Enabled": { - "name": "ログを有効にする" - }, "Comfy_MaskEditor_BrushAdjustmentSpeed": { "name": "ブラシ調整速度の倍率", "tooltip": "調整時にブラシのサイズと硬さがどれだけ速く変化するかを制御します。値が高いほど、変化が速くなります。" diff --git a/src/locales/ru.json b/src/locales/ru.json index 59af71b190..1b346f6037 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -323,9 +323,6 @@ "Comfy_Locale": { "name": "Язык" }, - "Comfy_Logging_Enabled": { - "name": "Включить ведение журнала" - }, "Comfy_MaskEditor_BrushAdjustmentSpeed": { "name": "Множитель скорости регулировки кисти", "tooltip": "Управляет тем, как быстро изменяются размер и жесткость кисти при регулировке. Более высокие значения означают более быстрые изменения." diff --git a/src/locales/zh.json b/src/locales/zh.json index 21e93cd00d..322ca4a960 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -323,9 +323,6 @@ "Comfy_Locale": { "name": "语言" }, - "Comfy_Logging_Enabled": { - "name": "启用日志记录" - }, "Comfy_MaskEditor_BrushAdjustmentSpeed": { "name": "画笔调整速度倍增器", "tooltip": "控制调整时画笔大小和硬度变化的速度。更高的值意味着更快的变化。" diff --git a/src/scripts/app.ts b/src/scripts/app.ts index 1543b3ce73..38acb87955 100644 --- a/src/scripts/app.ts +++ b/src/scripts/app.ts @@ -1,5 +1,4 @@ // @ts-strict-ignore -import { ComfyLogging } from './logging' import { type ComfyWidgetConstructor, ComfyWidgets, @@ -125,7 +124,6 @@ export class ComfyApp { vueAppReady: boolean ui: ComfyUI - logging: ComfyLogging extensions: ComfyExtension[] extensionManager: ExtensionManager _nodeOutputs: Record @@ -195,7 +193,6 @@ export class ComfyApp { constructor() { this.vueAppReady = false this.ui = new ComfyUI(this) - this.logging = new ComfyLogging(this) this.bodyTop = $el('div.comfyui-body-top', { parent: document.body }) this.bodyLeft = $el('div.comfyui-body-left', { parent: document.body }) this.bodyRight = $el('div.comfyui-body-right', { parent: document.body }) @@ -1683,7 +1680,6 @@ export class ComfyApp { useExtensionStore().loadDisabledExtensionNames() const extensions = await api.getExtensions() - this.logging.addEntry('Comfy.App', 'debug', { Extensions: extensions }) // Need to load core extensions first as some custom extensions // may depend on them. @@ -2059,10 +2055,6 @@ export class ComfyApp { if (useSettingStore().get('Comfy.Workflow.ShowMissingNodesWarning')) { showLoadWorkflowWarning({ missingNodeTypes }) } - - this.logging.addEntry('Comfy.App', 'warn', { - MissingNodes: missingNodeTypes - }) } #showMissingModelsError(missingModels, paths) { @@ -2072,10 +2064,6 @@ export class ComfyApp { paths }) } - - this.logging.addEntry('Comfy.App', 'warn', { - MissingModels: missingModels - }) } async loadGraphData( diff --git a/src/scripts/logging.ts b/src/scripts/logging.ts deleted file mode 100644 index 842d781f9d..0000000000 --- a/src/scripts/logging.ts +++ /dev/null @@ -1,383 +0,0 @@ -// @ts-strict-ignore -import { $el, ComfyDialog } from './ui' -import { api } from './api' -import type { ComfyApp } from './app' -import { useToastStore } from '@/stores/toastStore' - -$el('style', { - textContent: ` - .comfy-logging-logs { - display: grid; - color: var(--fg-color); - white-space: pre-wrap; - } - .comfy-logging-log { - display: contents; - } - .comfy-logging-title { - background: var(--tr-even-bg-color); - font-weight: bold; - margin-bottom: 5px; - text-align: center; - } - .comfy-logging-log div { - background: var(--row-bg); - padding: 5px; - } - `, - parent: document.body -}) - -// Stringify function supporting max depth and removal of circular references -// https://stackoverflow.com/a/57193345 -function stringify(val, depth, replacer, space, onGetObjID?) { - depth = isNaN(+depth) ? 1 : depth - var recursMap = new WeakMap() - function _build(val, depth, o?, a?, r?) { - // (JSON.stringify() has it's own rules, which we respect here by using it for property iteration) - return !val || typeof val != 'object' - ? val - : ((r = recursMap.has(val)), - recursMap.set(val, true), - (a = Array.isArray(val)), - r - ? (o = (onGetObjID && onGetObjID(val)) || null) - : JSON.stringify(val, function (k, v) { - if (a || depth > 0) { - if (replacer) v = replacer(k, v) - if (!k) return (a = Array.isArray(v)), (val = v) - !o && (o = a ? [] : {}) - o[k] = _build(v, a ? depth : depth - 1) - } - }), - o === void 0 ? (a ? [] : {}) : o) - } - return JSON.stringify(_build(val, depth), null, space) -} - -const jsonReplacer = (k, v, ui) => { - if (v instanceof Array && v.length === 1) { - v = v[0] - } - if (v instanceof Date) { - v = v.toISOString() - if (ui) { - v = v.split('T')[1] - } - } - if (v instanceof Error) { - let err = '' - if (v.name) err += v.name + '\n' - if (v.message) err += v.message + '\n' - if (v.stack) err += v.stack + '\n' - if (!err) { - err = v.toString() - } - v = err - } - return v -} - -const fileInput: HTMLInputElement = $el('input', { - type: 'file', - accept: '.json', - style: { display: 'none' }, - parent: document.body -}) as HTMLInputElement - -class ComfyLoggingDialog extends ComfyDialog { - logging: any - - constructor(logging) { - super() - this.logging = logging - } - - clear() { - this.logging.clear() - this.show() - } - - export() { - const blob = new Blob( - [stringify([...this.logging.entries], 20, jsonReplacer, '\t')], - { - type: 'application/json' - } - ) - const url = URL.createObjectURL(blob) - const a = $el('a', { - href: url, - download: `comfyui-logs-${Date.now()}.json`, - style: { display: 'none' }, - parent: document.body - }) - a.click() - setTimeout(function () { - a.remove() - window.URL.revokeObjectURL(url) - }, 0) - } - - import() { - fileInput.onchange = () => { - const reader = new FileReader() - reader.onload = () => { - fileInput.remove() - try { - const obj = JSON.parse(reader.result as string) - if (obj instanceof Array) { - this.show(obj) - } else { - throw new Error('Invalid file selected.') - } - } catch (error) { - useToastStore().addAlert('Unable to load logs: ' + error.message) - } - } - reader.readAsText(fileInput.files[0]) - } - fileInput.click() - } - - createButtons() { - return [ - $el('button', { - type: 'button', - textContent: 'Clear', - onclick: () => this.clear() - }), - $el('button', { - type: 'button', - textContent: 'Export logs...', - onclick: () => this.export() - }), - $el('button', { - type: 'button', - textContent: 'View exported logs...', - onclick: () => this.import() - }), - ...super.createButtons() - ] - } - - getTypeColor(type) { - switch (type) { - case 'error': - return 'red' - case 'warn': - return 'orange' - case 'debug': - return 'dodgerblue' - } - } - - show(entries?: any[]) { - if (!entries) entries = this.logging.entries - this.element.style.width = '100%' - const cols = { - source: 'Source', - type: 'Type', - timestamp: 'Timestamp', - message: 'Message' - } - const keys = Object.keys(cols) - const headers = Object.values(cols).map((title) => - $el('div.comfy-logging-title', { - textContent: title - }) - ) - const rows = entries.map((entry, i) => { - return $el( - 'div.comfy-logging-log', - { - $: (el) => - el.style.setProperty( - '--row-bg', - `var(--tr-${i % 2 ? 'even' : 'odd'}-bg-color)` - ) - }, - keys.map((key) => { - let v = entry[key] - let color - if (key === 'type') { - color = this.getTypeColor(v) - } else { - v = jsonReplacer(key, v, true) - - if (typeof v === 'object') { - v = stringify(v, 5, jsonReplacer, ' ') - } - } - - return $el('div', { - style: { - color - }, - textContent: v - }) - }) - ) - }) - - const grid = $el( - 'div.comfy-logging-logs', - { - style: { - gridTemplateColumns: `repeat(${headers.length}, 1fr)` - } - }, - [...headers, ...rows] - ) - const els = [grid] - if (!this.logging.enabled) { - els.unshift( - $el('h3', { - style: { textAlign: 'center' }, - textContent: 'Logging is disabled' - }) - ) - } - super.show($el('div', els)) - } -} - -export class ComfyLogging { - /** - * @type Array<{ source: string, type: string, timestamp: Date, message: any }> - */ - entries = [] - - #enabled - #console = {} - - app: ComfyApp - dialog: ComfyLoggingDialog - - get enabled() { - return this.#enabled - } - - set enabled(value) { - if (value === this.#enabled) return - if (value) { - this.patchConsole() - } else { - this.unpatchConsole() - } - this.#enabled = value - } - - constructor(app) { - this.app = app - - this.dialog = new ComfyLoggingDialog(this) - this.addSetting() - this.catchUnhandled() - this.addInitData() - } - - addSetting() { - const settingId = 'Comfy.Logging.Enabled' - const htmlSettingId = settingId.replaceAll('.', '-') - const setting = this.app.ui.settings.addSetting({ - id: settingId, - name: 'Enable logging', - defaultValue: true, - onChange: (value) => { - this.enabled = value - }, - type: (name, setter, value) => { - return $el('tr', [ - $el('td', [ - $el('label', { - textContent: 'Logging', - for: htmlSettingId - }) - ]), - $el('td', [ - $el('input', { - id: htmlSettingId, - type: 'checkbox', - checked: value, - onchange: (event) => { - setter(event.target.checked) - } - }), - $el('button', { - textContent: 'View Logs', - onclick: () => { - this.app.ui.settings.element.close() - this.dialog.show() - }, - style: { - fontSize: '14px', - display: 'block', - marginTop: '5px' - } - }) - ]) - ]) - } - }) - this.enabled = setting.value - } - - patchConsole() { - // Capture common console outputs - const self = this - for (const type of ['log', 'warn', 'error', 'debug']) { - const orig = console[type] - this.#console[type] = orig - console[type] = function () { - orig.apply(console, arguments) - self.addEntry('console', type, ...arguments) - } - } - } - - unpatchConsole() { - // Restore original console functions - for (const type of Object.keys(this.#console)) { - console[type] = this.#console[type] - } - this.#console = {} - } - - catchUnhandled() { - // Capture uncaught errors - window.addEventListener('error', (e) => { - this.addEntry('window', 'error', e.error ?? 'Unknown error') - return false - }) - - window.addEventListener('unhandledrejection', (e) => { - this.addEntry('unhandledrejection', 'error', e.reason ?? 'Unknown error') - }) - } - - clear() { - this.entries = [] - } - - addEntry(source, type, ...args) { - if (this.enabled) { - this.entries.push({ - source, - type, - timestamp: new Date(), - message: args - }) - } - } - - log(source, ...args) { - this.addEntry(source, 'log', ...args) - } - - async addInitData() { - if (!this.enabled) return - const source = 'ComfyUI.Logging' - this.addEntry(source, 'debug', { UserAgent: navigator.userAgent }) - } -}