effect-observability
Effect 4 logging, tracing and metrics, and their export.
Skill by andabove
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/andabove-effect-observability
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/effect-observability
What's inside
- Skill name
effect-observability- Description
- Effect 4 logging, tracing and metrics, and their export. Use when adding Effect.log calls or log annotations, choosing or replacing a logger, routing Effect logs into an existing structured logger, adding spans with Effect.fn or Effect.withSpan, recording metrics, or exporting telemetry with the effect/observability OTLP modules or an existing OpenTelemetry SDK.
- License
- MIT
- Instructions
- 194 lines in SKILL.md · view on GitHub
Files (5)
- SKILL.md
- effect-observability-export.md · references/
- effect-observability-loggers.md · references/
- effect-observability-metrics.md · references/
- effect-observability-tracing.md · references/
SKILL.md (first lines)
# Effect observability
Checked against `effect 4.0.0` and `@effect/opentelemetry 4.0.0`. When the project has a newer version, read `node_modules/effect/src/Logger.ts`, `Tracer.ts`, `Metric.ts`, `References.ts` and `node_modules/effect/src/observability/`, and `node_modules/effect/AGENTS.md`, before you trust a name here.
Import each module from its own subpath, as every example here does: `import * as Logger from "effect/Logger"`, `import * as Otlp from "effect/observability/Otlp"`, `import * as OtelTracer from "@effect/opentelemetry/OtelTracer"`.
Instrument with Effect APIs in every module. Choose where the telemetry goes once, at the entry point, with one layer. The signals share context: a log written inside a span becomes an event on that span, and a logger can read the current trace and span ids.
## Logging
```ts
import * as Effect from "effect/Effect"
declare const chargeCard: (orderId: string, cents: number) => Effect.Effect<string, "CardDeclined">
export const placeOrder = Effect.fn("Orders.place")(
function*(orderId: string, cents: number) {
yield* Effect.logDebug("pricing order")
const receipt = yield* chargeCard(orderId, cents).pipe(
Effect.tapError((error) => Effect.logWarning("charge refused").pipe(Effect.annotateLogs({ error })))
)
yield* Effect.logInfo("order placed").pipe(Effect.annotateLogs({ receipt, cents }))
return receipt
},
// trailing arguments receive the effect and the call arguments
(effect, orderId) => Effect.annotateLogs(effect, { orderId })
)
```
- Log with `Effect.logTrace`, `logDebug`, `logInfo` (same as `Effect.log`), `logWarning`, `logError`, `logFatal`. Use `console.log` only outside Effect code; it skips levels, annotations, spans and the configured logger.
- The minimum level is `"Info"`, so `logDebug` and `logTrace` print nothing by default. Set it once at the edge: `Layer.succeed(References.MinimumLogLevel, "Debug")`, or from config with `Config.LogLevel("LOG_LEVEL")` (values `"All"`, `"Trace"`, `"Debug"`, `"Info"`, `"Warn"`, `"Error"`, `"Fatal"`, `"None"`, case-sensitive). `"None"` silences all logs.
- Write a fixed event text as the only message, and put the variable data in `Effect.annotateLogs`. Extra arguments are kept as values in the message array, and a span event built from several arguments is named after their JSON.
- `Effect.annotateLogs(key, value)` or `Effect.annotateLogs({ ... })` reaches every log inside the effect, nested calls included. Annotate request id, tenant and user once at the boundary. `Effect.annotateLogsScoped({ ... })` annotates the rest of the current `Scope`.
- Pass a `Cause` as an argument to attach the failure: `Effect.catchCause((cause) => Effect.logError("import failed", cause))`. Loggers receive it as `cause`, not in the message.
- `Effect.withLogSpan("checkout")` adds `checkout=<ms>` to each log inside: a duration label, not a trace span.
- `Redacted` values print as `<redacted>` in every built-in logger.
## Loggers
A logger receives every entry at or above the minimum level. The default set holds `Logger.defaultLogger` (one human-readable line on stdout: `[12:00:00.000] INFO (#1) checkout=3ms: order placed { orderId: 'o-1' }`) and `Logger.tracerLogger` (adds each log as an event on the current span).
| Need | Layer |
| --- | --- |
| JSON lines for a log pipeline | `Logger.layer([Logger.consoleJson, Logger.tracerLogger])` |
| Colors for local development | `Logger.layer([Logger.consolePretty(), Logger.tracerLogger])` |
| logfmt | `Logger.layer([Logger.consoleLogFmt, Logger.tracerLogger])` |
| Add a logger, keep the current ones | `Logger.layer([myLogger], { mergeWithExisting: true })` |
| JSON lines on stderr | `Logger.layer([Logger.withConsoleError(Logger.formatJson), Logger.tracerLogger])` (`References.LogToStderr` moves only `defaultLogger` and `consolePretty`) |
- `Logger.layer([...])` replaces the whole set. Keep `Logger.tracerLogger` in the list, or logs stop appearing as span events.
- Provide one logger layer at the entry point. A second `Logger.layer` deeper in the program replaces the first for that part only.
- Never put two layers that set loggers (`Logger.layer`, the OTLP logger in `Otlp.layer*`, `OtelLogger.layer`) side by side in `Layer.mergeAll`. Each builds its set from the loggers current when it is built, so one silently drops the other. Nest them instead: `ObservabilityLive.pipe(Layer.provideMerge(LoggingLive))` keeps both.
- In tests, capture entries with `Logger.make` (see [the loggers reference](references/effect-observability-loggers.md)).
## A project with a structured logger already
When the project already ships a logger such as pino or winston, with its transports, redaction and log shipping, keep it as the one sink. Replace Effect's default logger with a bridge that maps level, message, annotations, log spans, cause and trace ids onto the project logger's fields:
```ts
import * as Cause from "effect/Cause"
import * as Logger from "effect/Logger"
import type * as LogLevel from "effect/LogLevel"
import * as Predicate from "effect/Predicate"
import * as References from "effect/References"
type LogFn = (fields: Record<string, unknown>, message: string) => void
// the project's existing logger, pino-style: logger.info(fields, message)
declare const appLogger: Record<"trace" | "debug" | "info" | "warn" | "error" | "fatal", LogFn>
const methods: Record<LogLevel.LogLevel, keyof typeof appLogger> = {
All: "trace", Trace: "trace", Debug: "debug", Info: "info", Warn: "warn", Error: "error", Fatal: "fatal", None: "info"
}
const appLoggerBridge = Logger.make(({ cause, date, fiber, logLevel, message }) => {
const parts: Array<unknown> = Array.isArray(message) ? [...message] : [message]
const text = typeof parts[0] === "string" ? String(parts.shift()) : ""
const fields: Record<string, unknown> = { ...fiber.getRef(References.CurrentLogAnnotations) }
const args: Array<unknown> = []
for (const value of parts) {
if (value instanceof Error) fields["err"] = value
else if (Predicate.isObject(value)) Object.assign(fields, value)
else args.push(value)
}
if (args.length > 0) fields["args"] = args
for (const [label, start] of fiber.getRef(References.CurrentLogSpans)) fields[`${label}_ms`] = date.getTime() - start
const span = fiber.cache.span
if (span !== undefined) Object.assign(fields, { trace_id: span.traceId, span_id: span.spanId })
if (cause.reasons.length > 0) fields["err"] = Cause.squash(cause)
appLogger[methods[logLevel]](fields, text)
})
export const LoggingLive = Logger.layer([appLoggerBridge, Logger.tracerLogger])
```
- Combine it with an OTLP or OpenTelemetry logger by nesting, not `Layer.mergeAll` (see [Loggers](#loggers)).
- Both sides filter by level. Set `References.MinimumLogLevel` to match the project logger's level, or `logDebug` calls are dropped before they reach it.
- Non-Effect code keeps calling the project logger directly. Effect code calls `Effect.log*` only, so annotations and spans apply.
- When the codebase is mostly Effect and has no logger to keep, skip the bridge and use `Logger.consoleJson`.
## Tracing
```ts
import * as Effect from "effect/Effect"
declare const insertOrder: (orderId: string) => Effect.Effect<void>
export const createOrder = Effect.fn("Orders.create", { attributes: { "order.source": "web" } })(
function*(orderId: string, lines: number) {
yield* Effect.annotateCurrentSpan({ "order.id": orderId, "order.lines": lines })
yield* insertOrder(orderId).pipe(Effect.withSpan("Orders.insert", { kind: "client" }))
}
)
export const handleRequest = createOrder("o-1", 3).pipe(
Effect.withSpan("POST /orders", { kind: "server", attributes: { "http.route": "/orders" } })
)
```
- Write every service method and exported effectful function as `Effect.fn("Service.method")(function*() { ... })`. The name becomes the span name and a stack frame. Name it after the function.From andabove/skills, MIT.
More from andabove/skills
- 0.570score
effect-testing
andabove
Testing Effect code with @effect/vitest, TestClock and test layers.
SkillAFreshness: AClaude Code +9 - 0.570score
effect
andabove
Effect (the TypeScript library) core and router to the other Effect skills.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-adoption
andabove
Adopting Effect in an existing Promise codebase one module at a time.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-concurrency
andabove
Effect concurrency - fibers, interruption, coordination and Schedule.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-data
andabove
Effect 4 data types, equality, caching and batching.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-errors
andabove
Effect error handling, for expected errors, defects and interruptions.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-schema
andabove
Effect 4 Schema for parsing and modelling data.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-services
andabove
Effect 4 services, layers and resources.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-streams
andabove
Effect Stream, Sink and Channel.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-v3-to-v4
andabove
Effect v3 to v4 migration.
SkillAFreshness: AClaude Code +9 - 0.565score
linear-comment
andabove
Write a comment on a Linear issue as a status record against its acceptance criteria and QA notes.
SkillAFreshness: AClaude Code +9 - 0.565score
code-style
andabove
Fifteen TypeScript code rules for modules, names, doc comments, types, boundaries, errors and side effects.
SkillAFreshness: AClaude Code +9
Signals
- Stars
- 0
- Forks
- 0
- Open issues
- 0
- Last commit (this folder)
- Oct 3, 2026 (26 days ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- Repository
- github.com/andabove/skills
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from andabove
- 0.570score
effect-data
andabove
Effect 4 data types, equality, caching and batching.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-concurrency
andabove
Effect concurrency - fibers, interruption, coordination and Schedule.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-testing
andabove
Testing Effect code with @effect/vitest, TestClock and test layers.
SkillAFreshness: AClaude Code +9 - 0.570score
effect
andabove
Effect (the TypeScript library) core and router to the other Effect skills.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-adoption
andabove
Adopting Effect in an existing Promise codebase one module at a time.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-errors
andabove
Effect error handling, for expected errors, defects and interruptions.
SkillAFreshness: AClaude Code +9
Cite this page
effect-observability skill. Agent Mart. https://agentmart.dev/skills/andabove-effect-observability (last updated 2026-10-24)