Skip to content

Commit 8a019fd

Browse files
committed
cleanup
1 parent b042647 commit 8a019fd

6 files changed

Lines changed: 50 additions & 58 deletions

File tree

bin/agent-data-plane/src/internal/env/workload/api.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -222,12 +222,8 @@ impl Supervisable for RemoteAgentWorkloadAPIWorker {
222222

223223
let diagnostics =
224224
DiagnosticsEmitter::from_dataspace(SubsystemIdentifier::from_segments(["workload-api"]), dataspace);
225-
diagnostics.register_collector("workload-tags-dump.json", move || {
226-
tags_state.tags_dump_json().into_bytes()
227-
});
228-
diagnostics.register_collector("workload-external-data-dump.json", move || {
229-
eds_state.eds_dump_json().into_bytes()
230-
});
225+
diagnostics.register_collector("workload-tags-dump.json", move || tags_state.tags_dump_json());
226+
diagnostics.register_collector("workload-external-data-dump.json", move || eds_state.eds_dump_json());
231227

232228
process_shutdown.await;
233229
Ok(())

lib/saluki-core/src/diagnostic/collector.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,13 @@ impl DiagnosticCollector {
2020
///
2121
/// `collect_fn` runs synchronously and must return promptly, as it can delay the collection of artifacts for the
2222
/// whole system.
23-
pub fn new(artifact_name: impl Into<String>, collect_fn: impl Fn() -> Vec<u8> + Send + Sync + 'static) -> Self {
23+
pub fn new<T>(artifact_name: impl Into<String>, collect_fn: impl Fn() -> T + Send + Sync + 'static) -> Self
24+
where
25+
T: Into<Vec<u8>>,
26+
{
2427
Self {
2528
artifact_name: artifact_name.into(),
26-
collect_fn: Arc::new(collect_fn),
29+
collect_fn: Arc::new(move || collect_fn().into()),
2730
}
2831
}
2932

lib/saluki-core/src/diagnostic/emitter.rs

Lines changed: 39 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
//! Subsystem-scoped diagnostics control surface.
22
3+
// TODO: probably rework process name construction to use `SubsystemIdentifier` under the hood,
4+
// and expose that, in addition to process ID, as a task-local we can access so that we can
5+
// make `DiagnosticEmitter::new` require no parameters at all while still doing the right thing
6+
37
use snafu::{OptionExt as _, Snafu};
8+
use stringtheory::MetaString;
49

510
use super::{DiagnosticCollector, DiagnosticEvent};
611
use crate::{
712
runtime::state::{DataspaceRegistry, Identifier, IdentifierFilter, Subscription},
813
support::SubsystemIdentifier,
914
};
1015

11-
/// An error that can occur when creating a [`DiagnosticsEmitter`] from the current context.
16+
/// Errors that can occur when creating a [`DiagnosticsEmitter`].
1217
#[derive(Debug, Snafu)]
1318
#[snafu(context(suffix(false)))]
1419
pub enum DiagnosticsEmitterError {
@@ -22,8 +27,8 @@ pub enum DiagnosticsEmitterError {
2227

2328
/// A subsystem-scoped control surface for exposing diagnostics.
2429
///
25-
/// A `DiagnosticsEmitter` is created for a single subsystem, identified by a [`SubsystemIdentifier`], and attaches to
26-
/// the current dataspace. It hides the boilerplate of interacting with the dataspace directly, while still using it
30+
/// A `DiagnosticsEmitter` is created for a single subsystem, identified by a [`SubsystemIdentifier`], and is attached
31+
/// to a specific dataspace. It hides the boilerplate of interacting with the dataspace directly, while still using it
2732
/// under the hood so that other subsystems can subscribe to what is exposed in a decoupled, eventually consistent way.
2833
///
2934
/// It exposes two capabilities:
@@ -49,16 +54,15 @@ pub enum DiagnosticsEmitterError {
4954
/// dataspace,
5055
/// );
5156
///
52-
/// // Expose an artifact that is produced on demand.
53-
/// emitter.register_collector("state.json", || b"{}".to_vec());
57+
/// // Expose an artifact that is produced on demand:
58+
/// emitter.register_collector("state.json", || b"{}");
5459
///
55-
/// // Emit a point-in-time event.
60+
/// // Emit a point-in-time event:
5661
/// emitter.emit(DiagnosticEvent::new("credentials rejected", DiagnosticDetails::InvalidApiKey));
5762
/// ```
5863
#[derive(Clone)]
5964
pub struct DiagnosticsEmitter {
60-
id: SubsystemIdentifier,
61-
event_id: Identifier,
65+
base_id: MetaString,
6266
dataspace: DataspaceRegistry,
6367
}
6468

@@ -67,65 +71,63 @@ impl DiagnosticsEmitter {
6771
///
6872
/// # Errors
6973
///
70-
/// Returns [`DiagnosticsEmitterError::NoDataspace`] if no dataspace is available in the current context (that is,
71-
/// when not running inside a supervision tree).
74+
/// If no dataspace is available, an error is returned.
7275
pub fn from_current(id: SubsystemIdentifier) -> Result<Self, DiagnosticsEmitterError> {
7376
let dataspace = DataspaceRegistry::try_current().context(NoDataspace)?;
7477
Ok(Self::from_dataspace(id, dataspace))
7578
}
7679

7780
/// Creates an emitter for the given subsystem from an already-held dataspace handle.
78-
///
79-
/// This avoids a second task-local lookup when the caller already holds a [`DataspaceRegistry`]. Holding one
80-
/// already proves a dataspace exists, so this is infallible.
8181
pub fn from_dataspace(id: SubsystemIdentifier, dataspace: DataspaceRegistry) -> Self {
82-
let event_id = Identifier::named(id.to_string());
82+
let base_id = id.to_string();
8383
Self {
84-
id,
85-
event_id,
84+
base_id: base_id.into(),
8685
dataspace,
8786
}
8887
}
8988

90-
/// Registers a named collector whose bytes are gathered into diagnostic artifacts on demand.
89+
/// Registers a collector for a given artifact.
9190
///
9291
/// The collector is exposed until it is explicitly removed via [`unregister_collector`], or until the owning
9392
/// process exits, whichever comes first. Registering a collector with an artifact name that is already registered
9493
/// by this subsystem replaces the previous one.
9594
///
96-
/// `collect_fn` runs synchronously and must return promptly, as it can delay the collection of artifacts for the
97-
/// whole system.
95+
/// Care should be taken when registering a collector:
96+
///
97+
/// - the given artifact name _should_ be unique within the overall system, and should be generally suitable as a
98+
/// file name when possible (artifact names are sanitized/normalized where necessary, but may lose useful
99+
/// information in the process)
100+
/// - the collection function (`collect_fn`) will be run synchronously and should return promptly, as it can delay
101+
/// the collection of artifacts for the whole system
98102
///
99103
/// [`unregister_collector`]: Self::unregister_collector
100-
pub fn register_collector<F>(&self, artifact_name: impl Into<String>, collect_fn: F)
104+
pub fn register_collector<F, T>(&self, artifact_name: impl Into<String>, collect_fn: F)
101105
where
102-
F: Fn() -> Vec<u8> + Send + Sync + 'static,
106+
F: Fn() -> T + Send + Sync + 'static,
107+
T: Into<Vec<u8>>,
103108
{
104109
let collector = DiagnosticCollector::new(artifact_name, collect_fn);
105-
let id = self.collector_identifier(collector.artifact_name());
110+
let id = self.build_collector_identifier(collector.artifact_name());
106111
self.dataspace.assert(collector, id);
107112
}
108113

109-
/// Removes a previously registered collector by artifact name.
114+
/// Removes a previously registered collector by name
110115
///
111116
/// Does nothing if no collector with that name is currently registered by this subsystem.
112117
pub fn unregister_collector(&self, artifact_name: impl AsRef<str>) {
113-
let id = self.collector_identifier(artifact_name.as_ref());
118+
let id = self.build_collector_identifier(artifact_name.as_ref());
114119
self.dataspace.retract::<DiagnosticCollector>(id);
115120
}
116121

117122
/// Emits a diagnostic event.
118123
///
119-
/// The event is sent as a transient dataspace message keyed by this subsystem's identifier: it is delivered only to
120-
/// subscribers present at the time of emission, is never stored or replayed, and is dropped if there are no
121-
/// matching subscribers.
124+
/// Diagnostics events are transient and only delivered to active listeners.
122125
pub fn emit(&self, event: DiagnosticEvent) {
123-
self.dataspace.send(event, self.event_id.clone());
126+
self.dataspace.send(event, self.base_id.clone());
124127
}
125128

126-
/// Returns the dataspace identifier for a collector with the given artifact name.
127-
fn collector_identifier(&self, artifact_name: &str) -> Identifier {
128-
Identifier::named(self.id.clone().child(artifact_name).to_string())
129+
fn build_collector_identifier(&self, artifact_name: &str) -> Identifier {
130+
Identifier::named(format!("{}-{}", self.base_id, artifact_name))
129131
}
130132
}
131133

@@ -136,7 +138,7 @@ impl DiagnosticsEmitter {
136138
///
137139
/// # Errors
138140
///
139-
/// Returns [`DiagnosticsEmitterError::NoDataspace`] if no dataspace is available in the current context.
141+
/// If no dataspace is available, an error is returned.
140142
pub fn subscribe_events(filter: IdentifierFilter) -> Result<Subscription<DiagnosticEvent>, DiagnosticsEmitterError> {
141143
let dataspace = DataspaceRegistry::try_current().context(NoDataspace)?;
142144
Ok(dataspace.subscribe::<DiagnosticEvent>(filter))
@@ -176,7 +178,7 @@ mod tests {
176178
#[test]
177179
fn register_collector_is_discoverable() {
178180
let registry = DataspaceRegistry::new();
179-
emitter(registry.clone()).register_collector("state.json", || b"hello".to_vec());
181+
emitter(registry.clone()).register_collector("state.json", || b"hello");
180182

181183
let collectors = registry.current_values::<DiagnosticCollector>(IdentifierFilter::all());
182184
assert_eq!(collectors.len(), 1);
@@ -204,8 +206,8 @@ mod tests {
204206
fn reregister_same_artifact_updates() {
205207
let registry = DataspaceRegistry::new();
206208
let emitter = emitter(registry.clone());
207-
emitter.register_collector("state.json", || b"v1".to_vec());
208-
emitter.register_collector("state.json", || b"v2".to_vec());
209+
emitter.register_collector("state.json", || b"v1");
210+
emitter.register_collector("state.json", || b"v2");
209211

210212
let collectors = registry.current_values::<DiagnosticCollector>(IdentifierFilter::all());
211213
assert_eq!(collectors.len(), 1);
@@ -225,7 +227,7 @@ mod tests {
225227
let mut recv = test_spawn(sub.recv());
226228
match assert_ready!(recv.poll()) {
227229
Some(DataspaceUpdate::Asserted(id, collector)) => {
228-
assert_eq!(id, Identifier::named("sub.state_json"));
230+
assert_eq!(id, Identifier::named("sub-state.json"));
229231
assert_eq!(collector.artifact_name(), "state.json");
230232
}
231233
_ => panic!("expected an assertion first"),
@@ -235,7 +237,7 @@ mod tests {
235237
// Second update: the retraction.
236238
let mut recv = test_spawn(sub.recv());
237239
match assert_ready!(recv.poll()) {
238-
Some(DataspaceUpdate::Retracted(id)) => assert_eq!(id, Identifier::named("sub.state_json")),
240+
Some(DataspaceUpdate::Retracted(id)) => assert_eq!(id, Identifier::named("sub-state.json")),
239241
_ => panic!("expected a retraction second"),
240242
}
241243
}

lib/saluki-core/src/diagnostic/event.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
//! Abstract diagnostic events.
22
33
/// Structured detail describing the nature of a [`DiagnosticEvent`].
4-
///
5-
/// This enum is intentionally minimal for now; additional variants will be added over time as more diagnostic
6-
/// conditions are modeled. It is marked `#[non_exhaustive]` so that new variants can be added without breaking
7-
/// downstream matches.
84
#[derive(Clone, Debug, Eq, PartialEq)]
95
#[non_exhaustive]
106
pub enum DiagnosticDetails {
@@ -14,9 +10,7 @@ pub enum DiagnosticDetails {
1410

1511
/// An abstract, point-in-time diagnostic event emitted by a subsystem.
1612
///
17-
/// An event pairs a human-readable message with a structured [`DiagnosticDetails`] value describing what occurred. The
18-
/// emitting subsystem is conveyed by the dataspace identifier the event is sent under, so it is not duplicated on the
19-
/// event itself.
13+
/// An event pairs a human-readable message with a structured [`DiagnosticDetails`] value describing what occurred.
2014
#[derive(Clone, Debug, Eq, PartialEq)]
2115
pub struct DiagnosticEvent {
2216
message: String,

lib/saluki-core/src/diagnostic/mod.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
1-
//! Diagnostics.
1+
//! Subsystem diagnostics.
22
//!
3-
//! This module provides a subsystem-scoped control surface, [`DiagnosticsEmitter`], for exposing diagnostics to the
4-
//! rest of the system in a decoupled, eventually consistent way. A subsystem uses it to register on-demand artifact
5-
//! [collectors][DiagnosticCollector] and to emit abstract [events][DiagnosticEvent], both carried over the runtime
6-
//! dataspace.
3+
//! This module provides a generalized system for exposing diagnostic information from a subsystem, both in a pull and push fashion.
74
85
mod collector;
96
pub use self::collector::DiagnosticCollector;

lib/saluki-core/src/health/worker.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ impl Supervisable for HealthRegistryWorker {
4848
// Expose our diagnostic artifact via the diagnostics control surface.
4949
let diagnostics =
5050
DiagnosticsEmitter::from_dataspace(SubsystemIdentifier::from_segments(["health-registry"]), dataspace);
51-
diagnostics.register_collector("health.json", move || health_registry.snapshot_json().into_bytes());
51+
diagnostics.register_collector("health.json", move || health_registry.snapshot_json());
5252

5353
// We pass the shutdown handle into the runner here, instead of our usual `select! { shutdown => ...,
5454
// main_loop_future => ... }` pattern because we try to ensure that we give back the liveness receiver

0 commit comments

Comments
 (0)