Session: wondrous-booping-lollipop-subagent-a5bdf2a — 2026-02-03

pro-desktop · Claude · branch master · claude-haiku-4-5-20251001 · 2026-02-03 13:14 · 1 msgs · 35 tools · 16 min read · updated 3 months ago

Find how Datadog events and metrics are sent in this codebase. Look for:

tools: Grep, Glob, Read
← pro-desktop Download .md .txt .json
Tool calls
Read Read: 18 calls (51.4%) 18 Grep Grep: 13 calls (37.1%) 13 Glob Glob: 4 calls (11.4%) 4
Token usage3.6M total
Input30.3K
Cache creation293.4K
Cache read3.2M
Output118
Cache hit ratio91%· healthy

Project: pro-desktop · Branch: master · Mode: ` · **Model:**claude-haiku-4-5-20251001`

Stats: 1 user messages, 35 tool calls, tools used: Grep, Glob, Read.

Conversation

Turn 1 — User

Find how Datadog events and metrics are sent in this codebase. Look for: - Existing Datadog event tracking implementations - Patterns for sending events to Datadog - Event naming conventions - Where Datadog client/service is configured - Examples of tracking user/account-level events

This will help understand how to implement the new tracking event for TI certificate types.

Turn 1 — Assistant

I'll search the codebase for Datadog event and metrics implementations. Let me start with a comprehensive search.

Tools used:

  • Grep: datadog|Datadog

