///|
/// Report formats supported by the operational reporting helpers.
pub(all) enum ProductionReportFormat {
CsvReport
MarkdownReport
LineReport
}
///|
pub fn production_report_format_name(format : ProductionReportFormat) -> String {
match format {
CsvReport => "csv"
MarkdownReport => "markdown"
LineReport => "line"
}
}
///|
/// Options controlling report size and precision.
pub struct ProductionReportOptions {
format : ProductionReportFormat
include_events : Bool
include_features : Bool
maximum_rows : Int
decimals : Int
}
///|
pub fn ProductionReportOptions::new(
format? : ProductionReportFormat = MarkdownReport,
include_events? : Bool = true,
include_features? : Bool = true,
maximum_rows? : Int = 256,
decimals? : Int = 6,
) -> ProductionReportOptions {
{
format,
include_events,
include_features,
maximum_rows: if maximum_rows < 1 {
1
} else {
maximum_rows
},
decimals: if decimals < 0 {
0
} else if decimals > 15 {
15
} else {
decimals
},
}
}
///|
pub fn ProductionReportOptions::format(
self : ProductionReportOptions,
) -> ProductionReportFormat {
self.format
}
///|
pub fn ProductionReportOptions::include_events(
self : ProductionReportOptions,
) -> Bool {
self.include_events
}
///|
pub fn ProductionReportOptions::include_features(
self : ProductionReportOptions,
) -> Bool {
self.include_features
}
///|
pub fn ProductionReportOptions::maximum_rows(
self : ProductionReportOptions,
) -> Int {
self.maximum_rows
}
///|
pub fn ProductionReportOptions::decimals(self : ProductionReportOptions) -> Int {
self.decimals
}
///|
/// A time-series point prepared for dashboard rendering.
pub struct ProductionDashboardPoint {
timestamp : Int64
value : Double
baseline : Double
score : Double
changed : Bool
state : ProductionHealthState
}
///|
pub fn ProductionDashboardPoint::new(
timestamp : Int64,
value : Double,
baseline : Double,
result : DetectionResult,
state : ProductionHealthState,
) -> ProductionDashboardPoint {
{
timestamp,
value,
baseline,
score: result.score,
changed: result.changed,
state,
}
}
///|
pub fn ProductionDashboardPoint::timestamp(
self : ProductionDashboardPoint,
) -> Int64 {
self.timestamp
}
///|
pub fn ProductionDashboardPoint::value(
self : ProductionDashboardPoint,
) -> Double {
self.value
}
///|
pub fn ProductionDashboardPoint::baseline(
self : ProductionDashboardPoint,
) -> Double {
self.baseline
}
///|
pub fn ProductionDashboardPoint::score(
self : ProductionDashboardPoint,
) -> Double {
self.score
}
///|
pub fn ProductionDashboardPoint::changed(
self : ProductionDashboardPoint,
) -> Bool {
self.changed
}
///|
pub fn ProductionDashboardPoint::state(
self : ProductionDashboardPoint,
) -> ProductionHealthState {
self.state
}
///|
pub struct ProductionDashboardSeries {
name : String
points : Array[ProductionDashboardPoint]
mut dropped : Int
}
///|
pub fn ProductionDashboardSeries::new(
name : String,
capacity? : Int = 512,
) -> ProductionDashboardSeries {
ignore(capacity)
{ name, points: [], dropped: 0 }
}
///|
pub fn ProductionDashboardSeries::name(
self : ProductionDashboardSeries,
) -> String {
self.name
}
///|
pub fn ProductionDashboardSeries::push(
self : ProductionDashboardSeries,
point : ProductionDashboardPoint,
capacity? : Int = 512,
) -> Unit {
self.points.push(point)
let safe_capacity = if capacity < 1 { 1 } else { capacity }
while self.points.length() > safe_capacity {
ignore(self.points.remove(0))
self.dropped += 1
}
}
///|
pub fn ProductionDashboardSeries::points(
self : ProductionDashboardSeries,
) -> Array[ProductionDashboardPoint] {
let result : Array[ProductionDashboardPoint] = []
for point in self.points {
result.push(point)
}
result
}
///|
pub fn ProductionDashboardSeries::length(
self : ProductionDashboardSeries,
) -> Int {
self.points.length()
}
///|
pub fn ProductionDashboardSeries::dropped(
self : ProductionDashboardSeries,
) -> Int {
self.dropped
}
///|
pub fn ProductionDashboardSeries::changed_count(
self : ProductionDashboardSeries,
) -> Int {
let mut count = 0
for point in self.points {
if point.changed() {
count += 1
}
}
count
}
///|
pub fn ProductionDashboardSeries::latest(
self : ProductionDashboardSeries,
) -> ProductionDashboardPoint? {
if self.points.length() == 0 {
None
} else {
Some(self.points[self.points.length() - 1])
}
}
///|
/// Counter set for monitoring ingestion and alert delivery itself.
pub struct ProductionTelemetryCounters {
mut samples_received : Int
mut samples_rejected : Int
mut samples_imputed : Int
mut late_samples : Int
mut detector_updates : Int
mut alerts_emitted : Int
mut alerts_suppressed : Int
mut incidents_opened : Int
mut incidents_resolved : Int
mut report_exports : Int
}
///|
pub fn ProductionTelemetryCounters::new() -> ProductionTelemetryCounters {
{
samples_received: 0,
samples_rejected: 0,
samples_imputed: 0,
late_samples: 0,
detector_updates: 0,
alerts_emitted: 0,
alerts_suppressed: 0,
incidents_opened: 0,
incidents_resolved: 0,
report_exports: 0,
}
}
///|
pub fn ProductionTelemetryCounters::observe_sample(
self : ProductionTelemetryCounters,
sample : ProductionSample,
accepted : Bool,
) -> Unit {
self.samples_received += 1
if !accepted {
self.samples_rejected += 1
}
if sample.imputed() {
self.samples_imputed += 1
}
if sample.late() {
self.late_samples += 1
}
}
///|
pub fn ProductionTelemetryCounters::observe_result(
self : ProductionTelemetryCounters,
result : DetectionResult,
emitted : Bool,
) -> Unit {
self.detector_updates += 1
if result.changed {
if emitted {
self.alerts_emitted += 1
} else {
self.alerts_suppressed += 1
}
}
}
///|
pub fn ProductionTelemetryCounters::observe_incident(
self : ProductionTelemetryCounters,
opened : Bool,
resolved : Bool,
) -> Unit {
if opened {
self.incidents_opened += 1
}
if resolved {
self.incidents_resolved += 1
}
}
///|
pub fn ProductionTelemetryCounters::observe_export(
self : ProductionTelemetryCounters,
) -> Unit {
self.report_exports += 1
}
///|
pub fn ProductionTelemetryCounters::samples_received(
self : ProductionTelemetryCounters,
) -> Int {
self.samples_received
}
///|
pub fn ProductionTelemetryCounters::samples_rejected(
self : ProductionTelemetryCounters,
) -> Int {
self.samples_rejected
}
///|
pub fn ProductionTelemetryCounters::samples_imputed(
self : ProductionTelemetryCounters,
) -> Int {
self.samples_imputed
}
///|
pub fn ProductionTelemetryCounters::late_samples(
self : ProductionTelemetryCounters,
) -> Int {
self.late_samples
}
///|
pub fn ProductionTelemetryCounters::detector_updates(
self : ProductionTelemetryCounters,
) -> Int {
self.detector_updates
}
///|
pub fn ProductionTelemetryCounters::alerts_emitted(
self : ProductionTelemetryCounters,
) -> Int {
self.alerts_emitted
}
///|
pub fn ProductionTelemetryCounters::alerts_suppressed(
self : ProductionTelemetryCounters,
) -> Int {
self.alerts_suppressed
}
///|
pub fn ProductionTelemetryCounters::incidents_opened(
self : ProductionTelemetryCounters,
) -> Int {
self.incidents_opened
}
///|
pub fn ProductionTelemetryCounters::incidents_resolved(
self : ProductionTelemetryCounters,
) -> Int {
self.incidents_resolved
}
///|
pub fn ProductionTelemetryCounters::report_exports(
self : ProductionTelemetryCounters,
) -> Int {
self.report_exports
}
///|
pub fn ProductionTelemetryCounters::summary(
self : ProductionTelemetryCounters,
) -> String {
"received=" +
self.samples_received.to_string() +
",rejected=" +
self.samples_rejected.to_string() +
",imputed=" +
self.samples_imputed.to_string() +
",late=" +
self.late_samples.to_string() +
",updates=" +
self.detector_updates.to_string() +
",emitted=" +
self.alerts_emitted.to_string() +
",suppressed=" +
self.alerts_suppressed.to_string() +
",opened=" +
self.incidents_opened.to_string() +
",resolved=" +
self.incidents_resolved.to_string() +
",exports=" +
self.report_exports.to_string()
}
///|
/// Exports monitor snapshots as a stable CSV schema.
pub fn production_snapshots_csv_header() -> String {
"name,state,processed,valid,invalid,warmup_remaining,changes,emitted,suppressed,recovery_count,latest_score,baseline,latest_value,quality,last_timestamp\n"
}
///|
pub fn production_snapshot_csv(snapshot : ProductionMonitorSnapshot) -> String {
snapshot.name() +
"," +
production_health_state_name(snapshot.state()) +
"," +
snapshot.processed().to_string() +
"," +
snapshot.valid().to_string() +
"," +
snapshot.invalid().to_string() +
"," +
snapshot.warmup_remaining().to_string() +
"," +
snapshot.changes().to_string() +
"," +
snapshot.emitted().to_string() +
"," +
snapshot.suppressed().to_string() +
"," +
snapshot.recovery_count().to_string() +
"," +
snapshot.latest_score().to_string() +
"," +
snapshot.baseline().to_string() +
"," +
snapshot.latest_value().to_string() +
"," +
snapshot.quality_ratio().to_string() +
"," +
snapshot.last_timestamp().to_string() +
"\n"
}
///|
pub fn production_snapshots_csv(
snapshots : Array[ProductionMonitorSnapshot],
) -> String {
let mut output = production_snapshots_csv_header()
for snapshot in snapshots {
output = output + production_snapshot_csv(snapshot)
}
output
}
///|
pub fn production_checkpoint_csv(
checkpoint : ProductionMonitorCheckpoint,
) -> String {
"fingerprint,processed,valid,invalid,changes,emitted,suppressed,recovery_count,last_timestamp,baseline,latest_value,latest_score,state\n" +
checkpoint.fingerprint() +
"," +
checkpoint.processed().to_string() +
"," +
checkpoint.valid().to_string() +
"," +
checkpoint.invalid().to_string() +
"," +
checkpoint.changes().to_string() +
"," +
checkpoint.emitted.to_string() +
"," +
checkpoint.suppressed.to_string() +
"," +
checkpoint.recovery_count.to_string() +
"," +
checkpoint.last_timestamp.to_string() +
"," +
checkpoint.baseline().to_string() +
"," +
checkpoint.latest_value().to_string() +
"," +
checkpoint.latest_score.to_string() +
"," +
production_health_state_name(checkpoint.state()) +
"\n"
}
///|
pub fn production_features_csv_header() -> String {
"name,kind,value,valid,sample_count,source_window\n"
}
///|
pub fn production_features_csv(vector : ProductionFeatureVector) -> String {
let mut output = production_features_csv_header()
for feature in vector.features() {
output = output +
feature.name() +
"," +
production_feature_kind_name(feature.kind()) +
"," +
feature.value().to_string() +
"," +
feature.valid().to_string() +
"," +
feature.sample_count().to_string() +
"," +
feature.source_window().to_string() +
"\n"
}
output
}
///|
pub fn production_incidents_markdown(
incidents : Array[ProductionIncident],
) -> String {
let mut output = "| id | metric | state | severity | alerts | max score | duration |\n|---:|---|---|---|---:|---:|---:|\n"
for incident in incidents {
output = output +
"| " +
incident.id().to_string() +
" | " +
incident.metric() +
" | " +
production_incident_state_name(incident.state()) +
" | " +
severity_name(incident.severity()) +
" | " +
incident.alert_count().to_string() +
" | " +
incident.max_score().to_string() +
" | " +
incident.duration().to_string() +
" |\n"
}
output
}
///|
pub fn production_calibration_markdown(
bins : Array[ProductionCalibrationBin],
) -> String {
let mut output = "| lower | upper | count | positives | mean score | observed rate |\n|---:|---:|---:|---:|---:|---:|\n"
for bin in bins {
output = output +
"| " +
bin.lower().to_string() +
" | " +
bin.upper().to_string() +
" | " +
bin.count().to_string() +
" | " +
bin.positives().to_string() +
" | " +
bin.mean_score().to_string() +
" | " +
bin.observed_rate().to_string() +
" |\n"
}
output
}
///|
pub fn production_drift_markdown(report : ProductionDriftReport) -> String {
"| metric | value |\n|---|---:|\n" +
"| baseline count | " +
report.baseline_count().to_string() +
" |\n" +
"| current count | " +
report.current_count().to_string() +
" |\n" +
"| mean shift | " +
report.mean_shift().to_string() +
" |\n" +
"| variance ratio | " +
report.variance_ratio().to_string() +
" |\n" +
"| KS distance | " +
report.ks_distance().to_string() +
" |\n" +
"| energy distance | " +
report.energy_distance().to_string() +
" |\n" +
"| drift score | " +
report.drift_score().to_string() +
" |\n" +
"| drifted | " +
report.drifted().to_string() +
" |\n"
}
///|
/// Produces a bounded dashboard-friendly time series from monitor events.
pub fn production_dashboard_series(
name : String,
events : Array[ProductionMonitorEvent],
maximum_rows? : Int = 512,
) -> ProductionDashboardSeries {
let series = ProductionDashboardSeries::new(name, capacity=maximum_rows)
let safe_rows = if maximum_rows < 1 { 1 } else { maximum_rows }
for event in events {
series.push(
ProductionDashboardPoint::new(
event.timestamp(),
event.value(),
event.baseline(),
event.result(),
event.state(),
),
capacity=safe_rows,
)
}
series
}
///|
pub fn production_dashboard_csv(series : ProductionDashboardSeries) -> String {
let mut output = "timestamp,value,baseline,score,changed,state\n"
for point in series.points() {
output = output +
point.timestamp().to_string() +
"," +
point.value().to_string() +
"," +
point.baseline().to_string() +
"," +
point.score().to_string() +
"," +
point.changed().to_string() +
"," +
production_health_state_name(point.state()) +
"\n"
}
output
}
///|
pub fn production_incident_rate_markdown(
incidents : Array[ProductionIncident],
start : Int64,
end : Int64,
) -> String {
let rate = if end <= start {
0.0
} else {
incidents.length().to_double() / (end - start).to_double()
}
"| metric | value |\n|---|---:|\n| incidents | " +
incidents.length().to_string() +
" |\n| rate | " +
rate.to_string() +
" |\n"
}