Skip to content

Commit 90776ec

Browse files
authoredApr 12, 2024··
make tracing spans cheaper to construct (#2502)
1 parent e3e0924 commit 90776ec

File tree

3 files changed

+98
-74
lines changed

3 files changed

+98
-74
lines changed
 

‎.changeset/nice-phones-attack.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"effect": patch
3+
---
4+
5+
make tracing spans cheaper to construct

‎packages/effect/src/internal/core-effect.ts

+76-65
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,11 @@ import type * as runtimeFlagsPatch from "../RuntimeFlagsPatch.js"
2727
import * as Tracer from "../Tracer.js"
2828
import type { MergeRecord, NoInfer } from "../Types.js"
2929
import * as internalCause from "./cause.js"
30+
import { clockTag } from "./clock.js"
3031
import * as core from "./core.js"
3132
import * as defaultServices from "./defaultServices.js"
3233
import * as fiberRefsPatch from "./fiberRefs/patch.js"
34+
import type { FiberRuntime } from "./fiberRuntime.js"
3335
import * as metricLabel from "./metric/label.js"
3436
import * as runtimeFlags from "./runtimeFlags.js"
3537
import * as SingleShotGen from "./singleShotGen.js"
@@ -2006,13 +2008,6 @@ export const currentSpan: Effect.Effect<Tracer.Span, Cause.NoSuchElementExceptio
20062008
}
20072009
)
20082010

2009-
const bigint0 = BigInt(0)
2010-
/** @internal */
2011-
export const currentTimeNanosTracing = core.fiberRefGetWith(
2012-
core.currentTracerTimingEnabled,
2013-
(enabled) => enabled ? Clock.currentTimeNanos : core.succeed(bigint0)
2014-
)
2015-
20162011
/* @internal */
20172012
export const linkSpans = dual<
20182013
(
@@ -2040,8 +2035,11 @@ export const linkSpans = dual<
20402035
)
20412036
)
20422037

