Skip to content

Commit a12deb1

Browse files
authored
Replace TraceHooks with TracedProvider (#39)
And update otel4s to 0.10 The IOLocal solution doesn't work for propagating trace context to traces created in the provider, and also doesn't provide much context for the evaluation details
1 parent cefad31 commit a12deb1

File tree

8 files changed

+203
-155
lines changed

8 files changed

+203
-155
lines changed

build.sbt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ import build.V
22

33
Global / onChangedBuildSource := ReloadOnSourceChanges
44

5-
// https://typelevel.org/sbt-typelevel/faq.html#what-is-a-base-version-anyway
6-
ThisBuild / tlBaseVersion := "0.4" // your current series x.y
5+
ThisBuild / tlBaseVersion := "0.5"
76

87
ThisBuild / organization := "io.cardell"
98
ThisBuild / organizationName := "Alex Cardell"

docs/index.md

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -142,13 +142,22 @@ def clientWithHook(client: FeatureClient[IO]) =
142142
```scala mdoc
143143
import cats.effect.IO
144144
import org.typelevel.otel4s.trace.Tracer
145-
import io.cardell.openfeature.FeatureClient
146-
import io.cardell.openfeature.otel4s.TraceHooks
145+
import io.cardell.openfeature.provider.EvaluationProvider
146+
import io.cardell.openfeature.otel4s.TracedProvider
147+
148+
def traceExample(
149+
provider: EvaluationProvider[IO]
150+
)(implicit T: Tracer[IO]) =
151+
new TracedProvider[IO](provider)
152+
153+
// or
154+
155+
import io.cardell.openfeature.otel4s.syntax._
147156

148-
def tracedClient(
149-
client: FeatureClient[IO]
150-
)(implicit T: Tracer[IO]) = TraceHooks.ioLocal
151-
.map(hooks => client.withHooks(hooks))
157+
def tracedProviderSyntax(
158+
provider: EvaluationProvider[IO]
159+
)(implicit T: Tracer[IO]) =
160+
provider.withTracing
152161
```
153162

154163
### Variants

openfeature/sdk-otel4s/src/main/scala/io/cardell/openfeature/otel4s/TraceHook.scala

Lines changed: 0 additions & 91 deletions
This file was deleted.
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
* Copyright 2023 Alex Cardell
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.cardell.openfeature.otel4s
18+
19+
import cats.MonadThrow
20+
import cats.syntax.all._
21+
import org.typelevel.otel4s.Attributes
22+
import org.typelevel.otel4s.trace.StatusCode
23+
import org.typelevel.otel4s.trace.Tracer
24+
25+
import io.cardell.openfeature.EvaluationContext
26+
import io.cardell.openfeature.StructureCodec
27+
import io.cardell.openfeature.otel4s.FeatureFlagAttributes.FeatureFlagKey
28+
import io.cardell.openfeature.otel4s.FeatureFlagAttributes.FeatureFlagProviderName
29+
import io.cardell.openfeature.otel4s.FeatureFlagAttributes.FeatureFlagVariant
30+
import io.cardell.openfeature.provider.EvaluationProvider
31+
import io.cardell.openfeature.provider.ProviderMetadata
32+
import io.cardell.openfeature.provider.ResolutionDetails
33+
34+
class TracedProvider[F[_]: Tracer: MonadThrow](
35+
provider: EvaluationProvider[F]
36+
) extends EvaluationProvider[F] {
37+
38+
override def metadata: ProviderMetadata = provider.metadata
39+
40+
override def resolveBooleanValue(
41+
flagKey: String,
42+
defaultValue: Boolean,
43+
context: EvaluationContext
44+
): F[ResolutionDetails[Boolean]] =
45+
trace("boolean", flagKey)(
46+
provider.resolveBooleanValue(
47+
flagKey,
48+
defaultValue,
49+
context
50+
)
51+
)
52+
53+
override def resolveStringValue(
54+
flagKey: String,
55+
defaultValue: String,
56+
context: EvaluationContext
57+
): F[ResolutionDetails[String]] =
58+
trace("string", flagKey)(
59+
provider.resolveStringValue(
60+
flagKey,
61+
defaultValue,
62+
context
63+
)
64+
)
65+
66+
override def resolveIntValue(
67+
flagKey: String,
68+
defaultValue: Int,
69+
context: EvaluationContext
70+
): F[ResolutionDetails[Int]] =
71+
trace("int", flagKey)(
72+
provider.resolveIntValue(
73+
flagKey,
74+
defaultValue,
75+
context
76+
)
77+
)
78+
79+
override def resolveDoubleValue(
80+
flagKey: String,
81+
defaultValue: Double,
82+
context: EvaluationContext
83+
): F[ResolutionDetails[Double]] =
84+
trace("double", flagKey)(
85+
provider.resolveDoubleValue(
86+
flagKey,
87+
defaultValue,
88+
context
89+
)
90+
)
91+
92+
override def resolveStructureValue[A: StructureCodec](
93+
flagKey: String,
94+
defaultValue: A,
95+
context: EvaluationContext
96+
): F[ResolutionDetails[A]] =
97+
trace("structure", flagKey)(
98+
provider.resolveStructureValue(
99+
flagKey,
100+
defaultValue,
101+
context
102+
)
103+
)
104+
105+
private def flagAttributes(flagKey: String): Attributes = Attributes(
106+
FeatureFlagKey(flagKey),
107+
FeatureFlagProviderName(metadata.name)
108+
)
109+
110+
private def variantAttributes(maybeVariant: Option[String]): Attributes =
111+
Attributes.empty.concat(FeatureFlagVariant.maybe(maybeVariant))
112+
113+
private def trace[A](flagType: String, flagKey: String)(
114+
fa: F[ResolutionDetails[A]]
115+
): F[ResolutionDetails[A]] = Tracer[F]
116+
.span(s"evaluate-${flagType}-flag")
117+
.use { span =>
118+
for {
119+
_ <- span.addAttributes(flagAttributes(flagKey))
120+
res <- fa.onError(span.recordException(_))
121+
_ <- span.addAttributes(variantAttributes(res.variant))
122+
_ <- span.setStatus(StatusCode.Ok)
123+
} yield res
124+
}
125+
126+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2023 Alex Cardell
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.cardell.openfeature.otel4s.syntax
18+
19+
import cats.MonadThrow
20+
import org.typelevel.otel4s.trace.Tracer
21+
22+
import io.cardell.openfeature.otel4s.TracedProvider
23+
import io.cardell.openfeature.provider.EvaluationProvider
24+
25+
class EvaluationProviderOps[F[_]: Tracer: MonadThrow](
26+
provider: EvaluationProvider[F]
27+
) {
28+
def withTracing: EvaluationProvider[F] = new TracedProvider[F](provider)
29+
}
30+
31+
trait EvaluationProviderSyntax {
32+
33+
implicit def ops[F[_]: Tracer: MonadThrow](
34+
provider: EvaluationProvider[F]
35+
): EvaluationProviderOps[F] = new EvaluationProviderOps[F](provider)
36+
37+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright 2023 Alex Cardell
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.cardell.openfeature.otel4s
18+
19+
package object syntax extends EvaluationProviderSyntax

0 commit comments

Comments
 (0)