File size: 2,563 Bytes
2166d7e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | #ifndef L9_OBS_H
#define L9_OBS_H
/* Layer 9 - Observability: metrics and a tamper-evident audit log.
*
* Metrics: counters, gauges and summaries (count/sum/min/max), exported as text.
* Audit: a ring of events, each chained to the previous one by SHA-256, so any edit to a retained
* event is detected by obs_audit_verify(). Observability never feeds back into the layers below. */
#include <stddef.h>
#include <stdint.h>
#include "cs_status.h"
#include "l3_sigma.h" /* sigma_clock_fn */
#define OBS_NAME_MAX 48
#define OBS_MAX_METRICS 64
#define OBS_AUDIT_CAP 128
#define OBS_MSG_MAX 96
typedef enum obs_kind { OBS_COUNTER = 0, OBS_GAUGE, OBS_SUMMARY } obs_kind;
typedef struct obs_metric {
char name[OBS_NAME_MAX];
obs_kind kind;
int64_t value; /* counter / gauge value, summary sum */
uint64_t count; /* summary only */
int64_t min, max; /* summary only */
} obs_metric;
typedef struct obs_event {
uint64_t seq;
uint64_t ts_ns;
int layer; /* 0..9 */
cs_status status;
char msg[OBS_MSG_MAX];
uint8_t chain[32]; /* SHA-256(prev chain || event fields) */
} obs_event;
typedef struct obs_ctx {
obs_metric metrics[OBS_MAX_METRICS];
size_t nmetrics;
obs_event ring[OBS_AUDIT_CAP];
uint64_t total_events;
uint8_t base_chain[32]; /* chain value preceding the oldest retained event */
sigma_clock_fn clock;
void *clock_ctx;
} obs_ctx;
void obs_init(obs_ctx *o, sigma_clock_fn clock, void *clock_ctx); /* NULL = CLOCK_MONOTONIC */
cs_status obs_counter_add(obs_ctx *o, const char *name, uint64_t delta);
cs_status obs_gauge_set(obs_ctx *o, const char *name, int64_t value);
cs_status obs_observe(obs_ctx *o, const char *name, int64_t value);
/* 1 if the metric exists (value written to *out), else 0 */
int obs_get(const obs_ctx *o, const char *name, obs_metric *out);
cs_status obs_audit(obs_ctx *o, int layer, cs_status status, const char *msg);
uint64_t obs_audit_total(const obs_ctx *o);
const obs_event *obs_audit_at(const obs_ctx *o, size_t i); /* 0 = oldest retained */
cs_status obs_audit_verify(const obs_ctx *o); /* CS_ERR_TAMPER on mismatch */
/* snprintf-style exports; return the length that would be written. */
size_t obs_export_metrics(const obs_ctx *o, char *buf, size_t cap);
size_t obs_export_audit(const obs_ctx *o, char *buf, size_t cap);
#endif
|