Trace operations where they mean something

Telemetry means logs, metrics, and traces.

Name the operation a person needs to understand. Add only context safe for that operation’s telemetry.

A tracing span records an operation’s timing and outcome. Export is a separate delivery step.

Name meaningful operations

FileInspector.inspect uses a named Effect.fn:

packages/core/src/file-inspector.ts · 65e9465f
  {
    readonly inspect: (
      path: string
    ) => Effect.Effect<FileStats, FileStatsError>;
  }
>()("@rat-stack/core/FileInspector", {
  make: Effect.gen(function* makeFileInspector() {
    const fileSystem = yield* FileSystem.FileSystem;

    const inspect = Effect.fn("FileInspector.inspect")(function* inspect(
      path: string
    ) {
      const content = yield* fileSystem
        .readFile(path)
        .pipe(
          Effect.mapError(
            (error) => new FileStatsError({ path, reason: error.message })
          )

Use a named fn for a reusable operation that deserves a span. Use withSpan around an existing Effect when that boundary carries useful meaning. Use fnUntraced for reusable functions that do not need tracing, especially small library functions and frequently executed code.

Do not create a span merely because a helper exists. Choose boundaries that answer a question about the job’s duration, dependencies or failure.

Add safe attributes deliberately

A span name should remain stable across requests. Put safe variation in attributes instead of generating a new name for every input. Keep unrestricted input, credentials, request bodies and private identities out of telemetry.

Useful contextAvoid
Operation phase or bounded outcome nameFull request or response bodies
A deliberate public categoryCredentials and authorization headers
A measured count relevant to the operationUnrestricted input or private identity

Structured attributes can outlive the request. Structure does not make a private value safe.

Use annotateCurrentSpan when adding attributes inside the operation. Use annotateSpans when supplying annotations through an enclosing Effect. Review the resulting payload as well as the annotation call.

Supply an exporter, serializer and transport

The exporter prepares trace data. The serializer encodes it. The transport sends it.

OTLP means OpenTelemetry Protocol. A collector receives trace data.

The checked fixture composes the OTLP tracer with JSON serialization and an in-memory HTTP client:

packages/core/test/trace-export.test.ts · 4019cffb
      const tracing = OtlpTracer.layer({
        resource: { serviceName: "wiki-fixture" },
        url: "https://collector.example.test/v1/traces",
      }).pipe(
        Layer.provide(OtlpSerialization.layerJson),
        Layer.provide(Layer.succeed(HttpClient.HttpClient, client))
      );

      yield* Effect.scoped(
        Effect.void.pipe(
          Effect.withSpan("fixture.read"),
          Effect.annotateSpans({ phase: "read" }),
          Effect.provide(tracing)
        )
      );

These observability modules are marked unstable in the exact 4.0.0 source. A stable package version does not make every exported module’s API stable. Keep the exact pin and check its source before changing exporter composition.

Check the delivery boundary you actually exercised

The fixture’s transport decodes outbound JSON through a small Schema. It records the payload in a Ref instead of contacting a collector. After shutdown, the test requires the operation name and the annotation key.

packages/core/test/trace-export.test.ts · 4019cffb

      const spans = (yield* Ref.get(deliveries)).flatMap((delivery) =>
        delivery.resourceSpans.flatMap((resource) =>
          resource.scopeSpans.flatMap((scope) => scope.spans)
        )
      );

      expect(spans.map((span) => span.name)).toContain("fixture.read");
      expect(
        spans.flatMap((span) =>
          span.attributes.map((attribute) => attribute.key)
        )
      ).toContain("phase");
    })

The fixture observes a serialized export request. It does not prove backend acceptance, storage, or a production exporter configuration.

EvidenceWhat it establishes
Named fn in sourceAn instrumentation boundary exists
Decoded outbound request in the fixtureThis composed exporter emits the expected trace fields
Collector receiptThat collector accepted the payload
A queried stored traceThe backend retained a trace you can retrieve

None of these observations substitutes for the next delivery boundary.

Native tracing includes platform data

TRACES_ENABLED defaults to false. TRACES_HEAD_SAMPLING_RATE defaults to 0.01 and accepts finite values from zero through one.

The Effect tracer drops arbitrary attributes, events and links. Its native completion attribute records only a fixed outcome. Its tests cover this boundary. They do not prove privacy for Cloudflare’s automatic spans.

Cloudflare documents these automatic fields:

SpanDocumented data
Fetch handlerFull URL, path, accept headers, language, user agent, geographic data and ASN
Outbound fetchFull URL and query, selected headers, method, status and body sizes
Cache operationRequest URL, selected cache and conditional headers, and payload sizes
D1 and Durable Object SQLSQL text; Durable Object SQL also records query bindings
KV and R2Keys, prefixes, metadata and operation details; R2 also lists encryption-key-related fields
RPCMethod or property path, target kind and correlation IDs
Email handlerSender, recipient and message size
Root and child spansWorker identity, invocation/version IDs and region; root spans add outcome and timing

Full URLs and query strings can contain tokens or email addresses. SQL bindings, storage keys and custom metadata can contain private values. The Effect attribute policy does not redact these platform fields.

For outbound fetch, the listed headers include content-type, content-length, accept and accept-encoding. Fetch handlers also list accept-language.

The documentation lists body sizes. Body contents, Authorization values and Cookie values are absent from that list. That list does not prove that all runtime versions omit other fields. The representation of R2 encryption-key-related fields remains unverified here.

Owner approval is required before enabling native traces. Review this list and the authenticated plan before changing the flag. A low sampling rate reduces collection volume. It does not make captured private values safe.

Mischief and RpcBackend register a per-event telemetry Layer. The Website builds its native tracer inside each request. Its development and prerender paths work without the Cloudflare runtime. These Layers retain no request tracer or async-context map across requests.

Keep other observers distinct

Devtools7 records capability calls and watched actor lifecycles. Request analytics18 captures request events through its own sink. Neither system substitutes for trace-export evidence.

Logs also have their own logger and export configuration. Do not claim a log was delivered because it appeared in a local console.

Common mistakes

Effect idiom and house rule

Next, run Effect at the integration boundary8 and connect observability lifetime to its runtime owner. Return to the Effect reading order17.

Sources

  1. Cloudflare. 2026. Spans and attributes. Updated September 17, 2026.. Cloudflare. Automatic spans include URLs, query strings, selected headers, SQL text, storage keys and metadata. These spans are separate from Effect attribute handling. Accessed 2026-10-09.
  2. Effect contributors. 2026. Effect tracing operators. Effect 4.0.0.. Effect-TS. Named fn creates tracing spans; fnUntraced avoids that tracing boundary; withSpan and annotation operators add useful context. Accessed 2026-10-06.
  3. Effect contributors. 2026. Setting up tracing with Otlp modules.. Effect-TS. Exporters require explicit serialization and HTTP transport Layers; creating spans and exporting them are distinct operations. Accessed 2026-10-06.
  4. Effect contributors. 2026. OtlpTracer.. Effect-TS. The tracer batches completed sampled spans, sends them through an exporter, and supplies scoped flushing. This module is marked unstable in the 4.0.0 source. Accessed 2026-10-06.
  5. rat-stack contributors. 2026. FileInspector operation tracing.. rat-stack. FileInspector.inspect names a useful operation with Effect.fn rather than tracing every expression. Accessed 2026-10-06.
  6. rat-stack contributors. 2026. Trace export fixture.. rat-stack. A supplied in-memory HTTP transport decodes the emitted OTLP JSON and checks the operation name and attribute key after scope shutdown. Accessed 2026-10-06.
  7. Langton, Kit. 2026. Observability. Effect Solutions.. Kit Langton. The draft frames OTLP composition. Its dependency and HTTP-import examples are not this page's version authority. Accessed 2026-10-06.

Last changed 2026-10-08 in 29ccee3. Source on GitHub. Change log.

Linked from

  1. Agent guide. An Effect stack so pure (aspirational) Kit Langton will blush.

    Trace operations where they mean something — Name useful operations, add safe context, and distinguish creating a span from delivering it to a backend.

  2. Change log. What changed in the files served here, newest first.

    Trace operations where they mean something — edited: feat: add opt-in request-scoped native tracing with privacy proofs

  3. Effect basics. An Effect describes work, expected failures, and required services before a runtime executes it.

    Tracing: name meaningful operations and inspect export evidence.¶

  4. Full agent guide. An Effect stack so pure (aspirational) Kit Langton will blush.
  5. HTTP success needs a status check and a decoder. Supply the client, check the response status, decode accepted data, and name failures at the adapter boundary.

    Then read tracing to observe the operation without exposing private values.

  6. Rat Stack lore | rat-stack. Short, source-grounded notes on the ideas and decisions behind rat-stack.

    Trace operations where they mean something — Name useful operations, add safe context, and distinguish creating a span from delivering it to a backend.

  7. Source change history (log.md). The generated change log as Markdown.

    Trace operations where they mean something — edited: feat: add opt-in request-scoped native tracing with privacy proofs

Unlinked mentions (5)
  • Analytics → The tail Worker has no public HTTP route and disables its own observability.
  • Anti-money → He names secrets and observability in that discussion.
  • Effect Meetup SF 2023: Why Effect? → Michael presents Effect as a missing standard library for TypeScript, bringing typed errors and requirements, structured concurrency, observability, resource safety, and composition into one runtime.
  • Interest signup → A trace span records an operation’s timing and outcome.¶
  • profile-a-worker → The dashboard has the same capture under the Worker’s Observability tab, view Flamegraph.¶

Content updated .