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
8 changes: 4 additions & 4 deletions docs/telemetry.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@ Alternatively in VS Code, you can disable telemetry through your VS Code setting

### CLI

For `cn`, the Continue CLI, set the environment variable `CONTINUE_ALLOW_ANONYMOUS_TELEMETRY=0` before running commands:
For `cn`, the Continue CLI, set the environment variable `CONTINUE_TELEMETRY_ENABLED=0` before running commands:

```bash
export CONTINUE_ALLOW_ANONYMOUS_TELEMETRY=0
export CONTINUE_TELEMETRY_ENABLED=0
cn <your prompt>
```

Or run it inline:

```bash
CONTINUE_ALLOW_ANONYMOUS_TELEMETRY=0 cn <your prompt>
```
CONTINUE_TELEMETRY_ENABLED=0 cn <your prompt>
```
23 changes: 12 additions & 11 deletions extensions/cli/spec/otlp-metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,18 @@ The Continue CLI should emit metrics that provide insights into:

### Environment Variables

| Environment Variable | Description | Example Values |
| ------------------------------- | --------------------------------------------------------- | ------------------------------------ |
| `CONTINUE_CLI_ENABLE_TELEMETRY` | Enables OTEL telemetry collection (required) | `1` |
| `OTEL_METRICS_EXPORTER` | Metrics exporter type(s) (comma-separated) | `console`, `otlp`, `prometheus` |
| `OTEL_LOGS_EXPORTER` | Logs/events exporter type(s) (comma-separated) | `console`, `otlp` |
| `OTEL_EXPORTER_OTLP_PROTOCOL` | Protocol for OTLP exporter (all signals) | `grpc`, `http/json`, `http/protobuf` |
| `OTEL_EXPORTER_OTLP_ENDPOINT` | OTLP collector endpoint (all signals) | `http://localhost:4317` |
| `OTEL_EXPORTER_OTLP_HEADERS` | Authentication headers for OTLP | `Authorization=Bearer token` |
| `OTEL_METRIC_EXPORT_INTERVAL` | Export interval in milliseconds (default: 60000) | `5000`, `60000` |
| `OTEL_LOGS_EXPORT_INTERVAL` | Logs export interval in milliseconds (default: 5000) | `1000`, `10000` |
| `OTEL_LOG_USER_PROMPTS` | Enable logging of user prompt content (default: disabled) | `1` to enable |
| Environment Variable | Description | Example Values |
| ------------------------------- | --------------------------------------------------------------- | ------------------------------------ |
| `CONTINUE_METRICS_ENABLED` | Enables OTEL telemetry collection (preferred, takes precedence) | `0` to disable, `1` to enable |
| `CONTINUE_CLI_ENABLE_TELEMETRY` | Enables OTEL telemetry collection (legacy, lower precedence) | `0` to disable, `1` to enable |
| `OTEL_METRICS_EXPORTER` | Metrics exporter type(s) (comma-separated) | `console`, `otlp`, `prometheus` |
| `OTEL_LOGS_EXPORTER` | Logs/events exporter type(s) (comma-separated) | `console`, `otlp` |
| `OTEL_EXPORTER_OTLP_PROTOCOL` | Protocol for OTLP exporter (all signals) | `grpc`, `http/json`, `http/protobuf` |
| `OTEL_EXPORTER_OTLP_ENDPOINT` | OTLP collector endpoint (all signals) | `http://localhost:4317` |
| `OTEL_EXPORTER_OTLP_HEADERS` | Authentication headers for OTLP | `Authorization=Bearer token` |
| `OTEL_METRIC_EXPORT_INTERVAL` | Export interval in milliseconds (default: 60000) | `5000`, `60000` |
| `OTEL_LOGS_EXPORT_INTERVAL` | Logs export interval in milliseconds (default: 5000) | `1000`, `10000` |
| `OTEL_LOG_USER_PROMPTS` | Enable logging of user prompt content (default: disabled) | `1` to enable |

### Metrics Cardinality Control

Expand Down
2 changes: 1 addition & 1 deletion extensions/cli/spec/telemtry.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

- Used by Continue for product metrics (not used by customers)
- uses public posthog key in repo
- CONTINUE_ALLOW_ANONYMOUS_TELEMETRY can be set to 0 to disable
- `CONTINUE_TELEMETRY_ENABLED=0` disables telemetry
- non-anonymous and private data like code is never sent to posthog
- Event user ids are the Continue user id is signed in, or a unique machine id if not
- Current events are slash command usage and chat calls
33 changes: 33 additions & 0 deletions extensions/cli/src/telemetry/posthogService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,5 +152,38 @@ describe("PosthogService", () => {
expect(client).toBeUndefined();
expect(dns.lookup).toHaveBeenCalledTimes(1);
});

