ObjectStackObjectStack

Metrics schema — System Protocol reference

Metrics Protocol - Performance and Operational Metrics. Reference for HistogramBucketConfig and 13 more: every property with its type and default.

Metrics Protocol - Performance and Operational Metrics

Comprehensive metrics collection and monitoring:

  • Counter, Gauge, Histogram, Summary metric types
  • Time-series data collection
  • SLI/SLO definitions
  • Metric aggregation and export
  • Integration with monitoring systems (Prometheus, etc.)

Source: packages/spec/src/system/metrics.zod.ts

TypeScript Usage

import { HistogramBucketConfigSchema, MetricAggregationConfigSchema, MetricAggregationType, MetricDataPointSchema, MetricDefinitionSchema, MetricExportConfigSchema, MetricLabelsSchema, MetricType, MetricUnit, MetricsConfigSchema, ServiceLevelIndicatorSchema, ServiceLevelObjectiveSchema, TimeSeriesSchema, TimeSeriesDataPointSchema } from '@objectstack/spec/system';
import type { HistogramBucketConfig, MetricAggregationConfig, MetricAggregationType, MetricDataPoint, MetricDefinition, MetricExportConfig, MetricLabels, MetricType, MetricUnit, MetricsConfig, ServiceLevelIndicator, ServiceLevelObjective, TimeSeries, TimeSeriesDataPoint } from '@objectstack/spec/system';

// Validate data
const result = HistogramBucketConfigSchema.parse(data);

HistogramBucketConfig

Histogram bucket configuration

Properties

PropertyTypeRequiredDescription
typeEnum<'linear' | 'exponential' | 'explicit'>✅Bucket type
linear{ start: number; width: number; count: integer }optional
exponential{ start: number; factor: number; count: integer }optional
explicit{ boundaries: number[] }optional

Nested Shape: HistogramBucketConfig.linear

PropertyTypeRequiredDescription
startnumber✅Start value
widthnumber✅Bucket width
countinteger✅Number of buckets

Nested Shape: HistogramBucketConfig.exponential

PropertyTypeRequiredDescription
startnumber✅Start value
factornumber✅Growth factor
countinteger✅Number of buckets

Nested Shape: HistogramBucketConfig.explicit

PropertyTypeRequiredDescription
boundariesnumber[]✅Bucket boundaries

MetricAggregationConfig

Metric aggregation configuration

Properties

PropertyTypeRequiredDescription
typeEnum<'sum' | 'avg' | 'min' | 'max' | 'count' | 'p50' | 'p75' | 'p90' | 'p95' | 'p99' | 'p999' | 'rate' | 'stddev'>✅Aggregation type
window{ durationSeconds: integer; sliding?: boolean; slideInterval?: integer }optional
groupBystring[]optionalGroup by label names
filtersRecord<string, any>optionalFilter criteria

Nested Shape: MetricAggregationConfig.window

PropertyTypeRequiredDescription
durationSecondsinteger✅Window duration in seconds
sizeneveroptional[REMOVED] The aggregation/SLI window key size was renamed to durationSeconds in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. The new name is not sizeSeconds: size means a byte or row count everywhere else in this spec, so the rename drops it rather than bolting a unit onto it. Rename window.size to window.durationSeconds on both MetricAggregationConfig and ServiceLevelIndicator; the value (seconds) is unchanged.
slidingbooleanoptional (default: false)
slideIntervalintegeroptionalSlide interval for sliding windows, in seconds

MetricAggregationType

Metric aggregation type

Allowed Values

  • sum
  • avg
  • min
  • max
  • count
  • p50
  • p75
  • p90
  • p95
  • p99
  • p999
  • rate
  • stddev

MetricDataPoint

Metric data point

Properties

