Skip to content

Conversation

oscartbeaumont
Copy link
Member

@oscartbeaumont oscartbeaumont commented Oct 15, 2025

This will allow us to get a better idea of what the average user feels when using Cap.

Summary by CodeRabbit

  • New Features

    • Background telemetry initializes at startup when configured.
    • Uploads now record and report duration and success/failure events.
  • Chores

    • Telemetry runs as non-blocking background tasks to avoid delaying workflows.
    • Improved startup logging and error handling for telemetry to reduce visible errors.

Copy link
Contributor

coderabbitai bot commented Oct 15, 2025

Walkthrough

Adds posthog-rs and a patch override, initializes PostHog on startup when VITE_POSTHOG_KEY is set, introduces a PostHogEvent enum and async_capture_event helper, and instruments multipart/video upload flows to emit success/failure events with elapsed durations and error details.

Changes

Cohort / File(s) Summary
Dependency & patch override
apps/desktop/src-tauri/Cargo.toml, Cargo.toml
Added posthog-rs = "0.3.7" to apps/desktop/src-tauri/Cargo.toml and added a patch.crates-io override in top-level Cargo.toml pointing to CapSoftware/posthog-rs at a specific revision.
New telemetry module
apps/desktop/src-tauri/src/posthog.rs
New module providing pub enum PostHogEvent { MultipartUploadComplete { duration: Duration }, MultipartUploadFailed { duration: Duration, error: String } }, From<PostHogEvent> for posthog_rs::Event, pub fn init() to initialize client (if env key present), and pub fn async_capture_event(event) to send events asynchronously with logging.
Startup wiring
apps/desktop/src-tauri/src/lib.rs
Import of mod posthog; and call to posthog::init() during startup after FFmpeg initialization. Removed an unused fmt import.
Upload instrumentation
apps/desktop/src-tauri/src/upload.rs
Added timing and PostHog events in upload_video and InstantMultipartUpload::spawn/wrapper: record start time and emit MultipartUploadComplete or MultipartUploadFailed (with duration and error) via async_capture_event. Added imports for telemetry helpers. No public API signature changes.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User as User
  participant App as Desktop App (Tauri)
  participant Telemetry as PostHog Module
  participant PH as PostHog API

  User->>App: Launch app
  Note over App: read VITE_POSTHOG_KEY\nif present -> spawn init (background)
  App->>Telemetry: init()
  Telemetry->>PH: initialize client (async)
  alt init ok
    PH-->>Telemetry: success
  else init error
    Telemetry-->>App: log init error
  end
Loading
sequenceDiagram
  autonumber
  participant UI as UI
  participant Upload as Upload Flow
  participant Telemetry as PostHog Module
  participant PH as PostHog API

  UI->>Upload: start upload (spawn)
  Upload->>Upload: record start = Instant::now()
  Upload->>Upload: run() (async)
  alt success
    Upload-->>UI: Ok
    Upload->>Telemetry: async_capture_event(MultipartUploadComplete{duration})
    Telemetry->>PH: capture event (async)
    PH-->>Telemetry: resp
  else failure
    Upload-->>UI: Err(error)
    Upload->>Telemetry: async_capture_event(MultipartUploadFailed{duration,error})
    Telemetry->>PH: capture event (async)
    PH-->>Telemetry: resp
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Button and api route for uploading logs #1221 — Modifies the same startup run function in apps/desktop/src-tauri/src/lib.rs (wiring around startup behavior); likely related to initialization ordering and environment-driven startup changes.

Poem

I thump, I time, I watch each byte,
A rabbit coder in the night.
I spawn a task, I send a ping—
Success or stumble, metrics sing.
Hops of telemetry, soft and bright 🐇📈

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "PostHog stats for uploader" directly and accurately describes the main objective of this pull request, which is to add PostHog telemetry integration to the uploader functionality. The changeset demonstrates this through the addition of the posthog-rs dependency, creation of a new posthog module with event definitions and initialization logic, and integration of event capturing into the upload process to track multipart upload completion and failures with timing information. The title is specific enough that a teammate reviewing history would understand this is about adding analytics to the uploader, and it avoids vague or generic terminology.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch posthog-stats-for-uploader

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@oscartbeaumont oscartbeaumont marked this pull request as ready for review October 15, 2025 07:04
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/desktop/src-tauri/src/upload.rs (1)

