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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//! §Fase 37.x.j (D4) — pin observability emitter.
//!
//! Centralizes the `tracing::info!` events fired on every flow-scoped
//! `PoolConnection<Postgres>` acquire. The structured fields are the
//! load-bearing diagnostic surface for two operational scenarios:
//!
//! 1. **Pin saturation observability** — under load the pool may run
//! out of connections; the operator wants to see WHICH flow held
//! HOW MANY pins for HOW LONG. The acquire-time event with
//! `store_name`, `flow_name`, `trace_id`, and `source` (eager vs
//! lazy) gives a foundation to compute these metrics in any log
//! aggregator (Loki, Datadog, ELK).
//!
//! 2. **Pin-leak detection** — an `acquire` event without a matching
//! drop-time release indicates a code path holds a pin past the
//! flow's lifetime. v1.39.0 ships ONLY acquire-time emit (the
//! release is implicit at `PoolConnection::drop` and happens
//! automatically when the flow-scoped HashMap drops); v1.40.0 may
//! add a `PinObserved` wrapper struct that emits at Drop for
//! explicit per-pin lifetime tracking. The minimal v1.39.0
//! surface honors the rule "no unnecessary observability machinery"
//! while still giving operators enough to detect saturation.
//!
//! `target = "axon::store::pin"` so adopters / SREs can filter the
//! tracing stream via standard subscriber-level filters
//! (`RUST_LOG=axon::store::pin=info`).
/// §Fase 37.x.j (D4) — Emit a structured `tracing::info!` event for a
/// flow-scoped pin acquisition.
///
/// `source` is one of:
///
/// - `"eager"` — acquired at flow start by
/// [`crate::runner::execute_server_flow`] (sync path) or
/// [`crate::streaming_via_dispatcher::run_streaming_via_dispatcher`]
/// (async path) during the eager pin-discovery walk.
/// - `"lazy"` — acquired on-demand at first store-op touch in a
/// par-branch sub-context whose `pinned_conns` map is empty
/// (D6.a default — see [`crate::flow_dispatcher::parallel`]).
///
/// `branch_index` is `Some(idx)` when the acquire happens inside a
/// par-block branch (D6.c); `None` for the parent flow's linear walk.
///
/// The emitted event surface (post-substitution):
///
/// ```text
/// INFO axon::store::pin: pin acquired
/// path="acquire"
/// source="eager" | "lazy"
/// store_name=<axonstore name>
/// flow_name=<executing flow name>
/// trace_id=<request trace id, or empty for CLI / unwired callers>
/// branch_index=<par-block index, or empty for linear path>
/// d_letter="37.x.j.D4"
/// ```
///
/// Pure + total: this is a single `tracing::info!` macro call with
/// structured fields; never panics; zero allocations beyond the
/// formatter's transient string buffers.
/// §Fase 37.x.j (D4) — Symmetric counterpart for the implicit release
/// at end-of-flow. Called once by the flow's outer scope (sync runner
/// or async dispatcher) AFTER the pin map drops, with the total count
/// of pins released. This is a SUMMARY event, not per-pin: per-pin
/// drop happens via `PoolConnection::drop` which fires the `after_release
/// DEALLOCATE ALL` hook (Fase 38.x.a D2) on the way back to the pool.
///
/// A `released_count == acquired_count` is the canonical healthy
/// signal. A persistent mismatch over time would suggest a code path
/// holds a pin in a structure outlasting the flow — load-bearing pin-
/// leak detection signal.