PropertyTypeRequiredDescription
namestring✅Metric name
typeEnum<'counter' | 'gauge' | 'histogram' | 'summary'>✅Metric type
timestampstring✅Observation timestamp
valuenumberoptionalMetric value
labelsRecord<string, string>optionalMetric labels
histogram{ count: integer; sum: number; buckets: object[] }optional
summary{ count: integer; sum: number; quantiles: object[] }optional

Nested Shape: MetricDataPoint.histogram

PropertyTypeRequiredDescription
countinteger✅Total count
sumnumber✅Sum of all values
buckets{ upperBound: number; count: integer }[]✅Histogram buckets

Nested Shape: MetricDataPoint.summary

PropertyTypeRequiredDescription
countinteger✅Total count
sumnumber✅Sum of all values
quantiles{ quantile: number; value: number }[]✅Summary quantiles

MetricDefinition

Metric definition

Properties

PropertyTypeRequiredDescription
namestring✅Metric name (snake_case)
labelstringoptionalDisplay label
typeEnum<'counter' | 'gauge' | 'histogram' | 'summary'>✅Metric type
unitEnum<'nanoseconds' | 'microseconds' | 'milliseconds' | 'seconds' | 'minutes' | 'hours' | 'days' | 'bytes' | 'kilobytes' | 'megabytes' | 'gigabytes' | 'terabytes' | … +8 more>optionalMetric unit
descriptionstringoptionalMetric description
labelNamesstring[]optional (default: [])Label names
histogram{ type: Enum<'linear' | 'exponential' | 'explicit'>; linear?: object; exponential?: object; explicit?: object }optionalHistogram bucket configuration
summary{ quantiles?: number[]; maxAgeSeconds?: integer; ageBuckets?: integer }optional
enabledbooleanoptional (default: true)

Allowed Values: MetricDefinition.unit

  • nanoseconds
  • microseconds
  • milliseconds
  • seconds
  • minutes
  • hours
  • days
  • bytes
  • kilobytes
  • megabytes
  • gigabytes
  • terabytes
  • requests_per_second
  • events_per_second
  • bytes_per_second
  • percent
  • ratio
  • count
  • operations
  • custom

Nested Shape: MetricDefinition.histogram

PropertyTypeRequiredDescription
typeEnum<'linear' | 'exponential' | 'explicit'>✅Bucket type
linear{ start: number; width: number; count: integer }optional
exponential{ start: number; factor: number; count: integer }optional
explicit{ boundaries: number[] }optional

Nested Shape: MetricDefinition.summary

PropertyTypeRequiredDescription
quantilesnumber[]optional (default: [0.5,0.9,0.99])
maxAgeSecondsintegeroptional (default: 600)Max age of observations in seconds
maxAgeneveroptional[REMOVED] MetricDefinition.summary.maxAge was renamed to maxAgeSeconds in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Its unit (seconds) lived in a source JSDoc only and the published description named none, so a reader of the reference page could not tell 600 seconds from 600 milliseconds. The new name keeps the age stem instead of becoming durationSeconds, because the sibling key ageBuckets counts buckets of that same age. Rename the key to maxAgeSeconds; the value (seconds) is unchanged.
ageBucketsintegeroptional (default: 5)

MetricExportConfig

Metric export configuration

Properties

PropertyTypeRequiredDescription
typeEnum<'prometheus' | 'openmetrics' | 'graphite' | 'statsd' | 'influxdb' | 'datadog' | 'cloudwatch' | 'stackdriver' | 'azure_monitor' | 'http' | 'custom'>✅Export type
endpointstringoptionalExport endpoint
intervalSecondsintegeroptional (default: 60)Export interval in seconds
intervalneveroptional[REMOVED] MetricExportConfig.interval was renamed to intervalSeconds in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Its unit (seconds) lived in a source JSDoc only and the key carried no describe at all, so a reader of the reference page could not tell 60 seconds from 60 milliseconds. Rename the key to intervalSeconds; the value (seconds) is unchanged.
batch{ enabled?: boolean; size?: integer }optional
auth{ type: Enum<'none' | 'basic' | 'bearer' | 'api_key'>; username?: string; password?: string; token?: string; … }optional
configRecord<string, any>optionalAdditional configuration