2038+
const bigint0 = BigInt(0)
2039+
20432040
/** @internal */
2044-
export const makeSpan = (
2041+
export const unsafeMakeSpan = <XA, XE>(
2042+
fiber: FiberRuntime<XA, XE>,
20452043
name: string,
20462044
options?: {
20472045
readonly attributes?: Record<string, unknown> | undefined
@@ -2050,55 +2048,67 @@ export const makeSpan = (
20502048
readonly root?: boolean | undefined
20512049
readonly context?: Context.Context<never> | undefined
20522050
}
2053-
): Effect.Effect<Tracer.Span> =>
2054-
core.flatMap(fiberRefs, (fiberRefs) =>
2055-
core.sync(() => {
2056-
const enabled = FiberRefs.getOrDefault(fiberRefs, core.currentTracerEnabled)
2057-
if (enabled === false) {
2058-
return core.noopSpan(name)
2059-
}
2051+
) => {
2052+
const enabled = fiber.getFiberRef(core.currentTracerEnabled)
2053+
if (enabled === false) {
2054+
return core.noopSpan(name)
2055+
}
20602056

2061-
const context = FiberRefs.getOrDefault(fiberRefs, core.currentContext)
2062-
const services = FiberRefs.getOrDefault(fiberRefs, defaultServices.currentServices)
2063-
2064-
const tracer = Context.get(services, internalTracer.tracerTag)
2065-
const clock = Context.get(services, Clock.Clock)
2066-
const timingEnabled = FiberRefs.getOrDefault(fiberRefs, core.currentTracerTimingEnabled)
2067-
const annotationsFromEnv = FiberRefs.get(fiberRefs, core.currentTracerSpanAnnotations)
2068-
const linksFromEnv = FiberRefs.get(fiberRefs, core.currentTracerSpanLinks)
2069-
2070-
const parent = options?.parent
2071-
? Option.some(options.parent)
2072-
: options?.root
2073-
? Option.none()
2074-
: Context.getOption(context, internalTracer.spanTag)
2075-
2076-
const links = linksFromEnv._tag === "Some" ?
2077-
options?.links !== undefined ?
2078-
[
2079-
...Chunk.toReadonlyArray(linksFromEnv.value),
2080-
...(options?.links ?? [])
2081-
] :
2082-
Chunk.toReadonlyArray(linksFromEnv.value) :
2083-
options?.links ?? ReadonlyArray.empty()
2084-
2085-
const span = tracer.span(
2086-
name,
2087-
parent,
2088-
options?.context ?? Context.empty(),
2089-
links,
2090-
timingEnabled ? clock.unsafeCurrentTimeNanos() : bigint0
2091-
)
2057+
const context = fiber.getFiberRef(core.currentContext)
2058+
const services = fiber.getFiberRef(defaultServices.currentServices)
2059+
2060+
const tracer = Context.get(services, internalTracer.tracerTag)
2061+
const clock = Context.get(services, Clock.Clock)
2062+
const timingEnabled = fiber.getFiberRef(core.currentTracerTimingEnabled)
2063+
2064+
const fiberRefs = fiber.getFiberRefs()
2065+
const annotationsFromEnv = FiberRefs.get(fiberRefs, core.currentTracerSpanAnnotations)
2066+
const linksFromEnv = FiberRefs.get(fiberRefs, core.currentTracerSpanLinks)
2067+
2068+
const parent = options?.parent
2069+
? Option.some(options.parent)
2070+
: options?.root
2071+
? Option.none()
2072+
: Context.getOption(context, internalTracer.spanTag)
2073+
2074+
const links = linksFromEnv._tag === "Some" ?
2075+
options?.links !== undefined ?
2076+
[
2077+
...Chunk.toReadonlyArray(linksFromEnv.value),
2078+
...(options?.links ?? [])
2079+
] :
2080+
Chunk.toReadonlyArray(linksFromEnv.value) :
2081+
options?.links ?? ReadonlyArray.empty()
2082+
2083+
const span = tracer.span(
2084+
name,
2085+
parent,
2086+
options?.context ?? Context.empty(),
2087+
links,
2088+
timingEnabled ? clock.unsafeCurrentTimeNanos() : bigint0
2089+
)
20922090

2093-
if (annotationsFromEnv._tag === "Some") {
2094-
HashMap.forEach(annotationsFromEnv.value, (value, key) => span.attribute(key, value))
2095-
}
2096-
if (options?.attributes) {
2097-
Object.entries(options.attributes).forEach(([k, v]) => span.attribute(k, v))
2098-
}
2091+
if (annotationsFromEnv._tag === "Some") {
2092+
HashMap.forEach(annotationsFromEnv.value, (value, key) => span.attribute(key, value))
2093+
}
2094+
if (options?.attributes !== undefined) {
2095+
Object.entries(options.attributes).forEach(([k, v]) => span.attribute(k, v))
2096+
}
20992097

2100-
return span
2101-
}))
2098+
return span
2099+
}
2100+
2101+
/** @internal */
2102+
export const makeSpan = (
2103+
name: string,
2104+
options?: {
2105+
readonly attributes?: Record<string, unknown> | undefined
2106+
readonly links?: ReadonlyArray<Tracer.SpanLink> | undefined
2107+
readonly parent?: Tracer.ParentSpan | undefined
2108+
readonly root?: boolean | undefined
2109+
readonly context?: Context.Context<never> | undefined
2110+
}
2111+
): Effect.Effect<Tracer.Span> => core.withFiberRuntime((fiber) => core.succeed(unsafeMakeSpan(fiber, name, options)))
21022112

21032113
/* @internal */
21042114
export const spanAnnotations: Effect.Effect<HashMap.HashMap<string, unknown>> = core
@@ -2134,17 +2144,18 @@ export const useSpan: {
21342144
} | undefined = args.length === 1 ? undefined : args[0]
21352145
const evaluate: (span: Tracer.Span) => Effect.Effect<A, E, R> = args[args.length - 1]
21362146

2137-
return core.acquireUseRelease(
2138-
makeSpan(name, options),
2139-
evaluate,
2140-
(span, exit) =>
2141-
span.status._tag === "Ended" ?
2142-
core.unit :
2143-
core.flatMap(
2144-
currentTimeNanosTracing,
2145-
(endTime) => core.sync(() => span.end(endTime, exit))
2146-
)
2147-
)
2147+
return core.withFiberRuntime<A, E, R>((fiber) => {
2148+
const span = unsafeMakeSpan(fiber, name, options)
2149+
const timingEnabled = fiber.getFiberRef(core.currentTracerTimingEnabled)
2150+
const clock = Context.get(fiber.getFiberRef(defaultServices.currentServices), clockTag)
2151+
return core.onExit(evaluate(span), (exit) =>
2152+
core.sync(() => {
2153+
if (span.status._tag === "Ended") {
2154+
return
2155+
}
2156+
span.end(timingEnabled ? clock.unsafeCurrentTimeNanos() : bigint0, exit)
2157+
}))
2158+
})
21482159
}
21492160

21502161
/** @internal */

‎packages/effect/src/internal/fiberRuntime.ts

+17-9
Original file line numberDiff line numberDiff line change
@@ -3578,15 +3578,23 @@ export const makeSpanScoped = (
35783578
readonly context?: Context.Context<never> | undefined
35793579
}
35803580
): Effect.Effect<Tracer.Span, never, Scope.Scope> =>
3581-
acquireRelease(
3582-
internalEffect.makeSpan(name, options),
3583-
(span, exit) =>
3584-
span.status._tag === "Ended" ?
3585-
core.unit :
3586-
core.flatMap(
3587-
internalEffect.currentTimeNanosTracing,
3588-
(endTime) => core.sync(() => span.end(endTime, exit))
3589-
)
3581+
core.uninterruptible(
3582+
core.withFiberRuntime((fiber) => {
3583+
const scope = Context.unsafeGet(fiber.getFiberRef(core.currentContext), scopeTag)
3584+
const span = internalEffect.unsafeMakeSpan(fiber, name, options)
3585+
const timingEnabled = fiber.getFiberRef(core.currentTracerTimingEnabled)
3586+
const clock_ = Context.get(fiber.getFiberRef(defaultServices.currentServices), clock.clockTag)
3587+
return core.as(
3588+
core.scopeAddFinalizerExit(scope, (exit) =>
3589+
core.sync(() => {
3590+
if (span.status._tag === "Ended") {
3591+
return
3592+
}
3593+
span.end(timingEnabled ? clock_.unsafeCurrentTimeNanos() : BigInt(0), exit)
3594+
})),
3595+
span
3596+
)
3597+
})
35903598
)
35913599

35923600
/* @internal */

0 commit comments

Comments
 (0)
Please sign in to comment.