Skip to content

feat(SDK-492): add observability hooks with PII protection#1237

Open
dmortal wants to merge 15 commits intomainfrom
da/perf
Open

feat(SDK-492): add observability hooks with PII protection#1237
dmortal wants to merge 15 commits intomainfrom
da/perf

Conversation

@dmortal
Copy link
Contributor

@dmortal dmortal commented Mar 12, 2026

Summary

Adds comprehensive observability hooks for error tracking and performance monitoring with built-in PII protection. SDK consumers can now integrate with tools like Sentry, Datadog, or custom monitoring solutions to track errors and performance metrics.

Usage Example:

import { GustoProvider } from '@gusto/embedded-react-sdk'
import type { ObservabilityHook } from '@gusto/embedded-react-sdk'
import * as Sentry from '@sentry/react'

const observability: ObservabilityHook = {
  onError: (error) => {
    Sentry.captureException(error.originalError, {
      level: error.type === 'validation_error' ? 'warning' : 'error',
      tags: {
        error_type: error.type,
        component: error.context.componentName, // Automatically set by SDK
      },
    })
  },
  onMetric: (metric) => {
    // Track performance metrics
    console.log(`[Metric] ${metric.name}: ${metric.value}${metric.unit}`)
  },
  sanitization: {
    enabled: true, // default
    includeOriginalError: false, // default - excludes PII
    additionalSensitiveFields: ['internalId', 'taxId'],
  }
}

<GustoProvider
  config={{
    baseUrl: '/api/',
    observability,
  }}
  components={components}
>
  <YourApp />
</GustoProvider>

// Component names are automatically tracked
<Employee.Profile
  companyId={companyId}
  employeeId={employeeId}
  onEvent={handleEvent}
/>

Changes

  • Added ObservabilityHook interface with onError and onMetric callbacks
  • Implemented automatic PII sanitization (SSN, emails, phone numbers, credit cards, sensitive field names)
  • Added error tracking for boundary errors, validation errors, API errors, and internal errors
  • Added performance metrics for form submissions and component loading
  • Components automatically report their names in error context and metrics for precise tracking
  • Created comprehensive documentation with integration examples for Sentry, Datadog, and custom solutions

Related

Testing

Manual Testing:

  1. Configure observability hook in GustoProvider
  2. Trigger errors (boundary, validation, API) and verify they're reported with component names
  3. Submit forms and verify metrics are tracked
  4. Test PII sanitization with sample data containing SSN, emails, etc.

Automated Tests:

npm run tsc                     # ✅ TypeScript compilation passes
npm run test -- --run           # ✅ All 130 test files pass (1438 tests)
npm run test -- --run src/contexts/ObservabilityProvider/sanitization.test.ts  # ✅ 20 PII sanitization tests

Test Results:

  • TypeScript: ✅ No errors
  • Tests: ✅ 1438 tests passing (including 20 new sanitization tests)
  • Linting: ✅ No issues

Documentation:

  • docs/integration-guide/observability.md - Complete guide
  • docs/integration-guide/observability-examples.md - Integration examples

@dmortal dmortal marked this pull request as ready for review March 13, 2026 17:25
Copilot AI review requested due to automatic review settings March 13, 2026 17:25
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds an SDK-level observability hook (errors + performance metrics) intended for integration with external monitoring tools, with built-in PII sanitization before data leaves the SDK.

Changes:

  • Introduces ObservabilityHook + related types, and wires an ObservabilityProvider into the provider tree.
  • Adds PII sanitization utilities with tests, and a wrapper hook to sanitize data before invoking consumer callbacks.
  • Emits observability events for error boundaries and form submit / suspense-loading durations, plus docs for usage/integrations.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
src/types/observability.ts Defines public observability types and sanitization config.
src/index.ts Exports observability types and createObservabilityError from package entrypoint.
src/contexts/index.ts Re-exports observability context/provider APIs.
src/contexts/ObservabilityProvider/useSanitizedObservability.ts Wraps callbacks to sanitize errors/metrics before dispatching.
src/contexts/ObservabilityProvider/useObservability.ts Context hook returning a sanitized observability hook.
src/contexts/ObservabilityProvider/sanitization.ts Implements recursive sanitization + PII redaction patterns.
src/contexts/ObservabilityProvider/sanitization.test.ts Adds sanitization unit tests.
src/contexts/ObservabilityProvider/observabilityUtils.ts Converts known SDK error classes into ObservabilityError.
src/contexts/ObservabilityProvider/index.ts Public exports for the ObservabilityProvider module.
src/contexts/ObservabilityProvider/ObservabilityProvider.tsx Context provider for passing consumer observability hook.
src/contexts/ObservabilityProvider/ObservabilityContext.ts Creates observability React context value type.
src/contexts/GustoProvider/GustoProviderCustomUIAdapter.tsx Wraps app with ObservabilityProvider and reports top-level boundary errors.
src/components/Contractor/Payments/CreatePayment/CreatePayment.tsx Supplies a component name into BaseComponent for tagging.
src/components/Base/useBaseSubmit.ts Emits observability errors + submit duration metrics on base submits.
src/components/Base/useBase.tsx Extends BaseContext to include an optional component name.
src/components/Base/Base.tsx Emits boundary errors + suspense loading-duration metrics, propagates component name.
docs/integration-guide/observability.md Adds observability + sanitization documentation and integration guidance.
docs/integration-guide/observability-examples.md Adds sample implementations (console/Sentry/Datadog/custom).
docs/integration-guide/error-handling.md Links error handling docs to observability hooks.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +8 to +13
if (context === undefined) {
return { observability: undefined }
}

const sanitizedObservability = useSanitizedObservability(context.observability)

// Sample metrics at different rates based on name
const sampleRates: Record<string, number> = {
'sdk.form.submit_duration': 0.1, // 10% of form submissions
'sdk.component.mount': 0.01, // 1% of component mounts
}

export interface ObservabilityMetric {
/** Metric name (e.g., 'sdk.component.mount', 'sdk.form.submit_duration') */
Comment on lines +55 to +56
/** The original error object */
originalError: unknown
dmortal added 8 commits March 13, 2026 15:26
- Pass additionalSensitiveFields to sanitizeObject instead of mutating global array
- Ensure consistent sanitization behavior across error and metric calls
- Prevent config leakage between different SDK instances
- Add tests to verify non-mutation and consistent behavior

Made-with: Cursor
- Import and use sanitizeError in GustoProviderCustomUIAdapter
- Ensure top-level internal_error reports respect sanitization config
- Prevent PII leakage in message, stack, and originalError
- Add tests to verify sanitization behavior for top-level errors

Made-with: Cursor
- Store observability and componentName in refs that update on change
- Ensures cleanup function uses current values, not stale mount-time captures
- Fixes metrics reporting incorrect observability hook or component name if they change during suspense

Made-with: Cursor
- Update docs to indicate componentName is reported 'when available'
- Note that not all SDK components currently report their names
- Add clarification that componentName may be undefined
- Adjust metric table to reflect 'when available' status

Made-with: Cursor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants