Merge pull request #1172 from zed-industries/more-logs

Antonio Scandurra created

Add more logging to `collab` to better understand user behavior

Change summary

crates/collab/src/rpc.rs       | 47 +++++++++++++++++++++++-------
crates/collab/src/rpc/store.rs | 56 ++++++++++++++++++++++++++++++++---
2 files changed, 86 insertions(+), 17 deletions(-)

Detailed changes

crates/collab/src/rpc.rs 🔗

@@ -220,9 +220,14 @@ impl Server {
                 let envelope = envelope.into_any().downcast::<TypedEnvelope<M>>().unwrap();
                 let span = info_span!(
                     "handle message",
-                    payload_type = envelope.payload_type_name(),
-                    payload = format!("{:?}", envelope.payload).as_str(),
+                    payload_type = envelope.payload_type_name()
                 );
+                span.in_scope(|| {
+                    tracing::info!(
+                        payload = format!("{:?}", envelope.payload).as_str(),
+                        "message payload"
+                    );
+                });
                 let future = (handler)(server, *envelope);
                 async move {
                     if let Err(error) = future.await {
@@ -618,6 +623,7 @@ impl Server {
             guest_user_id = state.user_id_for_connection(request.sender_id)?;
         };
 
+        tracing::info!(project_id, %host_user_id, %host_connection_id, "join project");
         let has_contact = self
             .app_state
             .db
@@ -773,6 +779,12 @@ impl Server {
         {
             let mut store = self.store_mut().await;
             project = store.leave_project(sender_id, project_id)?;
+            tracing::info!(
+                project_id,
+                host_user_id = %project.host_user_id,
+                host_connection_id = %project.host_connection_id,
+                "leave project"
+            );
 
             if project.remove_collaborator {
                 broadcast(sender_id, project.connection_ids, |conn_id| {
@@ -837,15 +849,28 @@ impl Server {
         request: TypedEnvelope<proto::UpdateWorktree>,
         response: Response<proto::UpdateWorktree>,
     ) -> Result<()> {
-        let (connection_ids, metadata_changed) = self.store_mut().await.update_worktree(
-            request.sender_id,
-            request.payload.project_id,
-            request.payload.worktree_id,
-            &request.payload.root_name,
-            &request.payload.removed_entries,
-            &request.payload.updated_entries,
-            request.payload.scan_id,
-        )?;
+        let (connection_ids, metadata_changed) = {
+            let mut store = self.store_mut().await;
+            let (connection_ids, metadata_changed, extension_counts) = store.update_worktree(
+                request.sender_id,
+                request.payload.project_id,
+                request.payload.worktree_id,
+                &request.payload.root_name,
+                &request.payload.removed_entries,
+                &request.payload.updated_entries,
+                request.payload.scan_id,
+            )?;
+            for (extension, count) in extension_counts {
+                tracing::info!(
+                    project_id = request.payload.project_id,
+                    worktree_id = request.payload.worktree_id,
+                    ?extension,
+                    %count,
+                    "worktree updated"
+                );
+            }
+            (connection_ids, metadata_changed)
+        };
 
         broadcast(request.sender_id, connection_ids, |connection_id| {
             self.peer

crates/collab/src/rpc/store.rs 🔗

@@ -3,7 +3,13 @@ use anyhow::{anyhow, Result};
 use collections::{hash_map::Entry, BTreeMap, HashMap, HashSet};
 use rpc::{proto, ConnectionId, Receipt};
 use serde::Serialize;
-use std::{collections::hash_map, mem, path::PathBuf};
+use std::{
+    collections::hash_map,
+    ffi::{OsStr, OsString},
+    mem,
+    path::{Path, PathBuf},
+    str,
+};
 use tracing::instrument;
 
 #[derive(Default, Serialize)]
@@ -43,6 +49,8 @@ pub struct Worktree {
     #[serde(skip)]
     pub entries: HashMap<u64, proto::Entry>,
     #[serde(skip)]
+    pub extension_counts: HashMap<OsString, usize>,
+    #[serde(skip)]
     pub diagnostic_summaries: BTreeMap<PathBuf, proto::DiagnosticSummary>,
     pub scan_id: u64,
 }
@@ -569,20 +577,49 @@ impl Store {
         removed_entries: &[u64],
         updated_entries: &[proto::Entry],
         scan_id: u64,
-    ) -> Result<(Vec<ConnectionId>, bool)> {
+    ) -> Result<(Vec<ConnectionId>, bool, &HashMap<OsString, usize>)> {
         let project = self.write_project(project_id, connection_id)?;
+        let connection_ids = project.connection_ids();
         let mut worktree = project.worktrees.entry(worktree_id).or_default();
         let metadata_changed = worktree_root_name != worktree.root_name;
         worktree.root_name = worktree_root_name.to_string();
+
         for entry_id in removed_entries {
-            worktree.entries.remove(&entry_id);
+            if let Some(entry) = worktree.entries.remove(&entry_id) {
+                if !entry.is_ignored {
+                    if let Some(extension) = extension_for_entry(&entry) {
+                        if let Some(count) = worktree.extension_counts.get_mut(extension) {
+                            *count = count.saturating_sub(1);
+                        }
+                    }
+                }
+            }
         }
+
         for entry in updated_entries {
-            worktree.entries.insert(entry.id, entry.clone());
+            if let Some(old_entry) = worktree.entries.insert(entry.id, entry.clone()) {
+                if !old_entry.is_ignored {
+                    if let Some(extension) = extension_for_entry(&old_entry) {
+                        if let Some(count) = worktree.extension_counts.get_mut(extension) {
+                            *count = count.saturating_sub(1);
+                        }
+                    }
+                }
+            }
+
+            if !entry.is_ignored {
+                if let Some(extension) = extension_for_entry(&entry) {
+                    if let Some(count) = worktree.extension_counts.get_mut(extension) {
+                        *count += 1;
+                    } else {
+                        worktree.extension_counts.insert(extension.into(), 1);
+                    }
+                }
+            }
         }
+
         worktree.scan_id = scan_id;
-        let connection_ids = project.connection_ids();
-        Ok((connection_ids, metadata_changed))
+        Ok((connection_ids, metadata_changed, &worktree.extension_counts))
     }
 
     pub fn project_connection_ids(
@@ -732,3 +769,10 @@ impl Channel {
         self.connection_ids.iter().copied().collect()
     }
 }
+
+fn extension_for_entry(entry: &proto::Entry) -> Option<&OsStr> {
+    str::from_utf8(&entry.path)
+        .ok()
+        .map(Path::new)
+        .and_then(|p| p.extension())
+}