tempestweb.observability¶
Adapter-pattern providers for what a production app needs and does not want to couple to: telemetry, structured logging, an error boundary, feature flags and authentication. Each ships a default implementation and accepts yours.
Guide with examples: Observability.
tempestweb.observability ¶
Trilho O — production / observability providers (adapter pattern).
Every provider here follows the same shape: a tiny, stable interface application code calls, plus one or more swappable adapters behind it. Changing the backend (console -> Sentry, in-memory flags -> LaunchDarkly, ...) never touches a call site.
Modules
* :mod:`telemetry` (O0) — ``track`` / ``identify`` with console/Sentry/PostHog
adapters.
* :mod:`logger` (O1) — structured logging with pluggable sinks and typed
levels.
* :mod:`error_boundary` (O2) — render-error fallback widget/decorator plus a
report hook into telemetry.
* :mod:`feature_flags` (O3) — runtime toggles with in-memory / GrowthBook /
LaunchDarkly adapters.
* :mod:`auth` (O4) — token store, route guard, JWT helpers and a refresh queue
that serializes concurrent renewals.
Import everything from this package level rather than from submodules.
AuthState ¶
A snapshot of the current authentication state.
Attributes:
| Name | Type | Description |
|---|---|---|
token |
str | None
|
The current access token, or |
user |
dict[str, Any] | None
|
The current user payload, or |
Source code in tempestweb/observability/auth.py
AuthStore ¶
An observable store of the current token and user.
Mutations (login / logout / set_token) notify subscribers, which
is how an auth change drives a re-render (e.g. swapping a login screen for the
app). The store holds no refresh logic itself — pair it with a
:class:RefreshQueue for that.
Source code in tempestweb/observability/auth.py
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | |
token
property
¶
The current access token, or None when logged out.
Returns:
| Type | Description |
|---|---|
str | None
|
The token, or |
user
property
¶
The current user payload, or None when logged out.
Returns:
| Type | Description |
|---|---|
dict[str, Any] | None
|
The user payload, or |
is_authenticated
property
¶
Whether a token is currently present.
Returns:
| Type | Description |
|---|---|
bool
|
|
state
property
¶
An immutable snapshot of the current state.
Returns:
| Name | Type | Description |
|---|---|---|
An |
AuthState
|
class: |
login ¶
Set the token (and optional user) and notify subscribers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
token
|
str
|
The access token to store. |
required |
user
|
dict[str, Any] | None
|
The user payload to store, if known. |
None
|
Returns:
| Type | Description |
|---|---|
None
|
None. |
Source code in tempestweb/observability/auth.py
set_token ¶
Replace the access token (e.g. after a refresh) and notify.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
token
|
str
|
The new access token. |
required |
Returns:
| Type | Description |
|---|---|
None
|
None. |
logout ¶
Clear the token and user and notify subscribers.
Returns:
| Type | Description |
|---|---|
None
|
None. |
subscribe ¶
Register a listener fired on every auth change.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
listener
|
AuthListener
|
A zero-argument callback invoked on change. |
required |
Returns:
| Type | Description |
|---|---|
Callable[[], None]
|
An unsubscribe callable. |
Source code in tempestweb/observability/auth.py
JWTError ¶
RefreshQueue ¶
Serializes concurrent token refreshes into a single in-flight renewal.
When a token expires, many requests can discover it at once and each try to refresh. Without coordination that fires N parallel renewals, races the store, and can invalidate each other's refresh tokens. This queue ensures exactly one refresh runs: the first caller starts it, every concurrent caller awaits the same result, and the new token is pushed into the store once. After it settles the queue resets so a later expiry refreshes again.
Source code in tempestweb/observability/auth.py
refresh_calls
property
¶
The number of times the underlying refresh_fn was actually run.
Useful in tests to assert that concurrent callers collapsed into a single renewal.
Returns:
| Type | Description |
|---|---|
int
|
The count of real refresh invocations. |
refresh
async
¶
Return a fresh token, coalescing concurrent callers into one renewal.
The first caller schedules the real renewal as a single
:class:asyncio.Task and stores it; every concurrent caller awaits that
same task instead of starting its own. The task resolves once for all
waiters, then the in-flight slot is cleared so a future expiry triggers a
new renewal. If the renewal raises, the exception propagates to every
waiter and the slot is cleared so a retry is possible.
Returns:
| Type | Description |
|---|---|
str
|
The new access token. |
Raises:
| Type | Description |
|---|---|
Exception
|
Whatever |
Source code in tempestweb/observability/auth.py
ErrorBoundary ¶
Bases: Component
A component that contains a render error in its wrapped subtree.
On :meth:render it invokes child_builder. If that returns a widget, the
widget is rendered unchanged. If it raises, the boundary captures the error
into an :class:ErrorInfo, calls on_error (if set) for reporting, and
returns fallback_builder(info) instead — so the exception never escapes
and the surrounding tree keeps rendering.
Source code in tempestweb/observability/error_boundary.py
render ¶
Render the protected subtree, falling back on any render error.
Returns:
| Type | Description |
|---|---|
Widget
|
The child's widget on success, or the fallback widget on failure. |
Source code in tempestweb/observability/error_boundary.py
ErrorInfo
dataclass
¶
A captured render failure, passed to the fallback and report hooks.
Attributes:
| Name | Type | Description |
|---|---|---|
error |
BaseException
|
The exception instance that was raised during render. |
error_type |
str
|
The exception class name (e.g. |
message |
str
|
The exception's string message. |
stack |
str
|
The formatted traceback, preserved for reporting rather than being swallowed. |
Source code in tempestweb/observability/error_boundary.py
from_exception
classmethod
¶
Build an :class:ErrorInfo from a raised exception.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
error
|
BaseException
|
The exception caught during render. |
required |
Returns:
| Type | Description |
|---|---|
ErrorInfo
|
A populated :class: |
Source code in tempestweb/observability/error_boundary.py
FeatureFlagsAdapter ¶
Bases: Protocol
The minimal contract every feature-flag backend must satisfy.
The interface is intentionally tiny (roughly twenty lines to implement):
fetch a value, and register a change subscription. get must never raise
for an unknown key — it returns the provided default — so the provider
can stay fail-safe.
Source code in tempestweb/observability/feature_flags.py
get ¶
Return the value of a flag, or default if unknown.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The flag key. |
required |
default
|
FlagValue
|
The value to return when the flag is not present. |
None
|
Returns:
| Type | Description |
|---|---|
FlagValue
|
The flag value, or |
Source code in tempestweb/observability/feature_flags.py
subscribe ¶
Register a listener fired whenever any flag changes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
listener
|
ChangeListener
|
A zero-argument callback invoked on change. |
required |
Returns:
| Type | Description |
|---|---|
Callable[[], None]
|
An unsubscribe callable that removes the listener. |
Source code in tempestweb/observability/feature_flags.py
FeatureFlagsProvider ¶
A backend-agnostic facade application code calls to read flags.
The provider forwards reads to its :class:FeatureFlagsAdapter and fans the
adapter's change notifications out to its own subscribers. is_enabled
coerces any value to a boolean so a gate check is uniform regardless of the
underlying value type. Swapping the adapter changes the flag source while
leaving every is_enabled / get / on_change call untouched.
Source code in tempestweb/observability/feature_flags.py
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | |
adapter
property
¶
The adapter currently backing this provider.
Returns:
| Type | Description |
|---|---|
FeatureFlagsAdapter
|
The active :class: |
get ¶
Return a flag's value, or default when unknown.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The flag key. |
required |
default
|
FlagValue
|
The value returned when the flag is absent. |
None
|
Returns:
| Type | Description |
|---|---|
FlagValue
|
The flag value, or |
Source code in tempestweb/observability/feature_flags.py
is_enabled ¶
Return whether a flag is truthy, defaulting safely when unknown.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The flag key. |
required |
default
|
bool
|
The boolean returned when the flag is absent. |
False
|
Returns:
| Type | Description |
|---|---|
bool
|
|
Source code in tempestweb/observability/feature_flags.py
on_change ¶
Register a listener fired whenever any flag changes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
listener
|
ChangeListener
|
A zero-argument callback invoked on change. |
required |
Returns:
| Type | Description |
|---|---|
Callable[[], None]
|
An unsubscribe callable that removes |
Source code in tempestweb/observability/feature_flags.py
GrowthBookFeatureFlagsAdapter ¶
An adapter that maps flag reads onto an injected GrowthBook instance.
growthbook is not a tempestweb dependency; the caller injects a client
exposing is_on(key) / get_feature_value(key, default). GrowthBook
does not push change events in this minimal wrapper, so :meth:refresh
re-evaluates and notifies subscribers after the caller reloads features.
Source code in tempestweb/observability/feature_flags.py
get ¶
Return a feature value from GrowthBook.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The feature key. |
required |
default
|
FlagValue
|
The value returned when the feature is absent. |
None
|
Returns:
| Type | Description |
|---|---|
FlagValue
|
The feature value, or |
Source code in tempestweb/observability/feature_flags.py
subscribe ¶
Register a change listener fired by :meth:refresh.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
listener
|
ChangeListener
|
A zero-argument callback invoked on change. |
required |
Returns:
| Type | Description |
|---|---|
Callable[[], None]
|
An unsubscribe callable. |
Source code in tempestweb/observability/feature_flags.py
refresh ¶
Notify subscribers after the caller reloads GrowthBook features.
Returns:
| Type | Description |
|---|---|
None
|
None. |
InMemoryFeatureFlagsAdapter ¶
A dependency-free adapter backed by an in-process dict.
Ideal for tests, local development and a safe default when no remote backend
is configured. Mutating a flag through :meth:set notifies subscribers,
which is how a flag flip drives a re-render in unit tests.
Source code in tempestweb/observability/feature_flags.py
get ¶
Return a flag's value, or default when unknown.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The flag key. |
required |
default
|
FlagValue
|
The value returned when the flag is absent. |
None
|
Returns:
| Type | Description |
|---|---|
FlagValue
|
The flag value, or |
Source code in tempestweb/observability/feature_flags.py
set ¶
Set a flag and notify subscribers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The flag key. |
required |
value
|
FlagValue
|
The new value. |
required |
Returns:
| Type | Description |
|---|---|
None
|
None. |
subscribe ¶
Register a change listener.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
listener
|
ChangeListener
|
A zero-argument callback invoked on change. |
required |
Returns:
| Type | Description |
|---|---|
Callable[[], None]
|
An unsubscribe callable. |
Source code in tempestweb/observability/feature_flags.py
LaunchDarklyFeatureFlagsAdapter ¶
An adapter that maps flag reads onto an injected LaunchDarkly client.
launchdarkly-server-sdk is not a tempestweb dependency; the caller
injects a client exposing variation(key, context, default) plus a stored
evaluation context. LaunchDarkly streams updates, so the caller wires the
SDK's update callback to :meth:notify.
Source code in tempestweb/observability/feature_flags.py
get ¶
Return a flag variation from LaunchDarkly.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The flag key. |
required |
default
|
FlagValue
|
The value returned when evaluation falls back. |
None
|
Returns:
| Type | Description |
|---|---|
FlagValue
|
The evaluated variation, or |
Source code in tempestweb/observability/feature_flags.py
subscribe ¶
Register a change listener fired by :meth:notify.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
listener
|
ChangeListener
|
A zero-argument callback invoked on change. |
required |
Returns:
| Type | Description |
|---|---|
Callable[[], None]
|
An unsubscribe callable. |
Source code in tempestweb/observability/feature_flags.py
notify ¶
Notify subscribers when LaunchDarkly streams a flag update.
Returns:
| Type | Description |
|---|---|
None
|
None. |
Logger ¶
A structured logger that fans records out to its sinks above a threshold.
Records below level are dropped before any sink runs, so an expensive
network sink never sees a filtered-out DEBUG line. A sink that raises is
isolated: the remaining sinks still receive the record, because one broken
destination must not take down logging for the rest.
Source code in tempestweb/observability/logger.py
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | |
level
property
¶
The current minimum severity threshold.
Returns:
| Type | Description |
|---|---|
LogLevel
|
The active :data: |
set_level ¶
Change the minimum severity threshold at runtime.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
level
|
LogLevel
|
The new minimum severity. |
required |
Returns:
| Type | Description |
|---|---|
None
|
None. |
log ¶
Emit a record at an explicit level.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
level
|
LogLevel
|
The severity of the record. |
required |
message
|
str
|
The log message. |
required |
**fields
|
Any
|
Arbitrary structured fields attached to the record. |
{}
|
Returns:
| Type | Description |
|---|---|
None
|
None. |
Source code in tempestweb/observability/logger.py
debug ¶
Emit a DEBUG record.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
str
|
The log message. |
required |
**fields
|
Any
|
Arbitrary structured fields. |
{}
|
Returns:
| Type | Description |
|---|---|
None
|
None. |
Source code in tempestweb/observability/logger.py
info ¶
Emit an INFO record.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
str
|
The log message. |
required |
**fields
|
Any
|
Arbitrary structured fields. |
{}
|
Returns:
| Type | Description |
|---|---|
None
|
None. |
Source code in tempestweb/observability/logger.py
warning ¶
Emit a WARNING record.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
str
|
The log message. |
required |
**fields
|
Any
|
Arbitrary structured fields. |
{}
|
Returns:
| Type | Description |
|---|---|
None
|
None. |
Source code in tempestweb/observability/logger.py
error ¶
Emit an ERROR record.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
str
|
The log message. |
required |
**fields
|
Any
|
Arbitrary structured fields. |
{}
|
Returns:
| Type | Description |
|---|---|
None
|
None. |
Source code in tempestweb/observability/logger.py
critical ¶
Emit a CRITICAL record.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
str
|
The log message. |
required |
**fields
|
Any
|
Arbitrary structured fields. |
{}
|
Returns:
| Type | Description |
|---|---|
None
|
None. |
Source code in tempestweb/observability/logger.py
LoggerSink ¶
Bases: Protocol
A destination for log records.
A sink is any callable taking a single :class:LogRecord. This is
deliberately the same shape as list.append and print-style helpers,
so capturing logs in a test is just passing my_list.append as a sink.
Source code in tempestweb/observability/logger.py
LogRecord
dataclass
¶
One structured log entry handed to every sink.
Attributes:
| Name | Type | Description |
|---|---|---|
level |
LogLevel
|
The severity of this record. |
message |
str
|
The human-readable log message. |
fields |
dict[str, Any]
|
Arbitrary JSON-able structured fields attached at the call site. |
Source code in tempestweb/observability/logger.py
PatchMetrics
dataclass
¶
Latency histogram and counters for the patch round trip.
A round is one event's whole cost as the operator experiences it: the handler, the rebuild, the diff and handing the batch to the transport. Splitting it finer would measure the core, which its own benchmark already does; this measures the server.
Attributes:
| Name | Type | Description |
|---|---|---|
buckets |
tuple[float, ...]
|
Upper bounds in seconds, ascending. |
counts |
list[int]
|
Cumulative count per bucket (Prometheus semantics). |
total_seconds |
float
|
Sum of observed durations, for the average. |
rounds |
int
|
How many rounds were observed. |
patches |
int
|
How many patches those rounds produced. |
Source code in tempestweb/observability/server.py
observe ¶
Record one patch round.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seconds
|
float
|
How long the round took. |
required |
patches
|
int
|
How many patches it produced. |
required |
Source code in tempestweb/observability/server.py
prometheus ¶
Render the histogram and counters as Prometheus text.
Returns:
| Type | Description |
|---|---|
str
|
The metric lines, newline-terminated. |
Source code in tempestweb/observability/server.py
ServerObservability ¶
The server's observability seam: metrics, structured logs, tracing.
Every part is optional and independent. The default instance is inert, which is what makes it safe to call from the hot path unconditionally: no histogram, no logger, a no-op tracer.
Attributes:
| Name | Type | Description |
|---|---|---|
metrics |
PatchMetrics | None
|
The latency/throughput collector, or None. |
logger |
Logger | None
|
The structured logger, or None. |
tracer |
Tracer
|
The tracer; :func: |
Source code in tempestweb/observability/server.py
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 | |
enabled
property
¶
Whether anything is actually collected.
Returns:
| Type | Description |
|---|---|
bool
|
True when metrics, a logger or a real tracer is wired. |
observe_patches ¶
Record one event-to-patch latency, when metrics are on.
seconds is the wait the client experienced: from the event arriving
to its patches being handed to the transport, rebuild included. That is the
number an SLO is written against, and the reason the histogram is not taken
around the handler alone.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seconds
|
float
|
How long the client waited. |
required |
patches
|
int
|
How many patches the batch carries. |
required |
Source code in tempestweb/observability/server.py
session ¶
Trace and log one session's whole lifetime.
The log carries the same session_id the span does, which is the point:
a complaint about one client becomes a log query and a trace lookup with
the same key.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session_id
|
str
|
The session's id. |
required |
**attributes
|
Any
|
Extra attributes for the span and the log records. |
{}
|
Yields:
| Type | Description |
|---|---|
Any
|
The session's span. |
Source code in tempestweb/observability/server.py
dispatch ¶
Trace one handler invocation.
This is the handler's span, and deliberately not where the latency
histogram is taken: the rebuild the handler triggers is coalesced, so it
runs after the handler returns and may cover several events. Timing this
block would report a number that stops before the work the client is waiting
for — measured, and it read as 0 patches per round. The histogram is
taken where the batch actually leaves (:meth:observe_patches).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session_id
|
str
|
The session the event belongs to. |
required |
event_type
|
str
|
The wire event type, as a span attribute. |
required |
Yields:
| Type | Description |
|---|---|
Any
|
The handler's span. |
Source code in tempestweb/observability/server.py
patch_batch ¶
Trace one outgoing patch batch.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session_id
|
str
|
The session the batch belongs to. |
required |
patches
|
int
|
How many patches the batch carries. |
required |
Yields:
| Type | Description |
|---|---|
Any
|
The batch's span. |
Source code in tempestweb/observability/server.py
prometheus ¶
Render the metrics this instance collected.
Returns:
| Type | Description |
|---|---|
str
|
Prometheus text, empty when metrics are off. |
Span ¶
Bases: Protocol
One unit of traced work, ended by the context manager that opened it.
Source code in tempestweb/observability/server.py
set_attribute ¶
Record one attribute on this span.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The attribute name. |
required |
value
|
Any
|
A scalar the exporter can carry. |
required |
Tracer ¶
Bases: Protocol
The tracing seam: open a span, get it back, end it on exit.
Source code in tempestweb/observability/server.py
span ¶
Open a span.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The span name. |
required |
**attributes
|
Any
|
Initial attributes. |
{}
|
Returns:
| Type | Description |
|---|---|
Any
|
A context manager yielding a :class: |
Source code in tempestweb/observability/server.py
ConsoleTelemetryAdapter ¶
A zero-dependency adapter that prints events through a sink callable.
This is the default adapter and the Mode A (browser) fallback: in the browser
the sink is console.log; under CPython it defaults to :func:print.
Injecting the sink keeps it trivially testable.
Source code in tempestweb/observability/telemetry.py
track ¶
Print a tracked event.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event
|
str
|
The event name. |
required |
props
|
dict[str, Any]
|
The event properties. |
required |
Returns:
| Type | Description |
|---|---|
None
|
None. |
Source code in tempestweb/observability/telemetry.py
identify ¶
Print an identify call.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_id
|
str
|
The user identifier. |
required |
traits
|
dict[str, Any]
|
The identity traits. |
required |
Returns:
| Type | Description |
|---|---|
None
|
None. |
Source code in tempestweb/observability/telemetry.py
PostHogTelemetryAdapter ¶
An adapter that maps telemetry onto an injected PostHog client.
posthog is not a tempestweb dependency; the caller injects a client
exposing capture and identify. A distinct_id is tracked across
calls so events emitted before an explicit identify still attach to the right
person once identity is known.
Source code in tempestweb/observability/telemetry.py
track ¶
Forward an event to PostHog under the current distinct id.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event
|
str
|
The event name. |
required |
props
|
dict[str, Any]
|
The event properties. |
required |
Returns:
| Type | Description |
|---|---|
None
|
None. |
Source code in tempestweb/observability/telemetry.py
identify ¶
Bind the distinct id and forward an identify call to PostHog.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_id
|
str
|
The user identifier, used as the new distinct id. |
required |
traits
|
dict[str, Any]
|
Person properties to attach. |
required |
Returns:
| Type | Description |
|---|---|
None
|
None. |
Source code in tempestweb/observability/telemetry.py
SentryTelemetryAdapter ¶
An adapter that maps telemetry onto an injected Sentry client.
sentry_sdk is not a tempestweb dependency; the caller injects the module
(or any object exposing capture_message and set_user). Events become
breadcrumb-style messages; identities become the Sentry user scope.
Source code in tempestweb/observability/telemetry.py
track ¶
Forward an event as a Sentry message with the props as extras.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event
|
str
|
The event name. |
required |
props
|
dict[str, Any]
|
The event properties, attached as Sentry |
required |
Returns:
| Type | Description |
|---|---|
None
|
None. |
Source code in tempestweb/observability/telemetry.py
identify ¶
Set the Sentry user scope.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_id
|
str
|
The user identifier, mapped to |
required |
traits
|
dict[str, Any]
|
Extra identity fields merged into the user dict. |
required |
Returns:
| Type | Description |
|---|---|
None
|
None. |
Source code in tempestweb/observability/telemetry.py
TelemetryAdapter ¶
Bases: Protocol
The minimal contract every telemetry backend must satisfy.
An adapter is intentionally tiny: two methods that map the provider's
vocabulary (track / identify) onto a concrete backend. Implementing a
new backend is a handful of lines, which keeps the seam between application
code and vendor SDK thin and swappable.
Source code in tempestweb/observability/telemetry.py
track ¶
Record a named event with arbitrary properties.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event
|
str
|
The event name (e.g. |
required |
props
|
dict[str, Any]
|
JSON-able properties describing the event. Must already be free of PII the caller does not want sent to the backend. |
required |
Returns:
| Type | Description |
|---|---|
None
|
None. |
Source code in tempestweb/observability/telemetry.py
identify ¶
Associate subsequent events with a user identity.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_id
|
str
|
A stable identifier for the current user. |
required |
traits
|
dict[str, Any]
|
JSON-able traits to attach to the identity. |
required |
Returns:
| Type | Description |
|---|---|
None
|
None. |
Source code in tempestweb/observability/telemetry.py
TelemetryProvider ¶
A backend-agnostic facade application code calls to emit telemetry.
The provider holds exactly one :class:TelemetryAdapter and forwards every
call to it. It also enforces two cross-cutting concerns that should never
leak into call sites:
- Sampling — a
sample_ratein[0.0, 1.0]drops a fraction oftrackcalls so a chatty event cannot flood the backend.identifyis never sampled (identities must be reliable). - Global properties —
default_propsare merged into every tracked event (e.g.{"mode": "wasm"}), without each call site repeating them.
Swapping the adapter changes the destination of every event while leaving all
track / identify calls untouched.
Source code in tempestweb/observability/telemetry.py
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | |
adapter
property
¶
The adapter currently backing this provider.
Returns:
| Type | Description |
|---|---|
TelemetryAdapter
|
The active :class: |
track ¶
Record a named event, subject to sampling and global properties.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event
|
str
|
The event name. |
required |
props
|
dict[str, Any] | None
|
Optional per-event properties; merged on top of
|
None
|
Returns:
| Type | Description |
|---|---|
None
|
None. |
Source code in tempestweb/observability/telemetry.py
identify ¶
Associate subsequent events with a user identity (never sampled).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_id
|
str
|
A stable identifier for the current user. |
required |
traits
|
dict[str, Any] | None
|
Optional traits to attach to the identity. |
None
|
Returns:
| Type | Description |
|---|---|
None
|
None. |
Source code in tempestweb/observability/telemetry.py
create_auth_store ¶
Create a fresh, logged-out :class:AuthStore.
Returns:
| Type | Description |
|---|---|
AuthStore
|
A new :class: |
create_refresh_queue ¶
Create a :class:RefreshQueue bound to a store and refresh function.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
store
|
AuthStore
|
The auth store updated after a successful refresh. |
required |
refresh_fn
|
RefreshFn
|
The async renewal function returning a new access token. |
required |
Returns:
| Type | Description |
|---|---|
RefreshQueue
|
A configured :class: |
Source code in tempestweb/observability/auth.py
decode_jwt ¶
Decode a JWT's payload claims without verifying the signature.
This is a client-side convenience for inspecting expiry and display claims. It must never be used to make an authorization decision — only the server (with the signing key) may trust a token's claims.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
token
|
str
|
A compact-serialization JWT ( |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
The decoded claims as a dictionary. |
Raises:
| Type | Description |
|---|---|
JWTError
|
If the token is malformed or its payload is not a JSON object. |
Source code in tempestweb/observability/auth.py
is_jwt_expired ¶
Return whether a JWT is expired based on its exp claim.
A token without an exp claim is treated as not expiring (returns
False). A malformed token is treated as expired (returns True) so the
caller refreshes rather than trusting garbage.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
token
|
str
|
The JWT to inspect. |
required |
leeway_seconds
|
int
|
Seconds of clock-skew tolerance; the token is considered
expired this many seconds before its real |
0
|
now
|
float | None
|
The current UNIX time in seconds; defaults to :func: |
None
|
Returns:
| Type | Description |
|---|---|
bool
|
|
Source code in tempestweb/observability/auth.py
route_guard ¶
Build a route guard that redirects unauthenticated navigation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
store
|
AuthStore
|
The auth store consulted for the current session. |
required |
redirect_to
|
str
|
The route an unauthenticated request is sent to. |
'/login'
|
Returns:
| Type | Description |
|---|---|
Callable[[str], str]
|
A function mapping a requested route name to the route that should |
Callable[[str], str]
|
actually render: the request unchanged when authenticated (or when it is |
Callable[[str], str]
|
already the redirect target), otherwise |
Source code in tempestweb/observability/auth.py
server_decode_jwt ¶
Verify and decode a JWT on the server via tempest_fastapi_sdk.JWTUtils.
Mode B issues and validates its own tokens. Rather than re-implement
signature verification, the server reuses the SDK's JWTUtils so token
handling stays consistent with the rest of the user's backend stack.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
token
|
str
|
The JWT to verify and decode. |
required |
secret
|
str
|
The signing secret used to verify the signature. |
required |
**kwargs
|
Any
|
Extra keyword arguments forwarded to |
{}
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
The verified claims dictionary. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If |
Source code in tempestweb/observability/auth.py
default_fallback ¶
Render a minimal, renderer-agnostic fallback for a failed subtree.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
info
|
ErrorInfo
|
The captured render failure. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
A |
Widget
|
class: |
Widget
|
error type (never the raw stack, which goes to the report hook). |
Source code in tempestweb/observability/error_boundary.py
telemetry_reporter ¶
Build a report hook that forwards captured errors to telemetry (O0).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
provider
|
TelemetryProvider
|
The telemetry provider that receives the error event. |
required |
event
|
str
|
The telemetry event name to emit. |
'render_error'
|
Returns:
| Name | Type | Description |
|---|---|---|
An |
ErrorReporter
|
data: |
ErrorReporter
|
message and stack as properties. |
Source code in tempestweb/observability/error_boundary.py
with_error_boundary ¶
with_error_boundary(*, fallback_builder: FallbackBuilder = default_fallback, on_error: ErrorReporter | None = None) -> Callable[[ChildBuilder], Callable[[], ErrorBoundary]]
Decorate a widget builder so it returns a boundary-wrapped component.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fallback_builder
|
FallbackBuilder
|
Builds the fallback subtree from the captured error. |
default_fallback
|
on_error
|
ErrorReporter | None
|
Optional report hook invoked on a render failure. |
None
|
Returns:
| Type | Description |
|---|---|
Callable[[ChildBuilder], Callable[[], ErrorBoundary]]
|
A decorator that turns a |
Callable[[ChildBuilder], Callable[[], ErrorBoundary]]
|
ErrorBoundary`` builder, wrapping the original so its render errors are |
Callable[[ChildBuilder], Callable[[], ErrorBoundary]]
|
contained. |
Source code in tempestweb/observability/error_boundary.py
console_sink ¶
Print a record to the console in a stable, greppable single-line format.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
record
|
LogRecord
|
The structured record to print. |
required |
Returns:
| Type | Description |
|---|---|
None
|
None. |
Source code in tempestweb/observability/logger.py
create_logger ¶
Create a :class:Logger with the given sinks and threshold.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sinks
|
list[LoggerSink] | None
|
The destinations to deliver records to. Defaults to a single
:func: |
None
|
level
|
LogLevel
|
The minimum severity to deliver. |
'INFO'
|
Returns:
| Type | Description |
|---|---|
Logger
|
A configured :class: |
Source code in tempestweb/observability/logger.py
json_log_sink ¶
Print one log record as a single JSON line.
A session log is only useful if it can be queried, and the console sink prints
prose. This prints one object per line — the shape every log pipeline ingests —
with the structured fields at the top level, so session_id is a field and
not a substring.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
record
|
LogRecord
|
The record to print. |
required |
Source code in tempestweb/observability/server.py
noop_tracer ¶
The tracer used when an app asks for no tracing.
Returns:
| Type | Description |
|---|---|
Tracer
|
A tracer whose spans do nothing. |
otel_tracer ¶
Adapt OpenTelemetry as the tracer, importing it only when called.
The import lives inside the function on purpose: the tracing default must not
make opentelemetry a dependency of every app that serves a page. Exporter
and sampler configuration stay with OpenTelemetry itself (env vars or an SDK
setup the app owns) — wrapping those would be a second, worse configuration
surface.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
service_name
|
str
|
The tracer name reported to the exporter. |
'tempestweb'
|
Returns:
| Type | Description |
|---|---|
Tracer
|
A tracer backed by the OpenTelemetry API. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If |