Tools used:

  • Glob: **/*datadog*

Tools used:

  • Grep: sendEvent|trackEvent|recordEvent

Tool results:

→ result (ok): Found 54 files tools/skope/src/shared/components/icons/Icons.tsx tools/skope/src/routing/routeTree.gen.ts tools/skope/src/routing/navigation.ts tools/skope/src/features/feature-management/frontend/tests/api.test.ts tools/skope/src/features/bug-hunter/frontend/types.ts tools/skope/src/features/bug-hunter/frontend/components/index.ts tools/skope/src/features/bug-hunter/frontend/hooks/useBugHunterProgress.ts tools/skope/src/features/bug-hunter/frontend/components/BugListComponents.tsx tools/sko …(truncated, 2571 more chars)

Tool results:

→ result (ok): Found 16 files src/modules/kbv-mobile-card-reader/renderer/settings/MobileCardReaderView.tsx src/modules/kbv-check-encryption-module/renderer/components/preferences/sections/KbvCheckModule.tsx src/modules/kbv-check-encryption-module/renderer/components/preferences/sections/KbvEncryptionModule.tsx src/modules/gematik-ti-environment/renderer/components/preferences/sections/TiEnvironment.tsx src/core/print/renderer/settings/shared/test/PrintTestFileCard.tsx packages/desktop-bridge/src/client/compat …(truncated, 504 more chars)

Tool results:

→ result (ok): /Users/USER/workspace/doctolib/doctolib-pro-desktop/.git/refs/remotes/origin/FHIR-1702-send-received-payload-on-qes-gematik-to-datadog /Users/USER/workspace/doctolib/doctolib-pro-desktop/.git/logs/refs/remotes/origin/FHIR-1702-send-received-payload-on-qes-gematik-to-datadog /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/observability/services/tests/datadogTransport.test.ts /Users/USER/workspace/doctolib/doctolib-pro-desktop/.claude/agents/monitoring/datadog-query.md /Users/USER …(truncated, 730 more chars)

Good! I found key files. Let me examine the main Datadog service files:

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/observability/services/sendToDatadog.ts

Tool results:

→ result (ok): 1→import { flatten } from 'flat' 2→ 3→import { isDevOrTest } from 'src/constants' 4→ 5→import { getDoctolibWebContents } from '@core/app/main/helpers/webcontents-helper' 6→import { fetch } from '@core/network/services/network' 7→ 8→import { ZipperWebRepository } from '@module/zipper-web/services/zipperWebRepository' 9→import { ZipperDesktopRepo } from '@module/zipper-desktop/services/zipperDesktopRepo' 10→ 11→import { isNodeError } from 'src/utils' …(truncated, 3857 more chars)

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/product-events/services/capturePro.ts

Tool results:

→ result (ok): 1→import { 2→ Conf, 3→ DataCaptureEventPayload, 4→ EventKind, 5→ EventError, 6→ EventPayload, 7→ ClientStore, 8→ EnvironmentType, 9→ capturePro as productCapturePro, 10→ defaults as productEventsDefaults, 11→} from '@doctolib/product-events' 12→ 13→import { isDev, isProd, isStaging } from 'src/constants' 14→ 15→import { createLogger, errorIsIgnorable } from '@core/logger' 16→import { userConsentedToAnalytics } from '@co …(truncated, 16496 more chars)

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/observability/main/ObservabilityQueue.ts

Tool results:

→ result (ok): 1→import { TrackingLabel } from '@core/monitoring/constants/tracking' 2→ 3→import getSystemInformationObservability from '../services/get-system-information' 4→import { Label, ObservabilityTrackingResult } from '../interfaces/tracking' 5→import sendToDatadog from '../services/sendToDatadog' 6→import getFeatureUsageObservability from '../services/get-feature-usage' 7→ 8→const MAX_RETRIES = 5 9→ 10→interface ObservabilityEvent { 11→ trackingLabel: L …(truncated, 3380 more chars)

Now let me look for event tracking examples and constants:

Tools used:

  • Grep: trackingLabel|TrackingLabel

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/monitoring/constants/tracking.ts

Tool results:

→ result (ok): 1→/* 2→ * List of constants used for Tracking Events 3→ / 4→import { PerformanceMonitoringEvent } from '@core/monitoring' 5→ 6→import { TabName } from 'src/shared/constants/tabName' 7→ 8→export enum TrackingEvent { 9→ // To be Migrated to Product Events and currently on Observability only 10→ OpenTab = 'dpd_tab_open', 11→ UpdateDownloadSpeed = 'dpd_update_download_speed', 12→ // Updater 13→ CheckUpdateMenuClicked = 'dpd_check_for_upd …(truncated, 12129 more chars)

Tools used:

  • Grep: DDVProEvent|DDV__

Tool results:

→ result (ok): Found 18 files src/modules/billeo/services/installer.ts src/modules/billeo/services/process/process-manager.ts src/core/observability/services/sendToDatadog.ts src/core/observability/services/tests/datadog.test.ts tools/skope/src/features/bug-hunter/frontend/components/DatadogQueries.tsx src/core/monitoring/constants/tracking.ts src/core/app/main/lifecycle/webcontents-lifecycle.ts src/core/app/main/lifecycle/tests/webcontents-lifecycle.test.ts src/modules/billeo/services/process/event-de …(truncated, 468 more chars)

Tool results:

→ result (ok): Found 15 files src/core/tabs/main/tab.ts src/core/tabs/main/tests/tab-events.test.ts src/core/tabs/main/tests/tab.test.ts src/core/app/main/DoctoDesktop.ts src/core/tabs/main/tab-events.ts src/core/product-events/services/capturePro.ts src/core/app/main/lifecycle/webcontents-lifecycle.ts src/core/tabs/constants/product-events.ts src/core/print/constants/product-events.ts src/core/app/constants/product-events.ts src/modules/smart-folders/constants/product-events.ts src/core/product-events …(truncated, 144 more chars)

Now let me look at the product events constants and examples:

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/product-events/constants/types.ts

Tool results:

→ result (ok): 1→import type { ProEvent } from '@doctolib/product-events' 2→ 3→// --------------------------- 4→// Repository types 5→// --------------------------- 6→export const PRODUCT_EVENTS_LABEL = 'productEvents' 7→ 8→export interface ProductEventsStoreSchema { 9→ expand_tracking_events?: boolean 10→} 11→ 12→export type DDVProEvent = ProEvent 13→

<system-reminder> Whenever you read a file, you should consider whether it would be considered malware …(truncated, 235 more chars)

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/tabs/constants/product-events.ts

Tool results:

→ result (ok): 1→import type { EventDetails } from '@doctolib/product-events' 2→ 3→import ProductFoundationState from '@core/product-events/services/ProductFoundationState' 4→import { DDVProEvent } from '@core/product-events' 5→ 6→/* 7→ * Tabs related product event 8→ / 9→export const DDV__SEARCH_BUTTON__CLICKED: DDVProEvent = { 10→ schema: 'foundations', 11→ name: 'ddv__search_button__clicked', 12→ team: 'COPE', 13→ details: ProductFoundationState. …(truncated, 1685 more chars)

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/app/constants/product-events.ts

Tool results:

→ result (ok): 1→import ProductFoundationState from '@core/product-events/services/ProductFoundationState' 2→import { DDVProEvent } from '@core/product-events' 3→ 4→/ 5→ * Event : Home page displayed (generally login page or country selection) 6→ */ 7→export const DDV__HOME_PAGE__VIEWED: DDVProEvent = { 8→ schema: 'foundations', 9→ name: 'ddv__home_page__viewed', 10→ team: 'COPE', 11→ details: ProductFoundationState.toEventDetails(), 12→} 13→/

