From 035cd37aa86917c43bc73a0d584751dbf9be865e Mon Sep 17 00:00:00 2001 From: Keith Simmons Date: Thu, 7 Apr 2022 16:00:51 -0700 Subject: [PATCH 1/6] Add explicit types for LanguageOverrides and Themes to SettingsFileContent in order to improve completions in zed settings file --- crates/settings/src/settings.rs | 71 +++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/crates/settings/src/settings.rs b/crates/settings/src/settings.rs index c897586017..3dcb55b2fe 100644 --- a/crates/settings/src/settings.rs +++ b/crates/settings/src/settings.rs @@ -1,8 +1,11 @@ use anyhow::Result; use gpui::font_cache::{FamilyId, FontCache}; -use schemars::{schema_for, JsonSchema}; +use schemars::{ + gen::{SchemaGenerator, SchemaSettings}, + JsonSchema, +}; use serde::Deserialize; -use std::{collections::HashMap, sync::Arc}; +use std::{collections::HashMap, fmt::Display, sync::Arc}; use theme::{Theme, ThemeRegistry}; use util::ResultExt as _; @@ -33,6 +36,53 @@ pub enum SoftWrap { PreferredLineLength, } +#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Eq, JsonSchema)] +pub enum ThemeNames { + Dark, + Light, +} + +impl Display for ThemeNames { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ThemeNames::Dark => write!(f, "Dark"), + ThemeNames::Light => write!(f, "Light"), + } + } +} + +#[derive(Clone, Debug, Deserialize, Default, JsonSchema)] +pub struct LanguageOverrides { + C: Option, + JSON: Option, + Markdown: Option, + PlainText: Option, + Rust: Option, + TSX: Option, + TypeScript: Option, +} + +impl IntoIterator for LanguageOverrides { + type Item = (String, LanguageOverride); + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + vec![ + ("C", self.C), + ("JSON", self.JSON), + ("Markdown", self.Markdown), + ("PlainText", self.PlainText), + ("Rust", self.Rust), + ("TSX", self.TSX), + ("TypeScript", self.TypeScript), + ] + .into_iter() + .filter_map(|(name, language_override)| language_override.map(|lo| (name.to_owned(), lo))) + .collect::>() + .into_iter() + } +} + #[derive(Clone, Debug, Default, Deserialize, JsonSchema)] pub struct SettingsFileContent { #[serde(default)] @@ -44,9 +94,9 @@ pub struct SettingsFileContent { #[serde(flatten)] pub editor: LanguageOverride, #[serde(default)] - pub language_overrides: HashMap, LanguageOverride>, + pub language_overrides: LanguageOverrides, #[serde(default)] - pub theme: Option, + pub theme: Option, } impl Settings { @@ -68,7 +118,12 @@ impl Settings { } pub fn file_json_schema() -> serde_json::Value { - serde_json::to_value(schema_for!(SettingsFileContent)).unwrap() + let settings = SchemaSettings::draft07().with(|settings| { + settings.option_nullable = true; + settings.option_add_null_type = false; + }); + let generator = SchemaGenerator::new(settings); + serde_json::to_value(generator.into_root_schema_for::()).unwrap() } pub fn with_overrides( @@ -128,7 +183,7 @@ impl Settings { } } if let Some(value) = &data.theme { - if let Some(theme) = theme_registry.get(value).log_err() { + if let Some(theme) = theme_registry.get(&value.to_string()).log_err() { self.theme = theme; } } @@ -142,10 +197,10 @@ impl Settings { data.editor.preferred_line_length, ); - for (language_name, settings) in &data.language_overrides { + for (language_name, settings) in data.language_overrides.clone().into_iter() { let target = self .language_overrides - .entry(language_name.clone()) + .entry(language_name.into()) .or_default(); merge_option(&mut target.tab_size, settings.tab_size); From 3e40b5beada237320a379c8e07c1ad9ece165c49 Mon Sep 17 00:00:00 2001 From: Keith Simmons Date: Thu, 7 Apr 2022 18:15:02 -0700 Subject: [PATCH 2/6] dynamically inject theme names and language properties into schema --- crates/language/src/language.rs | 8 ++ crates/settings/src/settings.rs | 138 ++++++++++++++++++++------------ crates/zed/src/zed.rs | 5 +- 3 files changed, 97 insertions(+), 54 deletions(-) diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 322fd19b9e..37377b6eef 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -234,6 +234,14 @@ impl LanguageRegistry { .cloned() } + pub fn language_names(&self) -> Vec { + self.languages + .read() + .iter() + .map(|language| language.name().to_string()) + .collect() + } + pub fn select_language(&self, path: impl AsRef) -> Option> { let path = path.as_ref(); let filename = path.file_name().and_then(|name| name.to_str()); diff --git a/crates/settings/src/settings.rs b/crates/settings/src/settings.rs index 3dcb55b2fe..98733e6920 100644 --- a/crates/settings/src/settings.rs +++ b/crates/settings/src/settings.rs @@ -2,10 +2,14 @@ use anyhow::Result; use gpui::font_cache::{FamilyId, FontCache}; use schemars::{ gen::{SchemaGenerator, SchemaSettings}, + schema::{ + InstanceType, ObjectValidation, Schema, SchemaObject, SingleOrVec, SubschemaValidation, + }, JsonSchema, }; use serde::Deserialize; -use std::{collections::HashMap, fmt::Display, sync::Arc}; +use serde_json::Value; +use std::{collections::HashMap, fmt::Display, os::unix::fs::chroot, sync::Arc}; use theme::{Theme, ThemeRegistry}; use util::ResultExt as _; @@ -36,53 +40,6 @@ pub enum SoftWrap { PreferredLineLength, } -#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Eq, JsonSchema)] -pub enum ThemeNames { - Dark, - Light, -} - -impl Display for ThemeNames { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - ThemeNames::Dark => write!(f, "Dark"), - ThemeNames::Light => write!(f, "Light"), - } - } -} - -#[derive(Clone, Debug, Deserialize, Default, JsonSchema)] -pub struct LanguageOverrides { - C: Option, - JSON: Option, - Markdown: Option, - PlainText: Option, - Rust: Option, - TSX: Option, - TypeScript: Option, -} - -impl IntoIterator for LanguageOverrides { - type Item = (String, LanguageOverride); - type IntoIter = std::vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - vec![ - ("C", self.C), - ("JSON", self.JSON), - ("Markdown", self.Markdown), - ("PlainText", self.PlainText), - ("Rust", self.Rust), - ("TSX", self.TSX), - ("TypeScript", self.TypeScript), - ] - .into_iter() - .filter_map(|(name, language_override)| language_override.map(|lo| (name.to_owned(), lo))) - .collect::>() - .into_iter() - } -} - #[derive(Clone, Debug, Default, Deserialize, JsonSchema)] pub struct SettingsFileContent { #[serde(default)] @@ -94,9 +51,9 @@ pub struct SettingsFileContent { #[serde(flatten)] pub editor: LanguageOverride, #[serde(default)] - pub language_overrides: LanguageOverrides, + pub language_overrides: HashMap, LanguageOverride>, #[serde(default)] - pub theme: Option, + pub theme: Option, } impl Settings { @@ -117,13 +74,88 @@ impl Settings { }) } - pub fn file_json_schema() -> serde_json::Value { + pub fn file_json_schema( + theme_names: Vec, + language_names: Vec, + ) -> serde_json::Value { let settings = SchemaSettings::draft07().with(|settings| { - settings.option_nullable = true; settings.option_add_null_type = false; }); let generator = SchemaGenerator::new(settings); - serde_json::to_value(generator.into_root_schema_for::()).unwrap() + let mut root_schema = generator.into_root_schema_for::(); + + // Construct theme names reference type + let theme_names = theme_names + .into_iter() + .map(|name| Value::String(name)) + .collect(); + let theme_names_schema = Schema::Object(SchemaObject { + instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))), + enum_values: Some(theme_names), + ..Default::default() + }); + root_schema + .definitions + .insert("ThemeName".to_owned(), theme_names_schema); + + // Construct language overrides reference type + let language_override_schema_reference = Schema::Object(SchemaObject { + reference: Some("#/definitions/LanguageOverride".to_owned()), + ..Default::default() + }); + let language_overrides_properties = language_names + .into_iter() + .map(|name| { + ( + name, + Schema::Object(SchemaObject { + subschemas: Some(Box::new(SubschemaValidation { + all_of: Some(vec![language_override_schema_reference.clone()]), + ..Default::default() + })), + ..Default::default() + }), + ) + }) + .collect(); + let language_overrides_schema = Schema::Object(SchemaObject { + instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Object))), + object: Some(Box::new(ObjectValidation { + properties: language_overrides_properties, + ..Default::default() + })), + ..Default::default() + }); + root_schema + .definitions + .insert("LanguageOverrides".to_owned(), language_overrides_schema); + + // Modify theme property to use new theme reference type + let settings_file_schema = root_schema.schema.object.as_mut().unwrap(); + let language_overrides_schema_reference = Schema::Object(SchemaObject { + reference: Some("#/definitions/ThemeName".to_owned()), + ..Default::default() + }); + settings_file_schema.properties.insert( + "theme".to_owned(), + Schema::Object(SchemaObject { + subschemas: Some(Box::new(SubschemaValidation { + all_of: Some(vec![language_overrides_schema_reference]), + ..Default::default() + })), + ..Default::default() + }), + ); + + // Modify language_overrides property to use LanguageOverrides reference + settings_file_schema.properties.insert( + "language_overrides".to_owned(), + Schema::Object(SchemaObject { + reference: Some("#/definitions/LanguageOverrides".to_owned()), + ..Default::default() + }), + ); + serde_json::to_value(root_schema).unwrap() } pub fn with_overrides( diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 86a059e6fd..976f78437c 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -137,13 +137,16 @@ pub fn build_workspace( let mut workspace = Workspace::new(&workspace_params, cx); let project = workspace.project().clone(); + let theme_names = app_state.themes.list().collect(); + let language_names = app_state.languages.language_names(); + project.update(cx, |project, _| { project.set_language_server_settings(serde_json::json!({ "json": { "schemas": [ { "fileMatch": "**/.zed/settings.json", - "schema": Settings::file_json_schema(), + "schema": Settings::file_json_schema(theme_names, language_names), } ] } From 7e5a3f9f6b8f457235a44be0eb2589bc71947ff5 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 8 Apr 2022 10:06:51 -0600 Subject: [PATCH 3/6] Introduce structured logging We're enabling the log crate feature everywhere, but only using it on the server for now. Co-Authored-By: Antonio Scandurra --- Cargo.lock | 76 +++++++++++++++++---- crates/client/Cargo.toml | 2 +- crates/editor/Cargo.toml | 2 +- crates/gpui/Cargo.toml | 4 +- crates/journal/Cargo.toml | 2 +- crates/language/Cargo.toml | 2 +- crates/lsp/Cargo.toml | 2 +- crates/project/Cargo.toml | 2 +- crates/rpc/Cargo.toml | 2 +- crates/search/Cargo.toml | 2 +- crates/server/Cargo.toml | 2 + crates/server/src/home.rs | 9 +-- crates/server/src/main.rs | 8 ++- crates/server/src/rpc.rs | 10 +-- crates/sum_tree/Cargo.toml | 2 +- crates/text/Cargo.toml | 2 +- crates/theme_selector/Cargo.toml | 2 +- crates/theme_selector/src/theme_selector.rs | 2 +- crates/util/Cargo.toml | 2 +- crates/vim/Cargo.toml | 2 +- crates/workspace/Cargo.toml | 2 +- crates/zed/Cargo.toml | 2 +- 22 files changed, 98 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e4b99c6566..8a026ee11b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -614,7 +614,7 @@ dependencies = [ "cexpr", "clang-sys", "clap 2.33.3", - "env_logger", + "env_logger 0.8.3", "lazy_static", "lazycell", "log", @@ -1634,7 +1634,7 @@ dependencies = [ "clock", "collections", "ctor", - "env_logger", + "env_logger 0.8.3", "futures", "fuzzy", "gpui", @@ -1702,6 +1702,15 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "log", +] + [[package]] name = "env_logger" version = "0.8.3" @@ -1724,6 +1733,15 @@ dependencies = [ "serde", ] +[[package]] +name = "erased-serde" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad132dd8d0d0b546348d7d86cb3191aad14b34e5f979781fc005c80d4ac67ffd" +dependencies = [ + "serde", +] + [[package]] name = "etagere" version = "0.2.4" @@ -1806,7 +1824,7 @@ version = "0.1.0" dependencies = [ "ctor", "editor", - "env_logger", + "env_logger 0.8.3", "fuzzy", "gpui", "postage", @@ -2235,7 +2253,7 @@ dependencies = [ "core-text", "ctor", "dhat", - "env_logger", + "env_logger 0.8.3", "etagere", "font-kit", "foreign-types", @@ -2652,6 +2670,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json_env_logger" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e2ec540ea0448b187d3a8b4a9f13e75527d06ef76b3a2baa1cd982aecb62ce2" +dependencies = [ + "env_logger 0.7.1", + "kv-log-macro", + "log", + "serde_json", +] + [[package]] name = "jwt-simple" version = "0.10.1" @@ -2715,7 +2745,7 @@ dependencies = [ "clock", "collections", "ctor", - "env_logger", + "env_logger 0.8.3", "futures", "fuzzy", "gpui", @@ -2834,11 +2864,12 @@ dependencies = [ [[package]] name = "log" -version = "0.4.14" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" dependencies = [ "cfg-if 1.0.0", + "serde", "value-bag", ] @@ -2871,7 +2902,7 @@ dependencies = [ "async-pipe", "collections", "ctor", - "env_logger", + "env_logger 0.8.3", "futures", "gpui", "log", @@ -4342,6 +4373,15 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_fmt" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2963a69a2b3918c1dc75a45a18bd3fcd1120e31d3f59deb1b2f9b5d5ffb8baa4" +dependencies = [ + "serde", +] + [[package]] name = "serde_json" version = "1.0.64" @@ -4986,7 +5026,7 @@ version = "0.1.0" dependencies = [ "arrayvec 0.7.1", "ctor", - "env_logger", + "env_logger 0.8.3", "log", "rand 0.8.3", ] @@ -5018,6 +5058,9 @@ name = "sval" version = "1.0.0-alpha.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45f6ee7c7b87caf59549e9fe45d6a69c75c8019e79e212a835c5da0e92f0ba08" +dependencies = [ + "serde", +] [[package]] name = "svg_fmt" @@ -5116,7 +5159,7 @@ dependencies = [ "clock", "collections", "ctor", - "env_logger", + "env_logger 0.8.3", "gpui", "lazy_static", "log", @@ -5704,11 +5747,14 @@ checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" [[package]] name = "value-bag" -version = "1.0.0-alpha.7" +version = "1.0.0-alpha.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd320e1520f94261153e96f7534476ad869c14022aee1e59af7c778075d840ae" +checksum = "79923f7731dc61ebfba3633098bf3ac533bbd35ccd8c57e7088d9a5eebe0263f" dependencies = [ "ctor", + "erased-serde", + "serde", + "serde_fmt", "sval", "version_check", ] @@ -6030,7 +6076,7 @@ dependencies = [ "dirs 3.0.1", "easy-parallel", "editor", - "env_logger", + "env_logger 0.8.3", "file_finder", "fsevent", "futures", @@ -6108,16 +6154,18 @@ dependencies = [ "ctor", "editor", "either", - "env_logger", + "env_logger 0.8.3", "envy", "futures", "gpui", "handlebars", "http-auth-basic", + "json_env_logger", "jwt-simple", "language", "lazy_static", "lipsum", + "log", "lsp", "oauth2", "oauth2-surf", diff --git a/crates/client/Cargo.toml b/crates/client/Cargo.toml index c60b82f1f8..211dc7a04b 100644 --- a/crates/client/Cargo.toml +++ b/crates/client/Cargo.toml @@ -21,7 +21,7 @@ async-tungstenite = { version = "0.16", features = ["async-tls"] } futures = "0.3" image = "0.23" lazy_static = "1.4.0" -log = "0.4" +log = { version = "0.4.16", features = ["kv_unstable_serde"] } parking_lot = "0.11.1" postage = { version = "0.4.1", features = ["futures-traits"] } rand = "0.8.3" diff --git a/crates/editor/Cargo.toml b/crates/editor/Cargo.toml index 076fecbfcb..a1c1409d06 100644 --- a/crates/editor/Cargo.toml +++ b/crates/editor/Cargo.toml @@ -40,7 +40,7 @@ futures = "0.3" indoc = "1.0.4" itertools = "0.10" lazy_static = "1.4" -log = "0.4" +log = { version = "0.4.16", features = ["kv_unstable_serde"] } ordered-float = "2.1.1" parking_lot = "0.11" postage = { version = "0.4", features = ["futures-traits"] } diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 9973ac6549..442a2b5b2f 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -25,7 +25,7 @@ etagere = "0.2" futures = "0.3" image = "0.23" lazy_static = "1.4.0" -log = "0.4" +log = { version = "0.4.16", features = ["kv_unstable_serde"] } num_cpus = "1.13" ordered-float = "2.1.1" parking = "2.0.0" @@ -67,6 +67,6 @@ core-graphics = "0.22.2" core-text = "19.2" font-kit = { git = "https://github.com/zed-industries/font-kit", rev = "8eaf7a918eafa28b0a37dc759e2e0e7683fa24f1" } foreign-types = "0.3" -log = "0.4" +log = { version = "0.4.16", features = ["kv_unstable_serde"] } metal = "0.21.0" objc = "0.2" diff --git a/crates/journal/Cargo.toml b/crates/journal/Cargo.toml index 8ccd9dc27f..94dcf8e407 100644 --- a/crates/journal/Cargo.toml +++ b/crates/journal/Cargo.toml @@ -14,4 +14,4 @@ util = { path = "../util" } workspace = { path = "../workspace" } chrono = "0.4" dirs = "4.0" -log = "0.4" \ No newline at end of file +log = { version = "0.4.16", features = ["kv_unstable_serde"] } diff --git a/crates/language/Cargo.toml b/crates/language/Cargo.toml index 0518261f84..275581f807 100644 --- a/crates/language/Cargo.toml +++ b/crates/language/Cargo.toml @@ -35,7 +35,7 @@ async-broadcast = "0.3.4" async-trait = "0.1" futures = "0.3" lazy_static = "1.4" -log = "0.4" +log = { version = "0.4.16", features = ["kv_unstable_serde"] } parking_lot = "0.11.1" postage = { version = "0.4.1", features = ["futures-traits"] } rand = { version = "0.8.3", optional = true } diff --git a/crates/lsp/Cargo.toml b/crates/lsp/Cargo.toml index 199da8c24e..c749261bf5 100644 --- a/crates/lsp/Cargo.toml +++ b/crates/lsp/Cargo.toml @@ -17,7 +17,7 @@ util = { path = "../util" } anyhow = "1.0" async-pipe = { git = "https://github.com/zed-industries/async-pipe-rs", rev = "82d00a04211cf4e1236029aa03e6b6ce2a74c553", optional = true } futures = "0.3" -log = "0.4" +log = { version = "0.4.16", features = ["kv_unstable_serde"] } lsp-types = "0.91" parking_lot = "0.11" postage = { version = "0.4.1", features = ["futures-traits"] } diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index 8fda3aa0f3..728dae3128 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -35,7 +35,7 @@ futures = "0.3" ignore = "0.4" lazy_static = "1.4.0" libc = "0.2" -log = "0.4" +log = { version = "0.4.16", features = ["kv_unstable_serde"] } parking_lot = "0.11.1" postage = { version = "0.4.1", features = ["futures-traits"] } rand = "0.8.3" diff --git a/crates/rpc/Cargo.toml b/crates/rpc/Cargo.toml index e773b3f0ba..62fe9e5bda 100644 --- a/crates/rpc/Cargo.toml +++ b/crates/rpc/Cargo.toml @@ -17,7 +17,7 @@ async-lock = "2.4" async-tungstenite = "0.16" base64 = "0.13" futures = "0.3" -log = "0.4" +log = { version = "0.4.16", features = ["kv_unstable_serde"] } parking_lot = "0.11.1" postage = { version = "0.4.1", features = ["futures-traits"] } prost = "0.8" diff --git a/crates/search/Cargo.toml b/crates/search/Cargo.toml index 77961de01f..295526939a 100644 --- a/crates/search/Cargo.toml +++ b/crates/search/Cargo.toml @@ -18,7 +18,7 @@ theme = { path = "../theme" } util = { path = "../util" } workspace = { path = "../workspace" } anyhow = "1.0" -log = "0.4" +log = { version = "0.4.16", features = ["kv_unstable_serde"] } postage = { version = "0.4.1", features = ["futures-traits"] } [dev-dependencies] diff --git a/crates/server/Cargo.toml b/crates/server/Cargo.toml index 6e27fa16c5..6c43b467ac 100644 --- a/crates/server/Cargo.toml +++ b/crates/server/Cargo.toml @@ -29,8 +29,10 @@ envy = "0.4.2" futures = "0.3" handlebars = "3.5" http-auth-basic = "0.1.3" +json_env_logger = "0.1" jwt-simple = "0.10.0" lipsum = { version = "0.8", optional = true } +log = { version = "0.4.16", features = ["kv_unstable_serde"] } oauth2 = { version = "4.0.0", default_features = false } oauth2-surf = "0.1.1" parking_lot = "0.11.1" diff --git a/crates/server/src/home.rs b/crates/server/src/home.rs index 69bee449a8..bddeadc352 100644 --- a/crates/server/src/home.rs +++ b/crates/server/src/home.rs @@ -1,7 +1,8 @@ use crate::{AppState, Request, RequestExt as _}; -use serde::Deserialize; +use log::as_serde; +use serde::{Deserialize, Serialize}; use std::sync::Arc; -use tide::{http::mime, log, Server}; +use tide::{http::mime, Server}; pub fn add_routes(app: &mut Server>) { app.at("/").get(get_home); @@ -18,7 +19,7 @@ async fn get_home(mut request: Request) -> tide::Result { } async fn post_signup(mut request: Request) -> tide::Result { - #[derive(Debug, Deserialize)] + #[derive(Debug, Deserialize, Serialize)] struct Form { github_login: String, email_address: String, @@ -38,7 +39,7 @@ async fn post_signup(mut request: Request) -> tide::Result { .map(str::to_string) .unwrap_or(form.github_login); - log::info!("Signup submitted: {:?}", form); + log::info!(form = as_serde!(form); "signup submitted"); // Save signup in the database request diff --git a/crates/server/src/main.rs b/crates/server/src/main.rs index 47c8c82190..97de59f36b 100644 --- a/crates/server/src/main.rs +++ b/crates/server/src/main.rs @@ -27,7 +27,7 @@ use rust_embed::RustEmbed; use serde::{Deserialize, Serialize}; use std::sync::Arc; use surf::http::cookies::SameSite; -use tide::{log, sessions::SessionMiddleware}; +use tide::sessions::SessionMiddleware; use tide_compress::CompressMiddleware; type Request = tide::Request>; @@ -138,7 +138,11 @@ struct LayoutData { #[async_std::main] async fn main() -> tide::Result<()> { - log::start(); + if std::env::var("LOG_JSON").is_ok() { + json_env_logger::init(); + } else { + tide::log::start(); + } if let Err(error) = env::load_dotenv() { log::error!( diff --git a/crates/server/src/rpc.rs b/crates/server/src/rpc.rs index 51c7807660..ace7080c81 100644 --- a/crates/server/src/rpc.rs +++ b/crates/server/src/rpc.rs @@ -11,6 +11,7 @@ use async_std::task; use async_tungstenite::{tungstenite::protocol::Role, WebSocketStream}; use collections::{HashMap, HashSet}; use futures::{channel::mpsc, future::BoxFuture, FutureExt, SinkExt, StreamExt}; +use log::{as_debug, as_display}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use rpc::{ proto::{self, AnyTypedEnvelope, EntityMessage, EnvelopedMessage, RequestMessage}, @@ -25,7 +26,6 @@ use std::{ }; use store::{Store, Worktree}; use surf::StatusCode; -use tide::log; use tide::{ http::headers::{HeaderName, CONNECTION, UPGRADE}, Request, Response, @@ -218,16 +218,16 @@ impl Server { if let Some(message) = message { let start_time = Instant::now(); let type_name = message.payload_type_name(); - log::info!("rpc message received. connection:{}, type:{}", connection_id, type_name); + log::info!(connection_id = connection_id.0, type_name = type_name; "rpc message received"); if let Some(handler) = this.handlers.get(&message.payload_type_id()) { let notifications = this.notifications.clone(); let is_background = message.is_background(); let handle_message = (handler)(this.clone(), message); let handle_message = async move { if let Err(err) = handle_message.await { - log::error!("rpc message error. connection:{}, type:{}, error:{:?}", connection_id, type_name, err); + log::error!(connection_id = connection_id.0, type = type_name, error = as_display!(err); "rpc message error"); } else { - log::info!("rpc message handled. connection:{}, type:{}, duration:{:?}", connection_id, type_name, start_time.elapsed()); + log::info!(connection_id = connection_id.0, type = type_name, duration = as_debug!(start_time.elapsed()); "rpc message handled"); } if let Some(mut notifications) = notifications { let _ = notifications.send(()).await; @@ -242,7 +242,7 @@ impl Server { log::warn!("unhandled message: {}", type_name); } } else { - log::info!("rpc connection closed {:?}", addr); + log::info!(address = as_debug!(addr); "rpc connection closed"); break; } } diff --git a/crates/sum_tree/Cargo.toml b/crates/sum_tree/Cargo.toml index f43cdd43d4..b430f2e6b0 100644 --- a/crates/sum_tree/Cargo.toml +++ b/crates/sum_tree/Cargo.toml @@ -9,7 +9,7 @@ doctest = false [dependencies] arrayvec = "0.7.1" -log = "0.4" +log = { version = "0.4.16", features = ["kv_unstable_serde"] } [dev-dependencies] ctor = "0.1" diff --git a/crates/text/Cargo.toml b/crates/text/Cargo.toml index f6a887eb27..a7209a7507 100644 --- a/crates/text/Cargo.toml +++ b/crates/text/Cargo.toml @@ -17,7 +17,7 @@ sum_tree = { path = "../sum_tree" } anyhow = "1.0.38" arrayvec = "0.7.1" lazy_static = "1.4" -log = "0.4" +log = { version = "0.4.16", features = ["kv_unstable_serde"] } parking_lot = "0.11" postage = { version = "0.4.1", features = ["futures-traits"] } rand = { version = "0.8.3", optional = true } diff --git a/crates/theme_selector/Cargo.toml b/crates/theme_selector/Cargo.toml index 585d10d563..9993287c85 100644 --- a/crates/theme_selector/Cargo.toml +++ b/crates/theme_selector/Cargo.toml @@ -14,7 +14,7 @@ gpui = { path = "../gpui" } theme = { path = "../theme" } settings = { path = "../settings" } workspace = { path = "../workspace" } -log = "0.4" +log = { version = "0.4.16", features = ["kv_unstable_serde"] } parking_lot = "0.11.1" postage = { version = "0.4.1", features = ["futures-traits"] } smol = "1.2.5" diff --git a/crates/theme_selector/src/theme_selector.rs b/crates/theme_selector/src/theme_selector.rs index 5bcbd62e09..74ff49e710 100644 --- a/crates/theme_selector/src/theme_selector.rs +++ b/crates/theme_selector/src/theme_selector.rs @@ -7,9 +7,9 @@ use gpui::{ AppContext, Axis, Element, ElementBox, Entity, MutableAppContext, RenderContext, View, ViewContext, ViewHandle, }; +use settings::Settings; use std::{cmp, sync::Arc}; use theme::{Theme, ThemeRegistry}; -use settings::Settings; use workspace::{ menu::{Confirm, SelectNext, SelectPrev}, Workspace, diff --git a/crates/util/Cargo.toml b/crates/util/Cargo.toml index 9d39fb04e2..cfc68e0b16 100644 --- a/crates/util/Cargo.toml +++ b/crates/util/Cargo.toml @@ -12,7 +12,7 @@ test-support = ["rand", "serde_json", "tempdir"] [dependencies] anyhow = "1.0.38" futures = "0.3" -log = "0.4" +log = { version = "0.4.16", features = ["kv_unstable_serde"] } rand = { version = "0.8", optional = true } surf = "2.2" tempdir = { version = "0.3.7", optional = true } diff --git a/crates/vim/Cargo.toml b/crates/vim/Cargo.toml index 4ffa6a4363..6386141ffc 100644 --- a/crates/vim/Cargo.toml +++ b/crates/vim/Cargo.toml @@ -14,7 +14,7 @@ gpui = { path = "../gpui" } language = { path = "../language" } settings = { path = "../settings" } workspace = { path = "../workspace" } -log = "0.4" +log = { version = "0.4.16", features = ["kv_unstable_serde"] } [dev-dependencies] indoc = "1.0.4" diff --git a/crates/workspace/Cargo.toml b/crates/workspace/Cargo.toml index 75d1b1b8f2..a2a6c74bac 100644 --- a/crates/workspace/Cargo.toml +++ b/crates/workspace/Cargo.toml @@ -22,7 +22,7 @@ theme = { path = "../theme" } util = { path = "../util" } anyhow = "1.0.38" futures = "0.3" -log = "0.4" +log = { version = "0.4.16", features = ["kv_unstable_serde"] } parking_lot = "0.11.1" postage = { version = "0.4.1", features = ["futures-traits"] } serde = { version = "1", features = ["derive", "rc"] } diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index f87046b05e..1a5a214f03 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -75,7 +75,7 @@ image = "0.23" indexmap = "1.6.2" lazy_static = "1.4.0" libc = "0.2" -log = "0.4" +log = { version = "0.4.16", features = ["kv_unstable_serde"] } log-panics = { version = "2.0", features = ["with-backtrace"] } num_cpus = "1.13.0" parking_lot = "0.11.1" From b507e218319f7283797dd1a32d48e450790e83b8 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 8 Apr 2022 10:08:52 -0600 Subject: [PATCH 4/6] Enable JSON logging at the trace log level in K8s Co-Authored-By: Antonio Scandurra --- crates/server/k8s/manifest.template.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/server/k8s/manifest.template.yml b/crates/server/k8s/manifest.template.yml index e1c33d4e49..cb6b710757 100644 --- a/crates/server/k8s/manifest.template.yml +++ b/crates/server/k8s/manifest.template.yml @@ -81,6 +81,10 @@ spec: secretKeyRef: name: api key: token + - name: LOG_JSON + value: "1" + - name: RUST_LOG + value: "trace" securityContext: capabilities: # FIXME - Switch to the more restrictive `PERFMON` capability. From 56fcffb6345157b6ebd2be73cf3fa2cbc2888f3b Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 9 Apr 2022 07:55:23 -0600 Subject: [PATCH 5/6] Remove unused imports --- crates/settings/src/settings.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/settings/src/settings.rs b/crates/settings/src/settings.rs index 98733e6920..622d73e663 100644 --- a/crates/settings/src/settings.rs +++ b/crates/settings/src/settings.rs @@ -9,7 +9,7 @@ use schemars::{ }; use serde::Deserialize; use serde_json::Value; -use std::{collections::HashMap, fmt::Display, os::unix::fs::chroot, sync::Arc}; +use std::{collections::HashMap, sync::Arc}; use theme::{Theme, ThemeRegistry}; use util::ResultExt as _; From f9e0899e5820ee2c7d9e66dd7e929d4e7573e238 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 11 Apr 2022 12:14:23 +0200 Subject: [PATCH 6/6] Fix divergence bug when peer reconnects reusing a prior replica id We forgot to observe the footprint of the reconnecting replica's prior undos into the local clock. This could cause the replica to generate edits with a version strictly smaller than what other peers may have observed. As such, those peers would think they had already seen those edits and skip them. --- crates/language/src/tests.rs | 56 ++++++++++++++++++++++++++++++++---- crates/text/src/text.rs | 5 ++-- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/crates/language/src/tests.rs b/crates/language/src/tests.rs index af2d8ee911..a194c26625 100644 --- a/crates/language/src/tests.rs +++ b/crates/language/src/tests.rs @@ -821,7 +821,10 @@ fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) { } 50..=59 if replica_ids.len() < max_peers => { let old_buffer = buffer.read(cx).to_proto(); - let new_replica_id = replica_ids.len() as ReplicaId; + let new_replica_id = (0..=replica_ids.len() as ReplicaId) + .filter(|replica_id| *replica_id != buffer.read(cx).replica_id()) + .choose(&mut rng) + .unwrap(); log::info!( "Adding new replica {} (replicating from {})", new_replica_id, @@ -830,6 +833,11 @@ fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) { new_buffer = Some(cx.add_model(|cx| { let mut new_buffer = Buffer::from_proto(new_replica_id, old_buffer, None, cx).unwrap(); + log::info!( + "New replica {} text: {:?}", + new_buffer.replica_id(), + new_buffer.text() + ); new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200))); let network = network.clone(); cx.subscribe(&cx.handle(), move |buffer, _, event, _| { @@ -843,8 +851,33 @@ fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) { .detach(); new_buffer })); - replica_ids.push(new_replica_id); network.borrow_mut().replicate(replica_id, new_replica_id); + + if new_replica_id as usize == replica_ids.len() { + replica_ids.push(new_replica_id); + } else { + let new_buffer = new_buffer.take().unwrap(); + while network.borrow().has_unreceived(new_replica_id) { + let ops = network + .borrow_mut() + .receive(new_replica_id) + .into_iter() + .map(|op| proto::deserialize_operation(op).unwrap()); + if ops.len() > 0 { + log::info!( + "peer {} (version: {:?}) applying {} ops from the network. {:?}", + new_replica_id, + buffer.read(cx).version(), + ops.len(), + ops + ); + new_buffer.update(cx, |new_buffer, cx| { + new_buffer.apply_ops(ops, cx).unwrap(); + }); + } + } + buffers[new_replica_id as usize] = new_buffer; + } } 60..=69 if mutation_count != 0 => { buffer.update(cx, |buffer, cx| { @@ -861,9 +894,11 @@ fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) { .map(|op| proto::deserialize_operation(op).unwrap()); if ops.len() > 0 { log::info!( - "peer {} applying {} ops from the network.", + "peer {} (version: {:?}) applying {} ops from the network. {:?}", replica_id, - ops.len() + buffer.read(cx).version(), + ops.len(), + ops ); buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap()); } @@ -886,6 +921,12 @@ fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) { let first_buffer = buffers[0].read(cx).snapshot(); for buffer in &buffers[1..] { let buffer = buffer.read(cx).snapshot(); + assert_eq!( + buffer.version(), + first_buffer.version(), + "Replica {} version != Replica 0 version", + buffer.replica_id() + ); assert_eq!( buffer.text(), first_buffer.text(), @@ -915,7 +956,12 @@ fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) { .filter(|(replica_id, _)| **replica_id != buffer.replica_id()) .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::>())) .collect::>(); - assert_eq!(actual_remote_selections, expected_remote_selections); + assert_eq!( + actual_remote_selections, + expected_remote_selections, + "Replica {} remote selections != expected selections", + buffer.replica_id() + ); } } diff --git a/crates/text/src/text.rs b/crates/text/src/text.rs index 1c351079a7..ed918cd5c5 100644 --- a/crates/text/src/text.rs +++ b/crates/text/src/text.rs @@ -826,6 +826,8 @@ impl Buffer { edit.timestamp, ); self.snapshot.version.observe(edit.timestamp.local()); + self.local_clock.observe(edit.timestamp.local()); + self.lamport_clock.observe(edit.timestamp.lamport()); self.resolve_edit(edit.timestamp.local()); } } @@ -836,6 +838,7 @@ impl Buffer { if !self.version.observed(undo.id) { self.apply_undo(&undo)?; self.snapshot.version.observe(undo.id); + self.local_clock.observe(undo.id); self.lamport_clock.observe(lamport_timestamp); } } @@ -1033,8 +1036,6 @@ impl Buffer { self.snapshot.visible_text = visible_text; self.snapshot.deleted_text = deleted_text; self.snapshot.insertions.edit(new_insertions, &()); - self.local_clock.observe(timestamp.local()); - self.lamport_clock.observe(timestamp.lamport()); self.subscriptions.publish_mut(&edits); }