refactor: tail log error that is ignorable (#1244)

This commit is contained in:
Myriad-Dreamin 2025-02-02 13:59:55 +08:00 committed by GitHub
parent 74c68f5485
commit 36d07464c1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 82 additions and 92 deletions

View file

@ -304,7 +304,7 @@ impl LockFileUpdate {
}
pub fn commit(self) {
let err = super::LockFile::update(&self.root, |l| {
super::LockFile::update(&self.root, |l| {
let root: EcoString = unix_slash(&self.root).into();
let root_hash = tinymist_std::hash::hash128(&root);
for update in self.updates {
@ -334,10 +334,8 @@ impl LockFileUpdate {
let data = serde_json::to_string(&mat).unwrap();
let path = cache_dir.join("path-material.json");
let result = tinymist_std::fs::paths::write_atomic(path, data);
if let Err(err) = result {
log::error!("ProjectCompiler: write material error: {err}");
}
tinymist_std::fs::paths::write_atomic(path, data)
.log_error("ProjectCompiler: write material error");
// todo: clean up old cache
}
@ -350,10 +348,8 @@ impl LockFileUpdate {
}
Ok(())
});
if let Err(err) = err {
log::error!("ProjectCompiler: lock file error: {err}");
}
})
.log_error("ProjectCompiler: lock file error");
}
}

View file

@ -12,7 +12,7 @@
use std::collections::HashMap;
use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher};
use tinymist_std::ImmutPath;
use tinymist_std::{error::IgnoreLogging, ImmutPath};
use tinymist_world::vfs::notify::NotifyDeps;
use tokio::sync::mpsc;
use typst::diag::FileError;
@ -110,14 +110,11 @@ impl<F: FnMut(FilesystemEvent) + Send + Sync> NotifyActor<F> {
/// Create a new actor.
pub fn new(interrupted_by_events: F) -> Self {
let (undetermined_send, undetermined_recv) = mpsc::unbounded_channel();
let (watcher_sender, watcher_receiver) = mpsc::unbounded_channel();
let (watcher_tx, watcher_rx) = mpsc::unbounded_channel();
let watcher = log_notify_error(
RecommendedWatcher::new(
move |event| {
let res = watcher_sender.send(event);
if let Err(err) = res {
log::warn!("error to send event: {err}");
}
watcher_tx.send(event).log_error("failed to send fs notify");
},
Config::default(),
),
@ -136,7 +133,7 @@ impl<F: FnMut(FilesystemEvent) + Send + Sync> NotifyActor<F> {
undetermined_recv,
watched_entries: HashMap::new(),
watcher: watcher.map(|it| (it, watcher_receiver)),
watcher: watcher.map(|it| (it, watcher_rx)),
}
}

View file

@ -243,6 +243,24 @@ impl From<&Error> for wasm_bindgen::JsValue {
/// The result type used in the `tinymist` crate.
pub type Result<T, Err = Error> = std::result::Result<T, Err>;
/// A trait to add context to a result.
pub trait IgnoreLogging<T>: Sized {
/// Log an error message and return `None`.
fn log_error(self, msg: &str) -> Option<T>;
/// Log an error message and return `None`.
fn log_error_with(self, f: impl FnOnce() -> String) -> Option<T>;
}
impl<T, E: std::fmt::Display> IgnoreLogging<T> for Result<T, E> {
fn log_error(self, msg: &str) -> Option<T> {
self.inspect_err(|e| log::error!("{msg}: {e}")).ok()
}
fn log_error_with(self, f: impl FnOnce() -> String) -> Option<T> {
self.inspect_err(|e| log::error!("{}: {e}", f())).ok()
}
}
/// A trait to add context to a result.
pub trait WithContext<T>: Sized {
/// Add a context to the result.
@ -311,7 +329,7 @@ pub mod prelude {
use super::ErrKindExt;
use crate::Error;
pub use super::{WithContext, WithContextUntyped};
pub use super::{IgnoreLogging, WithContext, WithContextUntyped};
pub use crate::Result;
pub fn map_string_err<T: ToString>(loc: &'static str) -> impl Fn(T) -> Error {

View file

@ -4,6 +4,7 @@ use lsp_types::notification::Notification;
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
use sync_lsp::{internal_error, LspClient, LspResult};
use tinymist_std::error::IgnoreLogging;
use tokio::sync::{mpsc, oneshot};
use typst_preview::{ControlPlaneMessage, Previewer};
@ -65,10 +66,9 @@ impl PreviewActor {
let h = tab.compile_handler.clone();
let task_id = tab.task_id.clone();
self.client.handle.spawn(async move {
let res = h.settle().await;
if let Err(e) = res {
log::error!("PreviewTask({task_id}): failed to settle: {:?}", e);
}
h.settle().await.log_error_with(|| {
format!("PreviewTask({task_id}): failed to settle")
});
});
}

View file

@ -8,7 +8,7 @@ use serde_json::{Map, Value as JsonValue};
use sync_lsp::*;
use tinymist_project::{Interrupt, ProjectResolutionKind};
use tinymist_query::{to_typst_range, PositionEncoding};
use tinymist_std::error::prelude::*;
use tinymist_std::error::{prelude::*, IgnoreLogging};
use tinymist_std::ImmutPath;
use typst::{diag::FileResult, syntax::Source};
@ -77,27 +77,20 @@ impl ServerState {
if old_config.compile.primary_opts() != self.config.compile.primary_opts() {
self.config.compile.fonts = OnceCell::new(); // todo: don't reload fonts if not changed
let err = self.restart_primary();
if let Err(err) = err {
log::error!("could not restart primary: {err}");
}
self.restart_primary()
.log_error("could not restart primary");
}
if old_config.semantic_tokens != self.config.semantic_tokens {
let err = self
.enable_sema_token_caps(self.config.semantic_tokens == SemanticTokensMode::Enable);
if let Err(err) = err {
log::error!("could not change semantic tokens config: {err}");
}
self.enable_sema_token_caps(self.config.semantic_tokens == SemanticTokensMode::Enable)
.log_error("could not change semantic tokens config");
}
let new_formatter_config = self.config.formatter();
if !old_config.formatter().eq(&new_formatter_config) {
let enabled = !matches!(new_formatter_config.config, FormatterConfig::Disable);
let err = self.enable_formatter_caps(enabled);
if let Err(err) = err {
log::error!("could not change formatter config: {err}");
}
self.enable_formatter_caps(enabled)
.log_error("could not change formatter config");
self.formatter.change_config(new_formatter_config);
}

View file

@ -32,7 +32,10 @@ use tinymist_query::{
CompilerQueryRequest, CompilerQueryResponse, DiagnosticsMap, SemanticRequest, StatefulRequest,
VersionedDocument,
};
use tinymist_std::{bail, error::prelude::*};
use tinymist_std::{
bail,
error::{prelude::*, IgnoreLogging},
};
use tokio::sync::mpsc;
use crate::actor::editor::{CompileStatus, DocVersion, EditorRequest, TinymistCompileStatusEnum};
@ -162,18 +165,15 @@ impl ProjectClient for LspClient {
impl ProjectClient for tokio::sync::mpsc::UnboundedSender<LspInterrupt> {
fn send_event(&self, event: LspInterrupt) {
if let Err(err) = self.send(event) {
log::error!("failed to send interrupt: {err}");
}
self.send(event).log_error("failed to send interrupt");
}
}
impl CompileHandlerImpl {
fn push_diagnostics(&self, dv: DocVersion, diagnostics: Option<DiagnosticsMap>) {
let res = self.editor_tx.send(EditorRequest::Diag(dv, diagnostics));
if let Err(err) = res {
log::error!("failed to send diagnostics: {err:#}");
}
self.editor_tx
.send(EditorRequest::Diag(dv, diagnostics))
.log_error("failed to send diagnostics");
}
fn notify_diagnostics(&self, snap: &LspCompiledArtifact) {

View file

@ -1,7 +1,7 @@
use lsp_types::*;
use request::{RegisterCapability, UnregisterCapability};
use sync_lsp::*;
use tinymist_std::error::prelude::*;
use tinymist_std::error::{prelude::*, IgnoreLogging};
use crate::{init::*, *};
@ -143,19 +143,15 @@ impl ServerState {
if self.const_config().tokens_dynamic_registration
&& self.config.semantic_tokens == SemanticTokensMode::Enable
{
let err = self.enable_sema_token_caps(true);
if let Err(err) = err {
log::error!("could not register semantic tokens for initialization: {err}");
}
self.enable_sema_token_caps(true)
.log_error("could not register semantic tokens for initialization");
}
if self.const_config().doc_fmt_dynamic_registration
&& self.config.formatter_mode != FormatterMode::Disable
{
let err = self.enable_formatter_caps(true);
if let Err(err) = err {
log::error!("could not register formatter for initialization: {err}");
}
self.enable_formatter_caps(true)
.log_error("could not register formatter for initialization");
}
if self.const_config().cfg_change_registration {
@ -164,16 +160,12 @@ impl ServerState {
const CONFIG_REGISTRATION_ID: &str = "config";
const CONFIG_METHOD_ID: &str = "workspace/didChangeConfiguration";
let err = self
.register_capability(vec![Registration {
id: CONFIG_REGISTRATION_ID.to_owned(),
method: CONFIG_METHOD_ID.to_owned(),
register_options: None,
}])
.err();
if let Some(err) = err {
log::error!("could not register to watch config changes: {err}");
}
self.register_capability(vec![Registration {
id: CONFIG_REGISTRATION_ID.to_owned(),
method: CONFIG_METHOD_ID.to_owned(),
register_options: None,
}])
.log_error("could not register to watch config changes");
}
log::info!("server initialized");

View file

@ -142,10 +142,9 @@ impl ServerState {
service.config.compile.notify_status,
);
let err = service.restart_primary();
if let Err(err) = err {
log::error!("could not restart primary: {err}");
}
service
.restart_primary()
.log_error("could not restart primary");
// Run the cluster in the background after we referencing it
client.handle.spawn(editor_actor.run());
@ -539,9 +538,7 @@ impl ServerState {
if let Some(Some(path)) = open.then_some(res.as_ref()) {
log::info!("open with system default apps: {path:?}");
if let Err(e) = do_open(path) {
log::error!("failed to open with system default apps: {e}");
};
do_open(path).log_error("failed to open with system default apps");
}
log::info!("CompileActor: on export end: {path:?} as {res:?}");

View file

@ -12,6 +12,7 @@ use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
use sync_lsp::{just_future, LspClient, SchedulableResponse};
use tinymist_project::LspWorld;
use tinymist_std::error::IgnoreLogging;
use typst::{syntax::Span, World};
use crate::{internal_error, ServerState};
@ -245,14 +246,15 @@ pub async fn make_http_server(
let timings = timings.clone();
let _ = alive_tx.send(());
async move {
// Make sure VSCode can connect to this http server but no malicious website a user
// might open in a browser. We recognize VSCode by an `Origin` header that starts
// with `vscode-webview://`. Malicious websites can (hopefully) not trick browsers
// into sending an `Origin` header that starts with `vscode-webview://`
// Make sure VSCode can connect to this http server but no malicious website a
// user might open in a browser. We recognize VSCode by an `Origin` header that
// starts with `vscode-webview://`. Malicious websites can (hopefully) not trick
// browsers into sending an `Origin` header that starts with
// `vscode-webview://`.
//
// See comment in `make_http_server` in `crates/tinymist/src/tool/preview.rs` for more
// details. In particular, note that this does _not_ protect against malicious users
// that share the same computer as us.
// See comment in `make_http_server` in `crates/tinymist/src/tool/preview.rs`
// for more details. In particular, note that this does _not_ protect against
// malicious users that share the same computer as us.
let Some(allowed_origin) = req
.headers()
.get("Origin")
@ -309,9 +311,7 @@ pub async fn make_http_server(
let conn = server.serve_connection(TokioIo::new(stream), make_service());
let conn = graceful.watch(conn.into_owned());
tokio::spawn(async move {
if let Err(err) = conn.await {
log::error!("error serving connection: {err:?}");
}
conn.await.log_error("cannot serve http");
});
};

View file

@ -21,6 +21,7 @@ use serde_json::Value as JsonValue;
use sync_lsp::just_ok;
use tinymist_assets::TYPST_PREVIEW_HTML;
use tinymist_project::ProjectInsId;
use tinymist_std::error::IgnoreLogging;
use tokio::sync::{mpsc, oneshot};
use typst::layout::{Frame, FrameItem, Point, Position};
use typst::syntax::{LinkedNode, Source, Span, SyntaxKind};
@ -220,13 +221,12 @@ impl PreviewState {
pub(crate) fn stop_all(&mut self) {
let watchers = std::mem::take(self.watchers.inner.lock().deref_mut());
for (_, watcher) in watchers {
let res = self.preview_tx.send(PreviewRequest::Kill(
watcher.task_id().to_owned(),
oneshot::channel().0,
));
if let Err(e) = res {
log::error!("failed to send kill request({:?}): {e}", watcher.task_id());
}
self.preview_tx
.send(PreviewRequest::Kill(
watcher.task_id().to_owned(),
oneshot::channel().0,
))
.log_error_with(|| format!("failed to send kill request({:?})", watcher.task_id()));
}
}
}
@ -555,9 +555,7 @@ pub async fn make_http_server(
let conn = server.serve_connection_with_upgrades(TokioIo::new(stream), make_service());
let conn = graceful.watch(conn.into_owned());
tokio::spawn(async move {
if let Err(err) = conn.await {
log::error!("Error serving connection: {err:?}");
}
conn.await.log_error("cannot serve http");
});
};
@ -764,9 +762,8 @@ pub async fn preview_main(args: PreviewCliArgs) -> Result<()> {
log::info!("Static file server listening on: {static_server_addr}");
if !args.dont_open_in_browser {
if let Err(e) = open::that_detached(format!("http://{static_server_addr}")) {
log::error!("failed to open browser: {e}");
};
open::that_detached(format!("http://{static_server_addr}"))
.log_error("failed to open browser for preview");
}
let _ = tokio::join!(previewer.join(), srv.join, control_plane_server_handle);