Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,17 @@
}
]
},
"commands": []
"commands": [],
"configuration": {
"title": "Overwrite",
"properties": {
"overwrite.telemetry.enabled": {
"type": "boolean",
"default": true,
"description": "Enable anonymous usage telemetry to help improve the extension. All data is anonymized and no file contents or paths are ever collected."
}
}
}
},
"scripts": {
"vscode:package": "pnpm run package && pnpm vsce package --no-dependencies",
Expand Down
86 changes: 50 additions & 36 deletions src/services/telemetry.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import crypto from 'node:crypto'
import fs from 'node:fs'
import path from 'node:path'
import { PostHog } from 'posthog-node'
import * as vscode from 'vscode'

Expand Down Expand Up @@ -33,16 +31,6 @@ class TelemetryService {
this.context = context
this.startedAt = Date.now()

if (!this.isEnabled()) return

const apiKey = this.getApiKey(context)
if (!apiKey) {
console.warn('[telemetry] POSTHOG_API_KEY not set; telemetry disabled')
return
}

this.client = new PostHog(apiKey, { host: 'https://us.i.posthog.com' })

// Persist anonymous id; never use VS Code machineId directly
this.distinctId = context.globalState.get<string>('telemetryDistinctId')
if (!this.distinctId) {
Expand All @@ -52,42 +40,68 @@ class TelemetryService {

this.sessionId = crypto.randomUUID()

// Initialize client if telemetry is enabled
this.initializeClient()

// Listen for configuration changes
context.subscriptions.push(
vscode.workspace.onDidChangeConfiguration((e) => {
if (
e.affectsConfiguration('overwrite.telemetry.enabled') ||
e.affectsConfiguration('telemetry.telemetryLevel')
) {
this.handleConfigurationChange()
}
}),
)
}

private initializeClient() {
if (!this.isEnabled()) return
if (this.client) return // Already initialized

const apiKey = 'phc_LBityQJ7WJhm3iikesHTPvcLGqwUrSoJqofTKJo35rg'
this.client = new PostHog(apiKey, { host: 'https://us.i.posthog.com' })

// Fire activation event with minimal props
this.capture('extension_activated', {
activation_time_ms: Date.now() - this.startedAt,
ext_version: context.extension.packageJSON?.version,
ext_version: this.context?.extension.packageJSON?.version,
vscode_version: vscode.version,
os: process.platform,
node_version: process.versions.node,
session_id: this.sessionId,
})
}

isEnabled(): boolean {
return true
}

private getApiKey(context: vscode.ExtensionContext): string | undefined {
if (process.env.POSTHOG_API_KEY) return process.env.POSTHOG_API_KEY

// Fallback: try to read a .env at the extension root once at startup
try {
const root = context.extensionUri.fsPath
const envPath = path.join(root, '.env')
if (!fs.existsSync(envPath)) return undefined
const content = fs.readFileSync(envPath, 'utf8')
for (const line of content.split(/\r?\n/)) {
const m = line.match(/^\s*POSTHOG_API_KEY\s*=\s*(.*)\s*$/)
if (m) {
// Strip optional quotes
const raw = m[1]?.trim().replace(/^['"]|['"]$/g, '')
if (raw) return raw
}
private handleConfigurationChange() {
if (this.isEnabled()) {
// Telemetry was enabled, initialize if not already done
this.initializeClient()
} else {
// Telemetry was disabled, shutdown client
if (this.client) {
void this.client.shutdown()
this.client = undefined
}
} catch {
// ignore
}
return undefined
}

isEnabled(): boolean {
// Check VS Code global telemetry setting
const globalTelemetryLevel = vscode.workspace
.getConfiguration('telemetry')
.get<string>('telemetryLevel')
if (globalTelemetryLevel === 'off') return false

// Check extension-specific setting
const extensionTelemetryEnabled = vscode.workspace
.getConfiguration('overwrite.telemetry')
.get<boolean>('enabled', true) // default to true

console.log(`Overwrite telemetry enabled: ${extensionTelemetryEnabled}`)

return extensionTelemetryEnabled
}

capture(event: TelemetryEvent, properties?: Record<string, unknown>) {
Expand Down
Loading