@@ -12,6 +12,9 @@ import (
12
12
"strings"
13
13
14
14
"github.com/samber/lo"
15
+ "go.opentelemetry.io/otel/attribute"
16
+ otelcodes "go.opentelemetry.io/otel/codes"
17
+ "go.opentelemetry.io/otel/trace"
15
18
16
19
"github.com/openmeterio/openmeter/openmeter/app"
17
20
appstripeentity "github.com/openmeterio/openmeter/openmeter/app/stripe/entity"
@@ -34,6 +37,7 @@ type subjectCustomerHook struct {
34
37
35
38
provisioner * CustomerProvisioner
36
39
logger * slog.Logger
40
+ tracer trace.Tracer
37
41
38
42
ignoreErrors bool
39
43
}
@@ -56,11 +60,33 @@ func (s subjectCustomerHook) provision(ctx context.Context, sub *subject.Subject
56
60
}
57
61
58
62
func (s subjectCustomerHook ) PostCreate (ctx context.Context , sub * subject.Subject ) error {
59
- return s .provision (ctx , sub )
63
+ ctx , span := s .tracer .Start (ctx , "subject_customer_hook.post_create" )
64
+ defer span .End ()
65
+
66
+ err := s .provision (ctx , sub )
67
+ if err != nil {
68
+ span .SetStatus (otelcodes .Error , "failed to provision customer for subject" )
69
+ span .RecordError (err )
70
+ } else {
71
+ span .SetStatus (otelcodes .Ok , "customer provisioned for subject" )
72
+ }
73
+
74
+ return err
60
75
}
61
76
62
77
func (s subjectCustomerHook ) PostUpdate (ctx context.Context , sub * subject.Subject ) error {
63
- return s .provision (ctx , sub )
78
+ ctx , span := s .tracer .Start (ctx , "subject_customer_hook.post_update" )
79
+ defer span .End ()
80
+
81
+ err := s .provision (ctx , sub )
82
+ if err != nil {
83
+ span .SetStatus (otelcodes .Error , "failed to provision customer for subject" )
84
+ span .RecordError (err )
85
+ } else {
86
+ span .SetStatus (otelcodes .Ok , "customer provisioned for subject" )
87
+ }
88
+
89
+ return err
64
90
}
65
91
66
92
func NewSubjectCustomerHook (config SubjectCustomerHookConfig ) (SubjectCustomerHook , error ) {
@@ -72,6 +98,7 @@ func NewSubjectCustomerHook(config SubjectCustomerHookConfig) (SubjectCustomerHo
72
98
Customer : config .Customer ,
73
99
CustomerOverride : config .CustomerOverride ,
74
100
Logger : config .Logger ,
101
+ Tracer : config .Tracer ,
75
102
})
76
103
if err != nil {
77
104
return nil , fmt .Errorf ("failed to initialize customer provisioner: %w" , err )
@@ -80,6 +107,7 @@ func NewSubjectCustomerHook(config SubjectCustomerHookConfig) (SubjectCustomerHo
80
107
return & subjectCustomerHook {
81
108
provisioner : provisioner ,
82
109
logger : config .Logger .With ("subsystem" , "subject_customer_provisioner" ),
110
+ tracer : config .Tracer ,
83
111
ignoreErrors : config .IgnoreErrors ,
84
112
}, nil
85
113
}
@@ -88,6 +116,7 @@ type SubjectCustomerHookConfig struct {
88
116
Customer customer.Service
89
117
CustomerOverride billing.CustomerOverrideService
90
118
Logger * slog.Logger
119
+ Tracer trace.Tracer
91
120
92
121
// IgnoreErrors if set to true makes the hooks ignore (not returning error)
93
122
IgnoreErrors bool
@@ -108,6 +137,10 @@ func (c SubjectCustomerHookConfig) Validate() error {
108
137
errs = append (errs , fmt .Errorf ("logger is required" ))
109
138
}
110
139
140
+ if c .Tracer == nil {
141
+ errs = append (errs , fmt .Errorf ("tracer is required" ))
142
+ }
143
+
111
144
return errors .Join (errs ... )
112
145
}
113
146
@@ -149,6 +182,7 @@ type CustomerProvisionerConfig struct {
149
182
Customer customer.Service
150
183
CustomerOverride billing.CustomerOverrideService
151
184
Logger * slog.Logger
185
+ Tracer trace.Tracer
152
186
}
153
187
154
188
func (c CustomerProvisionerConfig ) Validate () error {
@@ -166,6 +200,10 @@ func (c CustomerProvisionerConfig) Validate() error {
166
200
errs = append (errs , fmt .Errorf ("logger is required" ))
167
201
}
168
202
203
+ if c .Tracer == nil {
204
+ errs = append (errs , fmt .Errorf ("tracer is required" ))
205
+ }
206
+
169
207
return errors .Join (errs ... )
170
208
}
171
209
@@ -178,13 +216,15 @@ func NewCustomerProvisioner(config CustomerProvisionerConfig) (*CustomerProvisio
178
216
customer : config .Customer ,
179
217
customerOverride : config .CustomerOverride ,
180
218
logger : config .Logger .With ("subsystem" , "customer.provisioner" ),
219
+ tracer : config .Tracer ,
181
220
}, nil
182
221
}
183
222
184
223
type CustomerProvisioner struct {
185
224
customer customer.Service
186
225
customerOverride billing.CustomerOverrideService
187
226
logger * slog.Logger
227
+ tracer trace.Tracer
188
228
}
189
229
190
230
var ErrCustomerKeyConflict = errors .New ("customer key conflict" )
@@ -236,6 +276,26 @@ func (p CustomerProvisioner) EnsureCustomer(ctx context.Context, sub *subject.Su
236
276
return nil , errors .New ("failed to provision customer for subject: subject is nil" )
237
277
}
238
278
279
+ var err error
280
+
281
+ ctx , span := p .tracer .Start (ctx , "customer_provisioner.ensure_customer" )
282
+ defer func () {
283
+ if err != nil {
284
+ span .SetStatus (otelcodes .Error , err .Error ())
285
+ span .RecordError (err )
286
+ } else {
287
+ span .SetStatus (otelcodes .Ok , "customer provisioned for subject" )
288
+ }
289
+
290
+ span .End ()
291
+ }()
292
+
293
+ span .SetAttributes (
294
+ attribute .String ("subject.id" , sub .Id ),
295
+ attribute .String ("subject.key" , sub .Key ),
296
+ attribute .String ("subject.stripe_customer_id" , lo .FromPtrOr (sub .StripeCustomerId , "nil" )),
297
+ )
298
+
239
299
var keyConflict bool
240
300
241
301
cus , err := p .getCustomerForSubject (ctx , sub )
@@ -263,6 +323,11 @@ func (p CustomerProvisioner) EnsureCustomer(ctx context.Context, sub *subject.Su
263
323
}
264
324
265
325
if cus != nil {
326
+ span .AddEvent ("found customer" , trace .WithAttributes (
327
+ attribute .String ("customer.id" , cus .ID ),
328
+ attribute .String ("customer.key" , lo .FromPtrOr (cus .Key , "nil" )),
329
+ ))
330
+
266
331
if CmpSubjectCustomer (sub , cus ) {
267
332
return cus , nil
268
333
}
@@ -313,11 +378,13 @@ func (p CustomerProvisioner) EnsureCustomer(ctx context.Context, sub *subject.Su
313
378
customerID .Namespace , customerID .ID , err )
314
379
}
315
380
381
+ span .AddEvent ("updated customer" )
382
+
316
383
return cus , nil
317
384
}
318
385
319
386
// Create Customer for Subject in case there is none to be found
320
- return p .customer .CreateCustomer (
387
+ cus , err = p .customer .CreateCustomer (
321
388
subjectservicehooks .NewContextWithSkipSubjectCustomer (ctx ),
322
389
customer.CreateCustomerInput {
323
390
Namespace : sub .Namespace ,
@@ -341,6 +408,17 @@ func (p CustomerProvisioner) EnsureCustomer(ctx context.Context, sub *subject.Su
341
408
Annotation : & annotations ,
342
409
},
343
410
})
411
+ if err != nil {
412
+ return nil , fmt .Errorf ("failed to create customer for subject [namespace=%s subject.key=%s]: %w" ,
413
+ sub .Namespace , sub .Key , err )
414
+ }
415
+
416
+ span .AddEvent ("created customer" , trace .WithAttributes (
417
+ attribute .String ("customer.id" , cus .ID ),
418
+ attribute .String ("customer.key" , lo .FromPtrOr (cus .Key , "nil" )),
419
+ ))
420
+
421
+ return cus , err
344
422
}
345
423
346
424
type InvalidPaymentAppError struct {
@@ -353,6 +431,25 @@ func (e InvalidPaymentAppError) Error() string {
353
431
}
354
432
355
433
func (p CustomerProvisioner ) EnsureStripeCustomer (ctx context.Context , customerID customer.CustomerID , stripeCustomerID string ) error {
434
+ var err error
435
+
436
+ ctx , span := p .tracer .Start (ctx , "customer_provisioner.ensure_stripe_customer" )
437
+ defer func () {
438
+ if err != nil {
439
+ span .SetStatus (otelcodes .Error , err .Error ())
440
+ span .RecordError (err )
441
+ } else {
442
+ span .SetStatus (otelcodes .Ok , "stripe customer provisioned" )
443
+ }
444
+
445
+ span .End ()
446
+ }()
447
+
448
+ span .SetAttributes (
449
+ attribute .String ("customer.id" , customerID .ID ),
450
+ attribute .String ("customer.namespace" , customerID .Namespace ),
451
+ )
452
+
356
453
customerOverride , err := p .customerOverride .GetCustomerOverride (ctx , billing.GetCustomerOverrideInput {
357
454
Customer : customerID ,
358
455
Expand : billing.CustomerOverrideExpand {
@@ -366,6 +463,11 @@ func (p CustomerProvisioner) EnsureStripeCustomer(ctx context.Context, customerI
366
463
367
464
profile := customerOverride .MergedProfile
368
465
466
+ span .AddEvent ("fetched customer billing profile" , trace .WithAttributes (
467
+ attribute .String ("profile.id" , profile .ID ),
468
+ attribute .String ("profile.namespace" , profile .Namespace ),
469
+ ))
470
+
369
471
if profile .Apps == nil {
370
472
return fmt .Errorf ("failed to setup stripe customer id for customer [namespace=%s customer.id=%s]: apps profile is nil" ,
371
473
customerID .Namespace , customerID .ID )
@@ -389,6 +491,11 @@ func (p CustomerProvisioner) EnsureStripeCustomer(ctx context.Context, customerI
389
491
customerID .Namespace , customerID .ID , err )
390
492
}
391
493
494
+ span .AddEvent ("updated stripe customer data" , trace .WithAttributes (
495
+ attribute .String ("app.id" , profile .Apps .Payment .GetID ().ID ),
496
+ attribute .String ("app.namespace" , profile .Apps .Payment .GetID ().Namespace ),
497
+ ))
498
+
392
499
return nil
393
500
}
394
501
0 commit comments