Skip to content

Commit

Permalink
merge: feat: Better logger for Renderer Process.
Browse files Browse the repository at this point in the history
Feature:

- Better `console` log for _Renderer Process_.
  - Persist log into log file.
  - `ElementCapture` feature.
  - Checkout `docs/debugging.md` for more info.
- Update Settings Page to include Github repo info.

Fix:

- Fix the issue that enabling this plugins will cause `QQNT` to create several unused system process and which won't be closed after `QQNT` shutdown.
  • Loading branch information
nfnfgo authored Jul 8, 2024
2 parents e34e8c3 + f890d83 commit 0828369
Show file tree
Hide file tree
Showing 14 changed files with 367 additions and 90 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ settings.json

# ignore dist/
dist
log
release.zip
45 changes: 45 additions & 0 deletions docs/debugging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
部分情况下,您可能需要获取本插件的调试信息。

# 确保已开启调试输出

首先,请确保您已经开启本插件的调试信息输出功能,包括 `控制台输出` 以及 `日志文件输出`

![image](https://github.com/d0j1a1701/LiteLoaderQQNT-Markdown/assets/61616918/ca06d6e6-60b7-45c2-85bc-111b69bf47be)

## 开启元素抓取

部分情况下,开发者可能需要相关的元素调试信息来定位问题,您可以开启本插件设置中的 `启用元素调试` 功能。

![image](https://github.com/d0j1a1701/LiteLoaderQQNT-Markdown/assets/61616918/1bf4e4d5-e3f4-4190-9c10-4b6153103fb7)


启用该功能后,当您发送的消息包含:\`--mdit-debug-capture-element\` 时(需包含\`符号,该标志将会被渲染为`code`元素),该消息会被作为调试用消息进行抓取,并将相关信息保存到日志文件中。**在本功能启用时,请确保您发送的调试消息不包含任何您不想让其他人看到的敏感信息。** 请看下例:

- 消息框中输入的消息

![image](https://github.com/d0j1a1701/LiteLoaderQQNT-Markdown/assets/61616918/db4b29ee-1ec3-4c76-85ce-d5c2639ef254)

- 消息渲染结果

![image](https://github.com/d0j1a1701/LiteLoaderQQNT-Markdown/assets/61616918/4dab43b9-6988-4f55-be0a-e84514e2e8f8)

为保证隐私性,只有自己发送的消息才能被标记为调试消息。


# 进入日志文件目录

首先进入 `LiteLoaderQQNT` 插件设置页面,进入数据目录。

![image](https://github.com/d0j1a1701/LiteLoaderQQNT-Markdown/assets/61616918/bbbae1b8-fdd1-4daa-848f-1ec654dc9407)

随后依次进入 `plugins -> markdown_it -> log`,便能看到所有日志文件。

> 如果目录不存在,一般是由于之前从未开启过日志文件输出功能。在完成上一步开启调试输出后,重启QQ即可。
# 提供文件给开发者

您可以直接将文件发送给相关的开发者,也可以选择用文本编辑工具打开 `.log` 文件并复制其内容进行分享。如果目录内存在多个文件,一般情况下请提供最新的文件。

# 清理日志文件

您可以在 `QQNT` 未启动的情况下,直接删除日志文件中的所有日志。
20 changes: 18 additions & 2 deletions docs/dev/renderer.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@

- [Introduction](#introduction)
- [Start Developing](#start-developing)
- [Logging](#logging)
- [Create Release Version](#create-release-version)
- [UI Development](#ui-development)
- [UI Development](#ui-development)
- [Content Rendering Test Example](#content-rendering-test-example)


Expand All @@ -30,6 +31,21 @@ npm run dev

This will start `webpack` in watch mode with `development` flag enabled.

## Logging

A custom `conole` wrapper `mditLogger` is recommend when you need to log something in *Renderer Process*. You can import the logger by:

```javascript
import { mditLogger } from './utils/logger';

function someFunc() {
mditLogger('debug', 'debug info here.'); // Output: [MarkdownIt] debug info here.
}
```



Use `mditLogger` whenever possible.

## Create Release Version

Expand All @@ -45,7 +61,7 @@ The script `npm run release` will:
2. Run `git archive` to create a `release.zip` file contains all code included in `git`.
3. Run `zip -r` to add `dist` directory into previously generated `release.zip`.

# UI Development
## UI Development

You could use `React` to develop plugin settings UI interface. The entrance of user settings page is `src/components/setting_page.js`

Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
],
"injects": {
"renderer": "./dist/renderer.js",
"main": "./src/main.js",
"main": "./dist/main.js",
"preload": "./src/preload.js"
}
}
76 changes: 69 additions & 7 deletions src/components/setting_page.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';

import { useSettingsStore } from '@/states/settings';
import { mditLogger } from '@/utils/logger';


export function SettingPage() {
Expand All @@ -9,15 +10,17 @@ export function SettingPage() {

// use encapsulated <DescriptionTile> and <SwitchSettingTile> whenever possible.
return (<>

<setting-section data-title='关于'>
<setting-panel>
<setting-list data-direction='column'>
<setting-item data-direction='row'>
<setting-text>设置更新</setting-text>
<setting-text data-type='secondary'>在此页面更新设置后,需要重启QQ后方可生效</setting-text>
</setting-item>
<ButtonTile title='Github 仓库' caption='本项目的 Github 源代码仓库地址。' actionName='查看源代码' href='https://github.com/d0j1a1701/LiteLoaderQQNT-Markdown' />
<ButtonTile title='提交反馈' caption='提交您对于本插件的建议,或者反馈使用中遇到的问题。' actionName='提交反馈' href='https://github.com/d0j1a1701/LiteLoaderQQNT-Markdown/issues/new' />
</setting-list>
</setting-panel>

<setting-panel>
<setting-list data-direction='column'>
<DescriptionTile title='设置更新' caption='在此页面更新设置后,需要重启QQ后方可生效' />
</setting-list>
</setting-panel>
</setting-section>
Expand Down Expand Up @@ -77,12 +80,40 @@ export function SettingPage() {
<setting-list data-direction='column'>

<DescriptionTile title='SettingsState' caption={JSON.stringify(settings, undefined, ' ')} />
</setting-list>
</setting-panel>

<setting-panel>
<setting-list data-direction='column'>

<SwitchSettingTile
settingName='consoleOutput'
title='控制台输出'
caption='关闭后,将屏蔽 MarkdownIt 插件向控制台输出的信息,目前仅能屏蔽部分信息。' />

<SwitchSettingTile
settingName='fileOutput'
title='日志文件输出'
caption='关闭后,MarkdownIt 将不会将调试信息保存在日志文件中。' />

<SwitchSettingTile
settingName='enableElementCapture'
title='启用元素调试'
caption='开启后,日志文件中将会保存指定调试消息的HTML。'
/>

<ButtonTile
title='MarkdownIt 日志目录'
caption='日志存放于插件 [插件根目录]/log 文件夹中。'
actionName='插件目录'
path={LiteLoader.plugins.markdown_it.path.plugin} />

</setting-list>
</setting-panel>

<setting-panel>
<setting-list data-direction='column'>

<SwitchSettingTile
settingName='unescapeGtInText'
title='反转义消息字符中的">"符号'
Expand Down Expand Up @@ -121,11 +152,13 @@ function SwitchSettingTile({ settingName, title, caption }) {
return (
<setting-item>
<TextAndCaptionBlock title={title} caption={caption} />

<setting-switch data-direction='row'
onClick={() => { updateSetting(settingName, !settings[settingName]) }}
is-active={settingsValue == true ? true : undefined}
is-disabled={getForceValue()}
style={{
'flex': 'none',
}}
></setting-switch>
</setting-item>
);
Expand All @@ -145,7 +178,7 @@ function TextAndCaptionBlock({ title, caption }) {
'display': 'flex',
'flexWrap': 'wrap',
'flexDirection': 'column',
'width': '92%',
'flex': '1 1 auto',
}}>
<setting-text>{title}</setting-text>
<setting-text
Expand All @@ -160,4 +193,33 @@ function TextAndCaptionBlock({ title, caption }) {
}}>{caption}</p></setting-text>
</div>
);
}

function ButtonTile({ title, caption, href, path, callback, actionName }) {
callback ??= function () {
if (href !== undefined && href !== null) {
LiteLoader.api.openExternal(href);
return;
}
if (path !== undefined && path !== null) {
LiteLoader.api.openPath(path);
return;
}
mditLogger('debug', 'Button with no action clicked');

}

return (
<setting-item data-direction='row'>
<TextAndCaptionBlock title={title} caption={caption} />
<setting-button
data-type='secondary'
onClick={callback}
style={{
'flex': 'none',
}}>
{actionName}
</setting-button>
</setting-item>
);
}
54 changes: 11 additions & 43 deletions src/main.js
Original file line number Diff line number Diff line change
@@ -1,58 +1,26 @@
// 运行在 Electron 主进程 下的插件入口
const { shell, ipcMain } = require("electron");
const fs = require('fs/promises');
const { ipcMain } = require("electron");
import { generateMainProcessLogerWriter, LogPathHelper } from '@/utils/logger_main';

const plugin_path = LiteLoader.plugins["markdown_it"].path.plugin;
const loggerWriter = generateMainProcessLogerWriter();

// import { shell, ipcMain } from "electron";

const setttingsJsonFilePath = `${plugin_path}/settings.json`;

async function getSettings(key) {
var json = JSON.parse(await fs.readFile(setttingsJsonFilePath));
return json[key];
}

async function updateSettings({ name, value }) {
var json = {};
try { json = JSON.parse(await fs.readFile(setttingsJsonFilePath)); } catch (e) {
;
function onBrowserWindowCreated() {
try { onLoad(); } catch (e) {
console.error('[markdown-it]', e);
}
json[name] = value;
await fs.writeFile(setttingsJsonFilePath, JSON.stringify(json));
}

async function removeSettings(key) {
var json = JSON.parse(await fs.readFile(setttingsJsonFilePath));
json[key] = undefined;
await fs.writeFile(setttingsJsonFilePath, JSON.stringify(json));
}

onLoad();

// 加载插件时触发
function onLoad() {
ipcMain.handle("LiteLoader.markdown_it.open_link", (event, content) => {
if (content.indexOf("http") != 0) {
content = "http://" + content;
}
return shell.openExternal(content);
});

ipcMain.handle('LiteLoader.markdown_it.get_settings', (e, key) => {
return getSettings(key);
});

ipcMain.handle('LiteLoader.markdown_it.update_settings', (e, { name, value }) => {
return updateSettings({ name, value });
ipcMain.handle('LiteLoader.markdown_it.log', (e, consoleMode, ...args) => {
loggerWriter(consoleMode, ...args);
});

ipcMain.handle('LiteLoader.markdown_it.remove_settings', (e, key) => {
return removeSettings(key);
})
ipcMain.handle('LiteLoader.markdown_it.get_log_path', (e) => LogPathHelper.getLogFolderPath());
}

// 这两个函数都是可选的
module.exports = {
onLoad,
export {
onBrowserWindowCreated,
};
22 changes: 12 additions & 10 deletions src/preload.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ const { contextBridge, ipcRenderer } = require("electron");

// 在window对象下导出只读对象
contextBridge.exposeInMainWorld("markdown_it", {
render: (content) =>
ipcRenderer.invoke("LiteLoader.markdown_it.render", content),
open_link: (content) =>
ipcRenderer.invoke("LiteLoader.markdown_it.open_link", content),
get_settings: (key) =>
ipcRenderer.invoke("LiteLoader.markdown_it.get_settings", key),
update_settings: ({ name, value }) =>
ipcRenderer.invoke("LiteLoader.markdown_it.update_settings", { name, value }),
remove_settings: (key) =>
ipcRenderer.invoke("LiteLoader.markdown_it.remove_settings", key),
// render: (content) =>
// ipcRenderer.invoke("LiteLoader.markdown_it.render", content),
// open_link: (content) =>
// ipcRenderer.invoke("LiteLoader.markdown_it.open_link", content),
// get_settings: (key) =>
// ipcRenderer.invoke("LiteLoader.markdown_it.get_settings", key),
// update_settings: ({ name, value }) =>
// ipcRenderer.invoke("LiteLoader.markdown_it.update_settings", { name, value }),
// remove_settings: (key) =>
// ipcRenderer.invoke("LiteLoader.markdown_it.remove_settings", key),
log: (consoleType, ...args) => ipcRenderer.invoke('LiteLoader.markdown_it.log', consoleType, ...args),
get_log_path: () => ipcRenderer.invoke('LiteLoader.markdown_it.get_log_path'),
});
9 changes: 5 additions & 4 deletions src/renderer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { useSettingsStore } from '@/states/settings';

// Utils
import { debounce } from 'throttle-debounce';
import { mditLogger } from './utils/logger';
import { mditLogger, elementDebugLogger } from './utils/logger';


const markdownRenderedClassName = 'markdown-rendered';
Expand Down Expand Up @@ -203,10 +203,11 @@ function render() {
})
messageBox.removeChild(posBase);

changeDirectionToColumnWhenLargerHeight();

})
});

// code that runs after renderer work finished.
changeDirectionToColumnWhenLargerHeight();
elementDebugLogger();
}

function loadCSSFromURL(url, id) {
Expand Down
4 changes: 4 additions & 0 deletions src/states/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export interface SettingStateProperties {

// Debug settings
consoleOutput: boolean; // If false, mditLogger will not output to console.
fileOutput: boolean; // If false, mditLogger will not add log into log file.
enableElementCapture: boolean;
}

export interface SettingStateAction {
Expand Down Expand Up @@ -59,6 +61,8 @@ export const useSettingsStore = create<SettingStateProperties & SettingStateActi

// Debug settings
consoleOutput: true,
fileOutput: true,
enableElementCapture: false,

forceUnescapeBeforeHighlight: () => {
if (get().unescapeAllHtmlEntites === true) {
Expand Down
Loading

0 comments on commit 0828369

Please sign in to comment.