Nested Shape: MetricExportConfig.auth

PropertyTypeRequiredDescription
typeEnum<'none' | 'basic' | 'bearer' | 'api_key'>✅Auth type
usernamestringoptional
passwordstringoptional
tokenstringoptional
apiKeystringoptional

MetricLabels

Metric labels

Type: Record<string, string>


MetricType

Metric type

Allowed Values

  • counter
  • gauge
  • histogram
  • summary

MetricUnit

Metric unit

Allowed Values

  • nanoseconds
  • microseconds
  • milliseconds
  • seconds
  • minutes
  • hours
  • days
  • bytes
  • kilobytes
  • megabytes
  • gigabytes
  • terabytes
  • requests_per_second
  • events_per_second
  • bytes_per_second
  • percent
  • ratio
  • count
  • operations
  • custom

MetricsConfig

Metrics configuration

Properties

PropertyTypeRequiredDescription
namestring✅Configuration name (snake_case, max 64 chars)
labelstring✅Display label
enabledbooleanoptional (default: true)
metrics{ name: string; label?: string; type: Enum<'counter' | 'gauge' | 'histogram' | 'summary'>; unit?: Enum<'nanoseconds' | 'microseconds' | 'milliseconds' | 'seconds' | 'minutes' | …>; … }[]optional (default: [])
defaultLabelsRecord<string, string>optional (default: {})Metric labels
aggregations{ type: Enum<'sum' | 'avg' | 'min' | 'max' | 'count' | 'p50' | 'p75' | 'p90' | 'p95' | 'p99' | …>; window?: object; groupBy?: string[]; filters?: Record<string, any> }[]optional (default: [])
slis{ name: string; label: string; description?: string; metric: string; … }[]optional (default: [])
slos{ name: string; label: string; description?: string; sli: string; … }[]optional (default: [])
exports{ type: Enum<'prometheus' | 'openmetrics' | 'graphite' | 'statsd' | 'influxdb' | 'datadog' | …>; endpoint?: string; intervalSeconds?: integer; batch?: object; … }[]optional (default: [])
collectionIntervalSecondsintegeroptional (default: 15)Collection interval in seconds
collectionIntervalneveroptional[REMOVED] MetricsConfig.collectionInterval was renamed to collectionIntervalSeconds in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Its unit (seconds) lived in a source JSDoc only and the key carried no describe at all, so a reader of the reference page could not tell 15 seconds from 15 milliseconds. The qualifier is kept — collectionIntervalSeconds, not intervalSeconds — because MetricExportConfig.intervalSeconds is a different cadence one def over. Rename the key to collectionIntervalSeconds; the value (seconds) is unchanged.
retention{ durationSeconds?: integer; downsampling?: object[] }optional
cardinalityLimits{ maxLabelCombinations?: integer; onLimitExceeded?: Enum<'drop' | 'sample' | 'alert'> }optional

Nested Shape: MetricsConfig.metrics[number]

Metric definition

PropertyTypeRequiredDescription
namestring✅Metric name (snake_case)
labelstringoptionalDisplay label
typeEnum<'counter' | 'gauge' | 'histogram' | 'summary'>✅Metric type
unitEnum<'nanoseconds' | 'microseconds' | 'milliseconds' | 'seconds' | 'minutes' | …>optionalMetric unit
descriptionstringoptionalMetric description
labelNamesstring[]optional (default: [])Label names
histogram{ type: Enum<'linear' | 'exponential' | 'explicit'>; linear?: object; exponential?: object; explicit?: object }optionalHistogram bucket configuration
summary{ quantiles?: number[]; maxAgeSeconds?: integer; ageBuckets?: integer }optional
enabledbooleanoptional (default: true)

