Overview
Sentry Options is a multi-language configuration system with JSON schemas as the source of truth. It provides validated, hot-reloadable options without database overhead, replacing database-stored configuration with git-managed, schema-validated config files.
Key benefits:
- Fast reads - Options loaded in memory, file reads only on init and updates
- Schema validation - Type-safe options with defaults
- Hot-reload - Values update without pod restart (~1-2 min propagation)
- Audit trail - All changes tracked in git
Component flow
┌─────────────────────────────────────────────────────────────────┐
│ Build Time │
│ service repo (e.g., seer) │
│ └── sentry-options/schemas/seer/schema.json ──→ Docker image│
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ CI Pipeline │
│ sentry-options-automator repo │
│ └── option-values/seer/default/values.yaml │
│ ↓ │
│ sentry-options-cli (validates against schema) │
│ ↓ │
│ ConfigMap applied to cluster │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Runtime │
│ Kubernetes Pod │
│ ├── /etc/sentry-options/schemas/seer/schema.json (image) │
│ └── /etc/sentry-options/values/seer/values.json (ConfigMap) │
│ ↓ │
│ sentry_options client library │
│ - Validates values against schema │
│ - Polls for file changes (5s interval) │
│ - Returns defaults when values missing │
└─────────────────────────────────────────────────────────────────┘
Components
| Component | Location | Purpose |
|---|
| Schemas | Service repo (e.g., seer/sentry-options/schemas/) | Define options with types and defaults |
| Values | sentry-options-automator/option-values/ | Runtime configuration values |
| CLI | sentry-options-cli | Fetches schemas, validates YAML, generates ConfigMaps |
| Client (Python) | sentry_options (Python) | Reads options at runtime with hot-reload |
| Client (Rust) | sentry-options (Rust) | Reads options at runtime with hot-reload |
| Validation library | sentry-options-validation | Shared validation logic for CLI and clients |
Repository structure
The main sentry-options repository is organized as follows:
sentry-options/
├── Cargo.toml # Root Cargo workspace
├── schemas/ # Example JSON schemas
│ ├── getsentry/
│ │ └── schema.json
│ ├── relay/
│ │ └── schema.json
│ └── sentry/
│ └── schema.json
│
├── clients/ # Language-specific clients
│ ├── rust/ # Rust client library
│ │ └── src/lib.rs
│ │
│ └── python/ # Python client (PyO3 bindings)
│ ├── src/lib.rs
│ └── pyproject.toml
│
├── sentry-options-cli/ # CLI tool
│ ├── Cargo.toml
│ └── src/
│ ├── main.rs
│ ├── loader.rs
│ └── output.rs
│
├── sentry-options-validation/ # Shared validation library
│ ├── Cargo.toml
│ └── src/lib.rs
│
└── .github/
├── workflows/ # CI/CD
└── actions/
└── validate-schema/ # Composite action for schema validation
Client library architecture
Rust client
The Rust client (clients/rust/src/lib.rs) provides:
- Global initialization:
init() function sets up a global Options instance
- Namespace-based access:
options(namespace) returns a NamespaceOptions handle
- Thread-safe reads: Uses
Arc<RwLock<>> for shared state
- Automatic hot-reload: Background watcher thread integrated
Key types:
Options - Main options store with schema registry and values
NamespaceOptions - Handle for accessing options in a specific namespace
OptionsError - Error types for unknown namespaces/options
Python client
The Python client (clients/python/src/lib.rs) is implemented as PyO3 bindings to the Rust client:
- Thin wrapper: Delegates to Rust implementation
- Python-native types: Converts JSON values to Python bool, int, float, str, list
- Exception hierarchy: Custom exceptions for different error types
- Same API: Mirrors Rust client interface
Exceptions:
OptionsError - Base exception
SchemaError - Schema loading/validation failures
UnknownNamespaceError - Unknown namespace access
UnknownOptionError - Unknown option access
InitializationError - Already initialized error
Validation library
The shared validation library (sentry-options-validation/src/lib.rs) provides:
- SchemaRegistry: Loads and stores namespace schemas from disk (lib.rs:218-467)
- NamespaceSchema: Individual schema with validator and option metadata (lib.rs:175-216)
- ValuesWatcher: Background thread for file watching and hot-reload (lib.rs:483-672)
- Path resolution: Fallback chain for locating options directory (lib.rs:88-99)
Design decisions
Runtime validation (no codegen)
Schemas are loaded at runtime and values are validated against them.
Rationale:
- No build-time dependencies
- Can update schemas without rebuilding clients
- Simple to understand and debug
File watching strategy
Background thread with interval polling (not inotify/FSEvents) every 5 seconds.
Rationale:
- Works reliably with Kubernetes ConfigMaps, NFS, virtual filesystems
- Simple to implement and debug
- ConfigMap propagation is ~1-2 minutes, so 5s polling is acceptable overhead
Implementation details:
- Polls modification time of all
values.json files (lib.rs:548-583)
- Reloads all namespaces if any file changed (lib.rs:586-610)
- Emits Sentry transaction per namespace with metrics (lib.rs:612-644)
- Old values persist if validation fails (lib.rs:1389-1415)
Strict validation
Reject unknown options, fail fast on type mismatches.
Behavior:
- Unknown keys in values file → Error (catches typos)
- Type mismatch → Error
null values → Error (use defaults instead)
additionalProperties: false auto-injected (lib.rs:368-371)
JSON number handling
- Schema says
integer → Reject 5.5, accept 5
- Schema says
number → Accept both 5 and 5.5
Validated using jsonschema crate.
Configuration paths
The client libraries use a fallback chain to locate the options directory:
SENTRY_OPTIONS_DIR environment variable (if set)
/etc/sentry-options (if exists) - production path
sentry-options/ (local fallback) - development
Implementation: resolve_options_dir() in lib.rs:88-99
Within the options directory, the expected structure is:
/etc/sentry-options/
├── schemas/ # Baked into Docker image
│ └── {namespace}/
│ └── schema.json
└── values/ # Mounted via ConfigMap
└── {namespace}/
└── values.json
Environment variables
| Variable | Purpose | Default |
|---|
SENTRY_OPTIONS_DIR | Override options directory path | (uses fallback chain) |
SENTRY_OPTIONS_SUPPRESS_MISSING_DIR | Suppress missing directory errors | false |
Observability
The validation library includes a dedicated Sentry integration for tracking hot-reload operations:
- Dedicated DSN: Uses separate Sentry project (lib.rs:35-36)
- Transaction per namespace: Emitted on each reload (lib.rs:612-644)
- Metrics included:
reload_duration_ms - Time to reload and validate values
generated_at - When ConfigMap was generated (from values.json)
applied_at - When application loaded values
propagation_delay_secs - Time from generation to application
The dedicated Sentry Hub is isolated from the host application’s Sentry setup (lib.rs:42-63), ensuring observability metrics don’t interfere with application telemetry.