@@ -32,8 +32,14 @@ type ctxKey int
32
32
33
33
const (
34
34
sidId ctxKey = iota
35
+ parentRegionId
35
36
)
36
37
38
+ type trace2Region struct {
39
+ level int
40
+ tStart time.Time
41
+ }
42
+
37
43
type Trace2 struct {
38
44
logger * zap.Logger
39
45
}
@@ -105,24 +111,51 @@ func (l fieldList) withTime() fieldList {
105
111
return append (l , zap .Float64 ("t_abs" , time .Since (globalStart ).Seconds ()))
106
112
}
107
113
114
+ func (l fieldList ) withNesting (r trace2Region , includeTRel bool ) fieldList {
115
+ l = append (l , zap .Int ("nesting" , r .level ))
116
+ if includeTRel {
117
+ l = append (l , zap .Float64 ("t_rel" , time .Since (r .tStart ).Seconds ()))
118
+ }
119
+ return l
120
+ }
121
+
108
122
func (l fieldList ) with (f ... zap.Field ) fieldList {
109
123
return append (l , f ... )
110
124
}
111
125
126
+ func getContextValue [T any ](
127
+ ctx context.Context ,
128
+ key ctxKey ,
129
+ ) (bool , T ) {
130
+ var value T
131
+ haveValue := false
132
+ valueAny := ctx .Value (key )
133
+ if valueAny != nil {
134
+ value , haveValue = valueAny .(T )
135
+ }
136
+ return haveValue , value
137
+ }
138
+
139
+ func getOrSetContextValue [T any ](
140
+ ctx context.Context ,
141
+ key ctxKey ,
142
+ newValueFunc func () T ,
143
+ ) (context.Context , T ) {
144
+ var value T
145
+ haveValue , value := getContextValue [T ](ctx , key )
146
+ if ! haveValue {
147
+ value = newValueFunc ()
148
+ ctx = context .WithValue (ctx , key , value )
149
+ }
150
+
151
+ return ctx , value
152
+ }
153
+
112
154
func (t * Trace2 ) sharedFields (ctx context.Context ) (context.Context , fieldList ) {
113
155
fields := fieldList {}
114
156
115
157
// Get the session ID
116
- var sid uuid.UUID
117
- haveSid := false
118
- sidAny := ctx .Value (sidId )
119
- if sidAny != nil {
120
- sid , haveSid = sidAny .(uuid.UUID )
121
- }
122
- if ! haveSid {
123
- sid = uuid .New ()
124
- ctx = context .WithValue (ctx , sidId , sid )
125
- }
158
+ ctx , sid := getOrSetContextValue (ctx , sidId , uuid .New )
126
159
fields = append (fields , zap .String ("sid" , sid .String ()))
127
160
128
161
// Hardcode the thread to "main" because Go doesn't like to share its
@@ -166,6 +199,33 @@ func (t *Trace2) logExit(ctx context.Context, exitCode int) {
166
199
t .logger .Sync ()
167
200
}
168
201
202
+ func (t * Trace2 ) Region (ctx context.Context , category string , label string ) (context.Context , func ()) {
203
+ ctx , sharedFields := t .sharedFields (ctx )
204
+
205
+ // Get the nesting level & increment
206
+ hasParentRegion , nesting := getContextValue [trace2Region ](ctx , parentRegionId )
207
+ if ! hasParentRegion {
208
+ nesting = trace2Region {
209
+ level : 0 ,
210
+ tStart : time .Now (),
211
+ }
212
+ } else {
213
+ nesting .level ++
214
+ nesting .tStart = time .Now ()
215
+ }
216
+ ctx = context .WithValue (ctx , parentRegionId , nesting )
217
+
218
+ regionFields := fieldList {
219
+ zap .String ("category" , category ),
220
+ zap .String ("label" , label ),
221
+ }
222
+
223
+ t .logger .Debug ("region_enter" , sharedFields .withNesting (nesting , false ).with (regionFields ... )... )
224
+ return ctx , func () {
225
+ t .logger .Debug ("region_leave" , sharedFields .withNesting (nesting , true ).with (regionFields ... )... )
226
+ }
227
+ }
228
+
169
229
func (t * Trace2 ) LogCommand (ctx context.Context , commandName string ) context.Context {
170
230
ctx , sharedFields := t .sharedFields (ctx )
171
231
0 commit comments