Skip to main content
The sentry-options client libraries provide a simple API for reading configuration values with automatic hot-reload support.

Installation

pyproject.toml
dependencies = [
    "sentry_options>=0.0.14",
]

Basic usage

Initialization

Initialize the library once during application startup:
from sentry_options import init

# Call once early in your application startup
init()
The init() function:
  • Loads all schemas from /etc/sentry-options/schemas/ (or SENTRY_OPTIONS_DIR)
  • Loads values from /etc/sentry-options/values/
  • Validates values against schemas
  • Starts background file watcher for hot-reload
Call init() only once during application startup. Calling it multiple times will raise an InitializationError (Python) or AlreadyInitialized error (Rust).

Reading options

Access options by namespace:
from sentry_options import options

# Get namespace handle
opts = options('seer')

# Read values - returns Python native types
enabled: bool = opts.get('feature.enabled')
rate_limit: int = opts.get('feature.rate_limit')
sample_rate: float = opts.get('traces.sample-rate')
url: str = opts.get('system.url-prefix')
slugs: list[str] = opts.get('feature.enabled_slugs')

Complete examples

Python example

From the test application:
examples/python/main.py
"""An example usage of the Python options client library.

Every 3 seconds, prints out the value of example-option, float-option,
and bool-option.

Updating values in `../values` will be reflected in stdout.
Ctrl+C to exit.
"""
from __future__ import annotations

import time

from sentry_options import init
from sentry_options import options

init()
testing = options('sentry-options-testing')

while True:
    time.sleep(3)
    example_val = testing.get('example-option')
    float_val = testing.get('float-option')
    bool_val = testing.get('bool-option')
    string_val = testing.get('string-option')
    print(
        f"values: {example_val} | {float_val} | {bool_val} | {string_val}",
        flush=True,
    )

Rust example

From the test application:
examples/rust/src/main.rs
use std::{thread::sleep, time::Duration};

use sentry_options::{init, options};

/// An example usage of the Rust options client library
/// Every 3 seconds, prints out the value of example-option, float-option, and bool-option
///
/// Updating values in `../values` will be reflected in stdout
/// ^C to exit
fn main() -> anyhow::Result<()> {
    init()?;
    let sentry_options = options("sentry-options-testing");

    loop {
        sleep(Duration::from_secs(3));
        let string_value = sentry_options.get("example-option")?;
        let float_value = sentry_options.get("float-option")?;
        let bool_value = sentry_options.get("bool-option")?;
        println!(
            "values: {} | {} | {}",
            string_value, float_value, bool_value
        );
    }
}

Advanced usage

Checking if a value is set

Determine whether an option has an explicit value or is using the schema default:
from sentry_options import options

opts = options('seer')

# Check if value is explicitly set
if opts.isset('feature.enabled'):
    print("Feature enabled is explicitly configured")
else:
    print("Feature enabled is using schema default")
Returns:
  • True if the option has an explicit value in the values file
  • False if using the schema default
  • Raises UnknownOptionError if option doesn’t exist in schema

Error handling

from sentry_options import (
    init,
    options,
    OptionsError,
    SchemaError,
    UnknownNamespaceError,
    UnknownOptionError,
    InitializationError,
)

# Handle initialization errors
try:
    init()
except SchemaError as e:
    print(f"Schema validation failed: {e}")
except InitializationError as e:
    print(f"Already initialized: {e}")

# Handle read errors
try:
    opts = options('seer')
    value = opts.get('feature.enabled')
except UnknownNamespaceError:
    print("Namespace 'seer' not found")
except UnknownOptionError:
    print("Option 'feature.enabled' not found")
except OptionsError as e:
    print(f"Options error: {e}")

Hot-reload behavior

The client library automatically reloads values when the ConfigMap changes:
  • Polling interval: 5 seconds (file system is checked every 5 seconds)
  • ConfigMap propagation: ~1-2 minutes (Kubernetes kubelet sync period)
  • Total latency: ConfigMap update → ~1-2 min → file update → ~5 sec → reload
No pod restart is required when values change. The library detects file changes and atomically updates the in-memory values.

Configuration paths

The client library searches for configuration in this order:
  1. SENTRY_OPTIONS_DIR environment variable - If set, uses this path
  2. /etc/sentry-options - Production path (if directory exists)
  3. ./sentry-options - Local development fallback
Expected directory structure:
{SENTRY_OPTIONS_DIR}/
├── schemas/                   # Baked into Docker image
│   └── {namespace}/
│       └── schema.json
└── values/                    # Mounted via ConfigMap
    └── {namespace}/
        └── values.json
Example production structure:
/etc/sentry-options/
├── schemas/seer/schema.json          # From Docker image
└── values/seer/values.json           # From ConfigMap

Type conversion

Python

JSON values are automatically converted to Python native types:
JSON TypePython Type
stringstr
integerint
numberfloat
booleanbool
arraylist

Rust

Values are returned as serde_json::Value. Use the standard conversion methods:
let value = opts.get("option-name")?;

// Convert to specific types
let s: &str = value.as_str().unwrap();
let i: i64 = value.as_i64().unwrap();
let f: f64 = value.as_f64().unwrap();
let b: bool = value.as_bool().unwrap();
let arr: &Vec<Value> = value.as_array().unwrap();

Performance considerations

  • Fast reads: Options are loaded in memory, no file I/O on get()
  • File watching: Background thread polls every 5 seconds (minimal overhead)
  • Thread-safe: Multiple threads can safely read options concurrently
  • Atomic updates: Value reloads are atomic (no partial state visible)

Next steps

Test locally

Override values during development

Schema definition

Learn about supported types and validation

Build docs developers (and LLMs) love