Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Settings to enable telemetry for extension #55

Merged
merged 20 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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: 12 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,18 @@
"fontCharacter": "\\e90c"
}
}
},
"configuration": {
"id": "pullflow",
"title": "Pullflow",
"properties": {
"pullflow.telemetry.enabled": {
"type": "boolean",
"default": true,
"markdownDescription": "Enable Pullflow to transmit product usage telemetry. \n\n_**Important:** To activate telemetry transmission, both this setting and the VS Code telemetry option must be enabled. Telemetry will not be sent if either of these settings is disabled._"

}
}
}
},
"scripts": {
Expand Down
30 changes: 30 additions & 0 deletions src/utils/initialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
WindowState,
commands,
window,
workspace,
} from 'vscode'
import { Store } from './store'
import { log } from './logger'
Expand All @@ -27,6 +28,9 @@ export const initialize = async ({
statusBar: StatusBarItem
}) => {
log.info('initializing extension', module)

await initializeTelemetry(context)

const errorCount = { count: 0 }
await PullRequestState.update({
context,
Expand Down Expand Up @@ -116,3 +120,29 @@ const setSpaceUsers = async ({
spaceUsers: spaceUsers.spaceUsers,
})
}

const extensionTelemetryFlag = () =>
workspace
.getConfiguration('pullflow.telemetry.enabled')
.get<boolean>('pullflow.telemetry.enabled', true)

const vscodeTelemetryFlag = () =>
workspace.getConfiguration('telemetry').get<boolean>('enableTelemetry')

const initializeTelemetry = async (context: ExtensionContext) => {
await Store.set(context, {
isTelemetryEnabled: vscodeTelemetryFlag() && extensionTelemetryFlag(),
})

const disposable = workspace.onDidChangeConfiguration(async (event) => {
if (
event.affectsConfiguration('telemetry.enableTelemetry') ||
event.affectsConfiguration('pullflow.telemetry.enabled')
) {
await Store.set(context, {
isTelemetryEnabled: vscodeTelemetryFlag() && extensionTelemetryFlag(),
})
}
})
context.subscriptions.push(disposable)
}
67 changes: 47 additions & 20 deletions src/utils/trace.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-unused-vars */
import { Span, Tracer, SpanKind, Attributes } from '@opentelemetry/api'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
import { Resource } from '@opentelemetry/resources'
Expand All @@ -10,13 +11,46 @@ import { ExtensionContext, extensions } from 'vscode'
import { TraceAttributes } from './types'
import { Store } from './store'
import { AppConfig } from './appConfig'
import { log } from './logger'

const extensionInfo = extensions.getExtension('Pullflow.pullflow')?.packageJSON

export class Trace {
type FakeTracer = {}
type FakeBasicTracerProvider = {}
type FakeAttribute = {}

export function instantiatePullflowTracer(context: ExtensionContext) {
const { isTelemetryEnabled } = Store.get(context)
if (isTelemetryEnabled) {
return new Trace(context)
} else {
return new FakeTrace(context)
}
}
class FakeTrace {
tracer: FakeTracer
provider: FakeBasicTracerProvider
defaultAttributes: FakeAttribute

constructor(_context: ExtensionContext) {
this.provider = {}
this.tracer = {}
this.defaultAttributes = {}
}

dispose(): void {}
start({ name, attributes }: { name: string; attributes?: TraceAttributes }) {
console.log({ name, attributes })
Copy link
Collaborator

Choose a reason for hiding this comment

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

why are we doing console log here?

Copy link
Collaborator

Choose a reason for hiding this comment

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

because i need to use the attributes and name somehow otherwise it gives unused values errors.

Copy link
Collaborator

Choose a reason for hiding this comment

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

we can do it like one of these ways:
start({ _name, _attributes }: { name: string; attributes?: TraceAttributes }) { ... }

start({ }: { name: string; attributes?: TraceAttributes }) { ... }

what do you think @srzainab?

}
end({ attributes }: { attributes?: TraceAttributes }) {
console.log({ attributes })
}
}
class Trace {
tracer: Tracer
provider: BasicTracerProvider
defaultAttributes: Attributes
span: Span | undefined

constructor(context: ExtensionContext) {
this.provider = new BasicTracerProvider({
Expand All @@ -34,43 +68,36 @@ export class Trace {
this.tracer = this.provider.getTracer(extensionInfo.name)
const { user } = Store.get(context)
this.defaultAttributes = user || {}
this.span = undefined
}

dispose(): void {
void this.provider.shutdown()
}

start({
name,
attributes,
}: {
name: string
attributes?: TraceAttributes
}): Span {
const span = this.tracer.startSpan(name, {
start({ name, attributes }: { name: string; attributes?: TraceAttributes }) {
this.span = this.tracer.startSpan(name, {
kind: SpanKind.INTERNAL,
startTime: Date.now(),
})
if (attributes)
span.setAttributes({
this.span.setAttributes({
...attributes,
...this.defaultAttributes,
})
return span
}

end({
span,
attributes,
}: {
span: Span
attributes?: TraceAttributes
}): void {
end({ attributes }: { attributes?: TraceAttributes }): void {
if (this.span === undefined) {
log.warn('span is undefined', 'trace.ts')
return
}
if (attributes)
span.setAttributes({
this.span.setAttributes({
...attributes,
...this.defaultAttributes,
})
span.end(Date.now())
this.span.end(Date.now())
this.span = undefined
}
}
1 change: 1 addition & 0 deletions src/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export type CacheObject = {
keyStrokeCount?: number
lastKeyStrokeTime?: number | null
previousPresenceStatus?: PresenceStatus
isTelemetryEnabled?: boolean
}
export enum StatusBarState {
Loading,
Expand Down
8 changes: 3 additions & 5 deletions src/views/quickpicks/quickPick.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ExtensionContext, QuickPickItem, window } from 'vscode'
import { Trace } from '../../utils/trace'
import { instantiatePullflowTracer } from '../../utils/trace'

export const QuickPick = {
create: <Type extends QuickPickItem>({
Expand All @@ -17,8 +17,8 @@ export const QuickPick = {
}) => {
const quickPick = window.createQuickPick<Type>()

const trace = new Trace(context)
const span = trace.start({
const trace = instantiatePullflowTracer(context)
trace.start({
name: title,
})

Expand All @@ -29,7 +29,6 @@ export const QuickPick = {

quickPick.onDidHide(() => {
trace.end({
span,
attributes: {
title,
},
Expand All @@ -39,7 +38,6 @@ export const QuickPick = {

quickPick.onDidAccept(() => {
trace.end({
span,
attributes: {
title,
selectedItem: quickPick.selectedItems[0]?.label,
Expand Down
Loading