mirror of
https://github.com/lanyeeee/bilibili-video-downloader.git
synced 2026-09-09 01:27:27 +08:00
pref: 提高LogEvent的效率(移除发送前的反序列化步骤)
This commit is contained in:
+4
-12
@@ -1,23 +1,15 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use specta::Type;
|
use specta::Type;
|
||||||
use tauri_specta::Event;
|
use tauri_specta::Event;
|
||||||
|
|
||||||
use crate::{
|
use crate::downloader::{
|
||||||
downloader::{download_progress::DownloadProgress, download_task_state::DownloadTaskState},
|
download_progress::DownloadProgress, download_task_state::DownloadTaskState,
|
||||||
types::log_level::LogLevel,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Type, Event)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Type, Event)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct LogEvent {
|
pub struct LogEvent {
|
||||||
pub timestamp: String,
|
pub json_raw: String,
|
||||||
pub level: LogLevel,
|
|
||||||
pub fields: HashMap<String, serde_json::Value>,
|
|
||||||
pub target: String,
|
|
||||||
pub filename: String,
|
|
||||||
#[serde(rename = "line_number")]
|
|
||||||
pub line_number: i64,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Type, Event)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Type, Event)]
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ use crate::{
|
|||||||
downloader::download_manager::DownloadManager,
|
downloader::download_manager::DownloadManager,
|
||||||
errors::install_custom_eyre_handler,
|
errors::install_custom_eyre_handler,
|
||||||
events::{DownloadEvent, LogEvent},
|
events::{DownloadEvent, LogEvent},
|
||||||
|
types::log_metadata::LogMetadata,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn generate_context() -> tauri::Context<Wry> {
|
fn generate_context() -> tauri::Context<Wry> {
|
||||||
@@ -72,7 +73,8 @@ pub fn run() {
|
|||||||
get_skip_segments,
|
get_skip_segments,
|
||||||
get_available_media_formats,
|
get_available_media_formats,
|
||||||
])
|
])
|
||||||
.events(tauri_specta::collect_events![LogEvent, DownloadEvent]);
|
.events(tauri_specta::collect_events![LogEvent, DownloadEvent])
|
||||||
|
.typ::<LogMetadata>();
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
builder
|
builder
|
||||||
|
|||||||
+19
-14
@@ -13,7 +13,7 @@ use tracing_error::ErrorLayer;
|
|||||||
use tracing_subscriber::{
|
use tracing_subscriber::{
|
||||||
Layer, Registry,
|
Layer, Registry,
|
||||||
filter::{FilterExt, Targets, filter_fn},
|
filter::{FilterExt, Targets, filter_fn},
|
||||||
fmt::{layer, time::LocalTime},
|
fmt::{MakeWriter, layer, time::LocalTime},
|
||||||
layer::SubscriberExt,
|
layer::SubscriberExt,
|
||||||
registry::LookupSpan,
|
registry::LookupSpan,
|
||||||
util::SubscriberInitExt,
|
util::SubscriberInitExt,
|
||||||
@@ -30,17 +30,8 @@ struct LogEventWriter {
|
|||||||
|
|
||||||
impl Write for LogEventWriter {
|
impl Write for LogEventWriter {
|
||||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||||
let log_string = String::from_utf8_lossy(buf);
|
let json_raw = String::from_utf8_lossy(buf).to_string();
|
||||||
match serde_json::from_str::<LogEvent>(&log_string) {
|
let _ = LogEvent { json_raw }.emit(&self.app);
|
||||||
Ok(log_event) => {
|
|
||||||
let _ = log_event.emit(&self.app);
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
let log_string = log_string.to_string();
|
|
||||||
let message = err.to_string();
|
|
||||||
tracing::error!(log_string, message, "将日志字符串解析为LogEvent失败");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(buf.len())
|
Ok(buf.len())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,6 +40,20 @@ impl Write for LogEventWriter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct LogEventWriterFactory {
|
||||||
|
app: AppHandle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MakeWriter<'_> for LogEventWriterFactory {
|
||||||
|
type Writer = LogEventWriter;
|
||||||
|
|
||||||
|
fn make_writer(&self) -> Self::Writer {
|
||||||
|
LogEventWriter {
|
||||||
|
app: self.app.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static RELOAD_FN: OnceLock<Box<dyn Fn() -> eyre::Result<()> + Send + Sync>> = OnceLock::new();
|
static RELOAD_FN: OnceLock<Box<dyn Fn() -> eyre::Result<()> + Send + Sync>> = OnceLock::new();
|
||||||
static GUARD: OnceLock<parking_lot::Mutex<Option<WorkerGuard>>> = OnceLock::new();
|
static GUARD: OnceLock<parking_lot::Mutex<Option<WorkerGuard>>> = OnceLock::new();
|
||||||
|
|
||||||
@@ -70,9 +75,9 @@ pub fn init(app: &AppHandle) -> eyre::Result<()> {
|
|||||||
.with_file(true)
|
.with_file(true)
|
||||||
.with_line_number(true);
|
.with_line_number(true);
|
||||||
// 发送到前端
|
// 发送到前端
|
||||||
let log_event_writer = std::sync::Mutex::new(LogEventWriter { app: app.clone() });
|
let log_event_factory = LogEventWriterFactory { app: app.clone() };
|
||||||
let log_event_layer = layer()
|
let log_event_layer = layer()
|
||||||
.with_writer(log_event_writer)
|
.with_writer(log_event_factory)
|
||||||
.with_timer(LocalTime::rfc_3339())
|
.with_timer(LocalTime::rfc_3339())
|
||||||
.with_file(true)
|
.with_file(true)
|
||||||
.with_line_number(true)
|
.with_line_number(true)
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use specta::Type;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
|
||||||
pub enum LogLevel {
|
|
||||||
#[serde(rename = "TRACE")]
|
|
||||||
Trace,
|
|
||||||
#[serde(rename = "DEBUG")]
|
|
||||||
Debug,
|
|
||||||
#[serde(rename = "INFO")]
|
|
||||||
Info,
|
|
||||||
#[serde(rename = "WARN")]
|
|
||||||
Warn,
|
|
||||||
#[serde(rename = "ERROR")]
|
|
||||||
Error,
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use specta::Type;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||||
|
pub struct LogMetadata {
|
||||||
|
pub timestamp: String,
|
||||||
|
pub level: LogLevel,
|
||||||
|
pub fields: HashMap<String, serde_json::Value>,
|
||||||
|
pub target: String,
|
||||||
|
pub filename: String,
|
||||||
|
pub line_number: i64,
|
||||||
|
#[serde(default)]
|
||||||
|
pub span: serde_json::Value,
|
||||||
|
#[serde(default)]
|
||||||
|
pub spans: Vec<LogSpan>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||||
|
pub struct LogSpan {
|
||||||
|
pub name: String,
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub other_fields: HashMap<String, serde_json::Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
|
||||||
|
pub enum LogLevel {
|
||||||
|
#[serde(rename = "TRACE")]
|
||||||
|
Trace,
|
||||||
|
#[serde(rename = "DEBUG")]
|
||||||
|
Debug,
|
||||||
|
#[serde(rename = "INFO")]
|
||||||
|
Info,
|
||||||
|
#[serde(rename = "WARN")]
|
||||||
|
Warn,
|
||||||
|
#[serde(rename = "ERROR")]
|
||||||
|
Error,
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ pub mod get_history_info_params;
|
|||||||
pub mod get_normal_info_params;
|
pub mod get_normal_info_params;
|
||||||
pub mod get_user_video_info_params;
|
pub mod get_user_video_info_params;
|
||||||
pub mod history_info;
|
pub mod history_info;
|
||||||
pub mod log_level;
|
pub mod log_metadata;
|
||||||
pub mod normal_info;
|
pub mod normal_info;
|
||||||
pub mod normal_media_url;
|
pub mod normal_media_url;
|
||||||
pub mod player_info;
|
pub mod player_info;
|
||||||
|
|||||||
+3
-1
@@ -331,8 +331,10 @@ export type JsonTask = { selected: boolean; completed: boolean }
|
|||||||
export type JsonValue = null | boolean | number | string | JsonValue[] | { [key in string]: JsonValue }
|
export type JsonValue = null | boolean | number | string | JsonValue[] | { [key in string]: JsonValue }
|
||||||
export type LabelInUserInfo = { path: string; text: string; label_theme: string; text_color: string; bg_style: number; bg_color: string; border_color: string; use_img_label: boolean; img_label_uri_hans: string; img_label_uri_hant: string; img_label_uri_hans_static: string; img_label_uri_hant_static: string }
|
export type LabelInUserInfo = { path: string; text: string; label_theme: string; text_color: string; bg_style: number; bg_color: string; border_color: string; use_img_label: boolean; img_label_uri_hans: string; img_label_uri_hant: string; img_label_uri_hans_static: string; img_label_uri_hant_static: string }
|
||||||
export type LevelInfoInUserInfo = { current_level: number; current_min: number; current_exp: number }
|
export type LevelInfoInUserInfo = { current_level: number; current_min: number; current_exp: number }
|
||||||
export type LogEvent = { timestamp: string; level: LogLevel; fields: { [key in string]: JsonValue }; target: string; filename: string; line_number: number }
|
export type LogEvent = { jsonRaw: string }
|
||||||
export type LogLevel = "TRACE" | "DEBUG" | "INFO" | "WARN" | "ERROR"
|
export type LogLevel = "TRACE" | "DEBUG" | "INFO" | "WARN" | "ERROR"
|
||||||
|
export type LogMetadata = { timestamp: string; level: LogLevel; fields: { [key in string]: JsonValue }; target: string; filename: string; line_number: number; span?: JsonValue; spans?: LogSpan[] }
|
||||||
|
export type LogSpan = ({ [key in string]: null | boolean | number | string | JsonValue[] | { [key in string]: JsonValue } }) & { name: string }
|
||||||
export type MediaChunk = { start: number; end: number; completed: boolean }
|
export type MediaChunk = { start: number; end: number; completed: boolean }
|
||||||
export type MediaInFav = { id: number; type: number; title: string; cover: string; intro: string; page: number; duration: number; upper: UpperInMedia; attr: number; cnt_info: CntInfoInMedia; link: string; ctime: number; pubtime: number; fav_time: number; bv_id: string; bvid: string; ugc: Ugc | null; media_list_link: string }
|
export type MediaInFav = { id: number; type: number; title: string; cover: string; intro: string; page: number; duration: number; upper: UpperInMedia; attr: number; cnt_info: CntInfoInMedia; link: string; ctime: number; pubtime: number; fav_time: number; bv_id: string; bvid: string; ugc: Ugc | null; media_list_link: string }
|
||||||
export type MediaInWatchLater = { aid: number; videos: number; tid: number; tname: string; copyright: number; pic: string; title: string; pubdate: number; ctime: number; desc: string; state: number; duration: number; redirect_url: string | null; mission_id: number | null; rights: RightsInWatchLater; owner: OwnerInWatchLater; stat: StatInWatchLater; dynamic: string; dimension: DimensionInWatchLater; short_link_v2: string; up_from_v2: number | null; first_frame: string | null; pub_location: string | null; cover43: string; tidv2: number; tnamev2: string; pid_v2: number; pid_name_v2: string; page: PageInWatchLater; count: number; cid: number; progress: number; add_at: number; bvid: string; uri: string; enable_vt: number; view_text_1: string; card_type: number; left_icon_type: number; left_text: string; right_icon_type: number; right_text: string; arc_state: number; pgc_label: string; show_up: boolean; forbid_fav: boolean; forbid_sort: boolean; season_title: string; long_title: string; index_title: string; c_source: string; season_id: number | null }
|
export type MediaInWatchLater = { aid: number; videos: number; tid: number; tname: string; copyright: number; pic: string; title: string; pubdate: number; ctime: number; desc: string; state: number; duration: number; redirect_url: string | null; mission_id: number | null; rights: RightsInWatchLater; owner: OwnerInWatchLater; stat: StatInWatchLater; dynamic: string; dimension: DimensionInWatchLater; short_link_v2: string; up_from_v2: number | null; first_frame: string | null; pub_location: string | null; cover43: string; tidv2: number; tnamev2: string; pid_v2: number; pid_name_v2: string; page: PageInWatchLater; count: number; cid: number; progress: number; add_at: number; bvid: string; uri: string; enable_vt: number; view_text_1: string; card_type: number; left_icon_type: number; left_text: string; right_icon_type: number; right_text: string; arc_state: number; pgc_label: string; show_up: boolean; forbid_fav: boolean; forbid_sort: boolean; season_title: string; long_title: string; index_title: string; c_source: string; season_id: number | null }
|
||||||
|
|||||||
+17
-13
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="tsx">
|
<script setup lang="tsx">
|
||||||
import { LogEvent, LogLevel, events, commands } from '../bindings.ts'
|
import { LogLevel, events, commands, LogMetadata } from '../bindings.ts'
|
||||||
import {
|
import {
|
||||||
NButton,
|
NButton,
|
||||||
NCheckbox,
|
NCheckbox,
|
||||||
@@ -12,13 +12,13 @@ import {
|
|||||||
NVirtualList,
|
NVirtualList,
|
||||||
useNotification,
|
useNotification,
|
||||||
} from 'naive-ui'
|
} from 'naive-ui'
|
||||||
import { onMounted, ref, watch, computed } from 'vue'
|
import { onMounted, ref, watch, computed, shallowRef, triggerRef } from 'vue'
|
||||||
import { appDataDir } from '@tauri-apps/api/path'
|
import { appDataDir } from '@tauri-apps/api/path'
|
||||||
import { path } from '@tauri-apps/api'
|
import { path } from '@tauri-apps/api'
|
||||||
import { useStore } from '../store.ts'
|
import { useStore } from '../store.ts'
|
||||||
import { darkTheme } from 'naive-ui'
|
import { darkTheme } from 'naive-ui'
|
||||||
|
|
||||||
type LogRecord = LogEvent & { id: number; formatedLog: string }
|
type LogRecord = LogMetadata & { id: number; formatedLog: string }
|
||||||
|
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ const showing = defineModel<boolean>('showing', { required: true })
|
|||||||
|
|
||||||
let nextLogRecordId = 1
|
let nextLogRecordId = 1
|
||||||
|
|
||||||
const logRecords = ref<LogRecord[]>([])
|
const logRecords = shallowRef<LogRecord[]>([])
|
||||||
const searchText = ref<string>('')
|
const searchText = ref<string>('')
|
||||||
const selectedLevel = ref<LogLevel>('INFO')
|
const selectedLevel = ref<LogLevel>('INFO')
|
||||||
const logsDirSize = ref<number>(0)
|
const logsDirSize = ref<number>(0)
|
||||||
@@ -110,14 +110,18 @@ watch(showing, async () => {
|
|||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await events.logEvent.listen(async ({ payload: logEvent }) => {
|
await events.logEvent.listen(async ({ payload: logEvent }) => {
|
||||||
const logRecord: LogRecord = {
|
const logMetadata: LogMetadata = JSON.parse(logEvent.jsonRaw)
|
||||||
...logEvent,
|
|
||||||
id: nextLogRecordId++,
|
|
||||||
formatedLog: formatLogEvent(logEvent),
|
|
||||||
}
|
|
||||||
logRecords.value.push(logRecord)
|
|
||||||
|
|
||||||
const { level, fields } = logEvent
|
const logRecord: LogRecord = {
|
||||||
|
...logMetadata,
|
||||||
|
id: nextLogRecordId++,
|
||||||
|
formatedLog: formatLogMetadata(logMetadata),
|
||||||
|
}
|
||||||
|
|
||||||
|
logRecords.value.push(logRecord)
|
||||||
|
triggerRef(logRecords)
|
||||||
|
|
||||||
|
const { level, fields } = logMetadata
|
||||||
if (level === 'ERROR') {
|
if (level === 'ERROR') {
|
||||||
notification.error({
|
notification.error({
|
||||||
title: fields['err_title'] as string,
|
title: fields['err_title'] as string,
|
||||||
@@ -128,8 +132,8 @@ onMounted(async () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
function formatLogEvent(logEvent: LogEvent): string {
|
function formatLogMetadata(logMetadata: LogMetadata): string {
|
||||||
const { timestamp, level, fields, target, filename, line_number } = logEvent
|
const { timestamp, level, fields, target, filename, line_number } = logMetadata
|
||||||
const fields_str = Object.entries(fields)
|
const fields_str = Object.entries(fields)
|
||||||
.sort(([key1], [key2]) => key1.localeCompare(key2))
|
.sort(([key1], [key2]) => key1.localeCompare(key2))
|
||||||
.map(([key, value]) => `${key}=${value}`)
|
.map(([key, value]) => `${key}=${value}`)
|
||||||
|
|||||||
Reference in New Issue
Block a user