213-219: Unused start variable (will trip clippy).

Remove or use it to report image upload timing; currently it’s dead code.

-    let start = Instant::now();
🧹 Nitpick comments (3)
apps/desktop/src-tauri/Cargo.toml (1)

115-115: Make telemetry dependency optional (feature‑gated) to allow builds without analytics.

Helps ship OSS/no‑telemetry builds and simplifies compliance toggles.

Within this file:

-posthog-rs = "0.3.7"
+posthog-rs = { version = "0.3.7", optional = true }

Elsewhere in this file (outside selected lines), add:

[features]
default = []
telemetry = ["posthog-rs"]

And gate usage sites with #[cfg(feature = "telemetry")] as appropriate.

apps/desktop/src-tauri/src/lib.rs (2)

2773-2780: Guard event capture behind a runtime toggle; avoid sending without consent.

Early‑return if telemetry is disabled (env/config), and consider adding common props (e.g., app version).

Apply minimal guard:

 pub fn async_capture_event(event: posthog_rs::Event) {
-    tokio::spawn(async move {
+    if std::env::var("CAP_TELEMETRY_ENABLED").unwrap_or_else(|_| "1".into()) == "0" {
+        return;
+    }
+    tokio::spawn(async move {
         posthog_rs::capture(event)
             .await
             .map_err(|err| error!("Error sending event to PostHog: {err:?}"))
             .ok();
     });
 }

Also ensure codebase has a user‑visible setting persisted in GeneralSettings to control this toggle. Based on coding guidelines.


1947-1953: Refactor PostHog telemetry initialization

  • Load the public phc_… key from env/config (e.g. POSTHOG_KEY) instead of hard-coding.
  • Add explicit user opt-in/opt-out (with a global setting) before calling init_global.
  • Disable telemetry in debug builds to avoid dev noise.
  • Expose host/region config (e.g. POSTHOG_HOST) and perform a shutdown/flush on exit.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0d5700f and 7c1b908.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • apps/desktop/src-tauri/Cargo.toml (1 hunks)
  • apps/desktop/src-tauri/src/lib.rs (2 hunks)
  • apps/desktop/src-tauri/src/upload.rs (10 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Format Rust code using rustfmt and ensure all Rust code passes workspace-level clippy lints.
Rust modules should be named with snake_case, and crate directories should be in kebab-case.

Files:

  • apps/desktop/src-tauri/src/lib.rs
  • apps/desktop/src-tauri/src/upload.rs
🧬 Code graph analysis (2)
apps/desktop/src-tauri/src/lib.rs (1)
apps/desktop/src-tauri/src/upload.rs (1)
  • spawn (366-403)
apps/desktop/src-tauri/src/upload.rs (3)
apps/desktop/src-tauri/src/lib.rs (8)
  • async_capture_event (2773-2780)
  • run (1940-2518)
  • app (1176-1177)
  • app (2349-2349)
  • app (2380-2380)
  • app (2417-2417)
  • app (2423-2423)
  • app (2623-2624)
crates/utils/src/lib.rs (1)
  • spawn_actor (6-13)
apps/desktop/src-tauri/src/upload_legacy.rs (1)
  • run (620-803)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
  • GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (1)
apps/desktop/src-tauri/src/upload.rs (1)

6-6: Import looks fine.

No issues.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
apps/desktop/src-tauri/src/upload.rs (2)

153-169: Cast as_millis() to u64 and consider thumbnail result for accurate metrics.

Two issues:

  1. Critical: Duration::as_millis() returns u128, which JSON/serde may not accept reliably. Cast to u64 to ensure property insertion succeeds.

  2. Major: The "complete" event fires when video upload succeeds, even if the thumbnail upload fails (checked on line 170). This skews metrics.

Apply this diff to address both issues:

-    async_capture_event(match &video_result {
-        Ok(()) => {
+    async_capture_event(match (&video_result, &thumbnail_result) {
+        (Ok(()), Ok(())) => {
             let mut e = posthog_rs::Event::new_anon("multipart_upload_complete");
-            e.insert_prop("took", start.elapsed().as_millis())
+            e.insert_prop("took", start.elapsed().as_millis() as u64)
                 .map_err(|err| error!("Error adding PostHog property: {err:?}"))
                 .ok();
             e
         }
-        Err(err) => {
+        (Err(err), _) | (_, Err(err)) => {
             let mut e = posthog_rs::Event::new_anon("multipart_upload_failed");
             e.insert_prop("error", err.to_string())
                 .map_err(|err| error!("Error adding PostHog property: {err:?}"))
                 .ok();
             e
         }
     });

374-402: Cast as_millis() to u64 to prevent property insertion failure.

Duration::as_millis() returns u128, which JSON/serde may not handle reliably. Cast to u64 for compatibility with PostHog's expected integer type.

                     Ok(()) => {
                         let mut e = posthog_rs::Event::new_anon("multipart_upload_complete");
-                        e.insert_prop("took", start.elapsed().as_millis())
+                        e.insert_prop("took", start.elapsed().as_millis() as u64)
                             .map_err(|err| error!("Error adding PostHog property: {err:?}"))
                             .ok();
                         e
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7c1b908 and 485d508.

📒 Files selected for processing (2)
  • apps/desktop/src-tauri/src/lib.rs (2 hunks)
  • apps/desktop/src-tauri/src/upload.rs (5 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Format Rust code using rustfmt and ensure all Rust code passes workspace-level clippy lints.
Rust modules should be named with snake_case, and crate directories should be in kebab-case.

Files:

  • apps/desktop/src-tauri/src/lib.rs
  • apps/desktop/src-tauri/src/upload.rs
🧬 Code graph analysis (2)
apps/desktop/src-tauri/src/lib.rs (1)
apps/desktop/src-tauri/src/upload.rs (1)
  • spawn (366-404)
apps/desktop/src-tauri/src/upload.rs (2)
apps/desktop/src-tauri/src/lib.rs (7)
  • async_capture_event (2775-2784)
  • app (1176-1177)
  • app (2351-2351)
  • app (2382-2382)
  • app (2419-2419)
  • app (2425-2425)
  • app (2625-2626)
crates/utils/src/lib.rs (1)
  • spawn_actor (6-13)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
  • GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (3)
apps/desktop/src-tauri/src/lib.rs (2)

1947-1954: LGTM! PostHog initialization is non-blocking and well-handled.

The startup task correctly spawns asynchronously, logs errors without panicking, and only initializes when the environment variable is present.


2775-2784: LGTM! Helper function is well-structured.

The compile-time environment check and async spawn pattern are appropriate for fire-and-forget telemetry.

apps/desktop/src-tauri/src/upload.rs (1)

6-6: LGTM! Import is necessary for the telemetry integration.

.map_err(Into::into);
}

let start = Instant::now();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove unused start variable.

The start variable is captured but never used. This adds unnecessary overhead without providing value.

-    let start = Instant::now();
     let file_name = file_path
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let start = Instant::now();
let file_name = file_path
🤖 Prompt for AI Agents
In apps/desktop/src-tauri/src/upload.rs around line 213, the local variable
`start` is declared with Instant::now() but never used; remove the unused
`start` binding (delete the let start = Instant::now(); line) to eliminate the
dead variable and any unused import/unused variable warning.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 485d508 and 4badfe4.

📒 Files selected for processing (2)
  • apps/desktop/src-tauri/src/lib.rs (3 hunks)
  • apps/desktop/src-tauri/src/upload.rs (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/desktop/src-tauri/src/upload.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Format Rust code using rustfmt and ensure all Rust code passes workspace-level clippy lints.
Rust modules should be named with snake_case, and crate directories should be in kebab-case.

Files:

  • apps/desktop/src-tauri/src/lib.rs
🧬 Code graph analysis (1)
apps/desktop/src-tauri/src/lib.rs (1)
apps/desktop/src-tauri/src/upload.rs (1)
  • spawn (358-389)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
  • GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (3)
apps/desktop/src-tauri/src/lib.rs (3)

77-77: LGTM!

The Duration import is correctly added and necessary for the PostHogEvent enum.


2806-2815: LGTM with note on fire-and-forget pattern.

The fire-and-forget async pattern is appropriate for telemetry—failures won't block the application. The conditional check ensures events are only sent when PostHog is configured.

Note: If the typo in PostHogEvent variant names is fixed (see previous comment), ensure callers in upload.rs are updated accordingly.


1948-1955: Based on my investigation, I cannot find definitive documentation for the posthog-rs crate's behavior regarding event queuing before initialization. The crate is community-maintained and minimal (328 lines total), and available documentation doesn't explicitly address how pre-initialization events are handled. However, based on observable patterns:

  • The posthog-rs client is not async-friendly due to using the blocking feature of the reqwest crate
  • The code spawns init_global() asynchronously without awaiting it
  • No explicit queueing mechanism is documented

The original review comment raises a plausible but unverified concern. Since I cannot definitively confirm or refute whether posthog_rs handles pre-initialization events gracefully, I must recommend manual verification.

Verify PostHog event handling before initialization completes.

The code spawns asynchronous initialization without awaiting, and async_capture_event() calls (used in upload flows) may fire before initialization finishes. While posthog_rs is a minimal community-maintained crate, its behavior for pre-initialization event capture is not clearly documented. Recommend verifying in the actual crate implementation whether events sent before init_global() completes are queued, silently dropped, or error-prone.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
apps/desktop/src-tauri/src/upload.rs (1)

153-161: PostHog event only considers video result, not thumbnail result.

The event emission at lines 153-161 only checks video_result, meaning a "multipart_upload_complete" event fires even if thumbnail_result fails. Since line 163 will propagate the thumbnail error, the operation ultimately fails but metrics show success.

This issue was previously flagged and should consider both results:

-    async_capture_event(match &video_result {
-        Ok(()) => PostHogEvent::MultipartUploadComplete {
+    async_capture_event(match (&video_result, &thumbnail_result) {
+        (Ok(()), Ok(())) => PostHogEvent::MultipartUploadComplete {
             duration: start.elapsed(),
         },
-        Err(err) => PostHogEvent::MultipartUploadFailed {
+        (Err(err), _) | (_, Err(err)) => PostHogEvent::MultipartUploadFailed {
             duration: start.elapsed(),
             error: err.to_string(),
         },
     });
🧹 Nitpick comments (2)
apps/desktop/src-tauri/src/posthog.rs (2)

15-17: Error handling silently drops property insertion failures.

The pattern .map_err(|err| error!(...)).ok() logs insertion errors but continues, meaning events may be sent with missing properties. For telemetry this is acceptable, but consider whether partial events provide value or if failed insertions should skip the entire event.

Also applies to: 22-27


45-54: Fire-and-forget telemetry may lose events on quick app shutdown.

async_capture_event spawns a task without awaiting it, so if the application exits before the task completes, the event will be lost. This is acceptable for best-effort telemetry, but document this behavior if reliable event capture is ever required.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 35748d7 and 4e86e95.

📒 Files selected for processing (3)
  • apps/desktop/src-tauri/src/lib.rs (2 hunks)
  • apps/desktop/src-tauri/src/posthog.rs (1 hunks)
  • apps/desktop/src-tauri/src/upload.rs (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/desktop/src-tauri/src/lib.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Format Rust code using rustfmt and ensure all Rust code passes workspace-level clippy lints.
Rust modules should be named with snake_case, and crate directories should be in kebab-case.

Files:

  • apps/desktop/src-tauri/src/upload.rs
  • apps/desktop/src-tauri/src/posthog.rs
🧬 Code graph analysis (2)
apps/desktop/src-tauri/src/upload.rs (3)
apps/desktop/src-tauri/src/posthog.rs (1)
  • async_capture_event (45-54)
crates/utils/src/lib.rs (1)
  • spawn_actor (6-13)
apps/desktop/src-tauri/src/upload_legacy.rs (1)
  • run (620-803)
apps/desktop/src-tauri/src/posthog.rs (1)
apps/desktop/src-tauri/src/upload.rs (1)
  • spawn (358-389)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
  • GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (1)
apps/desktop/src-tauri/src/upload.rs (1)

366-387: LGTM!

The telemetry instrumentation in spawn correctly captures timing for the entire upload operation and emits appropriate events on both success and failure.

@Brendonovich Brendonovich merged commit 47cb080 into main Oct 17, 2025
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants