feat: support dynamically set log level

This commit is contained in:
Gabe
2025-10-12 23:17:50 +08:00
parent f19b6ef02f
commit bfce9b525a
8 changed files with 119 additions and 18 deletions

View File

@@ -32,7 +32,7 @@ import { trySyncAllSubRules } from "./libs/subRules";
import { saveRule } from "./libs/rules"; import { saveRule } from "./libs/rules";
import { getCurTabId } from "./libs/msg"; import { getCurTabId } from "./libs/msg";
import { injectInlineJs, injectInternalCss } from "./libs/injector"; import { injectInlineJs, injectInternalCss } from "./libs/injector";
import { kissLog } from "./libs/log"; import { kissLog, logger } from "./libs/log";
import { chromeDetect, chromeTranslate } from "./libs/builtinAI"; import { chromeDetect, chromeTranslate } from "./libs/builtinAI";
globalThis.ContextType = "BACKGROUND"; globalThis.ContextType = "BACKGROUND";
@@ -210,11 +210,17 @@ browser.runtime.onInstalled.addListener(() => {
* 浏览器启动 * 浏览器启动
*/ */
browser.runtime.onStartup.addListener(async () => { browser.runtime.onStartup.addListener(async () => {
// 同步数据 const {
await trySyncSettingAndRules(); clearCache,
contextMenuType,
subrulesList,
csplist,
orilist,
logLevel,
} = await getSettingWithDefault();
const { clearCache, contextMenuType, subrulesList, csplist, orilist } = // 设置日志
await getSettingWithDefault(); logger.setLevel(logLevel);
// 清除缓存 // 清除缓存
if (clearCache) { if (clearCache) {
@@ -233,6 +239,9 @@ browser.runtime.onStartup.addListener(async () => {
// 禁用CSP // 禁用CSP
updateCspRules({ csplist, orilist }); updateCspRules({ csplist, orilist });
// 同步数据
trySyncSettingAndRules();
// 同步订阅规则 // 同步订阅规则
trySyncAllSubRules({ subrulesList }); trySyncAllSubRules({ subrulesList });
}); });

View File

@@ -19,6 +19,7 @@ import { matchRule } from "./libs/rules";
import { trySyncAllSubRules } from "./libs/subRules"; import { trySyncAllSubRules } from "./libs/subRules";
import { isInBlacklist } from "./libs/blacklist"; import { isInBlacklist } from "./libs/blacklist";
import { runSubtitle } from "./subtitle/subtitle"; import { runSubtitle } from "./subtitle/subtitle";
import { logger } from "./libs/log";
/** /**
* 油猴脚本设置页面 * 油猴脚本设置页面
@@ -180,6 +181,12 @@ function touchOperation(translator) {
*/ */
export async function run(isUserscript = false) { export async function run(isUserscript = false) {
try { try {
// 读取设置信息
const setting = await getSettingWithDefault();
// 日志
logger.setLevel(setting.logLevel);
const href = document.location.href; const href = document.location.href;
// 设置页面 // 设置页面
@@ -192,9 +199,6 @@ export async function run(isUserscript = false) {
return; return;
} }
// 读取设置信息
const setting = await getSettingWithDefault();
// 黑名单 // 黑名单
if (isInBlacklist(href, setting)) { if (isInBlacklist(href, setting)) {
return; return;

View File

@@ -1628,6 +1628,11 @@ export const I18N = {
en: `The subtitle data is ready, please click the KT button to load it`, en: `The subtitle data is ready, please click the KT button to load it`,
zh_TW: `字幕資料已準備就緒請點擊KT按鈕加載`, zh_TW: `字幕資料已準備就緒請點擊KT按鈕加載`,
}, },
log_level: {
zh: `日志级别`,
en: `Log Level`,
zh_TW: `日誌等級`,
},
}; };
export const i18n = (lang) => (key) => I18N[key]?.[lang] || ""; export const i18n = (lang) => (key) => I18N[key]?.[lang] || "";

View File

@@ -1,3 +1,4 @@
import { LogLevel } from "../libs/log";
import { import {
OPT_DICT_BING, OPT_DICT_BING,
OPT_SUG_YOUDAO, OPT_SUG_YOUDAO,
@@ -181,4 +182,5 @@ export const DEFAULT_SETTING = {
preInit: true, // 是否预加载脚本 preInit: true, // 是否预加载脚本
transAllnow: false, // 是否立即全部翻译 transAllnow: false, // 是否立即全部翻译
subtitleSetting: DEFAULT_SUBTITLE_SETTING, // 字幕设置 subtitleSetting: DEFAULT_SUBTITLE_SETTING, // 字幕设置
logLevel: LogLevel.INFO.value, // 日志级别
}; };

View File

@@ -1,9 +1,16 @@
import { createContext, useCallback, useContext, useMemo } from "react"; import {
createContext,
useCallback,
useContext,
useMemo,
useEffect,
} from "react";
import Alert from "@mui/material/Alert"; import Alert from "@mui/material/Alert";
import { STOKEY_SETTING, DEFAULT_SETTING, KV_SETTING_KEY } from "../config"; import { STOKEY_SETTING, DEFAULT_SETTING, KV_SETTING_KEY } from "../config";
import { useStorage } from "./Storage"; import { useStorage } from "./Storage";
import { debounceSyncMeta } from "../libs/storage"; import { debounceSyncMeta } from "../libs/storage";
import Loading from "./Loading"; import Loading from "./Loading";
import { logger } from "../libs/log";
const SettingContext = createContext({ const SettingContext = createContext({
setting: DEFAULT_SETTING, setting: DEFAULT_SETTING,
@@ -19,6 +26,16 @@ export function SettingProvider({ children }) {
reload, reload,
} = useStorage(STOKEY_SETTING, DEFAULT_SETTING, KV_SETTING_KEY); } = useStorage(STOKEY_SETTING, DEFAULT_SETTING, KV_SETTING_KEY);
useEffect(() => {
(async () => {
try {
logger.setLevel(setting?.logLevel);
} catch (error) {
logger.error("Failed to fetch log level, using default.", error);
}
})();
}, [setting]);
const updateSetting = useCallback( const updateSetting = useCallback(
(objOrFn) => { (objOrFn) => {
update(objOrFn); update(objOrFn);

View File

@@ -7,6 +7,16 @@ export const LogLevel = {
SILENT: { value: 4, name: "SILENT" }, // 特殊级别,用于关闭所有日志 SILENT: { value: 4, name: "SILENT" }, // 特殊级别,用于关闭所有日志
}; };
function findLogLevelByValue(value) {
return Object.values(LogLevel).find((level) => level.value === value);
}
function findLogLevelByName(name) {
if (typeof name !== "string" || name.length === 0) return undefined;
const upperCaseName = name.toUpperCase();
return Object.values(LogLevel).find((level) => level.name === upperCaseName);
}
class Logger { class Logger {
/** /**
* @param {object} [options={}] 配置选项 * @param {object} [options={}] 配置选项
@@ -25,10 +35,37 @@ class Logger {
* @param {LogLevel} level - 新的日志级别 * @param {LogLevel} level - 新的日志级别
*/ */
setLevel(level) { setLevel(level) {
if (level && typeof level.value === "number") { let newLevelObject;
this.config.level = level;
console.log(`[${this.config.prefix}] Log level set to ${level.name}`); if (typeof level === "string") {
newLevelObject = findLogLevelByName(level);
if (!newLevelObject) {
this.warn(
`Invalid log level name provided: "${level}". Keeping current level.`
);
return;
} }
} else if (typeof level === "number") {
newLevelObject = findLogLevelByValue(level);
if (!newLevelObject) {
this.warn(
`Invalid log level value provided: ${level}. Keeping current level.`
);
return;
}
} else if (level && typeof level.value === "number") {
newLevelObject = level;
} else {
this.warn(
"Invalid argument passed to setLevel. Must be a LogLevel object, number, or string."
);
return;
}
this.config.level = newLevelObject;
console.log(
`[${this.config.prefix}] Log level dynamically set to ${this.config.level.name}`
);
} }
/** /**
@@ -118,9 +155,7 @@ class Logger {
} }
} }
const isDevelopment = export const logger = new Logger();
typeof process === "undefined" || process.env.NODE_ENV !== "development";
const defaultLevel = isDevelopment ? LogLevel.DEBUG : LogLevel.INFO;
export const logger = new Logger({ level: defaultLevel });
export const kissLog = logger.info.bind(logger); export const kissLog = logger.info.bind(logger);
// tododebug日志埋点

View File

@@ -231,6 +231,13 @@ class YouTubeCaptionProvider {
try { try {
const events = chunkEvents.filter((item) => item.text); const events = chunkEvents.filter((item) => item.text);
const chunkSign = `${events[0].start} --> ${events[events.length - 1].end}`; const chunkSign = `${events[0].start} --> ${events[events.length - 1].end}`;
logger.debug("Youtube Provider: aiSegment events", {
videoId,
chunkSign,
fromLang,
toLang,
events,
});
const subtitles = await apiSubtitle({ const subtitles = await apiSubtitle({
videoId, videoId,
chunkSign, chunkSign,
@@ -239,6 +246,7 @@ class YouTubeCaptionProvider {
events, events,
apiSetting: segApiSetting, apiSetting: segApiSetting,
}); });
logger.debug("Youtube Provider: aiSegment subtitles", subtitles);
if (Array.isArray(subtitles)) { if (Array.isArray(subtitles)) {
return subtitles; return subtitles;
} }
@@ -300,6 +308,9 @@ class YouTubeCaptionProvider {
OPT_LANGS_TO_CODE[OPT_TRANS_MICROSOFT].get(lang.slice(0, 2)) || OPT_LANGS_TO_CODE[OPT_TRANS_MICROSOFT].get(lang.slice(0, 2)) ||
"auto"; "auto";
logger.debug(
`Youtube Provider: fromLang: ${fromLang}, toLang: ${toLang}`
);
if (this.#isSameLang(fromLang, toLang)) { if (this.#isSameLang(fromLang, toLang)) {
logger.info("Youtube Provider: skip same lang", fromLang, toLang); logger.info("Youtube Provider: skip same lang", fromLang, toLang);
return; return;

View File

@@ -29,7 +29,7 @@ import { useShortcut } from "../../hooks/Shortcut";
import ShortcutInput from "./ShortcutInput"; import ShortcutInput from "./ShortcutInput";
import { useFab } from "../../hooks/Fab"; import { useFab } from "../../hooks/Fab";
import { sendBgMsg } from "../../libs/msg"; import { sendBgMsg } from "../../libs/msg";
import { kissLog } from "../../libs/log"; import { kissLog, LogLevel } from "../../libs/log";
import UploadButton from "./UploadButton"; import UploadButton from "./UploadButton";
import DownloadButton from "./DownloadButton"; import DownloadButton from "./DownloadButton";
import { getSettingOld } from "../../libs/storage"; import { getSettingOld } from "../../libs/storage";
@@ -99,6 +99,7 @@ export default function Settings() {
orilist = DEFAULT_ORILIST.join(",\n"), orilist = DEFAULT_ORILIST.join(",\n"),
transInterval = 100, transInterval = 100,
langDetector = "-", langDetector = "-",
logLevel = 1,
preInit = true, preInit = true,
skipLangs = [], skipLangs = [],
// detectRemote = true, // detectRemote = true,
@@ -337,6 +338,23 @@ export default function Settings() {
))} ))}
</TextField> </TextField>
</Grid> </Grid>
<Grid item xs={12} sm={12} md={6} lg={3}>
<TextField
select
fullWidth
size="small"
name="logLevel"
value={logLevel}
label={i18n("log_level")}
onChange={handleChange}
>
{Object.values(LogLevel).map(({ value, name }) => (
<MenuItem value={value} key={value}>
{name}
</MenuItem>
))}
</TextField>
</Grid>
</Grid> </Grid>
</Box> </Box>