13namespace morph::observe {
16enum class Metric : std::uint8_t {
50 std::span<const std::pair<std::string_view, std::string_view>>
tags;
54using MetricSink = std::function<void(
const MetricEvent&)>;
61using SpanId = std::uint64_t;
73 std::function<SpanId(std::string_view requestId, std::string_view modelType, std::string_view actionType)>
77 std::function<void(SpanId spanId,
bool ok)>
endSpan;
91 std::shared_ptr<const MetricSink> metricSink;
94 std::atomic<bool> metricsOn{
false};
99 std::shared_ptr<const TraceSink> traceSink;
101 std::atomic<bool> traceOn{
false};
108inline ObserveState& observeState() {
109 static ObserveState state;
142inline void emitMetric(Metric metric,
double value,
143 std::span<
const std::pair<std::string_view, std::string_view>> tags = {}) {
144 auto& state = observeState();
145 if (!state.metricsOn.load(std::memory_order_relaxed)) {
148 std::shared_ptr<const MetricSink> sink;
150 std::scoped_lock
const lock{state.metricMtx};
151 sink = state.metricSink;
153 if (!sink || !*sink) {
157 (*sink)(MetricEvent{.metric = metric, .value = value, .tags = tags});
169[[nodiscard]]
inline SpanId beginSpan(std::string_view requestId, std::string_view modelType,
170 std::string_view actionType) {
171 auto& state = observeState();
172 if (!state.traceOn.load(std::memory_order_relaxed)) {
175 std::shared_ptr<const TraceSink> sink;
177 std::scoped_lock
const lock{state.traceMtx};
178 sink = state.traceSink;
180 if (!sink || !sink->beginSpan) {
187 return sink->beginSpan(requestId, modelType, actionType);
198inline void endSpan(SpanId
id,
bool ok) {
202 auto& state = observeState();
203 std::shared_ptr<const TraceSink> sink;
205 std::scoped_lock
const lock{state.traceMtx};
206 sink = state.traceSink;
208 if (!sink || !sink->endSpan) {
213 sink->endSpan(
id, ok);
227inline void setMetricSink(MetricSink sink) {
228 auto& state = detail::observeState();
229 bool const enabled =
static_cast<bool>(sink);
230 auto held = std::make_shared<const MetricSink>(std::move(sink));
231 std::scoped_lock
const lock{state.metricMtx};
232 state.metricSink = std::move(held);
233 state.metricsOn.store(enabled, std::memory_order_relaxed);
238[[nodiscard]]
inline bool metricsEnabled() noexcept {
239 return detail::observeState().metricsOn.load(std::memory_order_relaxed);
250inline void setTraceSink(
TraceSink sink) {
251 auto& state = detail::observeState();
252 bool const enabled =
static_cast<bool>(sink.beginSpan) &&
static_cast<bool>(sink.endSpan);
253 auto held = std::make_shared<const TraceSink>(std::move(sink));
254 std::scoped_lock
const lock{state.traceMtx};
255 state.traceSink = std::move(held);
256 state.traceOn.store(enabled, std::memory_order_relaxed);
274 auto& state = detail::observeState();
276 std::scoped_lock
const lock{state.metricMtx};
277 if (state.metricSink) {
278 _savedMetricSink = *state.metricSink;
282 std::scoped_lock
const lock{state.traceMtx};
283 if (state.traceSink) {
284 _savedTraceSink = *state.traceSink;
291 setMetricSink(std::move(_savedMetricSink));
292 setTraceSink(std::move(_savedTraceSink));
301 MetricSink _savedMetricSink;
RAII helper that snapshots the global metric and trace sinks and restores them in the destructor.
~ScopedObserveOverride()
Restores the saved metric and trace sinks.
ScopedObserveOverride()
Snapshots the current metric and trace sinks without changing them.
One metric observation delivered to the installed MetricSink.
double value
The observed value (a duration, a count, or a gauge level).
Metric metric
Which metric this observation is for.
std::span< const std::pair< std::string_view, std::string_view > > tags
Dimensions for this observation (e.g. modelType, actionType, outcome), without baking them into Metri...
Host-supplied hooks bracketing one dispatch, for distributed tracing.
std::function< SpanId(std::string_view requestId, std::string_view modelType, std::string_view actionType)> beginSpan
Called when an execute begins dispatch (on the model strand).
std::function< void(SpanId spanId, bool ok)> endSpan
Called when the dispatch resolves. ok is true for a successful (ok/resolved-value) outcome,...