Merge pull request #19 from ApTx2012/feat/backend
fix: LogShare 采集改用轻量日志收集,修复崩溃日志上传失败
This commit is contained in:
2 files changed
+79
-32
No files matched your search
@@ -109,6 +109,7 @@ pub struct CrashAnalysisMod {
|
|||||||
struct SourceCandidate {
|
struct SourceCandidate {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
filename: String,
|
filename: String,
|
||||||
|
upload_name: String,
|
||||||
source_type: &'static str,
|
source_type: &'static str,
|
||||||
modified: SystemTime,
|
modified: SystemTime,
|
||||||
}
|
}
|
||||||
@@ -116,10 +117,25 @@ struct SourceCandidate {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct SourceText {
|
struct SourceText {
|
||||||
filename: String,
|
filename: String,
|
||||||
|
upload_name: String,
|
||||||
source_type: &'static str,
|
source_type: &'static str,
|
||||||
modified: SystemTime,
|
modified: SystemTime,
|
||||||
content: String,
|
content: String,
|
||||||
}
|
}
|
||||||
|
pub(super) struct CollectedCrashLog {
|
||||||
|
pub name: String,
|
||||||
|
pub content: CensoredString,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) struct CollectedCrashLogs {
|
||||||
|
pub combined_log: CensoredString,
|
||||||
|
pub sources: Vec<CollectedCrashLog>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CrashContext {
|
||||||
|
sources: Vec<SourceText>,
|
||||||
|
credentials: Vec<Credentials>,
|
||||||
|
}
|
||||||
|
|
||||||
struct Rule {
|
struct Rule {
|
||||||
id: &'static str,
|
id: &'static str,
|
||||||
@@ -1185,20 +1201,25 @@ async fn collect_candidates(
|
|||||||
) -> crate::Result<Vec<SourceCandidate>> {
|
) -> crate::Result<Vec<SourceCandidate>> {
|
||||||
let mut candidates = Vec::new();
|
let mut candidates = Vec::new();
|
||||||
let mut locations = vec![
|
let mut locations = vec![
|
||||||
(directories.game_logs_dir(instance_root), "minecraft_log"),
|
(
|
||||||
|
directories.game_logs_dir(instance_root),
|
||||||
|
"minecraft_log",
|
||||||
|
None,
|
||||||
|
),
|
||||||
(
|
(
|
||||||
directories.game_crash_reports_dir(instance_root),
|
directories.game_crash_reports_dir(instance_root),
|
||||||
"crash_report",
|
"crash_report",
|
||||||
|
Some("crash-reports"),
|
||||||
),
|
),
|
||||||
(instance_root.to_path_buf(), "instance_log"),
|
(instance_root.to_path_buf(), "instance_log", None),
|
||||||
];
|
];
|
||||||
if let Some(dot_minecraft) = isolated_minecraft_root(instance_root) {
|
if let Some(dot_minecraft) = isolated_minecraft_root(instance_root) {
|
||||||
// PCL-CE also searches the shared `.minecraft` root for JVM crash
|
// PCL-CE also searches the shared `.minecraft` root for JVM crash
|
||||||
// logs when a version-isolated instance is active.
|
// logs when a version-isolated instance is active.
|
||||||
locations.push((dot_minecraft, "minecraft_root_log"));
|
locations.push((dot_minecraft, "minecraft_root_log", None));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (directory, default_type) in locations {
|
for (directory, default_type, upload_prefix) in locations {
|
||||||
if !tokio::fs::try_exists(&directory).await? {
|
if !tokio::fs::try_exists(&directory).await? {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1248,6 +1269,9 @@ async fn collect_candidates(
|
|||||||
};
|
};
|
||||||
candidates.push(SourceCandidate {
|
candidates.push(SourceCandidate {
|
||||||
path: entry.path(),
|
path: entry.path(),
|
||||||
|
upload_name: upload_prefix
|
||||||
|
.map(|prefix| format!("{prefix}/{filename}"))
|
||||||
|
.unwrap_or_else(|| filename.clone()),
|
||||||
filename,
|
filename,
|
||||||
source_type,
|
source_type,
|
||||||
modified: metadata.modified().unwrap_or(SystemTime::UNIX_EPOCH),
|
modified: metadata.modified().unwrap_or(SystemTime::UNIX_EPOCH),
|
||||||
@@ -1257,6 +1281,53 @@ async fn collect_candidates(
|
|||||||
Ok(candidates)
|
Ok(candidates)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn collect_crash_context(
|
||||||
|
instance_id: &str,
|
||||||
|
) -> crate::Result<CrashContext> {
|
||||||
|
let state = State::get().await?;
|
||||||
|
let (instance_path, game_dir_override) =
|
||||||
|
resolve_instance_path(instance_id, &state).await?;
|
||||||
|
let instance_root = state
|
||||||
|
.directories
|
||||||
|
.resolve_game_dir(&instance_path, game_dir_override.as_deref());
|
||||||
|
let candidates =
|
||||||
|
collect_candidates(&instance_root, &state.directories).await?;
|
||||||
|
let selected = select_run_candidates(candidates);
|
||||||
|
let sources = read_sources(selected).await;
|
||||||
|
let credentials = Credentials::get_all(&state.pool)
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.map(|credential| credential.1)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
Ok(CrashContext {
|
||||||
|
sources,
|
||||||
|
credentials,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) async fn collect_crash_logs(
|
||||||
|
instance_id: &str,
|
||||||
|
) -> crate::Result<CollectedCrashLogs> {
|
||||||
|
let CrashContext {
|
||||||
|
sources,
|
||||||
|
credentials,
|
||||||
|
..
|
||||||
|
} = collect_crash_context(instance_id).await?;
|
||||||
|
let combined_log =
|
||||||
|
CensoredString::censor(build_combined_log(&sources), &credentials);
|
||||||
|
let sources = sources
|
||||||
|
.into_iter()
|
||||||
|
.map(|source| CollectedCrashLog {
|
||||||
|
name: source.upload_name,
|
||||||
|
content: CensoredString::censor(source.content, &credentials),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
Ok(CollectedCrashLogs {
|
||||||
|
combined_log,
|
||||||
|
sources,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn isolated_minecraft_root(instance_root: &Path) -> Option<PathBuf> {
|
fn isolated_minecraft_root(instance_root: &Path) -> Option<PathBuf> {
|
||||||
let versions_dir = instance_root.parent()?;
|
let versions_dir = instance_root.parent()?;
|
||||||
if versions_dir
|
if versions_dir
|
||||||
@@ -1320,6 +1391,7 @@ async fn read_sources(candidates: Vec<SourceCandidate>) -> Vec<SourceText> {
|
|||||||
};
|
};
|
||||||
sources.push(SourceText {
|
sources.push(SourceText {
|
||||||
filename: candidate.filename,
|
filename: candidate.filename,
|
||||||
|
upload_name: candidate.upload_name,
|
||||||
source_type: candidate.source_type,
|
source_type: candidate.source_type,
|
||||||
modified: candidate.modified,
|
modified: candidate.modified,
|
||||||
content: String::from_utf8_lossy(bytes).into_owned(),
|
content: String::from_utf8_lossy(bytes).into_owned(),
|
||||||
@@ -1779,6 +1851,7 @@ mod tests {
|
|||||||
fn source(filename: &str, content: &str) -> SourceText {
|
fn source(filename: &str, content: &str) -> SourceText {
|
||||||
SourceText {
|
SourceText {
|
||||||
filename: filename.to_string(),
|
filename: filename.to_string(),
|
||||||
|
upload_name: filename.to_string(),
|
||||||
source_type: "minecraft_log",
|
source_type: "minecraft_log",
|
||||||
modified: SystemTime::now(),
|
modified: SystemTime::now(),
|
||||||
content: content.to_string(),
|
content: content.to_string(),
|
||||||
@@ -1802,6 +1875,7 @@ mod tests {
|
|||||||
let candidates = vec![SourceCandidate {
|
let candidates = vec![SourceCandidate {
|
||||||
path: PathBuf::from("launcher_log.txt"),
|
path: PathBuf::from("launcher_log.txt"),
|
||||||
filename: "launcher_log.txt".to_string(),
|
filename: "launcher_log.txt".to_string(),
|
||||||
|
upload_name: "launcher_log.txt".to_string(),
|
||||||
source_type: "minecraft_log",
|
source_type: "minecraft_log",
|
||||||
modified: SystemTime::now() - Duration::from_secs(181),
|
modified: SystemTime::now() - Duration::from_secs(181),
|
||||||
}];
|
}];
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ use futures::StreamExt;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::{Value, json};
|
use serde_json::{Value, json};
|
||||||
|
|
||||||
use super::CensoredString;
|
use super::crash_analysis::collect_crash_logs;
|
||||||
use super::crash_analysis::analyze_crash;
|
|
||||||
use crate::State;
|
use crate::State;
|
||||||
use crate::emit_logshare_ai_event;
|
use crate::emit_logshare_ai_event;
|
||||||
|
|
||||||
@@ -200,32 +199,6 @@ fn source_identifier() -> String {
|
|||||||
format!("{LOGSHARE_SOURCE_PREFIX}/{}", env!("CARGO_PKG_VERSION"))
|
format!("{LOGSHARE_SOURCE_PREFIX}/{}", env!("CARGO_PKG_VERSION"))
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CollectedCrashLog {
|
|
||||||
name: String,
|
|
||||||
content: CensoredString,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CollectedCrashLogs {
|
|
||||||
combined_log: CensoredString,
|
|
||||||
sources: Vec<CollectedCrashLog>,
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn collect_crash_logs(
|
|
||||||
instance_id: &str,
|
|
||||||
) -> crate::Result<CollectedCrashLogs> {
|
|
||||||
let analysis = analyze_crash(instance_id).await?;
|
|
||||||
Ok(CollectedCrashLogs {
|
|
||||||
combined_log: analysis.combined_log,
|
|
||||||
sources: analysis
|
|
||||||
.sources
|
|
||||||
.into_iter()
|
|
||||||
.map(|source| CollectedCrashLog {
|
|
||||||
name: source.filename,
|
|
||||||
content: source.content,
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
async fn prepare_upload(instance_id: &str) -> crate::Result<UploadBody> {
|
async fn prepare_upload(instance_id: &str) -> crate::Result<UploadBody> {
|
||||||
let settings = get_log_share_settings().await?;
|
let settings = get_log_share_settings().await?;
|
||||||
let logs = collect_crash_logs(instance_id).await?;
|
let logs = collect_crash_logs(instance_id).await?;
|
||||||
|
|||||||
Reference in new issue
Block a user