it("returns false when DNS resolves to 0.0.0.0 (blocked)", async () => {
const dns: any = (await import("dns/promises")).default;
dns.lookup.mockResolvedValueOnce({
address: "0.0.0.0",
family: 4,
} as any);
const result = await (service as any).hasInternetConnection();
expect(result).toBe(false);
expect(dns.lookup).toHaveBeenCalledTimes(1);
});

it("returns false when DNS resolves to localhost", async () => {
const dns: any = (await import("dns/promises")).default;
dns.lookup.mockResolvedValueOnce({
address: "127.0.0.1",
family: 4,
} as any);
const result = await (service as any).hasInternetConnection();
expect(result).toBe(false);
expect(dns.lookup).toHaveBeenCalledTimes(1);
});

it("returns true when DNS resolves to valid address", async () => {
const dns: any = (await import("dns/promises")).default;
dns.lookup.mockResolvedValueOnce({
address: "1.1.1.1",
family: 4,
} as any);
const result = await (service as any).hasInternetConnection();
expect(result).toBe(true);
expect(dns.lookup).toHaveBeenCalledTimes(1);
});
});
});
29 changes: 26 additions & 3 deletions extensions/cli/src/telemetry/posthogService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import node_machine_id from "node-machine-id";
import type { PostHog as PostHogType } from "posthog-node";

import { isAuthenticatedConfig, loadAuthConfig } from "../auth/workos.js";
import { loggers } from "../logging.js";
import { isHeadlessMode, isServe } from "../util/cli.js";
import { isGitHubActions } from "../util/git.js";
import { logger } from "../util/logger.js";
Expand All @@ -13,6 +14,7 @@ import { getVersion } from "../version.js";
export class PosthogService {
private _os: string | undefined;
private _uniqueId: string | undefined;
private _telemetryBlocked: boolean = false;

constructor() {
// Initialization is now lazy to avoid issues with mocking in tests
Expand All @@ -36,10 +38,19 @@ export class PosthogService {
private async hasInternetConnection() {
const refetchConnection = async () => {
try {
await dns.lookup("app.posthog.com");
this._hasInternetConnection = true;
const result = await dns.lookup("app.posthog.com");
const isValidAddress =
result.address !== "0.0.0.0" && !result.address.startsWith("127.");
this._hasInternetConnection = isValidAddress;
this._telemetryBlocked = !isValidAddress;
if (!isValidAddress) {
logger.debug(
"DNS lookup returned invalid address for PostHog, skipping telemetry",
);
}
} catch {
this._hasInternetConnection = false;
this._telemetryBlocked = false;
}
};

Expand All @@ -53,14 +64,26 @@ export class PosthogService {
}

get isEnabled() {
if (process.env.CONTINUE_TELEMETRY_ENABLED === "0") {
return false;
}
if (process.env.CONTINUE_TELEMETRY_ENABLED === "1") {
return true;
}
return process.env.CONTINUE_ALLOW_ANONYMOUS_TELEMETRY !== "0";
}

private _client: PostHogType | undefined;
private async getClient() {
if (!(await this.hasInternetConnection())) {
this._client = undefined;
logger.warn("No internet connection, skipping telemetry");
if (this._telemetryBlocked && this.isEnabled) {
loggers.warning(
"Telemetry appears to be blocked by your network. To disable telemetry entirely, set CONTINUE_TELEMETRY_ENABLED=0",
);
} else if (this.isEnabled) {
logger.warn("No internet connection, skipping telemetry");
}
} else if (this.isEnabled) {
if (!this._client) {
const { PostHog } = await import("posthog-node");
Expand Down
13 changes: 11 additions & 2 deletions extensions/cli/src/telemetry/telemetryService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,17 @@ class TelemetryService {
process.env.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT ||
process.env.OTEL_METRICS_EXPORTER
);
const enabled =
process.env.CONTINUE_CLI_ENABLE_TELEMETRY !== "0" && hasOtelConfig;

let telemetryEnabled = true;
if (process.env.CONTINUE_METRICS_ENABLED === "0") {
telemetryEnabled = false;
} else if (process.env.CONTINUE_METRICS_ENABLED === "1") {
telemetryEnabled = true;
} else {
telemetryEnabled = process.env.CONTINUE_CLI_ENABLE_TELEMETRY !== "0";
}

const enabled = telemetryEnabled && hasOtelConfig;
const sessionId = uuidv4();

return {
Expand Down
Loading