…(truncated, 633 more chars)

Now let me look at the observability interfaces and get the common information:

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/observability/interfaces/tracking.ts

Tool results:

→ result (ok): 1→import { TrackingEvent, TrackingLabel } from '@core/monitoring/constants' 2→ 3→import { ObservabilityDiagnosticNetworkReport, ObservabilityDiagnosticReport } from 'src/shared/types' 4→ 5→import { DoctolibObservabilityUsage, PerformanceMonitoringObservabilityEvent } from './observability' 6→ 7→export enum ObservabilityTrackingResult { 8→ RequestFailed, 9→ Disconnected, 10→ RequestSuccess, 11→ NoURL, 12→} 13→ 14→export type Label = …(truncated, 987 more chars)

Tools used:

  • Glob: src/core/observability/services/get-common*

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/product-events/services/ProductFoundationState.ts

Tool results:

→ result (ok): 1→import { nativeTheme } from 'electron' 2→import { DetailValue } from '@doctolib/product-events' 3→ 4→import { AppRepository } from '@core/app/services/appRepository' 5→import { getUpdaterChannelName } from '@core/auto-updater/main/updater-utils' 6→import { I18NRepository } from '@core/i18n/services/i18nRepository' 7→import { isNotificationEnabled } from '@core/notification' 8→import { DebugContext } from '@core/app/services/debugRepo' 9→import { ProxyRep …(truncated, 3104 more chars)

Tool results:

→ result (ok): /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/observability/services/get-common-information.ts

Now let me check the common information and ObservabilityState:

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/observability/services/get-common-information.ts

Tool results:

→ result (ok): 1→import { APP_VERSION } from 'src/constants' 2→ 3→import { installerVersion } from '@core/system-information/services/get-os-architecture' 4→import { Country } from '@core/variation-management' 5→import { hostnameInfo, osInfo } from '@core/system-information' 6→ 7→import State from 'src/utils/State' 8→ 9→import { 10→ CommonInfoObservability, 11→ ddvInfoObservability, 12→ DDV_EVENT_TYPE, 13→ DoctolibAccountObservability, 14→ Doctol …(truncated, 4498 more chars)

Tools used:

  • Glob: src/core/observability/main/ObservabilityState*

Tools used:

  • Grep: ObservabilityState|userId

Tool results:

→ result (ok): Found 20 files limit: 20, offset: 0 src/modules/padok-integration/renderer/settings/tests/PadokSettings.test.tsx src/modules/kbv-ti-connect/services/types.ts src/modules/gematik-kim/services/index.ts src/modules/gematik-kim/services/kim-payloads.ts src/modules/gematik-kim/services/client/email.ts src/core/sentry/services/sentry-transport.ts src/core/observability/services/sendToDatadog.ts src/core/observability/services/tests/datadog.test.ts src/core/logger/services/tests/logger-tran …(truncated, 701 more chars)

Tool results:

→ result (ok): /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/observability/main/ObservabilityState.ts

Let me read the ObservabilityState file:

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/observability/main/ObservabilityState.ts

Tool results:

→ result (ok): 1→import { 2→ CommonInfoObservability, 3→ SystemCPUInfoObservability, 4→ SystemMemoryInfoObservability, 5→ SystemRuntimeInfoObservability, 6→ SystemStorageInfoObservability, 7→ updaterObservability, 8→} from '@core/observability/interfaces/observability' 9→import { ProductLineConfig } from '@core/variation-management' 10→import { getAnonymisedHostname } from '@core/system-information/services/get-hostname' 11→ 12→function getAnonymisedUse …(truncated, 1862 more chars)

Tools used:

  • Grep: accountLevel|account_level|certificate.*type|ti.*certificate|TI.*cert

Tool results:

→ result (ok): Found 66 files src/modules/kbv-ti-connect/services/soap-client-helpers.ts src/modules/kbv-ti-connect/services/service-directory-service/tests/service-directory-service.test.ts src/modules/kbv-ti-connect/services/mock/mock-certificate.ts src/modules/kbv-ti-connect/services/service-directory-service/tests/connectorConfigurationValidator.test.ts src/modules/kbv-ti-connect/services/tests/soap-client-helpers.test.ts src/modules/kbv-ti-connect/services/tests/ti-connect.test.ts src/modu …(truncated, 3993 more chars)

Let me search for TI certificate type tracking and look at how events are currently sent:

Tools used:

  • Grep: ti.*certificate.*type|certificate_type|TI_CERT|certificateType

Tools used:

  • Grep: trackingLabel\s*[=:]|add\s*\(\s*\{\s*trackingLabel

Tool results:

→ result (ok): Found 1 file src/modules/kbv-ti-connect/services/server-certificate-helpers.ts

Tool results:

→ result (ok): Found 9 files limit: 30, offset: 0 src/core/observability/services/sendToDatadog.ts src/core/observability/services/tests/datadog.test.ts tools/skope/src/features/bug-hunter/frontend/components/DatadogQueries.tsx src/modules/zipper/main/tests/install.test.ts src/modules/icanopee-json/services/icanopee-json.test.ts src/modules/icanopee-json/services/icanopee-json.ts src/core/observability/services/tests/observabilityQueue.test.ts src/core/observability/main/ObservabilityQueue.ts src/c …(truncated, 26 more chars)

Let me look at real examples of how events are currently being tracked:

Tools used:

  • Grep: observabilityQueue\.add|sendTracking|capturePro\(

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/modules/icanopee-json/services/icanopee-json.ts

Tool results:

→ result (ok): 1→import { ChildProcess, fork } from 'node:child_process' 2→import i18n from 'i18next' 3→import { join } from 'node:path' 4→import { v4 as uuid } from 'uuid' 5→ 6→import { errorToString } from '@core/logger' 7→import { TrackingLabel } from '@core/monitoring' 8→import { sendToDatadog } from '@core/observability' 9→import createLogger from '@core/logger/services' 10→ 11→import { isSubdomainProd } from 'src/utils/subdomains' 12→ 13→import {

…(truncated, 10289 more chars)

Tool results:

→ result (ok): Found 17 files limit: 30, offset: 0 src/core/tabs/main/tab.ts src/core/print/services/printManager.ts src/core/print/main/handleFileDownloadAndPrint.ts src/core/print/main/index.ts src/core/app/main/DoctoDesktop.ts src/core/tabs/main/tab-events.ts src/core/product-events/services/capturePro.ts src/core/app/main/lifecycle/webcontents-lifecycle.ts src/core/app/main/helpers/tests/deeplink-helper.test.ts src/modules/installers/main/installer.ts src/modules/smart-folders/services/folder.ts src/co …(truncated, 245 more chars)

Now let me look at how product events are tracked with dynamic details:

Tools used:

  • Grep: capturePro\(\s*DDV__.*\(|DDV__.*=.*\(.*details

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/tabs/main/tab-events.ts

Tool results:

→ result (ok): 1→import { getTabsManager } from '@core/tabs/main/getTabsManager' 2→import { typeSafeIpcMain } from '@core/type-safe' 3→import { TrackingAction } from '@core/monitoring' 4→import { AppEvent } from '@core/app' 5→import { createLogger } from '@core/logger' 6→import { capturePro } from '@core/product-events' 7→import { ipcManager } from '@core/ipc-manager' 8→ 9→import { DDV__REFRESH_BUTTON__CLICKED } from '../constants/product-events' 10→import { TabChrom …(truncated, 7204 more chars)

Tool results:

→ result (ok): Found 3 files limit: 30, offset: 0 src/core/product-events/services/capturePro.ts src/core/tabs/services/TabCreationService.ts src/core/tabs/services/TabNavigationService.ts

Now let me check how events with dynamic details are implemented:

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/tabs/services/TabCreationService.ts (1–100)

Tool results:

→ result (ok): 1→import { BrowserWindow } from 'electron' 2→ 3→import { isDev } from 'src/constants' 4→ 5→import { createLogger } from '@core/logger' 6→import { sendCustomTrackingEventToObservability, TrackingAction, TrackingEvent } from '@core/monitoring' 7→import { capturePro } from '@core/product-events' 8→import { handleFileDownloadAndPrint } from '@core/print/main/handleFileDownloadAndPrint' 9→ 10→import { TCSModalListener } from '@module/telehealth' 11→impo …(truncated, 3638 more chars)

Tools used:

  • Grep: sendToDatadog\(|observabilityQueue\.add\(

Tool results:

→ result (ok): Found 5 files limit: 50, offset: 0 src/core/observability/services/sendToDatadog.ts src/core/observability/services/tests/datadog.test.ts src/modules/icanopee-json/services/icanopee-json.ts src/core/observability/main/ObservabilityQueue.ts src/core/observability/index.ts

Let me check where product events with dynamic details are sent and look at sendCustomTrackingEventToObservability:

Tools used:

  • Grep: sendCustomTrackingEventToObservability

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/tabs/main/tab-utils.ts

Tool results:

→ result (ok): 1→import { EventDetails } from '@doctolib/product-events' 2→ 3→import { getDoctolibURL } from 'src/utils' 4→ 5→import { TabName } from 'src/shared/constants/tabName' 6→ 7→/* 8→ * Mapping between pathname & localization key 9→ / 10→const tabTitleMapping = new Map<string, string>([ 11→ ['activity_page', 'shortcuts.activity'], 12→ ['bills', 'shortcuts.bills'], 13→ ['calendar', 'shortcuts.calendar'], 14→ ['configuration', 'shortcuts.c …(truncated, 3519 more chars)

Tool results:

→ result (ok): Found 30 files src/modules/gematik-idp-authentication/services/tests_electron/idpAuthenticator.test.ts src/modules/billeo/services/billeo.ts src/modules/billeo/services/installer.ts src/modules/billeo/services/process/process-manager.ts src/core/print/services/printManager.ts src/core/print/services/tests/printManager.test.ts src/core/print/main/tests/handleFileDownloadAndPrint.test.ts src/core/print/main/handleFileDownloadAndPrint.ts src/core/print/main/index.ts src/core/auto-update …(truncated, 1064 more chars)

Let me check the monitoring module for sendCustomTrackingEventToObservability:

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/monitoring/index.ts

Tool results:

→ result (ok): 1→export * from './constants' 2→export { default as performanceMonitoring } from './services/performance-monitoring' 3→export { enqueueCustomDatadogEvent as sendCustomTrackingEventToObservability } from '@core/observability' 4→export { enqueueObservabilityEvent as sendObservabilityEvent } from '@core/observability' 5→export { enqueueDatadogEvent as sendTrackingEventToObservability } from '@core/observability' 6→

<system-reminder> Whenever you read a file, you should con …(truncated, 279 more chars)

Tools used:

  • Glob: src/core/monitoring/**/*.ts

Tool results:

→ result (ok): /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/monitoring/constants/index.ts /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/monitoring/index.ts /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/monitoring/services/tests/performance-monitoring.test.ts /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/monitoring/services/helpers/to-mb.ts /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/monitoring/services/helpers/with-precision.ts / …(truncated, 640 more chars)

Now let me check the observability index for these functions:

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/observability/index.ts

Tool results:

→ result (ok): 1→import { isTest } from 'src/constants' 2→ 3→import { TrackingEventMap } from '@core/monitoring/constants/tracking' 4→ 5→import { Label, TrackingObservabilityEventMap } from './interfaces/tracking' 6→import observabilityQueue from './main/ObservabilityQueue' 7→ 8→export * from './interfaces/observability' 9→export * from './interfaces/tracking' 10→export { default as observabilityState } from './main/ObservabilityState' 11→export { default as getO …(truncated, 1905 more chars)

Tools used:

  • Grep: enqueueCustomDatadogEvent|enqueueDatadogEvent|enqueueObservabilityEvent

Tool results:

→ result (ok): Found 9 files src/core/store/main/storeRegistry.ts src/core/store/main/tests/storeRegistry.test.ts src/core/native-module-health/services/health-tracker.ts src/core/native-module-health/services/recovery-tracker.ts src/core/monitoring/services/performance-monitoring.ts src/core/monitoring/index.ts src/core/observability/services/tests/datadogTransport.test.ts src/core/observability/services/observability-winston-transport.ts src/core/observability/index.ts

Perfect! Now I have enough information. Let me look at one more example to understand the account-level tracking:

Tools used:

  • Read: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/utils/ti-connect-event-observability.ts

Tool results:

→ result (ok): 1→import winston from 'winston' 2→ 3→import { sendCustomTrackingEventToObservability, TrackingEvent } from '@core/monitoring' 4→ 5→import { ExtraLog, extraLogParser } from 'src/utils/extraLogParser' 6→ 7→export class TiConnectEventObservability { 8→ constructor( 9→ private readonly logger: winston.Logger, 10→ private readonly trackingEvent: TrackingEvent, 11→ private readonly moduleName: string, 12→ ) {} 13→ 14→ send(extra: …(truncated, 1036 more chars)

Perfect! Now I have comprehensive information about how Datadog events and metrics are sent in this codebase. Let me provide a detailed report.

Summary: Datadog Event and Metrics Tracking in Doctolib Pro Desktop

I've found two main tracking systems in the codebase for sending events to Datadog:

1. Observability Events (sendToDatadog - Direct HTTP to Datadog)

Location: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/observability/

Key Components: - sendToDatadog.ts - Main service that sends events directly to Datadog via HTTP POST - ObservabilityQueue.ts - Queues events and sends them with retry logic (max 5 retries, exponential backoff) - ObservabilityState.ts - Manages caching of observability info (userId, account info, product line)

Configuration: - URL is retrieved from Doctolib web interface: window.dl_constants?.NGINX_NEWRELIC_EVENT_URL - Uses fetch API to send POST requests - Flattens event structure before sending

Event Structure (Observability):

// From sendToDatadog.ts - Line 20-23
interface ObservabilityEvent {
  trackingLabel: string  // Event type/label
  [key: string]: unknown // Dynamic properties
}

// Sends with common info automatically enriched:
{
  eventType: 'DDV_EVENT_TYPE',
  ddv: { version, updater, installer },
  hostname: anonymisedHostname,
  doctolib: { account, organization },
  os: { version, architecture, platform, release, edition },
  zipper: { web, desktop, pms },
  trackingLabel: 'YOUR_LABEL',
  // ... custom event properties
}

How to Send (Observability):

import { sendToDatadog } from '@core/observability'

await sendToDatadog({
  trackingLabel: TrackingLabel.IcanopeeProcess,
  source: 'source_name',
  status: 'OK',
  command: 'command_name',
  duration: 1234,
  // ... other fields
})

2. Product Events (capturePro - High-Level Analytics)

Location: /Users/USER/workspace/doctolib/doctolib-pro-desktop/src/core/product-events/

Key Components: - capturePro.ts - Main entry point for product events - ProductFoundationState.ts - Caches app configuration state for events - CommonDetailsState.ts - Retrieves common details for enrichment

Event Structure (Product Events):

// From product-events/constants/types.ts
type DDVProEvent = ProEvent

// Typical event definition:
{
  schema: 'foundations',  // Schema name
  name: 'ddv__tab_close_button__clicked',  // Event name
  team: 'COPE',  // Owning team
  details: {  // Event details
    auto_updater_enabled: boolean,
    debug_mode_enabled: boolean,
    is_dark_mode_enabled: boolean,
    notifications_enabled: boolean,
    open_doctolib_at_start: boolean,
    proxy_enabled: boolean,
    spell_check_activated: boolean,
    updater_channel: string,
    // ... custom fields
  }
}

How to Send (Product Events):

import { capturePro } from '@core/product-events'
import { DDV__TAB_CLOSE_BUTTON__CLICKED } from '@core/tabs/constants/product-events'

// Simple event (no dynamic details)
capturePro(DDV__REFRESH_BUTTON__CLICKED)

// Event with dynamic details
capturePro(DDV__TAB_CLOSE_BUTTON__CLICKED({
  ddv_tab_type: 'doctolib',
  ddv_tab_count: 5
}))

3. Custom Observability Events (Flexible Tracking)

For one-off tracking without predefined event types:

import { sendCustomTrackingEventToObservability } from '@core/monitoring'

// Uses TrackingEvent enum or custom labels
sendCustomTrackingEventToObservability(TrackingEvent.KbvTiConnect, {
  action: 'certificate_loaded',
  certificate_type: 'SMC-K',
  status: 'success',
  duration_ms: 1234
})

Alternative (raw):

import { enqueueCustomDatadogEvent } from '@core/observability'

enqueueCustomDatadogEvent('CUSTOM_LABEL', {
  any_field: 'value',
  certificate_type: 'SMC-K'
})

Event Naming Conventions

Observability Events: - Format: dpd_*, ddv_*, kbv_*, ehr_*, etc. - Examples: dpd_tab_open, kbv_ti_connect, ddv_native_module_health_check_completed - Located in: /src/core/monitoring/constants/tracking.ts

Product Events: - Format: ddv__<feature>__<action> (snake_case) - Examples: ddv__tab_close_button__clicked, ddv__home_page__viewed - Located in: **/constants/product-events.ts (per-feature)


Account/User-Level Tracking

User Info: - Tracked via ObservabilityState.userId (anonymised hostname-based) - Account ID from Doctolib: doctolib_account_id (from monolith observability attributes) - Country and product line from: ObservabilityState.productLineConfig

How to Access:

import ObservabilityState from '@core/observability/main/ObservabilityState'

// Static properties automatically included in all events:
ObservabilityState.userId
ObservabilityState.observabilityAttributes  // Contains doctolib_account_id
ObservabilityState.productLineConfig?.country

Where Datadog Client is Configured

  1. Datadog URL: Retrieved from Doctolib web interface at runtime - window.dl_constants?.NGINX_NEWRELIC_EVENT_URL - Falls back to ObservabilityTrackingResult.NoURL if unavailable

  2. Network: Uses @core/network/services/network.fetch()

  3. User Consent: Both systems check userConsentedToAnalytics() before sending

  4. Environment Handling: - Dev/Test: Events logged locally, not sent to Datadog - Staging: Events shown in console with env flag - Production: Events sent with environment detection via subdomain


Example: Implementation Pattern for TI Certificate Type Tracking

Option 1: Using Observability (simpler, direct):

// In tracking.ts
export enum TrackingEvent {
  TiCertificateTypeDetected = 'ti_certificate_type_detected'
}

// In tracking interfaces
[TrackingEvent.TiCertificateTypeDetected]: {
  certificate_type: string
  account_id?: string
  country?: string
  status: 'success' | 'error'
}

// In your module
import { sendCustomTrackingEventToObservability, TrackingEvent } from '@core/monitoring'

sendCustomTrackingEventToObservability(TrackingEvent.TiCertificateTypeDetected, {
  certificate_type: 'SMC-K',
  account_id: String(accountId),
  country: productLineConfig?.country,
  status: 'success'
})

Option 2: Using Product Events (for feature-level tracking):

// In constants/product-events.ts
export const DDV__TI_CERTIFICATE__DETECTED: DDVProEvent = {
  schema: 'ti_connect',
  name: 'ddv__ti_certificate__detected',
  team: 'FIRE',  // Appropriate team
  details: ProductFoundationState.toEventDetails()
}

// In your module
import { capturePro } from '@core/product-events'

capturePro(DDV__TI_CERTIFICATE__DETECTED)

Key Files Reference

File Purpose
/src/core/observability/services/sendToDatadog.ts HTTP sender to Datadog
/src/core/observability/main/ObservabilityQueue.ts Event queueing with retry
/src/core/product-events/services/capturePro.ts High-level product event API
/src/core/monitoring/constants/tracking.ts Event type definitions
/src/core/product-events/index.ts Product events exports
/src/utils/ti-connect-event-observability.ts TI-specific tracking example

Keyboard shortcuts

⌘K / Ctrl+KOpen command palette
/Focus search
g hGo to home
g pGo to projects
g sGo to sessions
j / kNext / prev row (tables)
?Show this help
EscClose dialogs

Structured queries

Mix key:value filters with free text in the palette:

type:sessionOnly session pages
project:llm-wikiFilter by project name (substring)
model:claudeFilter by model name (substring)
date:>2026-03-01Sessions after a date
date:<2026-04-01Sessions before a date
tags:rustPages mentioning a tag/topic
sort:dateSort results by date (newest first)

Example: type:session project:llm-wiki date:>2026-04 sort:date