-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New modules + span context maybe? #236
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 module setup looks good!
build.sbt
Outdated
lazy val `sdk-common` = crossProject(JVMPlatform, JSPlatform, NativePlatform) | ||
.crossType(CrossType.Pure) | ||
.in(file("sdk/common")) | ||
.dependsOn(`core-common`) | ||
.settings( | ||
name := "otel4s-sdk-common", | ||
libraryDependencies ++= Seq( | ||
"org.typelevel" %%% "cats-effect-kernel" % CatsEffectVersion, | ||
"org.typelevel" %%% "cats-mtl" % CatsMtlVersion, | ||
"org.scalameta" %%% "munit" % MUnitVersion % Test | ||
), | ||
) | ||
|
||
lazy val `sdk-trace` = crossProject(JVMPlatform, JSPlatform, NativePlatform) | ||
.crossType(CrossType.Pure) | ||
.in(file("sdk/trace")) | ||
.dependsOn(`sdk-common`, `core-trace`) | ||
.settings( | ||
name := "otel4s-sdk-trace", | ||
libraryDependencies ++= Seq( | ||
"org.typelevel" %%% "cats-effect" % CatsEffectVersion, | ||
), | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably we can add munitDependencies
to both modules. You are planning to write tests for tracing right 😜
lazy val `sdk-common` = crossProject(JVMPlatform, JSPlatform, NativePlatform) | |
.crossType(CrossType.Pure) | |
.in(file("sdk/common")) | |
.dependsOn(`core-common`) | |
.settings( | |
name := "otel4s-sdk-common", | |
libraryDependencies ++= Seq( | |
"org.typelevel" %%% "cats-effect-kernel" % CatsEffectVersion, | |
"org.typelevel" %%% "cats-mtl" % CatsMtlVersion, | |
"org.scalameta" %%% "munit" % MUnitVersion % Test | |
), | |
) | |
lazy val `sdk-trace` = crossProject(JVMPlatform, JSPlatform, NativePlatform) | |
.crossType(CrossType.Pure) | |
.in(file("sdk/trace")) | |
.dependsOn(`sdk-common`, `core-trace`) | |
.settings( | |
name := "otel4s-sdk-trace", | |
libraryDependencies ++= Seq( | |
"org.typelevel" %%% "cats-effect" % CatsEffectVersion, | |
), | |
) | |
lazy val `sdk-common` = crossProject(JVMPlatform, JSPlatform, NativePlatform) | |
.crossType(CrossType.Pure) | |
.in(file("sdk/common")) | |
.dependsOn(`core-common`) | |
.settings( | |
name := "otel4s-sdk-common", | |
libraryDependencies ++= Seq( | |
"org.typelevel" %%% "cats-effect-kernel" % CatsEffectVersion, | |
"org.typelevel" %%% "cats-mtl" % CatsMtlVersion | |
), | |
) | |
.settings(munitDependencies) | |
lazy val `sdk-trace` = crossProject(JVMPlatform, JSPlatform, NativePlatform) | |
.crossType(CrossType.Pure) | |
.in(file("sdk/trace")) | |
.dependsOn(`sdk-common`, `core-trace`) | |
.settings( | |
name := "otel4s-sdk-trace", | |
libraryDependencies ++= Seq( | |
"org.typelevel" %%% "cats-effect" % CatsEffectVersion, | |
), | |
) | |
.settings(munitDependencies) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, just saw this. Will revise to add :)
I wanted to clarify -- is an implementation of
Is the implementation instead going to sit in our existing |
* limitations under the License. | ||
*/ | ||
|
||
package org.typelevel.otel4s // ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this would be the appropriate package name?
package org.typelevel.otel4s // ? | |
package org.typelevel.otel4s.sdk.trace |
|
||
import org.typelevel.otel4s.trace.SpanContext | ||
|
||
final class SpanContextImpl extends SpanContext { // does a impl belong in the sdk? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can make this a case class
with all the fields below as its members. And actually we can probably keep the class private
, since users will always work with the SpanContext
interface.
Ohhhh, very good catch 🤔
That does sound like it should be implemented in the API, and not in the SDK. That seems fine for the Scala SDK, but will it complicate the Java wrapper? |
Wondering if some work here rightfully belongs in #243 instead. Will make new PR and shift some changes over there, if that's appropriate |
👍 yes definitely, I think the |
build.sbt
Outdated
) | ||
.settings(munitDependencies) | ||
|
||
lazy val `sdk-trace` = crossProject(JVMPlatform, JSPlatform, NativePlatform) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I forgot, you also need to add these to the "root aggregate" somewhere higher up in the build. I think that's why CI appears to be passing, because it's not actually compiling these sources yet 😅
samplingDecision: SamplingDecision, | ||
isValid: Boolean, | ||
isRemote: Boolean, | ||
storeInContext: Vault |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SpanContext
defines storeInContext
as follows:
def storeInContext(context: Vault): Vault =
context.insert(SpanContext.key, this)
Should we make it final
and remove it from the SpanContextImpl
? I guess it should work unless there will be a custom logic.
def samplingDecision: SamplingDecision = | ||
SamplingDecision.fromBoolean( | ||
(flags & SpanContext.SampledMask) == SpanContext.SampledMask | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@iRevive I'm a little confused if this is the right API to expose here.
I see SamplingDecision
is described here, which is actually an enum with three states.
https://opentelemetry.io/docs/specs/otel/trace/sdk/#shouldsample
But this seems to be different from the Sampled
flag, which is only a Boolean
and is described here.
https://opentelemetry.io/docs/specs/otel/trace/sdk/#sampling
I see that the Java API exposes a Boolean
on SpanContext
, even though they also have a SamplingDecision
enum.
otel4s/java/trace/src/main/scala/org/typelevel/otel4s/java/trace/WrappedSpanContext.scala
Lines 42 to 43 in 6bb372d
lazy val samplingDecision: SamplingDecision = | |
SamplingDecision.fromBoolean(jSpanContext.isSampled) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nearly there! Just needs a couple tests, some bike shed, some polish, and a fight with CI 😅
build.sbt
Outdated
"org.typelevel" %%% "cats-mtl" % CatsMtlVersion, | ||
), | ||
) | ||
.settings(munitDependencies) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add .enablePlugins(NoPublishPlugin)
for sdk-common
and sdk-trace
until we are ready to publish them.
def isValidSpanId(id: ByteVector): Boolean = | ||
(id.length == SpanContext.SpanId.HexLength) && (id != SpanContext.invalid.spanId) | ||
|
||
/** Checks whether a trace id has correct length and is not the | ||
* invalid id. | ||
*/ | ||
def isValidTraceId(id: ByteVector): Boolean = | ||
(id.length == SpanContext.TraceId.HexLength) && (id != SpanContext.invalid.traceId) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are some good methods to have some tests for.
|
||
sealed trait TraceFlags { | ||
def toByte: Byte | ||
def isSampled: Boolean |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think isSampled
is another good one to test. e.g. check that it's value is expected for fromByte(0)
and fromByte(1)
and maybe a couple other random values ...
private[trace] object WrappedSpanContext { | ||
private[java] object SpanConversions { | ||
|
||
def wrap(jSpanContext: JSpanContext): SpanContext = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe fromJSpanContext
, toJSpanContext
?
lazy val traceId: ByteVector = | ||
ByteVector(jSpanContext.getTraceIdBytes) | ||
|
||
lazy val spanId: ByteVector = | ||
ByteVector(jSpanContext.getSpanIdBytes) | ||
|
||
val traceFlags = TraceFlags.fromByte(jSpanContext.getTraceFlags().asByte()) | ||
|
||
def isRemote: Boolean = | ||
jSpanContext.isRemote |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably these can all be val
s now.
context match { | ||
case ctx: WrappedSpanContext => | ||
ctx.jSpanContext | ||
|
||
case other if other.isRemote => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we no longer need a match
, we can directly call methods on context
.
# Conflicts: # .github/workflows/ci.yml # java/trace/src/main/scala/org/typelevel/otel4s/java/ContextConversions.scala
Draft PR as usual! New modules added to the build file.
Feedback welcome; I took a guess at what to do here (and a very big guess at possible dependencies, though, I'll know as I go?)
I also figured "add a new module to the build file" and "implement my first thing (span context)?" could go hand-in-hand for my first PR, because with some implementation, I'll better know some of those dependencies (and also because the former, by itself, felt a bit small for one PR. Though let me know if we should get that merged first anyway, and I'll separate the concerns).