Nested Shape: MetricsConfig.aggregations[number]

Metric aggregation configuration

PropertyTypeRequiredDescription
typeEnum<'sum' | 'avg' | 'min' | 'max' | 'count' | 'p50' | 'p75' | 'p90' | 'p95' | 'p99' | …>✅Aggregation type
window{ durationSeconds: integer; sliding?: boolean; slideInterval?: integer }optional
groupBystring[]optionalGroup by label names
filtersRecord<string, any>optionalFilter criteria

Nested Shape: MetricsConfig.slis[number]

Service Level Indicator

PropertyTypeRequiredDescription
namestring✅SLI name (snake_case)
labelstring✅Display label
descriptionstringoptionalSLI description
metricstring✅Base metric name
typeEnum<'availability' | 'latency' | 'throughput' | 'error_rate' | 'saturation' | 'custom'>✅SLI type
successCriteria{ threshold: number; operator: Enum<'lt' | 'lte' | 'gt' | 'gte' | 'eq'>; percentile?: number }✅Success criteria — a structured threshold rule. A CEL predicate is NOT accepted here: that arm was removed in 17.5.0 because nothing evaluated it.
window{ durationSeconds: integer; rolling?: boolean }✅Measurement window
enabledbooleanoptional (default: true)

Nested Shape: MetricsConfig.slos[number]

Service Level Objective

PropertyTypeRequiredDescription
namestring✅SLO name (snake_case)
labelstring✅Display label
descriptionstringoptionalSLO description
slistring✅SLI name
targetnumber✅Target percentage
period{ type: Enum<'rolling' | 'calendar'>; durationSeconds?: integer; calendar?: Enum<'daily' | 'weekly' | 'monthly' | 'quarterly' | 'yearly'> }✅Time period
errorBudget{ enabled?: boolean; alertThreshold?: number; burnRateWindows?: object[] }optional
alerts{ name: string; severity: Enum<'info' | 'warning' | 'critical'>; condition: object }[]optional (default: [])
enabledbooleanoptional (default: true)

Nested Shape: MetricsConfig.exports[number]

Metric export configuration

PropertyTypeRequiredDescription
typeEnum<'prometheus' | 'openmetrics' | 'graphite' | 'statsd' | 'influxdb' | 'datadog' | …>✅Export type
endpointstringoptionalExport endpoint
intervalSecondsintegeroptional (default: 60)Export interval in seconds
intervalneveroptional[REMOVED] MetricExportConfig.interval was renamed to intervalSeconds in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Its unit (seconds) lived in a source JSDoc only and the key carried no describe at all, so a reader of the reference page could not tell 60 seconds from 60 milliseconds. Rename the key to intervalSeconds; the value (seconds) is unchanged.
batch{ enabled?: boolean; size?: integer }optional
auth{ type: Enum<'none' | 'basic' | 'bearer' | 'api_key'>; username?: string; password?: string; token?: string; … }optional
configRecord<string, any>optionalAdditional configuration

Nested Shape: MetricsConfig.retention

PropertyTypeRequiredDescription
durationSecondsintegeroptional (default: 604800)Retention duration in seconds
periodneveroptional[REMOVED] MetricsConfig.retention.period was renamed to durationSeconds in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Its unit (seconds) lived in a source JSDoc only and the key carried no describe at all, so a reader of the reference page could not tell 604800 seconds from 604800 milliseconds. The new name is not periodSeconds: period is calendar vocabulary elsewhere in this spec (ServiceLevelObjective.period.type selects rolling or calendar, PluginRegistryEntry.pricing.billingPeriod is monthly or yearly), so it would have kept the ambiguous half of the name, and durationSeconds is what this file already calls a length of time. Rename the key to durationSeconds; the value (seconds) is unchanged.
downsampling{ afterSeconds: integer; resolution: integer }[]optional

ServiceLevelIndicator

