@@ -3,6 +3,8 @@ package openfeature
33import (
44 "errors"
55 "fmt"
6+
7+ "github.com/go-logr/logr"
68)
79
810// IClient defines the behaviour required of an openfeature client
@@ -38,6 +40,7 @@ type Client struct {
3840 metadata ClientMetadata
3941 hooks []Hook
4042 evaluationContext EvaluationContext
43+ logger logr.Logger
4144}
4245
4346// NewClient returns a new Client. Name is a unique identifier for this client
@@ -46,9 +49,16 @@ func NewClient(name string) *Client {
4649 metadata : ClientMetadata {name : name },
4750 hooks : []Hook {},
4851 evaluationContext : EvaluationContext {},
52+ logger : api .logger ,
4953 }
5054}
5155
56+ // WithLogger sets the logger of the client
57+ func (c * Client ) WithLogger (l logr.Logger ) * Client {
58+ c .logger = l
59+ return c
60+ }
61+
5262// Metadata returns the client's metadata
5363func (c Client ) Metadata () ClientMetadata {
5464 return c .metadata
@@ -57,11 +67,15 @@ func (c Client) Metadata() ClientMetadata {
5767// AddHooks appends to the client's collection of any previously added hooks
5868func (c * Client ) AddHooks (hooks ... Hook ) {
5969 c .hooks = append (c .hooks , hooks ... )
70+ c .logger .V (info ).Info ("appended hooks to client" , "client" , c .Metadata ().name , "hooks" , hooks )
6071}
6172
6273// SetEvaluationContext sets the client's evaluation context
6374func (c * Client ) SetEvaluationContext (evalCtx EvaluationContext ) {
6475 c .evaluationContext = evalCtx
76+ c .logger .V (info ).Info (
77+ "set client evaluation context" , "client" , c .Metadata ().name , "evaluationContext" , evalCtx ,
78+ )
6579}
6680
6781// EvaluationContext returns the client's evaluation context
@@ -80,6 +94,18 @@ const (
8094 Object
8195)
8296
97+ func (t Type ) String () string {
98+ return typeToString [t ]
99+ }
100+
101+ var typeToString = map [Type ]string {
102+ Boolean : "bool" ,
103+ String : "string" ,
104+ Float : "float" ,
105+ Int : "int" ,
106+ Object : "object" ,
107+ }
108+
83109type EvaluationDetails struct {
84110 FlagKey string
85111 FlagType Type
@@ -88,14 +114,20 @@ type EvaluationDetails struct {
88114
89115// BooleanValue return boolean evaluation for flag
90116func (c Client ) BooleanValue (flag string , defaultValue bool , evalCtx EvaluationContext , options EvaluationOptions ) (bool , error ) {
117+
91118 evalDetails , err := c .evaluate (flag , Boolean , defaultValue , evalCtx , options )
92119 if err != nil {
93- return defaultValue , fmt . Errorf ( "evaluate: %w" , err )
120+ return defaultValue , err
94121 }
95122
96123 value , ok := evalDetails .Value .(bool )
97124 if ! ok {
98- return defaultValue , errors .New ("evaluated value is not a boolean" )
125+ err := errors .New ("evaluated value is not a boolean" )
126+ c .logger .Error (
127+ err , "invalid flag resolution type" , "expectedType" , "bool" ,
128+ "gotType" , fmt .Sprintf ("%T" , evalDetails .Value ),
129+ )
130+ return defaultValue , err
99131 }
100132
101133 return value , nil
@@ -105,12 +137,17 @@ func (c Client) BooleanValue(flag string, defaultValue bool, evalCtx EvaluationC
105137func (c Client ) StringValue (flag string , defaultValue string , evalCtx EvaluationContext , options EvaluationOptions ) (string , error ) {
106138 evalDetails , err := c .evaluate (flag , String , defaultValue , evalCtx , options )
107139 if err != nil {
108- return defaultValue , fmt . Errorf ( "evaluate: %w" , err )
140+ return defaultValue , err
109141 }
110142
111143 value , ok := evalDetails .Value .(string )
112144 if ! ok {
113- return defaultValue , errors .New ("evaluated value is not a string" )
145+ err := errors .New ("evaluated value is not a string" )
146+ c .logger .Error (
147+ err , "invalid flag resolution type" , "expectedType" , "string" ,
148+ "gotType" , fmt .Sprintf ("%T" , evalDetails .Value ),
149+ )
150+ return defaultValue , err
114151 }
115152
116153 return value , nil
@@ -120,12 +157,17 @@ func (c Client) StringValue(flag string, defaultValue string, evalCtx Evaluation
120157func (c Client ) FloatValue (flag string , defaultValue float64 , evalCtx EvaluationContext , options EvaluationOptions ) (float64 , error ) {
121158 evalDetails , err := c .evaluate (flag , Float , defaultValue , evalCtx , options )
122159 if err != nil {
123- return defaultValue , fmt . Errorf ( "evaluate: %w" , err )
160+ return defaultValue , err
124161 }
125162
126163 value , ok := evalDetails .Value .(float64 )
127164 if ! ok {
128- return defaultValue , errors .New ("evaluated value is not a float64" )
165+ err := errors .New ("evaluated value is not a float64" )
166+ c .logger .Error (
167+ err , "invalid flag resolution type" , "expectedType" , "float64" ,
168+ "gotType" , fmt .Sprintf ("%T" , evalDetails .Value ),
169+ )
170+ return defaultValue , err
129171 }
130172
131173 return value , nil
@@ -135,12 +177,17 @@ func (c Client) FloatValue(flag string, defaultValue float64, evalCtx Evaluation
135177func (c Client ) IntValue (flag string , defaultValue int64 , evalCtx EvaluationContext , options EvaluationOptions ) (int64 , error ) {
136178 evalDetails , err := c .evaluate (flag , Int , defaultValue , evalCtx , options )
137179 if err != nil {
138- return defaultValue , fmt . Errorf ( "evaluate: %w" , err )
180+ return defaultValue , err
139181 }
140182
141183 value , ok := evalDetails .Value .(int64 )
142184 if ! ok {
143- return defaultValue , errors .New ("evaluated value is not an int64" )
185+ err := errors .New ("evaluated value is not an int64" )
186+ c .logger .Error (
187+ err , "invalid flag resolution type" , "expectedType" , "int64" ,
188+ "gotType" , fmt .Sprintf ("%T" , evalDetails .Value ),
189+ )
190+ return defaultValue , err
144191 }
145192
146193 return value , nil
@@ -180,6 +227,10 @@ func (c Client) ObjectValueDetails(flag string, defaultValue interface{}, evalCt
180227func (c Client ) evaluate (
181228 flag string , flagType Type , defaultValue interface {}, evalCtx EvaluationContext , options EvaluationOptions ,
182229) (EvaluationDetails , error ) {
230+ c .logger .V (debug ).Info (
231+ "evaluating flag" , "flag" , flag , "type" , flagType .String (), "defaultValue" , defaultValue ,
232+ "evaluationContext" , evalCtx , "evaluationOptions" , options ,
233+ )
183234 evalCtx = mergeContexts (evalCtx , c .evaluationContext , api .evaluationContext ) // API (global) -> client -> invocation
184235
185236 var err error
@@ -208,7 +259,11 @@ func (c Client) evaluate(
208259 evalCtx , err = c .beforeHooks (hookCtx , apiClientInvocationProviderHooks , evalCtx , options )
209260 hookCtx .evaluationContext = evalCtx
210261 if err != nil {
211- err = fmt .Errorf ("execute before hook: %w" , err )
262+ c .logger .Error (
263+ err , "before hook" , "flag" , flag , "defaultValue" , defaultValue ,
264+ "evaluationContext" , evalCtx , "evaluationOptions" , options , "type" , flagType .String (),
265+ )
266+ err = fmt .Errorf ("before hook: %w" , err )
212267 c .errorHooks (hookCtx , providerInvocationClientApiHooks , err , options )
213268 return evalDetails , err
214269 }
@@ -238,7 +293,11 @@ func (c Client) evaluate(
238293
239294 err = resolution .Error ()
240295 if err != nil {
241- err = fmt .Errorf ("evaluate the flag: %w" , err )
296+ c .logger .Error (
297+ err , "flag resolution" , "flag" , flag , "defaultValue" , defaultValue ,
298+ "evaluationContext" , evalCtx , "evaluationOptions" , options , "type" , flagType .String (), "errorCode" , err ,
299+ )
300+ err = fmt .Errorf ("error code: %w" , err )
242301 c .errorHooks (hookCtx , providerInvocationClientApiHooks , err , options )
243302 return evalDetails , err
244303 }
@@ -247,11 +306,16 @@ func (c Client) evaluate(
247306 }
248307
249308 if err := c .afterHooks (hookCtx , providerInvocationClientApiHooks , evalDetails , options ); err != nil {
250- err = fmt .Errorf ("execute after hook: %w" , err )
309+ c .logger .Error (
310+ err , "after hook" , "flag" , flag , "defaultValue" , defaultValue ,
311+ "evaluationContext" , evalCtx , "evaluationOptions" , options , "type" , flagType .String (),
312+ )
313+ err = fmt .Errorf ("after hook: %w" , err )
251314 c .errorHooks (hookCtx , providerInvocationClientApiHooks , err , options )
252315 return evalDetails , err
253316 }
254317
318+ c .logger .V (debug ).Info ("evaluated flag" , "flag" , flag , "details" , evalDetails , "type" , flagType )
255319 return evalDetails , nil
256320}
257321
@@ -269,6 +333,9 @@ func flattenContext(evalCtx EvaluationContext) map[string]interface{} {
269333func (c Client ) beforeHooks (
270334 hookCtx HookContext , hooks []Hook , evalCtx EvaluationContext , options EvaluationOptions ,
271335) (EvaluationContext , error ) {
336+ c .logger .V (debug ).Info ("executing before hooks" )
337+ defer c .logger .V (debug ).Info ("executed before hooks" )
338+
272339 for _ , hook := range hooks {
273340 resultEvalCtx , err := hook .Before (hookCtx , options .hookHints )
274341 if resultEvalCtx != nil {
@@ -285,6 +352,9 @@ func (c Client) beforeHooks(
285352func (c Client ) afterHooks (
286353 hookCtx HookContext , hooks []Hook , evalDetails EvaluationDetails , options EvaluationOptions ,
287354) error {
355+ c .logger .V (debug ).Info ("executing after hooks" )
356+ defer c .logger .V (debug ).Info ("executed after hooks" )
357+
288358 for _ , hook := range hooks {
289359 if err := hook .After (hookCtx , evalDetails , options .hookHints ); err != nil {
290360 return err
@@ -295,12 +365,18 @@ func (c Client) afterHooks(
295365}
296366
297367func (c Client ) errorHooks (hookCtx HookContext , hooks []Hook , err error , options EvaluationOptions ) {
368+ c .logger .V (debug ).Info ("executing error hooks" )
369+ defer c .logger .V (debug ).Info ("executed error hooks" )
370+
298371 for _ , hook := range hooks {
299372 hook .Error (hookCtx , err , options .hookHints )
300373 }
301374}
302375
303376func (c Client ) finallyHooks (hookCtx HookContext , hooks []Hook , options EvaluationOptions ) {
377+ c .logger .V (debug ).Info ("executing finally hooks" )
378+ defer c .logger .V (debug ).Info ("executed finally hooks" )
379+
304380 for _ , hook := range hooks {
305381 hook .Finally (hookCtx , options .hookHints )
306382 }
0 commit comments