You've already forked AstralRinth
forked from didirus/AstralRinth
Include crash reports and attempt to order by age. (#1178)
* Include crash reports and attempt to order by age. * Do all sorting within rust. * Remove excess debug. * Remove new once_cell dep. * Use EPOCH as fallback instead of now() * Fix prettier lint warnings.
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
|
resolver = "2"
|
||||||
|
|
||||||
members = [
|
members = [
|
||||||
"theseus",
|
"theseus",
|
||||||
|
|||||||
@@ -1,23 +1,33 @@
|
|||||||
use std::io::{Read, SeekFrom};
|
use std::io::{Read, SeekFrom};
|
||||||
|
use std::time::SystemTime;
|
||||||
|
|
||||||
|
use futures::TryFutureExt;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tokio::{
|
||||||
|
fs::File,
|
||||||
|
io::{AsyncReadExt, AsyncSeekExt},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
prelude::{Credentials, DirectoryInfo},
|
prelude::{Credentials, DirectoryInfo},
|
||||||
util::io::{self, IOError},
|
util::io::{self, IOError},
|
||||||
{state::ProfilePathId, State},
|
{state::ProfilePathId, State},
|
||||||
};
|
};
|
||||||
use futures::TryFutureExt;
|
|
||||||
use serde::Serialize;
|
|
||||||
use tokio::{
|
|
||||||
fs::File,
|
|
||||||
io::{AsyncReadExt, AsyncSeekExt},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Serialize, Debug)]
|
#[derive(Serialize, Debug)]
|
||||||
pub struct Logs {
|
pub struct Logs {
|
||||||
|
pub log_type: LogType,
|
||||||
pub filename: String,
|
pub filename: String,
|
||||||
|
pub age: u64,
|
||||||
pub output: Option<CensoredString>,
|
pub output: Option<CensoredString>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, Eq, PartialEq)]
|
||||||
|
pub enum LogType {
|
||||||
|
InfoLog,
|
||||||
|
CrashReport,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Debug)]
|
#[derive(Serialize, Debug)]
|
||||||
pub struct LatestLogCursor {
|
pub struct LatestLogCursor {
|
||||||
pub cursor: u64,
|
pub cursor: u64,
|
||||||
@@ -54,15 +64,29 @@ impl CensoredString {
|
|||||||
|
|
||||||
impl Logs {
|
impl Logs {
|
||||||
async fn build(
|
async fn build(
|
||||||
|
log_type: LogType,
|
||||||
|
age: SystemTime,
|
||||||
profile_subpath: &ProfilePathId,
|
profile_subpath: &ProfilePathId,
|
||||||
filename: String,
|
filename: String,
|
||||||
clear_contents: Option<bool>,
|
clear_contents: Option<bool>,
|
||||||
) -> crate::Result<Self> {
|
) -> crate::Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
log_type,
|
||||||
|
age: age
|
||||||
|
.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
|
.unwrap_or_else(|_| std::time::Duration::from_secs(0))
|
||||||
|
.as_secs(),
|
||||||
output: if clear_contents.unwrap_or(false) {
|
output: if clear_contents.unwrap_or(false) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(get_output_by_filename(profile_subpath, &filename).await?)
|
Some(
|
||||||
|
get_output_by_filename(
|
||||||
|
profile_subpath,
|
||||||
|
log_type,
|
||||||
|
&filename,
|
||||||
|
)
|
||||||
|
.await?,
|
||||||
|
)
|
||||||
},
|
},
|
||||||
filename,
|
filename,
|
||||||
})
|
})
|
||||||
@@ -70,74 +94,118 @@ impl Logs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub async fn get_logs(
|
pub async fn get_logs_from_type(
|
||||||
profile_path: ProfilePathId,
|
profile_path: &ProfilePathId,
|
||||||
|
log_type: LogType,
|
||||||
clear_contents: Option<bool>,
|
clear_contents: Option<bool>,
|
||||||
) -> crate::Result<Vec<Logs>> {
|
logs: &mut Vec<crate::Result<Logs>>,
|
||||||
let profile_path =
|
) -> crate::Result<()> {
|
||||||
if let Some(p) = crate::profile::get(&profile_path, None).await? {
|
let logs_folder = match log_type {
|
||||||
p.profile_id()
|
LogType::InfoLog => {
|
||||||
} else {
|
DirectoryInfo::profile_logs_dir(profile_path).await?
|
||||||
return Err(crate::ErrorKind::UnmanagedProfileError(
|
}
|
||||||
profile_path.to_string(),
|
LogType::CrashReport => {
|
||||||
)
|
DirectoryInfo::crash_reports_dir(profile_path).await?
|
||||||
.into());
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let logs_folder = DirectoryInfo::profile_logs_dir(&profile_path).await?;
|
|
||||||
let mut logs = Vec::new();
|
|
||||||
if logs_folder.exists() {
|
if logs_folder.exists() {
|
||||||
for entry in std::fs::read_dir(&logs_folder)
|
for entry in std::fs::read_dir(&logs_folder)
|
||||||
.map_err(|e| IOError::with_path(e, &logs_folder))?
|
.map_err(|e| IOError::with_path(e, &logs_folder))?
|
||||||
{
|
{
|
||||||
let entry: std::fs::DirEntry =
|
let entry: std::fs::DirEntry =
|
||||||
entry.map_err(|e| IOError::with_path(e, &logs_folder))?;
|
entry.map_err(|e| IOError::with_path(e, &logs_folder))?;
|
||||||
|
let age = entry.metadata()?.created().unwrap_or_else(|_| SystemTime::UNIX_EPOCH);
|
||||||
let path = entry.path();
|
let path = entry.path();
|
||||||
if !path.is_file() {
|
if !path.is_file() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if let Some(file_name) = path.file_name() {
|
if let Some(file_name) = path.file_name() {
|
||||||
let file_name = file_name.to_string_lossy().to_string();
|
let file_name = file_name.to_string_lossy().to_string();
|
||||||
|
|
||||||
logs.push(
|
logs.push(
|
||||||
Logs::build(&profile_path, file_name, clear_contents).await,
|
Logs::build(
|
||||||
|
log_type,
|
||||||
|
age,
|
||||||
|
&profile_path,
|
||||||
|
file_name,
|
||||||
|
clear_contents,
|
||||||
|
)
|
||||||
|
.await,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument]
|
||||||
|
pub async fn get_logs(
|
||||||
|
profile_path_id: ProfilePathId,
|
||||||
|
clear_contents: Option<bool>,
|
||||||
|
) -> crate::Result<Vec<Logs>> {
|
||||||
|
let profile_path = profile_path_id.profile_path().await?;
|
||||||
|
|
||||||
|
let mut logs = Vec::new();
|
||||||
|
get_logs_from_type(
|
||||||
|
&profile_path,
|
||||||
|
LogType::InfoLog,
|
||||||
|
clear_contents,
|
||||||
|
&mut logs,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
get_logs_from_type(
|
||||||
|
&profile_path,
|
||||||
|
LogType::CrashReport,
|
||||||
|
clear_contents,
|
||||||
|
&mut logs,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
let mut logs = logs.into_iter().collect::<crate::Result<Vec<Logs>>>()?;
|
let mut logs = logs.into_iter().collect::<crate::Result<Vec<Logs>>>()?;
|
||||||
logs.sort_by_key(|x| x.filename.clone());
|
logs.sort_by(|a, b| b.age.cmp(&a.age).then(b.filename.cmp(&a.filename)));
|
||||||
Ok(logs)
|
Ok(logs)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub async fn get_logs_by_filename(
|
pub async fn get_logs_by_filename(
|
||||||
profile_path: ProfilePathId,
|
profile_path_id: ProfilePathId,
|
||||||
|
log_type: LogType,
|
||||||
filename: String,
|
filename: String,
|
||||||
) -> crate::Result<Logs> {
|
) -> crate::Result<Logs> {
|
||||||
let profile_path =
|
let profile_path = profile_path_id.profile_path().await?;
|
||||||
if let Some(p) = crate::profile::get(&profile_path, None).await? {
|
|
||||||
p.profile_id()
|
let path = match log_type {
|
||||||
} else {
|
LogType::InfoLog => {
|
||||||
return Err(crate::ErrorKind::UnmanagedProfileError(
|
DirectoryInfo::profile_logs_dir(&profile_path).await
|
||||||
profile_path.to_string(),
|
}
|
||||||
)
|
LogType::CrashReport => {
|
||||||
.into());
|
DirectoryInfo::crash_reports_dir(&profile_path).await
|
||||||
};
|
}
|
||||||
Ok(Logs {
|
}?
|
||||||
output: Some(get_output_by_filename(&profile_path, &filename).await?),
|
.join(&filename);
|
||||||
filename,
|
|
||||||
})
|
let metadata = std::fs::metadata(&path)?;
|
||||||
|
let age = metadata.created().unwrap_or_else(|_| SystemTime::UNIX_EPOCH);
|
||||||
|
|
||||||
|
Logs::build(log_type, age, &profile_path, filename, Some(true)).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub async fn get_output_by_filename(
|
pub async fn get_output_by_filename(
|
||||||
profile_subpath: &ProfilePathId,
|
profile_subpath: &ProfilePathId,
|
||||||
|
log_type: LogType,
|
||||||
file_name: &str,
|
file_name: &str,
|
||||||
) -> crate::Result<CensoredString> {
|
) -> crate::Result<CensoredString> {
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
let logs_folder = DirectoryInfo::profile_logs_dir(profile_subpath).await?;
|
|
||||||
|
let logs_folder = match log_type {
|
||||||
|
LogType::InfoLog => {
|
||||||
|
DirectoryInfo::profile_logs_dir(profile_subpath).await?
|
||||||
|
}
|
||||||
|
LogType::CrashReport => {
|
||||||
|
DirectoryInfo::crash_reports_dir(profile_subpath).await?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let path = logs_folder.join(file_name);
|
let path = logs_folder.join(file_name);
|
||||||
|
|
||||||
let credentials: Vec<Credentials> = state
|
let credentials: Vec<Credentials> = state
|
||||||
@@ -168,7 +236,7 @@ pub async fn get_output_by_filename(
|
|||||||
contents = [0; 1024];
|
contents = [0; 1024];
|
||||||
}
|
}
|
||||||
return Ok(CensoredString::censor(result, &credentials));
|
return Ok(CensoredString::censor(result, &credentials));
|
||||||
} else if ext == "log" {
|
} else if ext == "log" || ext == "txt" {
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
let mut contents = [0; 1024];
|
let mut contents = [0; 1024];
|
||||||
let mut file = std::fs::File::open(&path)
|
let mut file = std::fs::File::open(&path)
|
||||||
@@ -194,16 +262,8 @@ pub async fn get_output_by_filename(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub async fn delete_logs(profile_path: ProfilePathId) -> crate::Result<()> {
|
pub async fn delete_logs(profile_path_id: ProfilePathId) -> crate::Result<()> {
|
||||||
let profile_path =
|
let profile_path = profile_path_id.profile_path().await?;
|
||||||
if let Some(p) = crate::profile::get(&profile_path, None).await? {
|
|
||||||
p.profile_id()
|
|
||||||
} else {
|
|
||||||
return Err(crate::ErrorKind::UnmanagedProfileError(
|
|
||||||
profile_path.to_string(),
|
|
||||||
)
|
|
||||||
.into());
|
|
||||||
};
|
|
||||||
|
|
||||||
let logs_folder = DirectoryInfo::profile_logs_dir(&profile_path).await?;
|
let logs_folder = DirectoryInfo::profile_logs_dir(&profile_path).await?;
|
||||||
for entry in std::fs::read_dir(&logs_folder)
|
for entry in std::fs::read_dir(&logs_folder)
|
||||||
@@ -220,20 +280,21 @@ pub async fn delete_logs(profile_path: ProfilePathId) -> crate::Result<()> {
|
|||||||
|
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub async fn delete_logs_by_filename(
|
pub async fn delete_logs_by_filename(
|
||||||
profile_path: ProfilePathId,
|
profile_path_id: ProfilePathId,
|
||||||
|
log_type: LogType,
|
||||||
filename: &str,
|
filename: &str,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
let profile_path =
|
let profile_path = profile_path_id.profile_path().await?;
|
||||||
if let Some(p) = crate::profile::get(&profile_path, None).await? {
|
|
||||||
p.profile_id()
|
let logs_folder = match log_type {
|
||||||
} else {
|
LogType::InfoLog => {
|
||||||
return Err(crate::ErrorKind::UnmanagedProfileError(
|
DirectoryInfo::profile_logs_dir(&profile_path).await
|
||||||
profile_path.to_string(),
|
}
|
||||||
)
|
LogType::CrashReport => {
|
||||||
.into());
|
DirectoryInfo::crash_reports_dir(&profile_path).await
|
||||||
};
|
}
|
||||||
|
}?;
|
||||||
|
|
||||||
let logs_folder = DirectoryInfo::profile_logs_dir(&profile_path).await?;
|
|
||||||
let path = logs_folder.join(filename);
|
let path = logs_folder.join(filename);
|
||||||
io::remove_dir_all(&path).await?;
|
io::remove_dir_all(&path).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -249,19 +310,11 @@ pub async fn get_latest_log_cursor(
|
|||||||
|
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub async fn get_generic_live_log_cursor(
|
pub async fn get_generic_live_log_cursor(
|
||||||
profile_path: ProfilePathId,
|
profile_path_id: ProfilePathId,
|
||||||
log_file_name: &str,
|
log_file_name: &str,
|
||||||
mut cursor: u64, // 0 to start at beginning of file
|
mut cursor: u64, // 0 to start at beginning of file
|
||||||
) -> crate::Result<LatestLogCursor> {
|
) -> crate::Result<LatestLogCursor> {
|
||||||
let profile_path =
|
let profile_path = profile_path_id.profile_path().await?;
|
||||||
if let Some(p) = crate::profile::get(&profile_path, None).await? {
|
|
||||||
p.profile_id()
|
|
||||||
} else {
|
|
||||||
return Err(crate::ErrorKind::UnmanagedProfileError(
|
|
||||||
profile_path.to_string(),
|
|
||||||
)
|
|
||||||
.into());
|
|
||||||
};
|
|
||||||
|
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
let logs_folder = DirectoryInfo::profile_logs_dir(&profile_path).await?;
|
let logs_folder = DirectoryInfo::profile_logs_dir(&profile_path).await?;
|
||||||
|
|||||||
@@ -166,6 +166,14 @@ impl DirectoryInfo {
|
|||||||
Ok(profile_id.get_full_path().await?.join("logs"))
|
Ok(profile_id.get_full_path().await?.join("logs"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the crash reports dir for a given profile
|
||||||
|
#[inline]
|
||||||
|
pub async fn crash_reports_dir(
|
||||||
|
profile_id: &ProfilePathId,
|
||||||
|
) -> crate::Result<PathBuf> {
|
||||||
|
Ok(profile_id.get_full_path().await?.join("crash-reports"))
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn launcher_logs_dir() -> Option<PathBuf> {
|
pub fn launcher_logs_dir() -> Option<PathBuf> {
|
||||||
Self::get_initial_settings_dir()
|
Self::get_initial_settings_dir()
|
||||||
|
|||||||
@@ -88,6 +88,15 @@ impl ProfilePathId {
|
|||||||
.ok_or(crate::ErrorKind::UTFError(self.0.clone()).as_error())?;
|
.ok_or(crate::ErrorKind::UTFError(self.0.clone()).as_error())?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn profile_path(&self) -> crate::Result<ProfilePathId> {
|
||||||
|
if let Some(p) = crate::profile::get(&self, None).await? {
|
||||||
|
Ok(p.profile_id())
|
||||||
|
} else {
|
||||||
|
Err(crate::ErrorKind::UnmanagedProfileError(self.to_string())
|
||||||
|
.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl std::fmt::Display for ProfilePathId {
|
impl std::fmt::Display for ProfilePathId {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use theseus::{
|
|||||||
logs::{self, CensoredString, LatestLogCursor, Logs},
|
logs::{self, CensoredString, LatestLogCursor, Logs},
|
||||||
prelude::ProfilePathId,
|
prelude::ProfilePathId,
|
||||||
};
|
};
|
||||||
|
use theseus::logs::LogType;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A log is a struct containing the filename string, stdout, and stderr, as follows:
|
A log is a struct containing the filename string, stdout, and stderr, as follows:
|
||||||
@@ -42,15 +43,17 @@ pub async fn logs_get_logs(
|
|||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn logs_get_logs_by_filename(
|
pub async fn logs_get_logs_by_filename(
|
||||||
profile_path: ProfilePathId,
|
profile_path: ProfilePathId,
|
||||||
|
log_type: LogType,
|
||||||
filename: String,
|
filename: String,
|
||||||
) -> Result<Logs> {
|
) -> Result<Logs> {
|
||||||
Ok(logs::get_logs_by_filename(profile_path, filename).await?)
|
Ok(logs::get_logs_by_filename(profile_path, log_type, filename).await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the stdout for a profile by profile id and filename string
|
/// Get the stdout for a profile by profile id and filename string
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn logs_get_output_by_filename(
|
pub async fn logs_get_output_by_filename(
|
||||||
profile_path: ProfilePathId,
|
profile_path: ProfilePathId,
|
||||||
|
log_type: LogType,
|
||||||
filename: String,
|
filename: String,
|
||||||
) -> Result<CensoredString> {
|
) -> Result<CensoredString> {
|
||||||
let profile_path = if let Some(p) =
|
let profile_path = if let Some(p) =
|
||||||
@@ -64,7 +67,7 @@ pub async fn logs_get_output_by_filename(
|
|||||||
.into());
|
.into());
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(logs::get_output_by_filename(&profile_path, &filename).await?)
|
Ok(logs::get_output_by_filename(&profile_path, log_type, &filename).await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delete all logs for a profile by profile id
|
/// Delete all logs for a profile by profile id
|
||||||
@@ -77,9 +80,10 @@ pub async fn logs_delete_logs(profile_path: ProfilePathId) -> Result<()> {
|
|||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn logs_delete_logs_by_filename(
|
pub async fn logs_delete_logs_by_filename(
|
||||||
profile_path: ProfilePathId,
|
profile_path: ProfilePathId,
|
||||||
|
log_type: LogType,
|
||||||
filename: String,
|
filename: String,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
Ok(logs::delete_logs_by_filename(profile_path, &filename).await?)
|
Ok(logs::delete_logs_by_filename(profile_path, log_type, &filename).await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get live log from a cursor
|
/// Get live log from a cursor
|
||||||
|
|||||||
@@ -22,18 +22,22 @@ export async function get_logs(profilePath, clearContents) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get a profile's log by filename
|
/// Get a profile's log by filename
|
||||||
export async function get_logs_by_filename(profilePath, filename) {
|
export async function get_logs_by_filename(profilePath, logType, filename) {
|
||||||
return await invoke('plugin:logs|logs_get_logs_by_filename', { profilePath, filename })
|
return await invoke('plugin:logs|logs_get_logs_by_filename', { profilePath, logType, filename })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a profile's log text only by filename
|
/// Get a profile's log text only by filename
|
||||||
export async function get_output_by_filename(profilePath, filename) {
|
export async function get_output_by_filename(profilePath, logType, filename) {
|
||||||
return await invoke('plugin:logs|logs_get_output_by_filename', { profilePath, filename })
|
return await invoke('plugin:logs|logs_get_output_by_filename', { profilePath, logType, filename })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delete a profile's log by filename
|
/// Delete a profile's log by filename
|
||||||
export async function delete_logs_by_filename(profilePath, filename) {
|
export async function delete_logs_by_filename(profilePath, logType, filename) {
|
||||||
return await invoke('plugin:logs|logs_delete_logs_by_filename', { profilePath, filename })
|
return await invoke('plugin:logs|logs_delete_logs_by_filename', {
|
||||||
|
profilePath,
|
||||||
|
logType,
|
||||||
|
filename,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delete all logs for a given profile
|
/// Delete all logs for a given profile
|
||||||
@@ -50,6 +54,7 @@ export async function delete_logs(profilePath) {
|
|||||||
new_file: bool <- the cursor was too far, meaning that the file was likely rotated/reset. This signals to the frontend to clear the log and start over with this struct.
|
new_file: bool <- the cursor was too far, meaning that the file was likely rotated/reset. This signals to the frontend to clear the log and start over with this struct.
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// From latest.log directly
|
// From latest.log directly
|
||||||
export async function get_latest_log_cursor(profilePath, cursor) {
|
export async function get_latest_log_cursor(profilePath, cursor) {
|
||||||
return await invoke('plugin:logs|logs_get_latest_log_cursor', { profilePath, cursor })
|
return await invoke('plugin:logs|logs_get_latest_log_cursor', { profilePath, cursor })
|
||||||
|
|||||||
@@ -54,8 +54,8 @@
|
|||||||
v-model="levelFilters[level.toLowerCase()]"
|
v-model="levelFilters[level.toLowerCase()]"
|
||||||
class="filter-checkbox"
|
class="filter-checkbox"
|
||||||
>
|
>
|
||||||
{{ level }}</Checkbox
|
{{ level }}
|
||||||
>
|
</Checkbox>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="log-text">
|
<div class="log-text">
|
||||||
@@ -225,7 +225,7 @@ async function getLiveStdLog() {
|
|||||||
} else {
|
} else {
|
||||||
const logCursor = await get_latest_log_cursor(
|
const logCursor = await get_latest_log_cursor(
|
||||||
props.instance.path,
|
props.instance.path,
|
||||||
currentLiveLogCursor.value,
|
currentLiveLogCursor.value
|
||||||
).catch(handleError)
|
).catch(handleError)
|
||||||
if (logCursor.new_file) {
|
if (logCursor.new_file) {
|
||||||
currentLiveLog.value = ''
|
currentLiveLog.value = ''
|
||||||
@@ -241,14 +241,13 @@ async function getLiveStdLog() {
|
|||||||
|
|
||||||
async function getLogs() {
|
async function getLogs() {
|
||||||
return (await get_logs(props.instance.path, true).catch(handleError))
|
return (await get_logs(props.instance.path, true).catch(handleError))
|
||||||
.reverse()
|
|
||||||
.filter(
|
.filter(
|
||||||
// filter out latest_stdout.log or anything without .log in it
|
// filter out latest_stdout.log or anything without .log in it
|
||||||
(log) =>
|
(log) =>
|
||||||
log.filename !== 'latest_stdout.log' &&
|
log.filename !== 'latest_stdout.log' &&
|
||||||
log.filename !== 'latest_stdout' &&
|
log.filename !== 'latest_stdout' &&
|
||||||
log.stdout !== '' &&
|
log.stdout !== '' &&
|
||||||
log.filename.includes('.log'),
|
(log.filename.includes('.log') || log.filename.endsWith('.txt'))
|
||||||
)
|
)
|
||||||
.map((log) => {
|
.map((log) => {
|
||||||
log.name = log.filename || 'Unknown'
|
log.name = log.filename || 'Unknown'
|
||||||
@@ -291,7 +290,8 @@ watch(selectedLogIndex, async (newIndex) => {
|
|||||||
logs.value[newIndex].stdout = 'Loading...'
|
logs.value[newIndex].stdout = 'Loading...'
|
||||||
logs.value[newIndex].stdout = await get_output_by_filename(
|
logs.value[newIndex].stdout = await get_output_by_filename(
|
||||||
props.instance.path,
|
props.instance.path,
|
||||||
logs.value[newIndex].filename,
|
logs.value[newIndex].log_type,
|
||||||
|
logs.value[newIndex].filename
|
||||||
).catch(handleError)
|
).catch(handleError)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -306,9 +306,11 @@ const deleteLog = async () => {
|
|||||||
if (logs.value[selectedLogIndex.value] && selectedLogIndex.value !== 0) {
|
if (logs.value[selectedLogIndex.value] && selectedLogIndex.value !== 0) {
|
||||||
let deleteIndex = selectedLogIndex.value
|
let deleteIndex = selectedLogIndex.value
|
||||||
selectedLogIndex.value = deleteIndex - 1
|
selectedLogIndex.value = deleteIndex - 1
|
||||||
await delete_logs_by_filename(props.instance.path, logs.value[deleteIndex].filename).catch(
|
await delete_logs_by_filename(
|
||||||
handleError,
|
props.instance.path,
|
||||||
)
|
logs.value[deleteIndex].log_type,
|
||||||
|
logs.value[deleteIndex].filename
|
||||||
|
).catch(handleError)
|
||||||
await setLogs()
|
await setLogs()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -512,6 +514,7 @@ onUnmounted(() => {
|
|||||||
justify-self: center;
|
justify-self: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-group {
|
.filter-group {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 0.6rem;
|
padding: 0.6rem;
|
||||||
|
|||||||
Reference in New Issue
Block a user