5
5
"encoding/json"
6
6
"errors"
7
7
"fmt"
8
+ "github.com/harness/ff-golang-server-sdk/sdk_codes"
8
9
"log"
9
10
"math/rand"
10
11
"net/http"
@@ -90,7 +91,7 @@ func NewCfClient(sdkKey string, options ...ConfigOption) (*CfClient, error) {
90
91
}
91
92
92
93
if sdkKey == "" {
93
- config .Logger .Errorf ("Initialization failed: SDK Key cannot be empty. Please provide a valid SDK Key to initialize the client." )
94
+ config .Logger .Errorf ("%s Initialization failed: SDK Key cannot be empty. Please provide a valid SDK Key to initialize the client." , sdk_codes . InitMissingKey )
94
95
return client , EmptySDKKeyError
95
96
}
96
97
@@ -113,10 +114,13 @@ func NewCfClient(sdkKey string, options ...ConfigOption) (*CfClient, error) {
113
114
114
115
client .start ()
115
116
if config .waitForInitialized {
117
+ config .Logger .Infof ("%s The SDK is waiting for initialization to complete'" , sdk_codes .InitWaiting )
118
+
116
119
var initErr error
117
120
118
121
select {
119
122
case <- client .initialized :
123
+ config .Logger .Infof ("%s The SDK has successfully initialized'" , sdk_codes .InitSuccess )
120
124
return client , nil
121
125
case err := <- client .initializedErr :
122
126
initErr = err
@@ -144,6 +148,7 @@ func (c *CfClient) start() {
144
148
145
149
go func () {
146
150
if err := c .initAuthentication (context .Background ()); err != nil {
151
+ c .config .Logger .Error ("%s The SDK has failed to initialize due to an authentication error: %v' " , sdk_codes .InitAuthError , err )
147
152
c .initializedErr <- err
148
153
}
149
154
}()
@@ -240,7 +245,7 @@ func (c *CfClient) streamConnect(ctx context.Context) {
240
245
sseClient := sse .NewClient (fmt .Sprintf ("%s/stream?cluster=%s" , c .config .url , c .clusterIdentifier ))
241
246
242
247
streamErr := func () {
243
- c .config .Logger .Warn ( " Stream disconnected. Swapping to polling mode" )
248
+ c .config .Logger .Warnf ( "%s Stream disconnected. Swapping to polling mode", sdk_codes . StreamDisconnected )
244
249
c .mux .RLock ()
245
250
defer c .mux .RUnlock ()
246
251
c .streamConnected = false
@@ -276,25 +281,26 @@ func (c *CfClient) initAuthentication(ctx context.Context) error {
276
281
for {
277
282
err := c .authenticate (ctx )
278
283
if err == nil {
284
+ c .config .Logger .Infof ("%s Authenticated successfully'" , sdk_codes .AuthSuccess )
279
285
return nil
280
286
}
281
287
282
288
var nonRetryableAuthError NonRetryableAuthError
283
289
if errors .As (err , & nonRetryableAuthError ) {
284
- c .config .Logger .Error ("Authentication failed with a non-retryable error: '%s %s' Default variations will now be served" , nonRetryableAuthError .StatusCode , nonRetryableAuthError .Message )
290
+ c .config .Logger .Error ("%s Authentication failed with a non-retryable error: '%s %s' Default variations will now be served" , sdk_codes . AuthFailed , nonRetryableAuthError .StatusCode , nonRetryableAuthError .Message )
285
291
return err
286
292
}
287
293
288
294
// -1 is the default maxAuthRetries option and indicates there should be no max attempts
289
295
if c .config .maxAuthRetries != - 1 && attempts >= c .config .maxAuthRetries {
290
- c .config .Logger .Errorf ("Authentication failed with error: '%s'. Exceeded max attempts: '%v'." , err , c .config .maxAuthRetries )
296
+ c .config .Logger .Errorf ("%s Authentication failed with error: '%s'. Exceeded max attempts: '%v'." , sdk_codes . AuthExceededRetries , err , c .config .maxAuthRetries )
291
297
return err
292
298
}
293
299
294
300
jitter := time .Duration (rand .Float64 () * float64 (currentDelay ))
295
301
delayWithJitter := currentDelay + jitter
296
302
297
- c .config .Logger .Errorf ("Authentication failed with error: '%s'. Retrying in %v." , err , delayWithJitter )
303
+ c .config .Logger .Errorf ("%s Authentication failed with error: '%s'. Retrying in %v." , sdk_codes . AuthAttempt , err , delayWithJitter )
298
304
c .config .sleeper .Sleep (delayWithJitter )
299
305
300
306
currentDelay *= time .Duration (factor )
@@ -414,10 +420,12 @@ func (c *CfClient) makeTicker(interval uint) *time.Ticker {
414
420
func (c * CfClient ) pullCronJob (ctx context.Context ) {
415
421
poll := func () {
416
422
c .mux .RLock ()
423
+ c .config .Logger .Infof ("%s Polling started, interval: %v" , sdk_codes .PollStart , c .config .pullInterval )
417
424
if ! c .streamConnected {
418
425
ok := c .retrieve (ctx )
419
426
// we should only try and start the stream after the poll succeeded to make sure we get the latest changes
420
427
if ok && c .config .enableStream {
428
+ c .config .Logger .Infof ("%s Polling Stopped" , sdk_codes .PollStop )
421
429
// here stream is enabled but not connected, so we attempt to reconnect
422
430
c .config .Logger .Info ("Attempting to start stream" )
423
431
c .streamConnect (ctx )
@@ -437,6 +445,8 @@ func (c *CfClient) pullCronJob(ctx context.Context) {
437
445
select {
438
446
case <- ctx .Done ():
439
447
pullingTicker .Stop ()
448
+ c .config .Logger .Infof ("%s Polling stopped" , sdk_codes .PollStop )
449
+ c .config .Logger .Infof ("%s Stream stopped" , sdk_codes .StreamStop )
440
450
return
441
451
case <- pullingTicker .C :
442
452
poll ()
@@ -508,14 +518,18 @@ func (c *CfClient) setAnalyticsServiceClient(ctx context.Context) {
508
518
}
509
519
510
520
// BoolVariation returns the value of a boolean feature flag for a given target.
511
- //
512
521
// Returns defaultValue if there is an error or if the flag doesn't exist
513
522
func (c * CfClient ) BoolVariation (key string , target * evaluation.Target , defaultValue bool ) (bool , error ) {
514
523
if ! c .initializedBool {
515
- c .config .Logger .Info ( " Error when calling BoolVariation and returning default variation: 'Client is not initialized'" )
524
+ c .config .Logger .Infof ( "%s Error while evaluating boolean flag and returning default variation: 'Client is not initialized'", sdk_codes . EvaluationFailed )
516
525
return defaultValue , fmt .Errorf ("%w: Client is not initialized" , DefaultVariationReturnedError )
517
526
}
518
- value := c .evaluator .BoolVariation (key , target , defaultValue )
527
+ value , err := c .evaluator .BoolVariation (key , target , defaultValue )
528
+ if err != nil {
529
+ c .config .Logger .Infof ("%s Error while evaluating boolean flag and returning default variation '%s', err: %v" , sdk_codes .EvaluationFailed , key , err )
530
+ return value , fmt .Errorf ("%w: `%v`" , DefaultVariationReturnedError , err )
531
+ }
532
+ c .config .Logger .Debugf ("%s Evaluated boolean flag successfully: '%s'" , sdk_codes .EvaluationSuccess , key )
519
533
return value , nil
520
534
}
521
535
@@ -524,10 +538,15 @@ func (c *CfClient) BoolVariation(key string, target *evaluation.Target, defaultV
524
538
// Returns defaultValue if there is an error or if the flag doesn't exist
525
539
func (c * CfClient ) StringVariation (key string , target * evaluation.Target , defaultValue string ) (string , error ) {
526
540
if ! c .initializedBool {
527
- c .config .Logger .Info ( " Error when calling StringVariation and returning default variation: 'Client is not initialized'" )
541
+ c .config .Logger .Infof ( "%s Error while evaluating string flag and returning default variation: 'Client is not initialized'", sdk_codes . EvaluationFailed )
528
542
return defaultValue , fmt .Errorf ("%w: Client is not initialized" , DefaultVariationReturnedError )
529
543
}
530
- value := c .evaluator .StringVariation (key , target , defaultValue )
544
+ value , err := c .evaluator .StringVariation (key , target , defaultValue )
545
+ if err != nil {
546
+ c .config .Logger .Infof ("%s Error while evaluating string flag '%s', err: %v" , sdk_codes .EvaluationFailed , key , err )
547
+ return value , fmt .Errorf ("%w: `%v`" , DefaultVariationReturnedError , err )
548
+ }
549
+ c .config .Logger .Debugf ("%s Evaluated string flag successfully: '%s'" , sdk_codes .EvaluationSuccess , key )
531
550
return value , nil
532
551
}
533
552
@@ -536,10 +555,15 @@ func (c *CfClient) StringVariation(key string, target *evaluation.Target, defaul
536
555
// Returns defaultValue if there is an error or if the flag doesn't exist
537
556
func (c * CfClient ) IntVariation (key string , target * evaluation.Target , defaultValue int64 ) (int64 , error ) {
538
557
if ! c .initializedBool {
539
- c .config .Logger .Info ( " Error when calling IntVariation and returning default variation: 'Client is not initialized'" )
558
+ c .config .Logger .Infof ( "%s Error while evaluating int flag and returning default variation: 'Client is not initialized'", sdk_codes . EvaluationFailed )
540
559
return defaultValue , fmt .Errorf ("%w: Client is not initialized" , DefaultVariationReturnedError )
541
560
}
542
- value := c .evaluator .IntVariation (key , target , int (defaultValue ))
561
+ value , err := c .evaluator .IntVariation (key , target , int (defaultValue ))
562
+ if err != nil {
563
+ c .config .Logger .Infof ("%s Error while evaluating int flag '%s', err: %v" , sdk_codes .EvaluationFailed , key , err )
564
+ return int64 (value ), fmt .Errorf ("%w: `%v`" , DefaultVariationReturnedError , err )
565
+ }
566
+ c .config .Logger .Debugf ("%s Evaluated int flag successfully: '%s'" , sdk_codes .EvaluationSuccess , key )
543
567
return int64 (value ), nil
544
568
}
545
569
@@ -548,10 +572,15 @@ func (c *CfClient) IntVariation(key string, target *evaluation.Target, defaultVa
548
572
// Returns defaultValue if there is an error or if the flag doesn't exist
549
573
func (c * CfClient ) NumberVariation (key string , target * evaluation.Target , defaultValue float64 ) (float64 , error ) {
550
574
if ! c .initializedBool {
551
- c .config .Logger .Info ( " Error when calling NumberVariation and returning default variation: 'Client is not initialized'" )
575
+ c .config .Logger .Infof ( "%s Error while number number flag and returning default variation: 'Client is not initialized'", sdk_codes . EvaluationFailed )
552
576
return defaultValue , fmt .Errorf ("%w: Client is not initialized" , DefaultVariationReturnedError )
553
577
}
554
- value := c .evaluator .NumberVariation (key , target , defaultValue )
578
+ value , err := c .evaluator .NumberVariation (key , target , defaultValue )
579
+ if err != nil {
580
+ c .config .Logger .Infof ("%s Error while evaluating number flag '%s', err: %v" , sdk_codes .EvaluationFailed , key , err )
581
+ return value , fmt .Errorf ("%w: `%v`" , DefaultVariationReturnedError , err )
582
+ }
583
+ c .config .Logger .Debugf ("%s Evaluated number flag successfully: '%s'" , sdk_codes .EvaluationSuccess , key )
555
584
return value , nil
556
585
}
557
586
@@ -561,10 +590,15 @@ func (c *CfClient) NumberVariation(key string, target *evaluation.Target, defaul
561
590
// Returns defaultValue if there is an error or if the flag doesn't exist
562
591
func (c * CfClient ) JSONVariation (key string , target * evaluation.Target , defaultValue types.JSON ) (types.JSON , error ) {
563
592
if ! c .initializedBool {
564
- c .config .Logger .Info ( " Error when calling JSONVariation and returning default variation: 'Client is not initialized'" )
593
+ c .config .Logger .Infof ( "%s Error while evaluating json flag and returning default variation: 'Client is not initialized'", sdk_codes . EvaluationFailed )
565
594
return defaultValue , fmt .Errorf ("%w: Client is not initialized" , DefaultVariationReturnedError )
566
595
}
567
- value := c .evaluator .JSONVariation (key , target , defaultValue )
596
+ value , err := c .evaluator .JSONVariation (key , target , defaultValue )
597
+ if err != nil {
598
+ c .config .Logger .Infof ("%s Error while evaluating json flag '%s', err: %v" , sdk_codes .EvaluationFailed , key , err )
599
+ return value , fmt .Errorf ("%w: `%v`" , DefaultVariationReturnedError , err )
600
+ }
601
+ c .config .Logger .Debugf ("%s Evaluated json flag successfully: '%s'" , sdk_codes .EvaluationSuccess , key )
568
602
return value , nil
569
603
}
570
604
@@ -577,13 +611,21 @@ func (c *CfClient) Close() error {
577
611
if c .stopped .get () {
578
612
return errors .New ("client already closed" )
579
613
}
614
+ c .config .Logger .Infof ("%s Closing SDK" , sdk_codes .CloseStarted )
580
615
close (c .stop )
581
616
582
617
c .stopped .set (true )
618
+
619
+ // This flag is used by `IsInitialized` so set to true.
620
+ c .initializedBoolLock .Lock ()
621
+ c .initializedBool = false
622
+ c .initializedBoolLock .Unlock ()
623
+ c .config .Logger .Infof ("%s SDK Closed successfully" , sdk_codes .CloseSuccess )
624
+
583
625
return nil
584
626
}
585
627
586
- // Environment returns environment based on authenticated SDK key
628
+ // Environment returns environment based on authenticated SDK flagIdentifier
587
629
func (c * CfClient ) Environment () string {
588
630
return c .environmentID
589
631
}
0 commit comments