Skip to content

Commit

Permalink
Merge branch 'main' into update-scala3
Browse files Browse the repository at this point in the history
  • Loading branch information
alexcardell authored Dec 12, 2024
2 parents f06f9f4 + a12deb1 commit f85f37d
Show file tree
Hide file tree
Showing 8 changed files with 203 additions and 155 deletions.
3 changes: 1 addition & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import build.V

Global / onChangedBuildSource := ReloadOnSourceChanges

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

ThisBuild / organization := "io.cardell"
ThisBuild / organizationName := "Alex Cardell"
Expand Down
21 changes: 15 additions & 6 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,22 @@ def clientWithHook(client: FeatureClient[IO]) =
```scala mdoc
import cats.effect.IO
import org.typelevel.otel4s.trace.Tracer
import io.cardell.openfeature.FeatureClient
import io.cardell.openfeature.otel4s.TraceHooks
import io.cardell.openfeature.provider.EvaluationProvider
import io.cardell.openfeature.otel4s.TracedProvider

def traceExample(
provider: EvaluationProvider[IO]
)(implicit T: Tracer[IO]) =
new TracedProvider[IO](provider)

// or

import io.cardell.openfeature.otel4s.syntax._

def tracedClient(
client: FeatureClient[IO]
)(implicit T: Tracer[IO]) = TraceHooks.ioLocal
.map(hooks => client.withHooks(hooks))
def tracedProviderSyntax(
provider: EvaluationProvider[IO]
)(implicit T: Tracer[IO]) =
provider.withTracing
```

### Variants
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* Copyright 2023 Alex Cardell
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.cardell.openfeature.otel4s

import cats.MonadThrow
import cats.syntax.all._
import org.typelevel.otel4s.Attributes
import org.typelevel.otel4s.trace.StatusCode
import org.typelevel.otel4s.trace.Tracer

import io.cardell.openfeature.EvaluationContext
import io.cardell.openfeature.StructureCodec
import io.cardell.openfeature.otel4s.FeatureFlagAttributes.FeatureFlagKey
import io.cardell.openfeature.otel4s.FeatureFlagAttributes.FeatureFlagProviderName
import io.cardell.openfeature.otel4s.FeatureFlagAttributes.FeatureFlagVariant
import io.cardell.openfeature.provider.EvaluationProvider
import io.cardell.openfeature.provider.ProviderMetadata
import io.cardell.openfeature.provider.ResolutionDetails

class TracedProvider[F[_]: Tracer: MonadThrow](
provider: EvaluationProvider[F]
) extends EvaluationProvider[F] {

override def metadata: ProviderMetadata = provider.metadata

override def resolveBooleanValue(
flagKey: String,
defaultValue: Boolean,
context: EvaluationContext
): F[ResolutionDetails[Boolean]] =
trace("boolean", flagKey)(
provider.resolveBooleanValue(
flagKey,
defaultValue,
context
)
)

override def resolveStringValue(
flagKey: String,
defaultValue: String,
context: EvaluationContext
): F[ResolutionDetails[String]] =
trace("string", flagKey)(
provider.resolveStringValue(
flagKey,
defaultValue,
context
)
)

override def resolveIntValue(
flagKey: String,
defaultValue: Int,
context: EvaluationContext
): F[ResolutionDetails[Int]] =
trace("int", flagKey)(
provider.resolveIntValue(
flagKey,
defaultValue,
context
)
)

override def resolveDoubleValue(
flagKey: String,
defaultValue: Double,
context: EvaluationContext
): F[ResolutionDetails[Double]] =
trace("double", flagKey)(
provider.resolveDoubleValue(
flagKey,
defaultValue,
context
)
)

override def resolveStructureValue[A: StructureCodec](
flagKey: String,
defaultValue: A,
context: EvaluationContext
): F[ResolutionDetails[A]] =
trace("structure", flagKey)(
provider.resolveStructureValue(
flagKey,
defaultValue,
context
)
)

private def flagAttributes(flagKey: String): Attributes = Attributes(
FeatureFlagKey(flagKey),
FeatureFlagProviderName(metadata.name)
)

private def variantAttributes(maybeVariant: Option[String]): Attributes =
Attributes.empty.concat(FeatureFlagVariant.maybe(maybeVariant))

private def trace[A](flagType: String, flagKey: String)(
fa: F[ResolutionDetails[A]]
): F[ResolutionDetails[A]] = Tracer[F]
.span(s"evaluate-${flagType}-flag")
.use { span =>
for {
_ <- span.addAttributes(flagAttributes(flagKey))
res <- fa.onError(span.recordException(_))
_ <- span.addAttributes(variantAttributes(res.variant))
_ <- span.setStatus(StatusCode.Ok)
} yield res
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2023 Alex Cardell
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.cardell.openfeature.otel4s.syntax

import cats.MonadThrow
import org.typelevel.otel4s.trace.Tracer

import io.cardell.openfeature.otel4s.TracedProvider
import io.cardell.openfeature.provider.EvaluationProvider

class EvaluationProviderOps[F[_]: Tracer: MonadThrow](
provider: EvaluationProvider[F]
) {
def withTracing: EvaluationProvider[F] = new TracedProvider[F](provider)
}

trait EvaluationProviderSyntax {

implicit def ops[F[_]: Tracer: MonadThrow](
provider: EvaluationProvider[F]
): EvaluationProviderOps[F] = new EvaluationProviderOps[F](provider)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright 2023 Alex Cardell
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.cardell.openfeature.otel4s

package object syntax extends EvaluationProviderSyntax
Loading

0 comments on commit f85f37d

Please sign in to comment.