Skip to main content

systemprompt_logging/
attribution.rs

1//! Logging-side attribution cell.
2//!
3//! `tracing` macros fire from contexts where no `AppContext` handle is in
4//! scope (gateway access logs, OTLP ingest, panic hooks). Threading a
5//! resolved owner through every `info!()` call site is impractical, so the
6//! platform parks the resolved [`SystemAdmin`] in a logging-private
7//! `OnceLock` during runtime bootstrap. Only [`platform_attribution`] reads it.
8//!
9//! This is the *only* legitimate global owned by the logging crate. Other
10//! subsystems (MCP registry, scheduler) thread their owner explicitly through
11//! `AppContext` instead of consulting a process-wide cell.
12
13use std::sync::OnceLock;
14use systemprompt_identifiers::UserId;
15use systemprompt_models::services::SystemAdmin;
16use thiserror::Error;
17
18static PLATFORM_OWNER: OnceLock<SystemAdmin> = OnceLock::new();
19
20/// Returns the first-installed value; on a repeat call the argument is dropped.
21pub fn install_log_attribution(admin: SystemAdmin) -> &'static SystemAdmin {
22    PLATFORM_OWNER.get_or_init(|| admin)
23}
24
25pub fn platform_attribution() -> Result<&'static SystemAdmin, LogAttributionUnset> {
26    PLATFORM_OWNER.get().ok_or(LogAttributionUnset)
27}
28
29pub(crate) fn platform_owner_id() -> Result<&'static UserId, LogAttributionUnset> {
30    platform_attribution().map(SystemAdmin::id)
31}
32
33#[derive(Debug, Clone, Copy, Error)]
34#[error("log attribution not installed: AppContext bootstrap must run before platform log events")]
35pub struct LogAttributionUnset;