Service Level Indicator

Properties

PropertyTypeRequiredDescription
namestring✅SLI name (snake_case)
labelstring✅Display label
descriptionstringoptionalSLI description
metricstring✅Base metric name
typeEnum<'availability' | 'latency' | 'throughput' | 'error_rate' | 'saturation' | 'custom'>✅SLI type
successCriteria{ threshold: number; operator: Enum<'lt' | 'lte' | 'gt' | 'gte' | 'eq'>; percentile?: number }✅Success criteria — a structured threshold rule. A CEL predicate is NOT accepted here: that arm was removed in 17.5.0 because nothing evaluated it.
window{ durationSeconds: integer; rolling?: boolean }✅Measurement window
enabledbooleanoptional (default: true)

Nested Shape: ServiceLevelIndicator.successCriteria

PropertyTypeRequiredDescription
thresholdnumber✅Threshold value
operatorEnum<'lt' | 'lte' | 'gt' | 'gte' | 'eq'>✅Comparison operator
percentilenumberoptionalPercentile (0-1)

Nested Shape: ServiceLevelIndicator.window

PropertyTypeRequiredDescription
durationSecondsinteger✅Window duration in seconds
sizeneveroptional[REMOVED] The aggregation/SLI window key size was renamed to durationSeconds in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. The new name is not sizeSeconds: size means a byte or row count everywhere else in this spec, so the rename drops it rather than bolting a unit onto it. Rename window.size to window.durationSeconds on both MetricAggregationConfig and ServiceLevelIndicator; the value (seconds) is unchanged.
rollingbooleanoptional (default: true)

ServiceLevelObjective

Service Level Objective

Properties

PropertyTypeRequiredDescription
namestring✅SLO name (snake_case)
labelstring✅Display label
descriptionstringoptionalSLO description
slistring✅SLI name
targetnumber✅Target percentage
period{ type: Enum<'rolling' | 'calendar'>; durationSeconds?: integer; calendar?: Enum<'daily' | 'weekly' | 'monthly' | 'quarterly' | 'yearly'> }✅Time period
errorBudget{ enabled?: boolean; alertThreshold?: number; burnRateWindows?: object[] }optional
alerts{ name: string; severity: Enum<'info' | 'warning' | 'critical'>; condition: object }[]optional (default: [])
enabledbooleanoptional (default: true)

Nested Shape: ServiceLevelObjective.period

PropertyTypeRequiredDescription
typeEnum<'rolling' | 'calendar'>✅Period type
durationSecondsintegeroptionalDuration in seconds
durationneveroptional[REMOVED] ServiceLevelObjective.period.duration was renamed to durationSeconds in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Rename the key to durationSeconds; the value (seconds) is unchanged.
calendarEnum<'daily' | 'weekly' | 'monthly' | 'quarterly' | 'yearly'>optional

Nested Shape: ServiceLevelObjective.alerts[number]

PropertyTypeRequiredDescription
namestring✅Alert name
severityEnum<'info' | 'warning' | 'critical'>✅Alert severity
condition{ type: Enum<'slo_breach' | 'error_budget' | 'burn_rate'>; threshold?: number }✅Alert condition

TimeSeries

Time series

Properties

PropertyTypeRequiredDescription
namestring✅Series name
labelsRecord<string, string>optionalSeries labels
dataPoints{ timestamp: string; value: number; labels?: Record<string, string> }[]✅Data points
startTimestringoptionalStart time
endTimestringoptionalEnd time

Nested Shape: TimeSeries.dataPoints[number]

Time series data point

PropertyTypeRequiredDescription
timestampstring✅Timestamp
valuenumber✅Value
labelsRecord<string, string>optionalLabels

TimeSeriesDataPoint

Time series data point

Properties

PropertyTypeRequiredDescription
timestampstring✅Timestamp
valuenumber✅Value
labelsRecord<string, string>optionalLabels

On this page