mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 17:31:43 +00:00
Closes https://github.com/sourcegraph/sourcegraph/issues/56920
This commit is contained in:
parent
ca5b448a34
commit
c484b3ef4f
@ -6,6 +6,7 @@ import { isHTTPAuthError } from '@sourcegraph/http-client'
|
||||
import type { PlatformContext } from '@sourcegraph/shared/src/platform/context'
|
||||
import { mutateSettings, updateSettings } from '@sourcegraph/shared/src/settings/edit'
|
||||
import { EMPTY_SETTINGS_CASCADE, gqlToCascade, type SettingsSubject } from '@sourcegraph/shared/src/settings/settings'
|
||||
import { NoOpTelemetryRecorderProvider } from '@sourcegraph/shared/src/telemetry'
|
||||
import { toPrettyBlobURL } from '@sourcegraph/shared/src/util/url'
|
||||
|
||||
import { createGraphQLHelpers } from '../backend/requestGraphQl'
|
||||
@ -128,6 +129,12 @@ export function createPlatformContext(
|
||||
sourcegraphURL,
|
||||
clientApplication: 'other',
|
||||
getStaticExtensions: () => getInlineExtensions(assetsURL),
|
||||
/**
|
||||
* @todo Not yet implemented!
|
||||
*/
|
||||
telemetryRecorder: new NoOpTelemetryRecorderProvider({
|
||||
errorOnRecord: true, // should not be used at all
|
||||
}).getRecorder(),
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
@ -323,6 +323,7 @@ ts_project(
|
||||
"src/symbols/SymbolKind.tsx",
|
||||
"src/symbols/SymbolTag.tsx",
|
||||
"src/symbols/symbolIcons.ts",
|
||||
"src/telemetry/index.ts",
|
||||
"src/telemetry/telemetryService.ts",
|
||||
"src/theme.ts",
|
||||
"src/tracking/event-log-creators.ts",
|
||||
@ -346,6 +347,7 @@ ts_project(
|
||||
":node_modules/@sourcegraph/common",
|
||||
":node_modules/@sourcegraph/extension-api-types",
|
||||
":node_modules/@sourcegraph/http-client",
|
||||
":node_modules/@sourcegraph/telemetry",
|
||||
":node_modules/@sourcegraph/template-parser",
|
||||
":node_modules/@sourcegraph/wildcard",
|
||||
":node_modules/sourcegraph",
|
||||
|
||||
@ -13,18 +13,19 @@
|
||||
"watch-schema": "gulp watchSchema"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sourcegraph/testing": "workspace:*",
|
||||
"@sourcegraph/build-config": "workspace:*",
|
||||
"@sourcegraph/extension-api-types": "workspace:*",
|
||||
"@sourcegraph/testing": "workspace:*",
|
||||
"sourcegraph": "workspace:*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sourcegraph/wildcard": "workspace:*",
|
||||
"@sourcegraph/http-client": "workspace:*",
|
||||
"@sourcegraph/common": "workspace:*",
|
||||
"@sourcegraph/client-api": "workspace:*",
|
||||
"@sourcegraph/codeintellify": "workspace:*",
|
||||
"@sourcegraph/common": "workspace:*",
|
||||
"@sourcegraph/http-client": "workspace:*",
|
||||
"@sourcegraph/telemetry": "^0.11.0",
|
||||
"@sourcegraph/template-parser": "workspace:*",
|
||||
"@sourcegraph/codeintellify": "workspace:*"
|
||||
"@sourcegraph/wildcard": "workspace:*"
|
||||
},
|
||||
"sideEffects": true
|
||||
}
|
||||
}
|
||||
@ -10,6 +10,7 @@ import type { SettingsEdit } from '../api/client/services/settings'
|
||||
import type { ExecutableExtension } from '../api/extension/activation'
|
||||
import type { Scalars } from '../graphql-operations'
|
||||
import type { Settings, SettingsCascadeOrError } from '../settings/settings'
|
||||
import type { TelemetryRecorder } from '../telemetry'
|
||||
import type { TelemetryService } from '../telemetry/telemetryService'
|
||||
import type { FileSpec, UIPositionSpec, RawRepoSpec, RepoSpec, RevisionSpec, ViewStateSpec } from '../util/url'
|
||||
|
||||
@ -180,9 +181,20 @@ export interface PlatformContext {
|
||||
/**
|
||||
* A telemetry service implementation to log events.
|
||||
* Optional because it's currently only used in the web app platform.
|
||||
*
|
||||
* @deprecated Use 'telemetryRecorder' instead.
|
||||
*/
|
||||
telemetryService?: TelemetryService
|
||||
|
||||
/**
|
||||
* Telemetry recorder for the new telemetry framework, superseding
|
||||
* 'telemetryService' and 'logEvent' variants. Learn more here:
|
||||
* https://docs.sourcegraph.com/dev/background-information/telemetry
|
||||
*
|
||||
* It is backed by a '@sourcegraph/telemetry' implementation.
|
||||
*/
|
||||
telemetryRecorder: TelemetryRecorder
|
||||
|
||||
/**
|
||||
* If this is a function that returns a Subscribable of executable extensions,
|
||||
* the extension host will not activate any other settings (e.g. extensions from user settings)
|
||||
|
||||
61
client/shared/src/telemetry/index.ts
Normal file
61
client/shared/src/telemetry/index.ts
Normal file
@ -0,0 +1,61 @@
|
||||
import {
|
||||
TelemetryRecorderProvider as BaseTelemetryRecorderProvider,
|
||||
NoOpTelemetryExporter,
|
||||
type TelemetryProcessor,
|
||||
CallbackTelemetryProcessor,
|
||||
} from '@sourcegraph/telemetry'
|
||||
|
||||
/**
|
||||
* TelemetryRecorderProvider type used in Sourcegraph clients.
|
||||
*/
|
||||
export type TelemetryRecorderProvider = typeof noOptelemetryRecorderProvider
|
||||
|
||||
/**
|
||||
* TelemetryRecorder type used in Sourcegraph clients.
|
||||
*/
|
||||
export type TelemetryRecorder = typeof noOpTelemetryRecorder
|
||||
|
||||
/**
|
||||
* Events accept billing metadata for ease of categorization in analytics
|
||||
* pipelines - this type enumerates known categories.
|
||||
*/
|
||||
export type BillingCategory = 'exampleBillingCategory'
|
||||
|
||||
/**
|
||||
* Events accept billing metadata for ease of categorization in analytics
|
||||
* pipelines - this type enumerates known products.
|
||||
*/
|
||||
export type BillingProduct = 'exampleBillingProduct'
|
||||
|
||||
/**
|
||||
* Props interface that can be extended by React components depending on the
|
||||
* new telemetry framework: https://docs.sourcegraph.com/dev/background-information/telemetry
|
||||
* These properties are part of {@link PlatformContext}.
|
||||
*/
|
||||
export interface TelemetryV2Props {
|
||||
/**
|
||||
* Telemetry recorder for the new telemetry framework, superseding
|
||||
* 'telemetryService' and 'logEvent' variants. Learn more here:
|
||||
* https://docs.sourcegraph.com/dev/background-information/telemetry
|
||||
*
|
||||
* It is backed by a '@sourcegraph/telemetry' implementation.
|
||||
*/
|
||||
telemetryRecorder: TelemetryRecorder
|
||||
}
|
||||
|
||||
export class NoOpTelemetryRecorderProvider extends BaseTelemetryRecorderProvider<BillingCategory, BillingProduct> {
|
||||
constructor(opts?: { errorOnRecord?: boolean }) {
|
||||
const processors: TelemetryProcessor[] = []
|
||||
if (opts?.errorOnRecord) {
|
||||
processors.push(
|
||||
new CallbackTelemetryProcessor(() => {
|
||||
throw new Error('telemetry: unexpected use of no-op telemetry recorder')
|
||||
})
|
||||
)
|
||||
}
|
||||
super({ client: '' }, new NoOpTelemetryExporter(), processors)
|
||||
}
|
||||
}
|
||||
|
||||
export const noOptelemetryRecorderProvider = new NoOpTelemetryRecorderProvider()
|
||||
export const noOpTelemetryRecorder = noOptelemetryRecorderProvider.getRecorder()
|
||||
@ -1,19 +1,31 @@
|
||||
/**
|
||||
* Props interface that can be extended by React components depending on the TelemetryService.
|
||||
* These properties are part of {@link PlatformContext}.
|
||||
*
|
||||
* @deprecated Use TelemetryV2Props for a '@sourcegraph/telemetry' implementation
|
||||
* instead.
|
||||
*/
|
||||
export interface TelemetryProps {
|
||||
/**
|
||||
* A telemetry service implementation to log events.
|
||||
*
|
||||
* @deprecated Use telemetryRecorder instead from TelemetryV2Props, if it is
|
||||
* non-null (i.e. if the new SDK is available for the platform).
|
||||
*/
|
||||
telemetryService: TelemetryService
|
||||
}
|
||||
|
||||
/**
|
||||
* The telemetry service logs events.
|
||||
*
|
||||
* @deprecated Use a '@sourcegraph/telemetry' implementation instead.
|
||||
*/
|
||||
export interface TelemetryService {
|
||||
/**
|
||||
* Log an event (by sending it to the server).
|
||||
*
|
||||
* @deprecated Use a '@sourcegraph/telemetry' implementation instead where
|
||||
* available.
|
||||
*/
|
||||
log(eventName: string, eventProperties?: any, publicArgument?: any): void
|
||||
/**
|
||||
@ -25,11 +37,14 @@ export interface TelemetryService {
|
||||
/**
|
||||
* Log a pageview event (by sending it to the server).
|
||||
* Adheres to the new event naming policy
|
||||
*
|
||||
* @deprecated Use a '@sourcegraph/telemetry' implementation instead.
|
||||
*/
|
||||
logPageView(eventName: string, eventProperties?: any, publicArgument?: any): void
|
||||
/**
|
||||
* Listen for event logs
|
||||
*
|
||||
* @deprecated Use a '@sourcegraph/telemetry' implementation instead.
|
||||
* @returns a cleanup/removeEventListener function
|
||||
*/
|
||||
addEventLogListener?(callback: (eventName: string) => void): () => void
|
||||
|
||||
@ -1680,6 +1680,8 @@ ts_project(
|
||||
"src/team/new/NewTeamPage.tsx",
|
||||
"src/team/new/team-select/ParentTeamSelect.tsx",
|
||||
"src/team/new/team-select/backend.ts",
|
||||
"src/telemetry/apolloTelemetryExporter.ts",
|
||||
"src/telemetry/index.ts",
|
||||
"src/tour/GettingStartedTour.tsx",
|
||||
"src/tour/GettingStartedTourSetup.tsx",
|
||||
"src/tour/components/ItemPicker.tsx",
|
||||
@ -1774,6 +1776,7 @@ ts_project(
|
||||
":node_modules/@sourcegraph/http-client",
|
||||
":node_modules/@sourcegraph/observability-client",
|
||||
":node_modules/@sourcegraph/shared",
|
||||
":node_modules/@sourcegraph/telemetry",
|
||||
":node_modules/@sourcegraph/wildcard",
|
||||
"//:node_modules/@apollo/client",
|
||||
"//:node_modules/@codemirror/commands",
|
||||
|
||||
@ -23,8 +23,10 @@ const config = {
|
||||
* Note: Temporary increase from 400kb.
|
||||
* Primary cause is due to multiple ongoing migrations that mean we are duplicating similar dependencies.
|
||||
* Issue to track: https://github.com/sourcegraph/sourcegraph/issues/37845
|
||||
*
|
||||
* Note: Increased again from 500kb to get backport in.
|
||||
*/
|
||||
maxSize: '500kb',
|
||||
maxSize: '600kb',
|
||||
compression: 'none',
|
||||
},
|
||||
{
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
"@sourcegraph/observability-client": "workspace:*",
|
||||
"@sourcegraph/schema": "workspace:*",
|
||||
"@sourcegraph/shared": "workspace:*",
|
||||
"@sourcegraph/telemetry": "^0.11.0",
|
||||
"@sourcegraph/wildcard": "workspace:*"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -37,6 +37,7 @@ import {
|
||||
} from '@sourcegraph/shared/src/settings/settings'
|
||||
import { TemporarySettingsProvider } from '@sourcegraph/shared/src/settings/temporary/TemporarySettingsProvider'
|
||||
import { TemporarySettingsStorage } from '@sourcegraph/shared/src/settings/temporary/TemporarySettingsStorage'
|
||||
import { NoOpTelemetryRecorderProvider } from '@sourcegraph/shared/src/telemetry'
|
||||
import { WildcardThemeContext, type WildcardTheme } from '@sourcegraph/wildcard'
|
||||
|
||||
import { authenticatedUser as authenticatedUserSubject, type AuthenticatedUser, authenticatedUserValue } from './auth'
|
||||
@ -54,6 +55,7 @@ import { SearchResultsCacheProvider } from './search/results/SearchResultsCacheP
|
||||
import { GLOBAL_SEARCH_CONTEXT_SPEC } from './SearchQueryStateObserver'
|
||||
import type { StaticAppConfig } from './staticAppConfig'
|
||||
import { setQueryStateFromSettings, useNavbarQueryState } from './stores'
|
||||
import { TelemetryRecorderProvider } from './telemetry'
|
||||
import { eventLogger } from './tracking/eventLogger'
|
||||
import { UserSessionStores } from './UserSessionStores'
|
||||
import { siteSubjectNoAdmin, viewerSubjectFromSettings } from './util/settings'
|
||||
@ -76,6 +78,8 @@ interface LegacySourcegraphWebAppState extends SettingsCascadeProps {
|
||||
viewerSubject: LegacyLayoutProps['viewerSubject']
|
||||
|
||||
selectedSearchContextSpec?: string
|
||||
|
||||
platformContext: PlatformContext
|
||||
}
|
||||
|
||||
const WILDCARD_THEME: WildcardTheme = {
|
||||
@ -87,12 +91,18 @@ const WILDCARD_THEME: WildcardTheme = {
|
||||
*/
|
||||
export class LegacySourcegraphWebApp extends React.Component<StaticAppConfig, LegacySourcegraphWebAppState> {
|
||||
private readonly subscriptions = new Subscription()
|
||||
private readonly platformContext: PlatformContext = createPlatformContext()
|
||||
private readonly extensionsController: ExtensionsController | null = createNoopController(this.platformContext)
|
||||
private readonly extensionsController: ExtensionsController | null
|
||||
|
||||
constructor(props: StaticAppConfig) {
|
||||
super(props)
|
||||
|
||||
const basePlatformContext = createPlatformContext({
|
||||
telemetryRecorderProvider: new NoOpTelemetryRecorderProvider({
|
||||
errorOnRecord: true, // this will be replaced on render()
|
||||
}),
|
||||
})
|
||||
|
||||
this.extensionsController = createNoopController(basePlatformContext)
|
||||
if (this.extensionsController !== null) {
|
||||
this.subscriptions.add(this.extensionsController)
|
||||
}
|
||||
@ -101,6 +111,7 @@ export class LegacySourcegraphWebApp extends React.Component<StaticAppConfig, Le
|
||||
authenticatedUser: authenticatedUserValue,
|
||||
settingsCascade: EMPTY_SETTINGS_CASCADE,
|
||||
viewerSubject: siteSubjectNoAdmin(),
|
||||
platformContext: basePlatformContext,
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,12 +123,23 @@ export class LegacySourcegraphWebApp extends React.Component<StaticAppConfig, Le
|
||||
|
||||
getWebGraphQLClient()
|
||||
.then(graphqlClient => {
|
||||
// Create real telemetry recorder provider
|
||||
const telemetryRecorderProvider = new TelemetryRecorderProvider(graphqlClient, {
|
||||
enableBuffering: true,
|
||||
})
|
||||
this.subscriptions.add(telemetryRecorderProvider)
|
||||
|
||||
// Override the no-op telemetryRecorder from initialization
|
||||
const { platformContext } = this.state
|
||||
platformContext.telemetryRecorder = telemetryRecorderProvider.getRecorder()
|
||||
|
||||
this.setState({
|
||||
graphqlClient,
|
||||
temporarySettingsStorage: new TemporarySettingsStorage(
|
||||
graphqlClient,
|
||||
window.context.isAuthenticatedUser
|
||||
),
|
||||
platformContext,
|
||||
})
|
||||
})
|
||||
.catch(error => {
|
||||
@ -126,7 +148,7 @@ export class LegacySourcegraphWebApp extends React.Component<StaticAppConfig, Le
|
||||
|
||||
this.subscriptions.add(
|
||||
combineLatest([
|
||||
from(this.platformContext.settings),
|
||||
from(this.state.platformContext.settings),
|
||||
// Start with `undefined` while we don't know if the viewer is authenticated or not.
|
||||
authenticatedUserSubject,
|
||||
]).subscribe(([settingsCascade, authenticatedUser]) => {
|
||||
@ -196,7 +218,7 @@ export class LegacySourcegraphWebApp extends React.Component<StaticAppConfig, Le
|
||||
notebooksEnabled: this.props.notebooksEnabled,
|
||||
codeMonitoringEnabled: this.props.codeMonitoringEnabled,
|
||||
searchAggregationEnabled: this.props.searchAggregationEnabled,
|
||||
platformContext: this.platformContext,
|
||||
platformContext: this.state.platformContext,
|
||||
authenticatedUser,
|
||||
viewerSubject: this.state.viewerSubject,
|
||||
settingsCascade: this.state.settingsCascade,
|
||||
@ -279,7 +301,7 @@ export class LegacySourcegraphWebApp extends React.Component<StaticAppConfig, Le
|
||||
this.subscriptions.add(
|
||||
isSearchContextSpecAvailable({
|
||||
spec,
|
||||
platformContext: this.platformContext,
|
||||
platformContext: this.state.platformContext,
|
||||
}).subscribe(isAvailable => {
|
||||
if (isAvailable) {
|
||||
this.setSelectedSearchContextSpecWithNoChecks(spec)
|
||||
@ -300,7 +322,7 @@ export class LegacySourcegraphWebApp extends React.Component<StaticAppConfig, Le
|
||||
}
|
||||
|
||||
this.subscriptions.add(
|
||||
getDefaultSearchContextSpec({ platformContext: this.platformContext }).subscribe(spec => {
|
||||
getDefaultSearchContextSpec({ platformContext: this.state.platformContext }).subscribe(spec => {
|
||||
// Fall back to global if no default is returned.
|
||||
this.setSelectedSearchContextSpecWithNoChecks(spec || GLOBAL_SEARCH_CONTEXT_SPEC)
|
||||
})
|
||||
@ -327,5 +349,5 @@ export class LegacySourcegraphWebApp extends React.Component<StaticAppConfig, Le
|
||||
parameters: FetchFileParameters,
|
||||
force?: boolean | undefined
|
||||
): Observable<string[][]> =>
|
||||
fetchHighlightedFileLineRanges({ ...parameters, platformContext: this.platformContext }, force)
|
||||
fetchHighlightedFileLineRanges({ ...parameters, platformContext: this.state.platformContext }, force)
|
||||
}
|
||||
|
||||
@ -44,6 +44,7 @@ import { setQueryStateFromSettings, useNavbarQueryState } from './stores'
|
||||
import type { AppShellInit } from './storm/app-shell-init'
|
||||
import { Layout } from './storm/pages/LayoutPage/LayoutPage'
|
||||
import { loader } from './storm/pages/LayoutPage/LayoutPage.loader'
|
||||
import { TelemetryRecorderProvider } from './telemetry'
|
||||
import { UserSessionStores } from './UserSessionStores'
|
||||
import { siteSubjectNoAdmin, viewerSubjectFromSettings } from './util/settings'
|
||||
|
||||
@ -97,7 +98,6 @@ const suspenseCache = new SuspenseCache()
|
||||
*
|
||||
* Most of the dynamic values in the `SourcegraphWebApp` depend on this observable.
|
||||
*/
|
||||
const platformContext = createPlatformContext()
|
||||
|
||||
interface SourcegraphWebAppProps extends StaticAppConfig, AppShellInit {}
|
||||
|
||||
@ -106,6 +106,10 @@ export const SourcegraphWebApp: FC<SourcegraphWebAppProps> = props => {
|
||||
|
||||
const [subscriptions] = useState(() => new Subscription())
|
||||
|
||||
const telemetryRecorderProvider = new TelemetryRecorderProvider(graphqlClient, { enableBuffering: true })
|
||||
subscriptions.add(telemetryRecorderProvider)
|
||||
const platformContext = createPlatformContext({ telemetryRecorderProvider })
|
||||
|
||||
const [resolvedAuthenticatedUser, setResolvedAuthenticatedUser] = useState<AuthenticatedUser | null>(
|
||||
authenticatedUserValue
|
||||
)
|
||||
@ -146,7 +150,7 @@ export const SourcegraphWebApp: FC<SourcegraphWebAppProps> = props => {
|
||||
setSelectedSearchContextSpecWithNoChecks(spec || GLOBAL_SEARCH_CONTEXT_SPEC)
|
||||
})
|
||||
)
|
||||
}, [props.searchContextsEnabled, setSelectedSearchContextSpecWithNoChecks, subscriptions])
|
||||
}, [props.searchContextsEnabled, setSelectedSearchContextSpecWithNoChecks, subscriptions, platformContext])
|
||||
|
||||
const setSelectedSearchContextSpec = useCallback(
|
||||
(spec: string): void => {
|
||||
@ -183,6 +187,7 @@ export const SourcegraphWebApp: FC<SourcegraphWebAppProps> = props => {
|
||||
setSelectedSearchContextSpecToDefault,
|
||||
setSelectedSearchContextSpecWithNoChecks,
|
||||
subscriptions,
|
||||
platformContext,
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@ -18,6 +18,7 @@ import {
|
||||
import '../../SourcegraphWebApp.scss'
|
||||
|
||||
import { createPlatformContext } from '../../platform/context'
|
||||
import { TelemetryRecorderProvider } from '../../telemetry'
|
||||
|
||||
import { OpenNewTabAnchorLink } from './OpenNewTabAnchorLink'
|
||||
|
||||
@ -61,7 +62,16 @@ export const EmbeddedWebApp: FC<Props> = ({ graphqlClient }) => {
|
||||
)
|
||||
}, [setThemeSetting])
|
||||
|
||||
const platformContext = useMemo(() => createPlatformContext(), [])
|
||||
const telemetryRecorderProvider = useMemo(
|
||||
() => new TelemetryRecorderProvider(graphqlClient, { enableBuffering: true }),
|
||||
[graphqlClient]
|
||||
)
|
||||
useEffect(() => () => telemetryRecorderProvider.unsubscribe(), [telemetryRecorderProvider]) // unsubscribe on unmount
|
||||
|
||||
const platformContext = useMemo(
|
||||
() => createPlatformContext({ telemetryRecorderProvider }),
|
||||
[telemetryRecorderProvider]
|
||||
)
|
||||
|
||||
// 🚨 SECURITY: The `EmbeddedWebApp` is intended to be embedded into 3rd party sites where we do not have total control.
|
||||
// That is why it is essential to be mindful when adding new routes that may be vulnerable to clickjacking or similar exploits.
|
||||
|
||||
@ -4,6 +4,7 @@ import { mdiChevronDown, mdiInformationOutline } from '@mdi/js'
|
||||
|
||||
import { Timestamp } from '@sourcegraph/branded/src/components/Timestamp'
|
||||
import { UserAvatar } from '@sourcegraph/shared/src/components/UserAvatar'
|
||||
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
|
||||
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
import {
|
||||
Container,
|
||||
@ -49,14 +50,18 @@ import styles from './RepoSettingsPermissionsPage.module.scss'
|
||||
|
||||
type IUser = INode['user']
|
||||
|
||||
export interface RepoSettingsPermissionsPageProps extends TelemetryProps {
|
||||
export interface RepoSettingsPermissionsPageProps extends TelemetryProps, TelemetryV2Props {
|
||||
repo: SettingsAreaRepositoryFields
|
||||
}
|
||||
|
||||
/**
|
||||
* The repository settings permissions page.
|
||||
*/
|
||||
export const RepoSettingsPermissionsPage: FC<RepoSettingsPermissionsPageProps> = ({ repo, telemetryService }) => {
|
||||
export const RepoSettingsPermissionsPage: FC<RepoSettingsPermissionsPageProps> = ({
|
||||
repo,
|
||||
telemetryService,
|
||||
telemetryRecorder,
|
||||
}) => {
|
||||
useEffect(() => eventLogger.logViewEvent('RepoSettingsPermissions'))
|
||||
|
||||
const [{ query }, setSearchQuery] = useURLSyncedState({ query: '' })
|
||||
@ -170,7 +175,12 @@ export const RepoSettingsPermissionsPage: FC<RepoSettingsPermissionsPageProps> =
|
||||
className="my-3 pt-3"
|
||||
/>
|
||||
<Container className="mb-3">
|
||||
<PermissionsSyncJobsTable telemetryService={telemetryService} minimal={true} repoID={repo.id} />
|
||||
<PermissionsSyncJobsTable
|
||||
telemetryService={telemetryService}
|
||||
telemetryRecorder={telemetryRecorder}
|
||||
minimal={true}
|
||||
repoID={repo.id}
|
||||
/>
|
||||
</Container>
|
||||
<PageHeader
|
||||
headingElement="h2"
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import sinon from 'sinon'
|
||||
|
||||
import { getDocumentNode } from '@sourcegraph/http-client'
|
||||
import { noOpTelemetryRecorder } from '@sourcegraph/shared/src/telemetry'
|
||||
import { NOOP_TELEMETRY_SERVICE } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
import { MockedTestProvider, waitForNextApolloResponse } from '@sourcegraph/shared/src/testing/apollo'
|
||||
import { renderWithBrandedContext } from '@sourcegraph/wildcard/src/testing'
|
||||
@ -81,6 +82,7 @@ describe('UserSettingsPermissionsPage', () => {
|
||||
<UserSettingsPermissionsPage
|
||||
user={{ id: gqlUserID, username: 'alice' }}
|
||||
telemetryService={NOOP_TELEMETRY_SERVICE}
|
||||
telemetryRecorder={noOpTelemetryRecorder}
|
||||
/>
|
||||
</MockedTestProvider>,
|
||||
{}
|
||||
@ -132,6 +134,7 @@ describe('UserSettingsPermissionsPage', () => {
|
||||
<UserSettingsPermissionsPage
|
||||
user={{ id: gqlUserID, username: 'alice' }}
|
||||
telemetryService={NOOP_TELEMETRY_SERVICE}
|
||||
telemetryRecorder={noOpTelemetryRecorder}
|
||||
/>
|
||||
</MockedTestProvider>,
|
||||
{}
|
||||
|
||||
@ -4,6 +4,7 @@ import { mdiInformationOutline } from '@mdi/js'
|
||||
|
||||
import { Timestamp } from '@sourcegraph/branded/src/components/Timestamp'
|
||||
import { RepoLink } from '@sourcegraph/shared/src/components/RepoLink'
|
||||
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
|
||||
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
import {
|
||||
Container,
|
||||
@ -39,7 +40,7 @@ import { scheduleUserPermissionsSync, UserPermissionsInfoQuery } from './backend
|
||||
|
||||
import styles from './UserSettingsPermissionsPage.module.scss'
|
||||
|
||||
interface Props extends TelemetryProps {
|
||||
interface Props extends TelemetryProps, TelemetryV2Props {
|
||||
user: { id: string; username: string }
|
||||
}
|
||||
|
||||
@ -49,6 +50,7 @@ interface Props extends TelemetryProps {
|
||||
export const UserSettingsPermissionsPage: React.FunctionComponent<React.PropsWithChildren<Props>> = ({
|
||||
user,
|
||||
telemetryService,
|
||||
telemetryRecorder,
|
||||
}) => {
|
||||
useEffect(() => eventLogger.logViewEvent('UserSettingsPermissions'), [])
|
||||
|
||||
@ -142,7 +144,12 @@ export const UserSettingsPermissionsPage: React.FunctionComponent<React.PropsWit
|
||||
className="my-3 pt-3"
|
||||
/>
|
||||
<Container className="mb-3">
|
||||
<PermissionsSyncJobsTable telemetryService={telemetryService} minimal={true} userID={user.id} />
|
||||
<PermissionsSyncJobsTable
|
||||
telemetryService={telemetryService}
|
||||
telemetryRecorder={telemetryRecorder}
|
||||
minimal={true}
|
||||
userID={user.id}
|
||||
/>
|
||||
</Container>
|
||||
<PageHeader
|
||||
headingElement="h2"
|
||||
|
||||
@ -16,14 +16,23 @@ import {
|
||||
type RenderModeSpec,
|
||||
type UIRangeSpec,
|
||||
} from '@sourcegraph/shared/src/util/url'
|
||||
import { CallbackTelemetryProcessor } from '@sourcegraph/telemetry'
|
||||
|
||||
import { getWebGraphQLClient, requestGraphQL } from '../backend/graphql'
|
||||
import type { TelemetryRecorderProvider } from '../telemetry'
|
||||
import { eventLogger } from '../tracking/eventLogger'
|
||||
|
||||
/**
|
||||
* Creates the {@link PlatformContext} for the web app.
|
||||
*/
|
||||
export function createPlatformContext(): PlatformContext {
|
||||
export function createPlatformContext(props: {
|
||||
/**
|
||||
* The {@link TelemetryRecorderProvider} for the platform. Callers should
|
||||
* make sure to configure desired buffering and add the teardown of the
|
||||
* provider to a subscription or similar.
|
||||
*/
|
||||
telemetryRecorderProvider: TelemetryRecorderProvider
|
||||
}): PlatformContext {
|
||||
const settingsQueryWatcherPromise = watchViewerSettingsQuery()
|
||||
|
||||
const context: PlatformContext = {
|
||||
@ -78,6 +87,15 @@ export function createPlatformContext(): PlatformContext {
|
||||
sourcegraphURL: window.context.externalURL,
|
||||
clientApplication: 'sourcegraph',
|
||||
telemetryService: eventLogger,
|
||||
telemetryRecorder: props.telemetryRecorderProvider.getRecorder(
|
||||
window.context.debug
|
||||
? [
|
||||
new CallbackTelemetryProcessor(event =>
|
||||
logger.info(`telemetry: ${event.feature}/${event.action}`, { event })
|
||||
),
|
||||
]
|
||||
: undefined
|
||||
),
|
||||
}
|
||||
|
||||
return context
|
||||
|
||||
@ -476,7 +476,13 @@ export const RepoContainer: FC<RepoContainerProps> = props => {
|
||||
path={repoNameAndRevision + repoSettingsAreaPath}
|
||||
errorElement={<RouteError />}
|
||||
// Always render the `RepoSettingsArea` even for empty repo to allow side-admins access it.
|
||||
element={<RepoSettingsArea {...repoRevisionContainerContext} repoName={repoName} />}
|
||||
element={
|
||||
<RepoSettingsArea
|
||||
{...repoRevisionContainerContext}
|
||||
repoName={repoName}
|
||||
telemetryRecorder={props.platformContext.telemetryRecorder}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<Route
|
||||
|
||||
@ -8,6 +8,7 @@ import { of } from 'rxjs'
|
||||
import { catchError } from 'rxjs/operators'
|
||||
|
||||
import { asError, type ErrorLike, isErrorLike } from '@sourcegraph/common'
|
||||
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
|
||||
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
import { useObservable, ErrorMessage } from '@sourcegraph/wildcard'
|
||||
|
||||
@ -22,13 +23,13 @@ import { RepoSettingsSidebar, type RepoSettingsSideBarGroups } from './RepoSetti
|
||||
|
||||
import styles from './RepoSettingsArea.module.scss'
|
||||
|
||||
export interface RepoSettingsAreaRouteContext extends TelemetryProps {
|
||||
export interface RepoSettingsAreaRouteContext extends TelemetryProps, TelemetryV2Props {
|
||||
repo: SettingsAreaRepositoryFields
|
||||
}
|
||||
|
||||
export interface RepoSettingsAreaRoute extends RouteV6Descriptor<RepoSettingsAreaRouteContext> {}
|
||||
|
||||
interface Props extends BreadcrumbSetters, TelemetryProps {
|
||||
interface Props extends BreadcrumbSetters, TelemetryProps, TelemetryV2Props {
|
||||
repoSettingsAreaRoutes: readonly RepoSettingsAreaRoute[]
|
||||
repoSettingsSidebarGroups: RepoSettingsSideBarGroups
|
||||
repoName: string
|
||||
@ -82,6 +83,7 @@ export const RepoSettingsArea: React.FunctionComponent<React.PropsWithChildren<P
|
||||
const context: RepoSettingsAreaRouteContext = {
|
||||
repo: repoOrError,
|
||||
telemetryService: props.telemetryService,
|
||||
telemetryRecorder: props.telemetryRecorder,
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@ -3,6 +3,7 @@ import { cleanup, screen } from '@testing-library/react'
|
||||
import { EMPTY, NEVER } from 'rxjs'
|
||||
import sinon from 'sinon'
|
||||
|
||||
import { noOpTelemetryRecorder } from '@sourcegraph/shared/src/telemetry'
|
||||
import { NOOP_TELEMETRY_SERVICE } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
import { renderWithBrandedContext } from '@sourcegraph/wildcard/src/testing'
|
||||
|
||||
@ -55,6 +56,7 @@ describe('TreePage', () => {
|
||||
urlToFile: () => '',
|
||||
sourcegraphURL: 'https://sourcegraph.com',
|
||||
clientApplication: 'sourcegraph',
|
||||
telemetryRecorder: noOpTelemetryRecorder,
|
||||
},
|
||||
telemetryService: NOOP_TELEMETRY_SERVICE,
|
||||
codeIntelligenceEnabled: false,
|
||||
|
||||
@ -11,6 +11,7 @@ import {
|
||||
PermissionsSyncJobReasonGroup,
|
||||
PermissionsSyncJobState,
|
||||
} from '@sourcegraph/shared/src/graphql-operations'
|
||||
import { noOpTelemetryRecorder } from '@sourcegraph/shared/src/telemetry'
|
||||
import { NOOP_TELEMETRY_SERVICE } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
import { MockedTestProvider } from '@sourcegraph/shared/src/testing/apollo'
|
||||
|
||||
@ -89,7 +90,10 @@ export const SixSyncJobsFound: Story = () => (
|
||||
])
|
||||
}
|
||||
>
|
||||
<PermissionsSyncJobsTable telemetryService={NOOP_TELEMETRY_SERVICE} />
|
||||
<PermissionsSyncJobsTable
|
||||
telemetryService={NOOP_TELEMETRY_SERVICE}
|
||||
telemetryRecorder={noOpTelemetryRecorder}
|
||||
/>
|
||||
</MockedTestProvider>
|
||||
)}
|
||||
</WebStory>
|
||||
|
||||
@ -11,6 +11,7 @@ import { animated, useSpring } from 'react-spring'
|
||||
import { Timestamp } from '@sourcegraph/branded/src/components/Timestamp'
|
||||
import { useMutation } from '@sourcegraph/http-client'
|
||||
import { convertREMToPX } from '@sourcegraph/shared/src/components/utils/size'
|
||||
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
|
||||
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
import {
|
||||
Alert,
|
||||
@ -95,7 +96,7 @@ const DEFAULT_FILTERS = {
|
||||
}
|
||||
export const PERMISSIONS_SYNC_JOBS_POLL_INTERVAL = 2000
|
||||
|
||||
interface Props extends TelemetryProps {
|
||||
interface Props extends TelemetryProps, TelemetryV2Props {
|
||||
minimal?: boolean
|
||||
userID?: string
|
||||
repoID?: string
|
||||
@ -103,6 +104,7 @@ interface Props extends TelemetryProps {
|
||||
|
||||
export const PermissionsSyncJobsTable: React.FunctionComponent<React.PropsWithChildren<Props>> = ({
|
||||
telemetryService,
|
||||
telemetryRecorder,
|
||||
minimal = false,
|
||||
userID,
|
||||
repoID,
|
||||
@ -189,6 +191,9 @@ export const PermissionsSyncJobsTable: React.FunctionComponent<React.PropsWithCh
|
||||
const handleTriggerPermsSync = useCallback(
|
||||
([job]: PermissionsSyncJob[]) => {
|
||||
if (job.subject.__typename === 'Repository') {
|
||||
telemetryRecorder.recordEvent('permissions-center.repository.sync', 'trigger', {
|
||||
privateMetadata: { repo: job.subject.id },
|
||||
})
|
||||
triggerRepoSync({
|
||||
variables: { repo: job.subject.id },
|
||||
onCompleted: () =>
|
||||
@ -199,6 +204,9 @@ export const PermissionsSyncJobsTable: React.FunctionComponent<React.PropsWithCh
|
||||
noop
|
||||
)
|
||||
} else {
|
||||
telemetryRecorder.recordEvent('permissions-center.user.sync', 'trigger', {
|
||||
privateMetadata: { user: job.subject.id },
|
||||
})
|
||||
triggerUserSync({
|
||||
variables: { user: job.subject.id },
|
||||
onCompleted: () => toggleNotification({ text: 'User permissions sync successfully scheduled' }),
|
||||
@ -209,7 +217,7 @@ export const PermissionsSyncJobsTable: React.FunctionComponent<React.PropsWithCh
|
||||
)
|
||||
}
|
||||
},
|
||||
[triggerUserSync, triggerRepoSync, onError, toggleNotification]
|
||||
[triggerUserSync, triggerRepoSync, onError, toggleNotification, telemetryRecorder]
|
||||
)
|
||||
|
||||
const handleCancelSyncJob = useCallback(
|
||||
@ -223,16 +231,36 @@ export const PermissionsSyncJobsTable: React.FunctionComponent<React.PropsWithCh
|
||||
// noop here is used because an error is handled in `onError` option of `useMutation` above.
|
||||
noop
|
||||
)
|
||||
|
||||
if (syncJob.subject.__typename === 'Repository') {
|
||||
telemetryRecorder.recordEvent('permissions-center.repository.sync', 'cancel', {
|
||||
privateMetadata: { repo: syncJob.subject.id },
|
||||
})
|
||||
} else {
|
||||
telemetryRecorder.recordEvent('permissions-center.user.sync', 'cancel', {
|
||||
privateMetadata: { user: syncJob.subject.id },
|
||||
})
|
||||
}
|
||||
},
|
||||
[cancelSyncJob, onError, toggleNotification]
|
||||
[cancelSyncJob, onError, toggleNotification, telemetryRecorder]
|
||||
)
|
||||
|
||||
const handleViewJobDetails = useCallback(
|
||||
([syncJob]: PermissionsSyncJob[]) => {
|
||||
setShowModal(true)
|
||||
setSelectedJob(syncJob)
|
||||
|
||||
if (syncJob.subject.__typename === 'Repository') {
|
||||
telemetryRecorder.recordEvent('permissions-center.repository.sync', 'view', {
|
||||
privateMetadata: { repo: syncJob.subject.id },
|
||||
})
|
||||
} else {
|
||||
telemetryRecorder.recordEvent('permissions-center.user.sync', 'view', {
|
||||
privateMetadata: { user: syncJob.subject.id },
|
||||
})
|
||||
}
|
||||
},
|
||||
[setShowModal, setSelectedJob]
|
||||
[setShowModal, setSelectedJob, telemetryRecorder]
|
||||
)
|
||||
|
||||
if (minimal) {
|
||||
|
||||
@ -252,7 +252,9 @@ export const otherSiteAdminRoutes: readonly SiteAdminAreaRoute[] = [
|
||||
},
|
||||
{
|
||||
path: '/permissions-syncs',
|
||||
render: props => <PermissionsSyncJobsTable {...props} />,
|
||||
render: props => (
|
||||
<PermissionsSyncJobsTable {...props} telemetryRecorder={props.platformContext.telemetryRecorder} />
|
||||
),
|
||||
},
|
||||
{
|
||||
path: '/gitservers',
|
||||
|
||||
28
client/web/src/telemetry/apolloTelemetryExporter.ts
Normal file
28
client/web/src/telemetry/apolloTelemetryExporter.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { type ApolloClient, gql } from '@apollo/client'
|
||||
|
||||
import type { TelemetryEventInput, TelemetryExporter } from '@sourcegraph/telemetry'
|
||||
|
||||
import type { ExportTelemetryEventsResult } from '../graphql-operations'
|
||||
|
||||
/**
|
||||
* ApolloTelemetryExporter exports events via the new Sourcegraph telemetry
|
||||
* framework: https://docs.sourcegraph.com/dev/background-information/telemetry
|
||||
*/
|
||||
export class ApolloTelemetryExporter implements TelemetryExporter {
|
||||
constructor(private client: ApolloClient<object>) {}
|
||||
|
||||
public async exportEvents(events: TelemetryEventInput[]): Promise<void> {
|
||||
await this.client.mutate<ExportTelemetryEventsResult>({
|
||||
mutation: gql`
|
||||
mutation ExportTelemetryEvents($events: [TelemetryEventInput!]!) {
|
||||
telemetry {
|
||||
recordEvents(events: $events) {
|
||||
alwaysNil
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: { events },
|
||||
})
|
||||
}
|
||||
}
|
||||
83
client/web/src/telemetry/index.ts
Normal file
83
client/web/src/telemetry/index.ts
Normal file
@ -0,0 +1,83 @@
|
||||
import type { ApolloClient } from '@apollo/client'
|
||||
|
||||
import type { BillingCategory, BillingProduct } from '@sourcegraph/shared/src/telemetry'
|
||||
import {
|
||||
TelemetryRecorderProvider as BaseTelemetryRecorderProvider,
|
||||
MarketingTrackingTelemetryProcessor,
|
||||
type MarketingTrackingProvider,
|
||||
type TelemetryEventMarketingTrackingInput,
|
||||
} from '@sourcegraph/telemetry'
|
||||
|
||||
import { sessionTracker } from '../tracking/sessionTracker'
|
||||
import { userTracker } from '../tracking/userTracker'
|
||||
|
||||
import { ApolloTelemetryExporter } from './apolloTelemetryExporter'
|
||||
|
||||
function getTelemetrySourceClient(): string {
|
||||
if (window.context?.codyAppMode) {
|
||||
return 'app.web'
|
||||
}
|
||||
if (window.context?.sourcegraphDotComMode) {
|
||||
return 'dotcom.web'
|
||||
}
|
||||
return 'server.web'
|
||||
}
|
||||
|
||||
/**
|
||||
* TelemetryRecorderProvider is the default provider implementation for the
|
||||
* Sourcegraph web app.
|
||||
*/
|
||||
export class TelemetryRecorderProvider extends BaseTelemetryRecorderProvider<BillingCategory, BillingProduct> {
|
||||
constructor(
|
||||
apolloClient: ApolloClient<object>,
|
||||
options: {
|
||||
/**
|
||||
* Enables buffering of events for export. Only enable if there is a
|
||||
* reliable unsubscribe mechanism available.
|
||||
*/
|
||||
enableBuffering: boolean
|
||||
}
|
||||
) {
|
||||
super(
|
||||
{
|
||||
client: getTelemetrySourceClient(),
|
||||
clientVersion: window.context.version,
|
||||
},
|
||||
new ApolloTelemetryExporter(apolloClient),
|
||||
[new MarketingTrackingTelemetryProcessor(new TrackingMetadataProvider())],
|
||||
{
|
||||
/**
|
||||
* Use buffer time of 100ms - some existing buffering uses
|
||||
* 1000ms, but we use a more conservative value.
|
||||
*/
|
||||
bufferTimeMs: options.enableBuffering ? 100 : 0,
|
||||
bufferMaxSize: 10,
|
||||
errorHandler: error => {
|
||||
throw new Error(error)
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TrackingMetadataProvider implements MarketingTrackingProvider {
|
||||
private user = userTracker
|
||||
private session = sessionTracker
|
||||
|
||||
public getMarketingTrackingMetadata(): TelemetryEventMarketingTrackingInput | null {
|
||||
if (!window.context?.sourcegraphDotComMode) {
|
||||
return null // don't report this data outside of dotcom
|
||||
}
|
||||
|
||||
return {
|
||||
cohortID: this.user.cohortID,
|
||||
deviceSessionID: this.user.deviceSessionID,
|
||||
firstSourceURL: this.session.getFirstSourceURL(),
|
||||
lastSourceURL: this.session.getLastSourceURL(),
|
||||
referrer: this.session.getReferrer(),
|
||||
sessionFirstURL: this.session.getSessionFirstURL(),
|
||||
sessionReferrer: this.session.getSessionReferrer(),
|
||||
url: window.location.href,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -77,6 +77,10 @@ export class EventLogger implements TelemetryService, SharedEventLogger {
|
||||
private eventID = 0
|
||||
private listeners: Set<(eventName: string) => void> = new Set()
|
||||
|
||||
/**
|
||||
* @deprecated Use a TelemetryRecorder or TelemetryRecorderProvider from
|
||||
* src/telemetry instead.
|
||||
*/
|
||||
constructor() {
|
||||
// EventLogger is never teared down
|
||||
// eslint-disable-next-line rxjs/no-ignored-subscription
|
||||
@ -105,6 +109,9 @@ export class EventLogger implements TelemetryService, SharedEventLogger {
|
||||
/**
|
||||
* Log a pageview.
|
||||
* Page titles should be specific and human-readable in pascal case, e.g. "SearchResults" or "Blob" or "NewOrg"
|
||||
*
|
||||
* @deprecated Use a TelemetryRecorder or TelemetryRecorderProvider from
|
||||
* src/telemetry instead.
|
||||
*/
|
||||
public logViewEvent(pageTitle: string, eventProperties?: any, logAsActiveUser = true): void {
|
||||
// call to refresh the session
|
||||
@ -120,6 +127,8 @@ export class EventLogger implements TelemetryService, SharedEventLogger {
|
||||
/**
|
||||
* Log a pageview, following the new event naming conventions
|
||||
*
|
||||
* @deprecated Use a TelemetryRecorder or TelemetryRecorderProvider from
|
||||
* src/telemetry instead.
|
||||
* @param eventName should be specific and human-readable in pascal case, e.g. "SearchResults" or "Blob" or "NewOrg"
|
||||
*/
|
||||
public logPageView(eventName: string, eventProperties?: any, logAsActiveUser = true): void {
|
||||
@ -137,6 +146,8 @@ export class EventLogger implements TelemetryService, SharedEventLogger {
|
||||
* Log a user action or event.
|
||||
* Event labels should be specific and follow a ${noun}${verb} structure in pascal case, e.g. "ButtonClicked" or "SignInInitiated"
|
||||
*
|
||||
* @deprecated Use a TelemetryRecorder or TelemetryRecorderProvider from
|
||||
* src/telemetry instead.
|
||||
* @param eventLabel the event name.
|
||||
* @param eventProperties event properties. These get logged to our database, but do not get
|
||||
* sent to our analytics systems. This may contain private info such as repository names or search queries.
|
||||
@ -205,6 +216,10 @@ export class EventLogger implements TelemetryService, SharedEventLogger {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use a TelemetryRecorder or TelemetryRecorderProvider from
|
||||
* src/telemetry instead.
|
||||
*/
|
||||
export const eventLogger = new EventLogger()
|
||||
|
||||
/**
|
||||
|
||||
@ -1,13 +1,25 @@
|
||||
import { logEvent } from '../../user/settings/backend'
|
||||
|
||||
class ServerAdminWrapper {
|
||||
/**
|
||||
* @deprecated Use a TelemetryRecorder or TelemetryRecorderProvider from
|
||||
* src/telemetry instead.
|
||||
*/
|
||||
public trackPageView(eventAction: string, eventProperties?: any, publicArgument?: any): void {
|
||||
logEvent(eventAction, eventProperties, publicArgument)
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use a TelemetryRecorder or TelemetryRecorderProvider from
|
||||
* src/telemetry instead.
|
||||
*/
|
||||
public trackAction(eventAction: string, eventProperties?: any, publicArgument?: any): void {
|
||||
logEvent(eventAction, eventProperties, publicArgument)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use a TelemetryRecorder or TelemetryRecorderProvider from
|
||||
* src/telemetry instead.
|
||||
*/
|
||||
export const serverAdmin = new ServerAdminWrapper()
|
||||
|
||||
@ -17,6 +17,7 @@ export const userAreaRoutes: readonly UserAreaRoute[] = [
|
||||
{...props}
|
||||
routes={props.userSettingsAreaRoutes}
|
||||
sideBarItems={props.userSettingsSideBarItems}
|
||||
telemetryRecorder={props.platformContext.telemetryRecorder}
|
||||
/>
|
||||
),
|
||||
},
|
||||
|
||||
@ -5,6 +5,7 @@ import MapSearchIcon from 'mdi-react/MapSearchIcon'
|
||||
import { Route, Routes } from 'react-router-dom'
|
||||
|
||||
import { gql, useQuery } from '@sourcegraph/http-client'
|
||||
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
|
||||
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
import { LoadingSpinner } from '@sourcegraph/wildcard'
|
||||
|
||||
@ -30,7 +31,7 @@ import styles from './UserSettingsArea.module.scss'
|
||||
|
||||
export interface UserSettingsAreaRoute extends RouteV6Descriptor<UserSettingsAreaRouteContext> {}
|
||||
|
||||
export interface UserSettingsAreaProps extends UserAreaRouteContext, TelemetryProps {
|
||||
export interface UserSettingsAreaProps extends UserAreaRouteContext, TelemetryProps, TelemetryV2Props {
|
||||
authenticatedUser: AuthenticatedUser
|
||||
sideBarItems: UserSettingsSidebarItems
|
||||
routes: readonly UserSettingsAreaRoute[]
|
||||
|
||||
@ -159,6 +159,9 @@ batchedEvents
|
||||
*
|
||||
* When invoked on a non-Sourcegraph.com instance, this data is stored in the
|
||||
* instance's database, and not sent to Sourcegraph.com.
|
||||
*
|
||||
* @deprecated Use a TelemetryRecorder or TelemetryRecorderProvider from
|
||||
* src/telemetry instead.
|
||||
*/
|
||||
export function logEvent(event: string, eventProperties?: unknown, publicArgument?: unknown): void {
|
||||
batchedEvents.next(createEvent(event, eventProperties, publicArgument))
|
||||
@ -170,6 +173,9 @@ export function logEvent(event: string, eventProperties?: unknown, publicArgumen
|
||||
* used only when low event latency is necessary (e.g., on an external link).
|
||||
*
|
||||
* See logEvent for additional details.
|
||||
*
|
||||
* @deprecated Use a TelemetryRecorder or TelemetryRecorderProvider from
|
||||
* src/telemetry instead.
|
||||
*/
|
||||
export function logEventSynchronously(
|
||||
event: string,
|
||||
|
||||
@ -78,7 +78,7 @@ func (j *exporterJob) Handle(ctx context.Context) error {
|
||||
// Check the current licensing mode.
|
||||
if licensing.GetTelemetryEventsExportMode(conf.DefaultClient()) ==
|
||||
licensing.TelemetryEventsExportDisabled {
|
||||
logger.Debug("export is currently disabled entirely via licensing")
|
||||
logger.Info("export is currently disabled entirely via licensing")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
|
||||
load("@rules_buf//buf:defs.bzl", "buf_lint_test")
|
||||
load("@rules_proto//proto:defs.bzl", "proto_library")
|
||||
load("//dev:proto.bzl", "write_proto_stubs_to_source")
|
||||
|
||||
|
||||
@ -9,9 +9,12 @@ import (
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
"github.com/sourcegraph/sourcegraph/internal/conf/conftypes"
|
||||
"github.com/sourcegraph/sourcegraph/internal/env"
|
||||
"github.com/sourcegraph/sourcegraph/internal/license"
|
||||
)
|
||||
|
||||
var forceExportAll = env.MustGetBool("SRC_TELEMETRY_EVENTS_EXPORT_ALL", false, "Set to true to forcibly enable all events export.")
|
||||
|
||||
// telemetryExportEnablementCutOffDate is Oct 4, 2023 UTC, and all licenses
|
||||
// created after this date will have telemetry export enabled by default.
|
||||
//
|
||||
@ -27,6 +30,10 @@ var telemetryEventsExportMode = atomic.NewPointer((*evaluatedTelemetryEventsExpo
|
||||
// GetTelemetryEventsExportMode returns the degree of telemetry events export
|
||||
// enabled. See TelemetryEventsExportMode for more details.
|
||||
func GetTelemetryEventsExportMode(c conftypes.SiteConfigQuerier) TelemetryEventsExportMode {
|
||||
if forceExportAll {
|
||||
return TelemetryEventsExportAll
|
||||
}
|
||||
|
||||
evaluatedMode := telemetryEventsExportMode.Load()
|
||||
|
||||
// Update if changed license key has changed
|
||||
|
||||
@ -1495,6 +1495,9 @@ importers:
|
||||
'@sourcegraph/http-client':
|
||||
specifier: workspace:*
|
||||
version: link:../http-client
|
||||
'@sourcegraph/telemetry':
|
||||
specifier: ^0.11.0
|
||||
version: 0.11.0
|
||||
'@sourcegraph/template-parser':
|
||||
specifier: workspace:*
|
||||
version: link:../template-parser
|
||||
@ -1604,6 +1607,9 @@ importers:
|
||||
'@sourcegraph/shared':
|
||||
specifier: workspace:*
|
||||
version: link:../shared
|
||||
'@sourcegraph/telemetry':
|
||||
specifier: ^0.11.0
|
||||
version: 0.11.0
|
||||
'@sourcegraph/wildcard':
|
||||
specifier: workspace:*
|
||||
version: link:../wildcard
|
||||
@ -9507,6 +9513,12 @@ packages:
|
||||
stylelint: 14.3.0
|
||||
dev: true
|
||||
|
||||
/@sourcegraph/telemetry@0.11.0:
|
||||
resolution: {integrity: sha512-cOlkCwX3V5lVJO/F8w7VauhMZob3PrMbE4DApTKwasTMwm4+OxtT6+afC5wJTwZwNWc31V83sNjV2nBkEtFPZg==}
|
||||
dependencies:
|
||||
rxjs: 7.8.1
|
||||
dev: false
|
||||
|
||||
/@sourcegraph/tsconfig@4.0.1:
|
||||
resolution: {integrity: sha512-G/xsejsR84G5dj3kHJ7svKBo9E5tWl96rUHKP94Y2UDtA7BzUhAYbieM+b9ZUpIRt66h3+MlYbG5HK4UI2zDzw==}
|
||||
dev: true
|
||||
@ -16893,7 +16905,7 @@ packages:
|
||||
chalk: 4.1.2
|
||||
date-fns: 2.29.3
|
||||
lodash: 4.17.21
|
||||
rxjs: 7.6.0
|
||||
rxjs: 7.8.1
|
||||
shell-quote: 1.8.1
|
||||
spawn-command: 0.0.2-1
|
||||
supports-color: 8.1.1
|
||||
@ -22393,7 +22405,7 @@ packages:
|
||||
mute-stream: 0.0.8
|
||||
ora: 5.4.1
|
||||
run-async: 2.4.1
|
||||
rxjs: 7.6.0
|
||||
rxjs: 7.8.1
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
through: 2.3.8
|
||||
@ -24767,7 +24779,7 @@ packages:
|
||||
log-update: 4.0.0
|
||||
p-map: 4.0.0
|
||||
rfdc: 1.3.0
|
||||
rxjs: 7.6.0
|
||||
rxjs: 7.8.1
|
||||
through: 2.3.8
|
||||
wrap-ansi: 7.0.0
|
||||
dev: true
|
||||
@ -30303,11 +30315,10 @@ packages:
|
||||
dependencies:
|
||||
tslib: 2.1.0
|
||||
|
||||
/rxjs@7.6.0:
|
||||
resolution: {integrity: sha512-DDa7d8TFNUalGC9VqXvQ1euWNN7sc63TrUCuM9J998+ViviahMIjKSOU7rfcgFOF+FCD71BhDRv4hrFz+ImDLQ==}
|
||||
/rxjs@7.8.1:
|
||||
resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
|
||||
dependencies:
|
||||
tslib: 2.1.0
|
||||
dev: true
|
||||
|
||||
/sade@1.8.1:
|
||||
resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
|
||||
|
||||
@ -133,6 +133,7 @@ env:
|
||||
GRPC_INTERNAL_ERROR_LOGGING_LOG_PROTOBUF_MESSAGES_HANDLING_MAX_MESSAGE_SIZE_BYTES: "100MB"
|
||||
|
||||
TELEMETRY_GATEWAY_EXPORTER_EXPORT_ADDR: "http://127.0.0.1:10080"
|
||||
SRC_TELEMETRY_EVENTS_EXPORT_ALL: "true"
|
||||
|
||||
commands:
|
||||
server:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user