mirror of
https://code.gri.mw/GUI/grim.git
synced 2026-07-04 05:57:29 +00:00
log: info level into file, crash report for android
This commit is contained in:
Generated
+2
@@ -4009,6 +4009,7 @@ dependencies = [
|
||||
"arti-client",
|
||||
"async-std",
|
||||
"backtrace",
|
||||
"built",
|
||||
"bytes 1.11.1",
|
||||
"chrono",
|
||||
"curve25519-dalek 4.1.3",
|
||||
@@ -4048,6 +4049,7 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"local-ip-address",
|
||||
"log",
|
||||
"log4rs",
|
||||
"nokhwa",
|
||||
"num-bigint 0.4.6",
|
||||
"parking_lot 0.12.5",
|
||||
|
||||
+5
-1
@@ -52,6 +52,7 @@ egui-async = "0.3.4"
|
||||
rust-i18n = "3.1.5"
|
||||
|
||||
## other
|
||||
log4rs = "1.4.0"
|
||||
anyhow = "1.0.97"
|
||||
pin-project = "1.1.10"
|
||||
backtrace = "0.3.76"
|
||||
@@ -136,4 +137,7 @@ android_logger = "0.15.0"
|
||||
jni = "0.21.1"
|
||||
android-activity = { version = "0.6.0", features = ["game-activity"] }
|
||||
winit = { version = "0.30.12", features = ["android-game-activity"] }
|
||||
eframe = { version = "0.33.2", default-features = false, features = ["glow", "android-game-activity"] }
|
||||
eframe = { version = "0.33.2", default-features = false, features = ["glow", "android-game-activity"] }
|
||||
|
||||
[build-dependencies]
|
||||
built = "0.8.0"
|
||||
|
||||
@@ -2,6 +2,8 @@ use std::process::Command;
|
||||
use std::{env, fs};
|
||||
|
||||
fn main() {
|
||||
built::write_built_file().expect("Failed to acquire build-time information");
|
||||
|
||||
let out_dir = env::var("OUT_DIR").unwrap();
|
||||
let tor_out_dir = format!("{}/tor", out_dir);
|
||||
let mut webtunnel_file = format!("{}/webtunnel", tor_out_dir);
|
||||
|
||||
@@ -117,7 +117,7 @@ impl ContentContainer for Content {
|
||||
|
||||
if self.first_draw {
|
||||
// Show crash report or integrated node Android warning.
|
||||
if Settings::crash_report_path().exists() {
|
||||
if Settings::crash_check_path().exists() {
|
||||
Modal::new(CRASH_REPORT_MODAL)
|
||||
.closeable(false)
|
||||
.position(ModalPosition::Center)
|
||||
@@ -276,14 +276,14 @@ impl Content {
|
||||
.size(16.0)
|
||||
.color(Colors::text(false)));
|
||||
ui.add_space(6.0);
|
||||
// Draw button to share crash report.
|
||||
// Draw button to share log file.
|
||||
let text = format!("{} {}", FILE_X, t!("share"));
|
||||
View::colored_text_button(ui, text, Colors::blue(), Colors::white_or_black(false), || {
|
||||
if let Ok(data) = fs::read_to_string(Settings::crash_report_path()) {
|
||||
let name = Settings::CRASH_REPORT_FILE_NAME.to_string();
|
||||
if let Ok(data) = fs::read_to_string(Settings::log_path()) {
|
||||
let name = Settings::LOG_FILE_NAME.to_string();
|
||||
let _ = cb.share_data(name, data.as_bytes().to_vec());
|
||||
}
|
||||
Settings::delete_crash_report();
|
||||
Settings::delete_crash_check();
|
||||
Modal::close();
|
||||
});
|
||||
});
|
||||
@@ -292,7 +292,7 @@ impl Content {
|
||||
ui.add_space(8.0);
|
||||
ui.vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
Settings::delete_crash_report();
|
||||
Settings::delete_crash_check();
|
||||
Modal::close();
|
||||
});
|
||||
});
|
||||
|
||||
+5
-9
@@ -19,8 +19,8 @@ rust_i18n::i18n!("locales");
|
||||
use eframe::NativeOptions;
|
||||
use egui::{Context, Stroke, Theme};
|
||||
use lazy_static::lazy_static;
|
||||
use std::sync::Arc;
|
||||
use parking_lot::RwLock;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
use winit::platform::android::activity::AndroidApp;
|
||||
@@ -28,9 +28,9 @@ use winit::platform::android::activity::AndroidApp;
|
||||
pub use settings::AppConfig;
|
||||
pub use settings::Settings;
|
||||
|
||||
use crate::gui::{Colors, App};
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
use crate::gui::views::View;
|
||||
use crate::gui::{App, Colors};
|
||||
use crate::node::Node;
|
||||
|
||||
mod node;
|
||||
@@ -39,6 +39,7 @@ mod tor;
|
||||
mod settings;
|
||||
mod http;
|
||||
pub mod gui;
|
||||
pub mod logger;
|
||||
|
||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
@@ -47,13 +48,8 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
#[cfg(target_os = "android")]
|
||||
#[no_mangle]
|
||||
fn android_main(app: AndroidApp) {
|
||||
{
|
||||
std::env::set_var("RUST_BACKTRACE", "full");
|
||||
let log_config = android_logger::Config::default()
|
||||
.with_max_level(log::LevelFilter::Info)
|
||||
.with_tag("grim");
|
||||
android_logger::init_once(log_config);
|
||||
}
|
||||
// Setup logger.
|
||||
logger::init_logger();
|
||||
|
||||
use gui::platform::Android;
|
||||
let platform = Android::new(app.clone());
|
||||
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
// Copyright 2026 The Grim Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::{panic, thread};
|
||||
use std::fs::File;
|
||||
use backtrace::Backtrace;
|
||||
use log4rs::append::Append;
|
||||
use log4rs::append::console::ConsoleAppender;
|
||||
use log4rs::append::rolling_file::policy::compound::CompoundPolicy;
|
||||
use log4rs::append::rolling_file::policy::compound::roll::fixed_window::FixedWindowRoller;
|
||||
use log4rs::append::rolling_file::policy::compound::trigger::size::SizeTrigger;
|
||||
use log4rs::append::rolling_file::RollingFileAppender;
|
||||
use log4rs::Config;
|
||||
use log4rs::config::{Appender, Root};
|
||||
use log4rs::encode::pattern::PatternEncoder;
|
||||
use log4rs::filter::threshold::ThresholdFilter;
|
||||
use log::{error, LevelFilter};
|
||||
|
||||
use crate::Settings;
|
||||
|
||||
const LOGGING_PATTERN: &str = "{d(%Y%m%d %H:%M:%S%.3f)} {h({l})} {M} - {m}{n}";
|
||||
|
||||
/// 32 log files to rotate over by default.
|
||||
const ROTATE_LOG_FILES: u32 = 32;
|
||||
/// Size of the log in bytes to rotate over (6 megabytes).
|
||||
const MAX_FILE_SIZE: u64 = 1024 * 1024 * 6;
|
||||
|
||||
/// Include build information.
|
||||
pub mod built_info {
|
||||
include!(concat!(env!("OUT_DIR"), "/built.rs"));
|
||||
}
|
||||
|
||||
/// Initialize the logger.
|
||||
pub fn init_logger() {
|
||||
let stdout = ConsoleAppender::builder()
|
||||
.encoder(Box::new(PatternEncoder::new(&LOGGING_PATTERN)))
|
||||
.build();
|
||||
|
||||
let mut root = Root::builder();
|
||||
|
||||
let mut app = vec![];
|
||||
app.push(
|
||||
Appender::builder()
|
||||
.filter(Box::new(ThresholdFilter::new(LevelFilter::Info)))
|
||||
.build("stdout", Box::new(stdout)),
|
||||
);
|
||||
root = root.appender("stdout");
|
||||
|
||||
// Setup file logging.
|
||||
let filter = Box::new(ThresholdFilter::new(LevelFilter::Info));
|
||||
let file: Box<dyn Append> = {
|
||||
let path = Settings::log_path();
|
||||
let roller = FixedWindowRoller::builder()
|
||||
.build(&format!("{}.{{}}.gz", path), ROTATE_LOG_FILES)
|
||||
.unwrap();
|
||||
let trigger = SizeTrigger::new(MAX_FILE_SIZE);
|
||||
let policy = CompoundPolicy::new(Box::new(trigger), Box::new(roller));
|
||||
Box::new(
|
||||
RollingFileAppender::builder()
|
||||
.append(true)
|
||||
.encoder(Box::new(PatternEncoder::new(&LOGGING_PATTERN)))
|
||||
.build(path, Box::new(policy))
|
||||
.expect("Failed to create logfile"),
|
||||
)
|
||||
};
|
||||
app.push(
|
||||
Appender::builder()
|
||||
.filter(filter)
|
||||
.build("file", file),
|
||||
);
|
||||
root = root.appender("file");
|
||||
|
||||
let config = Config::builder()
|
||||
.appenders(app)
|
||||
.build(root.build(LevelFilter::Info))
|
||||
.unwrap();
|
||||
let _ = log4rs::init_config(config).unwrap();
|
||||
|
||||
log::info!("{}", build_info());
|
||||
|
||||
send_panic_to_log();
|
||||
}
|
||||
|
||||
/// Get information about application build.
|
||||
fn build_info() -> String {
|
||||
format!(
|
||||
"This is Grim version {}, built for {} by {}.",
|
||||
built_info::PKG_VERSION,
|
||||
built_info::TARGET,
|
||||
built_info::RUSTC_VERSION,
|
||||
)
|
||||
}
|
||||
|
||||
/// Hook to send panics to logs as well as stderr.
|
||||
fn send_panic_to_log() {
|
||||
panic::set_hook(Box::new(|info| {
|
||||
let backtrace = Backtrace::new();
|
||||
|
||||
let thread = thread::current();
|
||||
let thread = thread.name().unwrap_or("unnamed");
|
||||
|
||||
let msg = match info.payload().downcast_ref::<&'static str>() {
|
||||
Some(s) => *s,
|
||||
None => match info.payload().downcast_ref::<String>() {
|
||||
Some(s) => &**s,
|
||||
None => "Box<Any>",
|
||||
},
|
||||
};
|
||||
|
||||
match info.location() {
|
||||
Some(location) => {
|
||||
error!(
|
||||
"{}\nThread '{}' panicked at '{}': {}:{}{:?}\n\n",
|
||||
build_info(),
|
||||
thread,
|
||||
msg,
|
||||
location.file(),
|
||||
location.line(),
|
||||
backtrace
|
||||
);
|
||||
}
|
||||
None => error!("Thread '{}' panicked at '{}'{:?}", thread, msg, backtrace),
|
||||
}
|
||||
// Also print to stderr.
|
||||
eprintln!(
|
||||
"Thread '{}' panicked with message:\n\"{}\"\nSee {} for further details.",
|
||||
thread, msg, Settings::log_path()
|
||||
);
|
||||
// Create file to show report send on launch.
|
||||
let log = Settings::crash_check_path();
|
||||
let _ = File::create(log);
|
||||
}));
|
||||
}
|
||||
+10
-48
@@ -23,11 +23,8 @@ pub fn main() {
|
||||
#[allow(dead_code)]
|
||||
#[cfg(not(target_os = "android"))]
|
||||
fn real_main() {
|
||||
env_logger::builder()
|
||||
.filter_level(log::LevelFilter::Info)
|
||||
.parse_default_env()
|
||||
.init();
|
||||
|
||||
// Initialize logger.
|
||||
grim::logger::init_logger();
|
||||
// Handle file path argument passing.
|
||||
let args: Vec<_> = std::env::args().collect();
|
||||
let mut data = None;
|
||||
@@ -40,50 +37,15 @@ fn real_main() {
|
||||
data = content
|
||||
}
|
||||
|
||||
// Setup callback on panic crash.
|
||||
std::panic::set_hook(Box::new(|info| {
|
||||
// Format error.
|
||||
let backtrace = backtrace::Backtrace::new();
|
||||
let time = grim::gui::views::View::format_time(chrono::Utc::now().timestamp());
|
||||
let os = egui::os::OperatingSystem::from_target_os();
|
||||
let ver = grim::VERSION;
|
||||
let msg = panic_info_message(info);
|
||||
let loc = if let Some(location) = info.location() {
|
||||
format!("{}:{}:{}", location.file(), location.line(), location.column())
|
||||
} else {
|
||||
"no location found.".parse().unwrap()
|
||||
};
|
||||
let err = format!("{} - {:?} - v{}\n{}\n{}\n\n{:?}", time, os, ver, msg, loc, backtrace);
|
||||
// Save backtrace to file.
|
||||
let log = grim::Settings::crash_report_path();
|
||||
if log.exists() {
|
||||
use std::io::{Seek, SeekFrom, Write};
|
||||
let mut file = std::fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.append(true)
|
||||
.open(log)
|
||||
.unwrap();
|
||||
if file.seek(SeekFrom::End(0)).is_ok() {
|
||||
file.write(err.as_bytes()).unwrap_or_default();
|
||||
}
|
||||
} else {
|
||||
std::fs::write(log, err.as_bytes()).unwrap_or_default();
|
||||
}
|
||||
// Print message error.
|
||||
println!("{}\n{}", msg, loc);
|
||||
}));
|
||||
|
||||
// Start GUI.
|
||||
let _ = std::panic::catch_unwind(|| {
|
||||
if is_app_running(&data) {
|
||||
return;
|
||||
} else if let Some(data) = data {
|
||||
grim::on_data(data);
|
||||
}
|
||||
let platform = grim::gui::platform::Desktop::new();
|
||||
start_app_socket(platform.clone());
|
||||
start_desktop_gui(platform);
|
||||
});
|
||||
if is_app_running(&data) {
|
||||
return;
|
||||
} else if let Some(data) = data {
|
||||
grim::on_data(data);
|
||||
}
|
||||
let platform = grim::gui::platform::Desktop::new();
|
||||
start_app_socket(platform.clone());
|
||||
start_desktop_gui(platform);
|
||||
}
|
||||
|
||||
/// Get panic message from crash payload.
|
||||
|
||||
@@ -48,10 +48,10 @@ pub struct Settings {
|
||||
impl Settings {
|
||||
/// Main application directory name.
|
||||
pub const MAIN_DIR_NAME: &'static str = ".grim";
|
||||
/// Crash report file name.
|
||||
pub const CRASH_REPORT_FILE_NAME: &'static str = "crash.log";
|
||||
/// Application socket name.
|
||||
pub const SOCKET_NAME: &'static str = "grim.sock";
|
||||
/// Log file name.
|
||||
pub const LOG_FILE_NAME: &'static str = "grim.log";
|
||||
|
||||
/// Initialize settings with app and node configs.
|
||||
fn init() -> Self {
|
||||
@@ -148,6 +148,13 @@ impl Settings {
|
||||
path
|
||||
}
|
||||
|
||||
/// Get log file path.
|
||||
pub fn log_path() -> String {
|
||||
let mut log_path = Self::base_path(None);
|
||||
log_path.push(Self::LOG_FILE_NAME);
|
||||
log_path.to_str().unwrap().into()
|
||||
}
|
||||
|
||||
/// Get desktop application socket path.
|
||||
pub fn socket_path() -> PathBuf {
|
||||
let mut socket_path = Self::base_path(None);
|
||||
@@ -162,16 +169,16 @@ impl Settings {
|
||||
path
|
||||
}
|
||||
|
||||
/// Get configuration file path from provided name and subdirectory if needed.
|
||||
pub fn crash_report_path() -> PathBuf {
|
||||
/// Get path of file created when application crashed.
|
||||
pub fn crash_check_path() -> PathBuf {
|
||||
let mut path = Self::base_path(None);
|
||||
path.push(Self::CRASH_REPORT_FILE_NAME);
|
||||
path.push("crashed");
|
||||
path
|
||||
}
|
||||
|
||||
/// Delete crash report file.
|
||||
pub fn delete_crash_report() {
|
||||
let log = Self::crash_report_path();
|
||||
/// Delete crash file.
|
||||
pub fn delete_crash_check() {
|
||||
let log = Self::crash_check_path();
|
||||
if log.exists() {
|
||||
let _ = fs::remove_file(log.clone());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user