Skip to content

Effect 中的追踪

虽然日志和指标对于理解单个服务的行为很有用,但它们不足以提供分布式系统中请求生命周期的完整概览。

在分布式系统中,一个请求可以跨越多个服务,每个服务可以向其他服务发出多个请求来完成该请求。在这种情况下,我们需要有一种方法来跟踪请求在多个服务中的生命周期,以诊断哪些服务是瓶颈以及请求在哪里花费了大部分时间。

span 表示请求中的单个工作单元或操作。它提供了该特定操作执行期间发生的事情的详细视图。

每个 span 通常包含以下信息:

Span 组件描述
Name描述正在跟踪的特定操作。
Timing Data指示操作何时开始及其持续时间的时间戳。
Log Messages捕获操作期间重要事件的结构化日志。
Attributes提供有关操作的额外上下文的元数据。

Span 是追踪中的关键构建块,帮助您可视化和理解请求通过各种服务的流程。

trace 记录请求(由应用程序或最终用户发出)在多服务架构(如微服务和无服务器应用程序)中传播时所采取的路径。

没有追踪,很难确定分布式系统中性能问题的原因。

trace 由一个或多个 span 组成。第一个 span 表示根 span。每个根 span 表示从开始到结束的请求。父级下面的 span 提供了请求期间发生的事情(或构成请求的步骤)的更深入上下文。

许多可观测性后端将 trace 可视化为瀑布图,可能看起来像这样:

Trace Waterfall Diagram

瀑布图显示根 span 与其子 span 之间的父子关系。当一个 span 封装另一个 span 时,这也表示嵌套关系。

您可以通过使用 Effect.withSpan API 创建 span 来为 effect 添加追踪。这有助于您跟踪 effect 中的特定操作。

示例(为 Effect 添加 Span)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
// 定义一个延迟 100 毫秒的 effect
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const void: Effect.Effect<void, never, never>
export void

Represents an effect that does nothing and produces no value.

When to Use

Use this effect when you need to represent an effect that does nothing. This is useful in scenarios where you need to satisfy an effect-based interface or control program flow without performing any operations. For example, it can be used in situations where you want to return an effect from a function but do not need to compute or return any result.

@since2.0.0

void
.
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<void, never, never>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<void, never, never> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const delay: (duration: DurationInput) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Delays the execution of an effect by a specified Duration.

**Details

This function postpones the execution of the provided effect by the specified duration. The duration can be provided in various formats supported by the Duration module.

Internally, this function does not block the thread; instead, it uses an efficient, non-blocking mechanism to introduce the delay.

Example

import { Console, Effect } from "effect"
const task = Console.log("Task executed")
const program = Console.log("start").pipe(
Effect.andThen(
// Delays the log message by 2 seconds
task.pipe(Effect.delay("2 seconds"))
)
)
Effect.runFork(program)
// Output:
// start
// Task executed

@since2.0.0

delay
("100 millis"))
// 使用 span 对 effect 进行检测以进行追踪
const
const instrumented: Effect.Effect<void, never, never>
instrumented
=
const program: Effect.Effect<void, never, never>
program
.
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<void, never, never>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<void, never, never> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const withSpan: (name: string, options?: SpanOptions | undefined) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, ParentSpan>> (+1 overload)

Wraps the effect with a new span for tracing.

@since2.0.0

withSpan
("myspan"))

使用 span 检测 effect 不会改变其类型。如果您从 Effect<A, E, R> 开始,结果仍然是 Effect<A, E, R>

要打印 span 用于调试或分析,您需要安装所需的追踪工具。以下是如何为您的项目设置它们。

选择您的包管理器并安装必要的库:

Terminal window
# 安装用于将 OpenTelemetry 与 Effect 集成的主库
npm install @effect/opentelemetry
# 安装追踪和指标所需的 OpenTelemetry SDK
npm install @opentelemetry/sdk-trace-base
npm install @opentelemetry/sdk-trace-node
npm install @opentelemetry/sdk-trace-web
npm install @opentelemetry/sdk-metrics

安装依赖项后,您可以使用 OpenTelemetry 设置 span 打印。以下是一个示例,展示如何为 effect 打印 span。

示例(设置和打印 Span)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
import {
import NodeSdk
NodeSdk
} from "@effect/opentelemetry"
import {
class ConsoleSpanExporter

This is implementation of

SpanExporter

that prints spans to the console. This class can be used for diagnostic purposes.

NOTE: This

SpanExporter

is intended for diagnostics use only, output rendered to the console may change at any time.

ConsoleSpanExporter
,
class BatchSpanProcessor
BatchSpanProcessor
} from "@opentelemetry/sdk-trace-base"
// 定义一个延迟 100 毫秒的 effect
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const void: Effect.Effect<void, never, never>
export void

Represents an effect that does nothing and produces no value.

When to Use

Use this effect when you need to represent an effect that does nothing. This is useful in scenarios where you need to satisfy an effect-based interface or control program flow without performing any operations. For example, it can be used in situations where you want to return an effect from a function but do not need to compute or return any result.

@since2.0.0

void
.
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<void, never, never>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<void, never, never> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const delay: (duration: DurationInput) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Delays the execution of an effect by a specified Duration.

**Details

This function postpones the execution of the provided effect by the specified duration. The duration can be provided in various formats supported by the Duration module.

Internally, this function does not block the thread; instead, it uses an efficient, non-blocking mechanism to introduce the delay.

Example

import { Console, Effect } from "effect"
const task = Console.log("Task executed")
const program = Console.log("start").pipe(
Effect.andThen(
// Delays the log message by 2 seconds
task.pipe(Effect.delay("2 seconds"))
)
)
Effect.runFork(program)
// Output:
// start
// Task executed

@since2.0.0

delay
("100 millis"))
// 使用 span 对 effect 进行检测以进行追踪
const
const instrumented: Effect.Effect<void, never, never>
instrumented
=
const program: Effect.Effect<void, never, never>
program
.
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<void, never, never>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<void, never, never> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const withSpan: (name: string, options?: SpanOptions | undefined) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, ParentSpan>> (+1 overload)

Wraps the effect with a new span for tracing.

@since2.0.0

withSpan
("myspan"))
// 使用 OpenTelemetry SDK 设置追踪
const
const NodeSdkLive: Layer<Resource, never, never>
NodeSdkLive
=
import NodeSdk
NodeSdk
.
const layer: (evaluate: LazyArg<NodeSdk.Configuration>) => Layer<Resource> (+1 overload)

@since1.0.0

layer
(() => ({
Configuration.resource?: {
readonly serviceName: string;
readonly serviceVersion?: string;
readonly attributes?: Attributes;
} | undefined
resource
: {
serviceName: string
serviceName
: "example" },
// 将 span 数据导出到控制台
Configuration.spanProcessor?: SpanProcessor | readonly SpanProcessor[] | undefined
spanProcessor
: new
new BatchSpanProcessor<BufferConfig>(_exporter: SpanExporter, config?: BufferConfig | undefined): BatchSpanProcessor
BatchSpanProcessor
(new
new ConsoleSpanExporter(): ConsoleSpanExporter

This is implementation of

SpanExporter

that prints spans to the console. This class can be used for diagnostic purposes.

NOTE: This

SpanExporter

is intended for diagnostics use only, output rendered to the console may change at any time.

ConsoleSpanExporter
())
}))
// 运行 effect,提供追踪层
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runPromise: <void, never>(effect: Effect.Effect<void, never, never>, options?: {
readonly signal?: AbortSignal | undefined;
} | undefined) => Promise<void>

Executes an effect and returns the result as a Promise.

Details

This function runs an effect and converts its result into a Promise. If the effect succeeds, the Promise will resolve with the successful result. If the effect fails, the Promise will reject with an error, which includes the failure details of the effect.

The optional options parameter allows you to pass an AbortSignal for cancellation, enabling more fine-grained control over asynchronous tasks.

When to Use

Use this function when you need to execute an effect and work with its result in a promise-based system, such as when integrating with third-party libraries that expect Promise results.

Example (Running a Successful Effect as a Promise)

import { Effect } from "effect"
Effect.runPromise(Effect.succeed(1)).then(console.log)
// Output: 1

Example (Handling a Failing Effect as a Rejected Promise)

import { Effect } from "effect"
Effect.runPromise(Effect.fail("my error")).catch(console.error)
// Output:
// (FiberFailure) Error: my error

@seerunPromiseExit for a version that returns an Exit type instead of rejecting.

@since2.0.0

runPromise
(
const instrumented: Effect.Effect<void, never, never>
instrumented
.
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<void, never, never>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<void, never, never> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const provide: <Resource, never, never>(layer: Layer<Resource, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Resource>> (+9 overloads)

Provides necessary dependencies to an effect, removing its environmental requirements.

Details

This function allows you to supply the required environment for an effect. The environment can be provided in the form of one or more Layers, a Context, a Runtime, or a ManagedRuntime. Once the environment is provided, the effect can run without requiring external dependencies.

You can compose layers to create a modular and reusable way of setting up the environment for effects. For example, layers can be used to configure databases, logging services, or any other required dependencies.

Example

import { Context, Effect, Layer } from "effect"
class Database extends Context.Tag("Database")<
Database,
{ readonly query: (sql: string) => Effect.Effect<Array<unknown>> }
>() {}
const DatabaseLive = Layer.succeed(
Database,
{
// Simulate a database query
query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([]))
}
)
// ┌─── Effect<unknown[], never, Database>
// ▼
const program = Effect.gen(function*() {
const database = yield* Database
const result = yield* database.query("SELECT * FROM users")
return result
})
// ┌─── Effect<unknown[], never, never>
// ▼
const runnable = Effect.provide(program, DatabaseLive)
Effect.runPromise(runnable).then(console.log)
// Output:
// timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users"
// []

@seeprovideService for providing a service to an effect.

@since2.0.0

provide
(
const NodeSdkLive: Layer<Resource, never, never>
NodeSdkLive
)))
/*
示例输出:
{
resource: {
attributes: {
'service.name': 'example',
'telemetry.sdk.language': 'nodejs',
'telemetry.sdk.name': '@effect/opentelemetry',
'telemetry.sdk.version': '1.28.0'
}
},
instrumentationScope: { name: 'example', version: undefined, schemaUrl: undefined },
traceId: '673c06608bd815f7a75bf897ef87e186',
parentId: undefined,
traceState: undefined,
name: 'myspan',
id: '401b2846170cd17b',
kind: 0,
timestamp: 1733220735529855.5,
duration: 102079.958,
attributes: {},
status: { code: 1 },
events: [],
links: []
}
*/

输出提供了有关 span 的详细信息:

字段描述
traceId整个追踪的唯一标识符,帮助追踪请求或操作在应用程序中的移动。
parentId标识当前 span 的父 span,当没有父 span 时在输出中标记为 undefined,使其成为根 span。
name描述 span 的名称,指示正在跟踪的操作(例如,“myspan”)。
id当前 span 的唯一标识符,将其与追踪中的其他 span 区分开来。
timestamp表示 span 开始时间的时间戳,以自 Unix 纪元以来的微秒为单位测量。
duration指定 span 的持续时间,表示完成操作所需的时间(例如,2895.769 微秒)。
attributesSpan 可能包含属性,这些属性是提供有关操作的额外上下文或信息的键值对。在此输出中,它是一个空对象,表示此 span 中没有特定属性。
status状态字段提供有关 span 状态的信息。在这种情况下,它的代码为 1,通常表示 OK 状态(而代码 2 表示 ERROR 状态)
eventsSpan 可以包含事件,这些事件是 span 生命周期中特定时刻的记录。在此输出中,它是一个空数组,表示没有记录特定事件。
links链接可用于将此 span 与不同追踪中的其他 span 关联。在输出中,它是一个空数组,表示此 span 没有特定链接。

以下是当 effect 遇到错误时 span 的样子:

示例(失败的 Effect 的 Span)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
import {
import NodeSdk
NodeSdk
} from "@effect/opentelemetry"
import {
class ConsoleSpanExporter

This is implementation of

SpanExporter

that prints spans to the console. This class can be used for diagnostic purposes.

NOTE: This

SpanExporter

is intended for diagnostics use only, output rendered to the console may change at any time.

ConsoleSpanExporter
,
class BatchSpanProcessor
BatchSpanProcessor
} from "@opentelemetry/sdk-trace-base"
const
const program: Effect.Effect<never, string, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fail: <string>(error: string) => Effect.Effect<never, string, never>

Creates an Effect that represents a recoverable error.

When to Use

Use this function to explicitly signal an error in an Effect. The error will keep propagating unless it is handled. You can handle the error with functions like

catchAll

or

catchTag

.

Example (Creating a Failed Effect)

import { Effect } from "effect"
// ┌─── Effect<never, Error, never>
// ▼
const failure = Effect.fail(
new Error("Operation failed due to network error")
)

@seesucceed to create an effect that represents a successful value.

@since2.0.0

fail
("Oh no!").
Pipeable.pipe<Effect.Effect<never, string, never>, Effect.Effect<never, string, never>, Effect.Effect<never, string, never>>(this: Effect.Effect<never, string, never>, ab: (_: Effect.Effect<never, string, never>) => Effect.Effect<never, string, never>, bc: (_: Effect.Effect<never, string, never>) => Effect.Effect<never, string, never>): Effect.Effect<never, string, never> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const delay: (duration: DurationInput) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Delays the execution of an effect by a specified Duration.

**Details

This function postpones the execution of the provided effect by the specified duration. The duration can be provided in various formats supported by the Duration module.

Internally, this function does not block the thread; instead, it uses an efficient, non-blocking mechanism to introduce the delay.

Example

import { Console, Effect } from "effect"
const task = Console.log("Task executed")
const program = Console.log("start").pipe(
Effect.andThen(
// Delays the log message by 2 seconds
task.pipe(Effect.delay("2 seconds"))
)
)
Effect.runFork(program)
// Output:
// start
// Task executed

@since2.0.0

delay
("100 millis"),
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const withSpan: (name: string, options?: SpanOptions | undefined) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, ParentSpan>> (+1 overload)

Wraps the effect with a new span for tracing.

@since2.0.0

withSpan
("myspan")
)
const
const NodeSdkLive: Layer<Resource, never, never>
NodeSdkLive
=
import NodeSdk
NodeSdk
.
const layer: (evaluate: LazyArg<NodeSdk.Configuration>) => Layer<Resource> (+1 overload)

@since1.0.0

layer
(() => ({
Configuration.resource?: {
readonly serviceName: string;
readonly serviceVersion?: string;
readonly attributes?: Attributes;
} | undefined
resource
: {
serviceName: string
serviceName
: "example" },
Configuration.spanProcessor?: SpanProcessor | readonly SpanProcessor[] | undefined
spanProcessor
: new
new BatchSpanProcessor<BufferConfig>(_exporter: SpanExporter, config?: BufferConfig | undefined): BatchSpanProcessor
BatchSpanProcessor
(new
new ConsoleSpanExporter(): ConsoleSpanExporter

This is implementation of

SpanExporter

that prints spans to the console. This class can be used for diagnostic purposes.

NOTE: This

SpanExporter

is intended for diagnostics use only, output rendered to the console may change at any time.

ConsoleSpanExporter
())
}))
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runPromiseExit: <never, string>(effect: Effect.Effect<never, string, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<Exit<never, string>>

Runs an effect and returns a Promise that resolves to an Exit, representing the outcome.

Details

This function executes an effect and resolves to an Exit object. The Exit type provides detailed information about the result of the effect:

  • If the effect succeeds, the Exit will be of type Success and include the value produced by the effect.
  • If the effect fails, the Exit will be of type Failure and contain a Cause object, detailing the failure.

Using this function allows you to examine both successful results and failure cases in a unified way, while still leveraging Promise for handling the asynchronous behavior of the effect.

When to Use

Use this function when you need to understand the outcome of an effect, whether it succeeded or failed, and want to work with this result using Promise syntax. This is particularly useful when integrating with systems that rely on promises but need more detailed error handling than a simple rejection.

Example (Handling Results as Exit)

import { Effect } from "effect"
// Execute a successful effect and get the Exit result as a Promise
Effect.runPromiseExit(Effect.succeed(1)).then(console.log)
// Output:
// {
// _id: "Exit",
// _tag: "Success",
// value: 1
// }
// Execute a failing effect and get the Exit result as a Promise
Effect.runPromiseExit(Effect.fail("my error")).then(console.log)
// Output:
// {
// _id: "Exit",
// _tag: "Failure",
// cause: {
// _id: "Cause",
// _tag: "Fail",
// failure: "my error"
// }
// }

@since2.0.0

runPromiseExit
(
const program: Effect.Effect<never, string, never>
program
.
Pipeable.pipe<Effect.Effect<never, string, never>, Effect.Effect<never, string, never>>(this: Effect.Effect<never, string, never>, ab: (_: Effect.Effect<never, string, never>) => Effect.Effect<never, string, never>): Effect.Effect<never, string, never> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const provide: <Resource, never, never>(layer: Layer<Resource, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Resource>> (+9 overloads)

Provides necessary dependencies to an effect, removing its environmental requirements.

Details

This function allows you to supply the required environment for an effect. The environment can be provided in the form of one or more Layers, a Context, a Runtime, or a ManagedRuntime. Once the environment is provided, the effect can run without requiring external dependencies.

You can compose layers to create a modular and reusable way of setting up the environment for effects. For example, layers can be used to configure databases, logging services, or any other required dependencies.

Example

import { Context, Effect, Layer } from "effect"
class Database extends Context.Tag("Database")<
Database,
{ readonly query: (sql: string) => Effect.Effect<Array<unknown>> }
>() {}
const DatabaseLive = Layer.succeed(
Database,
{
// Simulate a database query
query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([]))
}
)
// ┌─── Effect<unknown[], never, Database>
// ▼
const program = Effect.gen(function*() {
const database = yield* Database
const result = yield* database.query("SELECT * FROM users")
return result
})
// ┌─── Effect<unknown[], never, never>
// ▼
const runnable = Effect.provide(program, DatabaseLive)
Effect.runPromise(runnable).then(console.log)
// Output:
// timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users"
// []

@seeprovideService for providing a service to an effect.

@since2.0.0

provide
(
const NodeSdkLive: Layer<Resource, never, never>
NodeSdkLive
))).
Promise<Exit<never, string>>.then<void, never>(onfulfilled?: ((value: Exit<never, string>) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<void>

Attaches callbacks for the resolution and/or rejection of the Promise.

@paramonfulfilled The callback to execute when the Promise is resolved.

@paramonrejected The callback to execute when the Promise is rejected.

@returnsA Promise for the completion of which ever callback is executed.

then
(
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
)
/*
Example Output:
{
resource: {
attributes: {
'service.name': 'example',
'telemetry.sdk.language': 'nodejs',
'telemetry.sdk.name': '@effect/opentelemetry',
'telemetry.sdk.version': '1.28.0'
}
},
instrumentationScope: { name: 'example', version: undefined, schemaUrl: undefined },
traceId: 'eee9619866179f209b7aae277283e71f',
parentId: undefined,
traceState: undefined,
name: 'myspan',
id: '3a5725c91884c9e1',
kind: 0,
timestamp: 1733220830575626,
duration: 106578.042,
attributes: {
'code.stacktrace': 'at <anonymous> (/Users/giuliocanti/Documents/GitHub/website/content/dev/index.ts:10:10)'
},
status: { code: 2, message: 'Oh no!' },
events: [
{
name: 'exception',
attributes: {
'exception.type': 'Error',
'exception.message': 'Oh no!',
'exception.stacktrace': 'Error: Oh no!'
},
time: [ 1733220830, 682204083 ],
droppedAttributesCount: 0
}
],
links: []
}
{
_id: 'Exit',
_tag: 'Failure',
cause: { _id: 'Cause', _tag: 'Fail', failure: 'Oh no!' }
}
*/

In this example, the span’s status code is 2, indicating an error. The message in the status provides more details about the failure.

You can provide extra information to a span by utilizing the Effect.annotateCurrentSpan function. This function allows you to attach key-value pairs, offering more context about the execution of the span.

Example (Annotating a Span)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
import {
import NodeSdk
NodeSdk
} from "@effect/opentelemetry"
import {
class ConsoleSpanExporter

This is implementation of

SpanExporter

that prints spans to the console. This class can be used for diagnostic purposes.

NOTE: This

SpanExporter

is intended for diagnostics use only, output rendered to the console may change at any time.

ConsoleSpanExporter
,
class BatchSpanProcessor
BatchSpanProcessor
} from "@opentelemetry/sdk-trace-base"
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const void: Effect.Effect<void, never, never>
export void

Represents an effect that does nothing and produces no value.

When to Use

Use this effect when you need to represent an effect that does nothing. This is useful in scenarios where you need to satisfy an effect-based interface or control program flow without performing any operations. For example, it can be used in situations where you want to return an effect from a function but do not need to compute or return any result.

@since2.0.0

void
.
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>, Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<void, never, never>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>, bc: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>, cd: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<void, never, never> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const delay: (duration: DurationInput) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Delays the execution of an effect by a specified Duration.

**Details

This function postpones the execution of the provided effect by the specified duration. The duration can be provided in various formats supported by the Duration module.

Internally, this function does not block the thread; instead, it uses an efficient, non-blocking mechanism to introduce the delay.

Example

import { Console, Effect } from "effect"
const task = Console.log("Task executed")
const program = Console.log("start").pipe(
Effect.andThen(
// Delays the log message by 2 seconds
task.pipe(Effect.delay("2 seconds"))
)
)
Effect.runFork(program)
// Output:
// start
// Task executed

@since2.0.0

delay
("100 millis"),
// Annotate the span with a key-value pair
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const tap: <void, Effect.Effect<void, never, never>>(f: (a: void) => Effect.Effect<void, never, never>) => <E, R>(self: Effect.Effect<void, E, R>) => Effect.Effect<void, E, R> (+7 overloads)

Runs a side effect with the result of an effect without changing the original value.

Details

This function works similarly to flatMap, but it ignores the result of the function passed to it. The value from the previous effect remains available for the next part of the chain. Note that if the side effect fails, the entire chain will fail too.

When to Use

Use this function when you want to perform a side effect, like logging or tracking, without modifying the main value. This is useful when you need to observe or record an action but want the original value to be passed to the next step.

Example (Logging a step in a pipeline)

import { Console, Effect, pipe } from "effect"
// Function to apply a discount safely to a transaction amount
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
// Simulated asynchronous task to fetch a transaction amount from database
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const finalAmount = pipe(
fetchTransactionAmount,
// Log the fetched transaction amount
Effect.tap((amount) => Console.log(`Apply a discount to: ${amount}`)),
// `amount` is still available!
Effect.flatMap((amount) => applyDiscount(amount, 5))
)
Effect.runPromise(finalAmount).then(console.log)
// Output:
// Apply a discount to: 100
// 95

@seeflatMap for a version that allows you to change the value.

@since2.0.0

tap
(() =>
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const annotateCurrentSpan: (key: string, value: unknown) => Effect.Effect<void> (+1 overload)

Adds annotations to the currently active span for traceability.

Details

This function adds key-value annotations to the currently active span in the effect's trace. These annotations help provide more context about the operation being executed at a specific point in time. Unlike

annotateSpans

, which applies to all spans in an effect, this function focuses solely on the active span.

You can either pass a single key-value pair or a record of key-value pairs to annotate the span. These annotations are useful for adding metadata to operations, especially in systems with detailed observability requirements.

@since2.0.0

annotateCurrentSpan
("key", "value")),
// Wrap the effect in a span named 'myspan'
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const withSpan: (name: string, options?: SpanOptions | undefined) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, ParentSpan>> (+1 overload)

Wraps the effect with a new span for tracing.

@since2.0.0

withSpan
("myspan")
)
// Set up tracing with the OpenTelemetry SDK
const
const NodeSdkLive: Layer<Resource, never, never>
NodeSdkLive
=
import NodeSdk
NodeSdk
.
const layer: (evaluate: LazyArg<NodeSdk.Configuration>) => Layer<Resource> (+1 overload)

@since1.0.0

layer
(() => ({
Configuration.resource?: {
readonly serviceName: string;
readonly serviceVersion?: string;
readonly attributes?: Attributes;
} | undefined
resource
: {
serviceName: string
serviceName
: "example" },
Configuration.spanProcessor?: SpanProcessor | readonly SpanProcessor[] | undefined
spanProcessor
: new
new BatchSpanProcessor<BufferConfig>(_exporter: SpanExporter, config?: BufferConfig | undefined): BatchSpanProcessor
BatchSpanProcessor
(new
new ConsoleSpanExporter(): ConsoleSpanExporter

This is implementation of

SpanExporter

that prints spans to the console. This class can be used for diagnostic purposes.

NOTE: This

SpanExporter

is intended for diagnostics use only, output rendered to the console may change at any time.

ConsoleSpanExporter
())
}))
// Run the effect, providing the tracing layer
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runPromise: <void, never>(effect: Effect.Effect<void, never, never>, options?: {
readonly signal?: AbortSignal | undefined;
} | undefined) => Promise<void>

Executes an effect and returns the result as a Promise.

Details

This function runs an effect and converts its result into a Promise. If the effect succeeds, the Promise will resolve with the successful result. If the effect fails, the Promise will reject with an error, which includes the failure details of the effect.

The optional options parameter allows you to pass an AbortSignal for cancellation, enabling more fine-grained control over asynchronous tasks.

When to Use

Use this function when you need to execute an effect and work with its result in a promise-based system, such as when integrating with third-party libraries that expect Promise results.

Example (Running a Successful Effect as a Promise)

import { Effect } from "effect"
Effect.runPromise(Effect.succeed(1)).then(console.log)
// Output: 1

Example (Handling a Failing Effect as a Rejected Promise)

import { Effect } from "effect"
Effect.runPromise(Effect.fail("my error")).catch(console.error)
// Output:
// (FiberFailure) Error: my error

@seerunPromiseExit for a version that returns an Exit type instead of rejecting.

@since2.0.0

runPromise
(
const program: Effect.Effect<void, never, never>
program
.
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<void, never, never>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<void, never, never> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const provide: <Resource, never, never>(layer: Layer<Resource, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Resource>> (+9 overloads)

Provides necessary dependencies to an effect, removing its environmental requirements.

Details

This function allows you to supply the required environment for an effect. The environment can be provided in the form of one or more Layers, a Context, a Runtime, or a ManagedRuntime. Once the environment is provided, the effect can run without requiring external dependencies.

You can compose layers to create a modular and reusable way of setting up the environment for effects. For example, layers can be used to configure databases, logging services, or any other required dependencies.

Example

import { Context, Effect, Layer } from "effect"
class Database extends Context.Tag("Database")<
Database,
{ readonly query: (sql: string) => Effect.Effect<Array<unknown>> }
>() {}
const DatabaseLive = Layer.succeed(
Database,
{
// Simulate a database query
query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([]))
}
)
// ┌─── Effect<unknown[], never, Database>
// ▼
const program = Effect.gen(function*() {
const database = yield* Database
const result = yield* database.query("SELECT * FROM users")
return result
})
// ┌─── Effect<unknown[], never, never>
// ▼
const runnable = Effect.provide(program, DatabaseLive)
Effect.runPromise(runnable).then(console.log)
// Output:
// timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users"
// []

@seeprovideService for providing a service to an effect.

@since2.0.0

provide
(
const NodeSdkLive: Layer<Resource, never, never>
NodeSdkLive
)))
/*
Example Output:
{
resource: {
attributes: {
'service.name': 'example',
'telemetry.sdk.language': 'nodejs',
'telemetry.sdk.name': '@effect/opentelemetry',
'telemetry.sdk.version': '1.28.0'
}
},
instrumentationScope: { name: 'example', version: undefined, schemaUrl: undefined },
traceId: 'c8120e01c0f1ea83ccc1d388e5cdebd3',
parentId: undefined,
traceState: undefined,
name: 'myspan',
id: '81c430ba4979f1db',
kind: 0,
timestamp: 1733220874356084,
duration: 102821.417,
attributes: { key: 'value' },
status: { code: 1 },
events: [],
links: []
}
*/

In the context of tracing, logs are converted into “Span Events.” These events offer structured insights into your application’s activities and provide a timeline of when specific operations occurred.

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
import {
import NodeSdk
NodeSdk
} from "@effect/opentelemetry"
import {
class ConsoleSpanExporter

This is implementation of

SpanExporter

that prints spans to the console. This class can be used for diagnostic purposes.

NOTE: This

SpanExporter

is intended for diagnostics use only, output rendered to the console may change at any time.

ConsoleSpanExporter
,
class BatchSpanProcessor
BatchSpanProcessor
} from "@opentelemetry/sdk-trace-base"
// Define a program that logs a message and delays for 100 milliseconds
const
const program: Effect.Effect<void, never, never>
program
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

Logs one or more messages or error causes at the current log level.

Details

This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

Example

import { Cause, Effect } from "effect"
const program = Effect.log(
"message1",
"message2",
Cause.die("Oh no!"),
Cause.die("Oh uh!")
)
Effect.runFork(program)
// Output:
// timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
// Error: Oh uh!"

@since2.0.0

log
("Hello").
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<void, never, never>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>, bc: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<void, never, never> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const delay: (duration: DurationInput) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Delays the execution of an effect by a specified Duration.

**Details

This function postpones the execution of the provided effect by the specified duration. The duration can be provided in various formats supported by the Duration module.

Internally, this function does not block the thread; instead, it uses an efficient, non-blocking mechanism to introduce the delay.

Example

import { Console, Effect } from "effect"
const task = Console.log("Task executed")
const program = Console.log("start").pipe(
Effect.andThen(
// Delays the log message by 2 seconds
task.pipe(Effect.delay("2 seconds"))
)
)
Effect.runFork(program)
// Output:
// start
// Task executed

@since2.0.0

delay
("100 millis"),
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const withSpan: (name: string, options?: SpanOptions | undefined) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, ParentSpan>> (+1 overload)

Wraps the effect with a new span for tracing.

@since2.0.0

withSpan
("myspan")
)
// Set up tracing with the OpenTelemetry SDK
const
const NodeSdkLive: Layer<Resource, never, never>
NodeSdkLive
=
import NodeSdk
NodeSdk
.
const layer: (evaluate: LazyArg<NodeSdk.Configuration>) => Layer<Resource> (+1 overload)

@since1.0.0

layer
(() => ({
Configuration.resource?: {
readonly serviceName: string;
readonly serviceVersion?: string;
readonly attributes?: Attributes;
} | undefined
resource
: {
serviceName: string
serviceName
: "example" },
Configuration.spanProcessor?: SpanProcessor | readonly SpanProcessor[] | undefined
spanProcessor
: new
new BatchSpanProcessor<BufferConfig>(_exporter: SpanExporter, config?: BufferConfig | undefined): BatchSpanProcessor
BatchSpanProcessor
(new
new ConsoleSpanExporter(): ConsoleSpanExporter

This is implementation of

SpanExporter

that prints spans to the console. This class can be used for diagnostic purposes.

NOTE: This

SpanExporter

is intended for diagnostics use only, output rendered to the console may change at any time.

ConsoleSpanExporter
())
}))
// Run the effect, providing the tracing layer
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runPromise: <void, never>(effect: Effect.Effect<void, never, never>, options?: {
readonly signal?: AbortSignal | undefined;
} | undefined) => Promise<void>

Executes an effect and returns the result as a Promise.

Details

This function runs an effect and converts its result into a Promise. If the effect succeeds, the Promise will resolve with the successful result. If the effect fails, the Promise will reject with an error, which includes the failure details of the effect.

The optional options parameter allows you to pass an AbortSignal for cancellation, enabling more fine-grained control over asynchronous tasks.

When to Use

Use this function when you need to execute an effect and work with its result in a promise-based system, such as when integrating with third-party libraries that expect Promise results.

Example (Running a Successful Effect as a Promise)

import { Effect } from "effect"
Effect.runPromise(Effect.succeed(1)).then(console.log)
// Output: 1

Example (Handling a Failing Effect as a Rejected Promise)

import { Effect } from "effect"
Effect.runPromise(Effect.fail("my error")).catch(console.error)
// Output:
// (FiberFailure) Error: my error

@seerunPromiseExit for a version that returns an Exit type instead of rejecting.

@since2.0.0

runPromise
(
const program: Effect.Effect<void, never, never>
program
.
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<void, never, never>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<void, never, never> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const provide: <Resource, never, never>(layer: Layer<Resource, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Resource>> (+9 overloads)

Provides necessary dependencies to an effect, removing its environmental requirements.

Details

This function allows you to supply the required environment for an effect. The environment can be provided in the form of one or more Layers, a Context, a Runtime, or a ManagedRuntime. Once the environment is provided, the effect can run without requiring external dependencies.

You can compose layers to create a modular and reusable way of setting up the environment for effects. For example, layers can be used to configure databases, logging services, or any other required dependencies.

Example

import { Context, Effect, Layer } from "effect"
class Database extends Context.Tag("Database")<
Database,
{ readonly query: (sql: string) => Effect.Effect<Array<unknown>> }
>() {}
const DatabaseLive = Layer.succeed(
Database,
{
// Simulate a database query
query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([]))
}
)
// ┌─── Effect<unknown[], never, Database>
// ▼
const program = Effect.gen(function*() {
const database = yield* Database
const result = yield* database.query("SELECT * FROM users")
return result
})
// ┌─── Effect<unknown[], never, never>
// ▼
const runnable = Effect.provide(program, DatabaseLive)
Effect.runPromise(runnable).then(console.log)
// Output:
// timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users"
// []

@seeprovideService for providing a service to an effect.

@since2.0.0

provide
(
const NodeSdkLive: Layer<Resource, never, never>
NodeSdkLive
)))
/*
Example Output:
{
resource: {
attributes: {
'service.name': 'example',
'telemetry.sdk.language': 'nodejs',
'telemetry.sdk.name': '@effect/opentelemetry',
'telemetry.sdk.version': '1.28.0'
}
},
instrumentationScope: { name: 'example', version: undefined, schemaUrl: undefined },
traceId: 'b0f4f012b5b13c0a040f7002a1d7b020',
parentId: undefined,
traceState: undefined,
name: 'myspan',
id: 'b9ba8472002715a8',
kind: 0,
timestamp: 1733220905504162.2,
duration: 103790,
attributes: {},
status: { code: 1 },
events: [
{
name: 'Hello',
attributes: { 'effect.fiberId': '#0', 'effect.logLevel': 'INFO' }, // Log attributes
time: [ 1733220905, 607761042 ], // Event timestamp
droppedAttributesCount: 0
}
],
links: []
}
*/

Each span can include events, which capture specific moments during the execution of a span. In this example, a log message "Hello" is recorded as an event within the span. Key details of the event include:

FieldDescription
nameThe name of the event, which corresponds to the logged message (e.g., 'Hello').
attributesKey-value pairs that provide additional context about the event, such as fiberId and log level.
timeThe timestamp of when the event occurred, shown in a high-precision format.
droppedAttributesCountIndicates how many attributes were discarded, if any. In this case, no attributes were dropped.

Spans can be nested to represent a hierarchy of operations. This allows you to track how different parts of your application relate to one another during execution. The following example demonstrates how to create and manage nested spans.

Example (Nesting Spans in a Trace)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
} from "effect"
import {
import NodeSdk
NodeSdk
} from "@effect/opentelemetry"
import {
class ConsoleSpanExporter

This is implementation of

SpanExporter

that prints spans to the console. This class can be used for diagnostic purposes.

NOTE: This

SpanExporter

is intended for diagnostics use only, output rendered to the console may change at any time.

ConsoleSpanExporter
,
class BatchSpanProcessor
BatchSpanProcessor
} from "@opentelemetry/sdk-trace-base"
const
const child: Effect.Effect<void, never, never>
child
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const void: Effect.Effect<void, never, never>
export void

Represents an effect that does nothing and produces no value.

When to Use

Use this effect when you need to represent an effect that does nothing. This is useful in scenarios where you need to satisfy an effect-based interface or control program flow without performing any operations. For example, it can be used in situations where you want to return an effect from a function but do not need to compute or return any result.

@since2.0.0

void
.
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<void, never, never>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>, bc: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<void, never, never> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const delay: (duration: DurationInput) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R> (+1 overload)

Delays the execution of an effect by a specified Duration.

**Details

This function postpones the execution of the provided effect by the specified duration. The duration can be provided in various formats supported by the Duration module.

Internally, this function does not block the thread; instead, it uses an efficient, non-blocking mechanism to introduce the delay.

Example

import { Console, Effect } from "effect"
const task = Console.log("Task executed")
const program = Console.log("start").pipe(
Effect.andThen(
// Delays the log message by 2 seconds
task.pipe(Effect.delay("2 seconds"))
)
)
Effect.runFork(program)
// Output:
// start
// Task executed

@since2.0.0

delay
("100 millis"),
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const withSpan: (name: string, options?: SpanOptions | undefined) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, ParentSpan>> (+1 overload)

Wraps the effect with a new span for tracing.

@since2.0.0

withSpan
("child")
)
const
const parent: Effect.Effect<void, never, never>
parent
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<void, never, never> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const sleep: (duration: DurationInput) => Effect.Effect<void>

Suspends the execution of an effect for a specified Duration.

Details

This function pauses the execution of an effect for a given duration. It is asynchronous, meaning that it does not block the fiber executing the effect. Instead, the fiber is suspended during the delay period and can resume once the specified time has passed.

The duration can be specified using various formats supported by the Duration module, such as a string ("2 seconds") or numeric value representing milliseconds.

Example

import { Effect } from "effect"
const program = Effect.gen(function*() {
console.log("Starting task...")
yield* Effect.sleep("3 seconds") // Waits for 3 seconds
console.log("Task completed!")
})
Effect.runFork(program)
// Output:
// Starting task...
// Task completed!

@since2.0.0

sleep
("20 millis")
yield*
const child: Effect.Effect<void, never, never>
child
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const sleep: (duration: DurationInput) => Effect.Effect<void>

Suspends the execution of an effect for a specified Duration.

Details

This function pauses the execution of an effect for a given duration. It is asynchronous, meaning that it does not block the fiber executing the effect. Instead, the fiber is suspended during the delay period and can resume once the specified time has passed.

The duration can be specified using various formats supported by the Duration module, such as a string ("2 seconds") or numeric value representing milliseconds.

Example

import { Effect } from "effect"
const program = Effect.gen(function*() {
console.log("Starting task...")
yield* Effect.sleep("3 seconds") // Waits for 3 seconds
console.log("Task completed!")
})
Effect.runFork(program)
// Output:
// Starting task...
// Task completed!

@since2.0.0

sleep
("10 millis")
}).
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<void, never, never>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<void, never, never> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const withSpan: (name: string, options?: SpanOptions | undefined) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, ParentSpan>> (+1 overload)

Wraps the effect with a new span for tracing.

@since2.0.0

withSpan
("parent"))
// Set up tracing with the OpenTelemetry SDK
const
const NodeSdkLive: Layer<Resource, never, never>
NodeSdkLive
=
import NodeSdk
NodeSdk
.
const layer: (evaluate: LazyArg<NodeSdk.Configuration>) => Layer<Resource> (+1 overload)

@since1.0.0

layer
(() => ({
Configuration.resource?: {
readonly serviceName: string;
readonly serviceVersion?: string;
readonly attributes?: Attributes;
} | undefined
resource
: {
serviceName: string
serviceName
: "example" },
Configuration.spanProcessor?: SpanProcessor | readonly SpanProcessor[] | undefined
spanProcessor
: new
new BatchSpanProcessor<BufferConfig>(_exporter: SpanExporter, config?: BufferConfig | undefined): BatchSpanProcessor
BatchSpanProcessor
(new
new ConsoleSpanExporter(): ConsoleSpanExporter

This is implementation of

SpanExporter

that prints spans to the console. This class can be used for diagnostic purposes.

NOTE: This

SpanExporter

is intended for diagnostics use only, output rendered to the console may change at any time.

ConsoleSpanExporter
())
}))
// Run the effect, providing the tracing layer
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runPromise: <void, never>(effect: Effect.Effect<void, never, never>, options?: {
readonly signal?: AbortSignal | undefined;
} | undefined) => Promise<void>

Executes an effect and returns the result as a Promise.

Details

This function runs an effect and converts its result into a Promise. If the effect succeeds, the Promise will resolve with the successful result. If the effect fails, the Promise will reject with an error, which includes the failure details of the effect.

The optional options parameter allows you to pass an AbortSignal for cancellation, enabling more fine-grained control over asynchronous tasks.

When to Use

Use this function when you need to execute an effect and work with its result in a promise-based system, such as when integrating with third-party libraries that expect Promise results.

Example (Running a Successful Effect as a Promise)

import { Effect } from "effect"
Effect.runPromise(Effect.succeed(1)).then(console.log)
// Output: 1

Example (Handling a Failing Effect as a Rejected Promise)

import { Effect } from "effect"
Effect.runPromise(Effect.fail("my error")).catch(console.error)
// Output:
// (FiberFailure) Error: my error

@seerunPromiseExit for a version that returns an Exit type instead of rejecting.

@since2.0.0

runPromise
(
const parent: Effect.Effect<void, never, never>
parent
.
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<void, never, never>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<void, never, never> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const provide: <Resource, never, never>(layer: Layer<Resource, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Resource>> (+9 overloads)

Provides necessary dependencies to an effect, removing its environmental requirements.

Details

This function allows you to supply the required environment for an effect. The environment can be provided in the form of one or more Layers, a Context, a Runtime, or a ManagedRuntime. Once the environment is provided, the effect can run without requiring external dependencies.

You can compose layers to create a modular and reusable way of setting up the environment for effects. For example, layers can be used to configure databases, logging services, or any other required dependencies.

Example

import { Context, Effect, Layer } from "effect"
class Database extends Context.Tag("Database")<
Database,
{ readonly query: (sql: string) => Effect.Effect<Array<unknown>> }
>() {}
const DatabaseLive = Layer.succeed(
Database,
{
// Simulate a database query
query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([]))
}
)
// ┌─── Effect<unknown[], never, Database>
// ▼
const program = Effect.gen(function*() {
const database = yield* Database
const result = yield* database.query("SELECT * FROM users")
return result
})
// ┌─── Effect<unknown[], never, never>
// ▼
const runnable = Effect.provide(program, DatabaseLive)
Effect.runPromise(runnable).then(console.log)
// Output:
// timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users"
// []

@seeprovideService for providing a service to an effect.

@since2.0.0

provide
(
const NodeSdkLive: Layer<Resource, never, never>
NodeSdkLive
)))
/*
Example Output:
{
resource: {
attributes: {
'service.name': 'example',
'telemetry.sdk.language': 'nodejs',
'telemetry.sdk.name': '@effect/opentelemetry',
'telemetry.sdk.version': '1.28.0'
}
},
instrumentationScope: { name: 'example', version: undefined, schemaUrl: undefined },
traceId: 'a9cd69ad70698a0c7b7b774597c77d39',
parentId: 'a09e5c3fdfdbbc1d', // This indicates the span is a child of 'parent'
traceState: undefined,
name: 'child',
id: '210d2f9b648389a4', // Unique ID for the child span
kind: 0,
timestamp: 1733220970590126.2,
duration: 101579.875,
attributes: {},
status: { code: 1 },
events: [],
links: []
}
{
resource: {
attributes: {
'service.name': 'example',
'telemetry.sdk.language': 'nodejs',
'telemetry.sdk.name': '@effect/opentelemetry',
'telemetry.sdk.version': '1.28.0'
}
},
instrumentationScope: { name: 'example', version: undefined, schemaUrl: undefined },
traceId: 'a9cd69ad70698a0c7b7b774597c77d39',
parentId: undefined, // Indicates this is the root span
traceState: undefined,
name: 'parent',
id: 'a09e5c3fdfdbbc1d', // Unique ID for the parent span
kind: 0,
timestamp: 1733220970569015.2,
duration: 132612.208,
attributes: {},
status: { code: 1 },
events: [],
links: []
}
*/

The parent-child relationship is evident in the span output, where the parentId of the child span matches the id of the parent span. This structure helps track how operations are related within a single trace.

In this tutorial, we will guide you through visualizing traces generated by a sample Effect application. The sample application has also been configured to export traces traces and/or metrics via HTTP using OTLP format.

To visualize the traces being exported by our application, we will use a Docker image that contains a preconfigured OpenTelemetry backend based on the OpenTelemetry Collector, Prometheus, Loki, Tempo, and Grafana.

Let’s understand the tools we’ll be using in simple terms:

  • Docker: Docker allows us to run applications in containers. Think of a container as a lightweight and isolated environment where your application can run consistently, regardless of the host system. It’s a bit like a virtual machine but more efficient.

  • Prometheus: Prometheus is a monitoring and alerting toolkit. It collects metrics and data about your applications and stores them for further analysis. This helps in identifying performance issues and understanding the behavior of your applications.

  • Loki: Loki is a log aggregation system inspired by Prometheus. It does not index the contents of the logs, but rather a set of labels for each log stream.

  • Grafana: Grafana is a visualization and analytics platform. It helps in creating beautiful and interactive dashboards to visualize your application’s data. You can use it to graphically represent metrics collected by Prometheus.

  • Tempo: Tempo is a distributed tracing system that allows you to trace the journey of a request as it flows through your application. It provides insights into how requests are processed and helps in debugging and optimizing your applications.

To get Docker, follow these steps:

  1. Visit the Docker website at https://www.docker.com/.

  2. Download Docker Desktop for your operating system (Windows or macOS) and install it.

  3. After installation, open Docker Desktop, and it will run in the background.

  1. Start the OpenTelemetry Backend

    Before we begin generating and exporting traces from our sample application, we will need to get our OpenTelemetry backend running in Docker.

    This can be done using the following command:

    Terminal window
    docker run -p 3000:3000 -p 4317:4317 -p 4318:4318 --rm -it docker.io/grafana/otel-lgtm
  2. Install Dependencies

    We also need to install a few additional dependencies, as well as the latest version of effect:

    Terminal window
    # If not already installed
    npm install effect
    # Required to integrate Effect with OpenTelemetry
    npm install @effect/opentelemetry
    # Required to export traces over HTTP in OTLP format
    npm install @opentelemetry/exporter-trace-otlp-http
    # Required by all applications
    npm install @opentelemetry/sdk-trace-base
    # For NodeJS applications
    npm install @opentelemetry/sdk-trace-node
    # For browser applications
    npm install @opentelemetry/sdk-trace-web
    # If you also need to export metrics
    npm install @opentelemetry/sdk-metrics
  3. Simulate Traces

    Now, let’s simulate traces using a sample Node.js application.

    The following code simulates a set of tasks and generates traces for each task. It also sets up a Layer which will export traces from our application to our OpenTelemetry backend over HTTP in OTLP format.

    import {
    import Effect

    @since2.0.0

    @since2.0.0

    @since2.0.0

    Effect
    } from "effect"
    import {
    import NodeSdk
    NodeSdk
    } from "@effect/opentelemetry"
    import {
    class BatchSpanProcessor
    BatchSpanProcessor
    } from "@opentelemetry/sdk-trace-base"
    import {
    class OTLPTraceExporter

    Collector Trace Exporter for Node

    OTLPTraceExporter
    } from "@opentelemetry/exporter-trace-otlp-http"
    // Function to simulate a task with possible subtasks
    const
    const task: (name: string, delay: number, children?: ReadonlyArray<Effect.Effect<void>>) => Effect.Effect<void, never, never>
    task
    = (
    name: string
    name
    : string,
    delay: number
    delay
    : number,
    children: readonly Effect.Effect<void, never, never>[]
    children
    :
    interface ReadonlyArray<T>
    ReadonlyArray
    <
    import Effect

    @since2.0.0

    @since2.0.0

    @since2.0.0

    Effect
    .
    interface Effect<out A, out E = never, out R = never>

    The Effect interface defines a value that describes a workflow or job, which can succeed or fail.

    Details

    The Effect interface represents a computation that can model a workflow involving various types of operations, such as synchronous, asynchronous, concurrent, and parallel interactions. It operates within a context of type R, and the result can either be a success with a value of type A or a failure with an error of type E. The Effect is designed to handle complex interactions with external resources, offering advanced features such as fiber-based concurrency, scheduling, interruption handling, and scalability. This makes it suitable for tasks that require fine-grained control over concurrency and error management.

    To execute an Effect value, you need a Runtime, which provides the environment necessary to run and manage the computation.

    @since2.0.0

    @since2.0.0

    Effect
    <void>> = []
    ) =>
    import Effect

    @since2.0.0

    @since2.0.0

    @since2.0.0

    Effect
    .
    const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<void, never, never> (+1 overload)

    Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

    When to Use

    Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

    The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

    Example

    import { Effect } from "effect"
    const addServiceCharge = (amount: number) => amount + 1
    const applyDiscount = (
    total: number,
    discountRate: number
    ): Effect.Effect<number, Error> =>
    discountRate === 0
    ? Effect.fail(new Error("Discount rate cannot be zero"))
    : Effect.succeed(total - (total * discountRate) / 100)
    const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
    const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
    export const program = Effect.gen(function* () {
    const transactionAmount = yield* fetchTransactionAmount
    const discountRate = yield* fetchDiscountRate
    const discountedAmount = yield* applyDiscount(
    transactionAmount,
    discountRate
    )
    const finalAmount = addServiceCharge(discountedAmount)
    return `Final amount to charge: ${finalAmount}`
    })

    @since2.0.0

    gen
    (function* () {
    yield*
    import Effect

    @since2.0.0

    @since2.0.0

    @since2.0.0

    Effect
    .
    const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

    Logs one or more messages or error causes at the current log level.

    Details

    This function provides a simple way to log messages or error causes during the execution of your effects. By default, logs are recorded at the INFO level, but this can be adjusted using other logging utilities (Logger.withMinimumLogLevel). Multiple items, including Cause instances, can be logged in a single call. When logging Cause instances, detailed error information is included in the log output.

    The log output includes useful metadata like the current timestamp, log level, and fiber ID, making it suitable for debugging and tracking purposes. This function does not interrupt or alter the effect's execution flow.

    Example

    import { Cause, Effect } from "effect"
    const program = Effect.log(
    "message1",
    "message2",
    Cause.die("Oh no!"),
    Cause.die("Oh uh!")
    )
    Effect.runFork(program)
    // Output:
    // timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no!
    // Error: Oh uh!"

    @since2.0.0

    log
    (
    name: string
    name
    )
    yield*
    import Effect

    @since2.0.0

    @since2.0.0

    @since2.0.0

    Effect
    .
    const sleep: (duration: DurationInput) => Effect.Effect<void>

    Suspends the execution of an effect for a specified Duration.

    Details

    This function pauses the execution of an effect for a given duration. It is asynchronous, meaning that it does not block the fiber executing the effect. Instead, the fiber is suspended during the delay period and can resume once the specified time has passed.

    The duration can be specified using various formats supported by the Duration module, such as a string ("2 seconds") or numeric value representing milliseconds.

    Example

    import { Effect } from "effect"
    const program = Effect.gen(function*() {
    console.log("Starting task...")
    yield* Effect.sleep("3 seconds") // Waits for 3 seconds
    console.log("Task completed!")
    })
    Effect.runFork(program)
    // Output:
    // Starting task...
    // Task completed!

    @since2.0.0

    sleep
    (`${
    delay: number
    delay
    } millis`)
    for (const
    const child: Effect.Effect<void, never, never>
    child
    of
    children: readonly Effect.Effect<void, never, never>[]
    children
    ) {
    yield*
    const child: Effect.Effect<void, never, never>
    child
    }
    yield*
    import Effect

    @since2.0.0

    @since2.0.0

    @since2.0.0

    Effect
    .
    const sleep: (duration: DurationInput) => Effect.Effect<void>

    Suspends the execution of an effect for a specified Duration.

    Details

    This function pauses the execution of an effect for a given duration. It is asynchronous, meaning that it does not block the fiber executing the effect. Instead, the fiber is suspended during the delay period and can resume once the specified time has passed.

    The duration can be specified using various formats supported by the Duration module, such as a string ("2 seconds") or numeric value representing milliseconds.

    Example

    import { Effect } from "effect"
    const program = Effect.gen(function*() {
    console.log("Starting task...")
    yield* Effect.sleep("3 seconds") // Waits for 3 seconds
    console.log("Task completed!")
    })
    Effect.runFork(program)
    // Output:
    // Starting task...
    // Task completed!

    @since2.0.0

    sleep
    (`${
    delay: number
    delay
    } millis`)
    }).
    Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<void, never, never>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<void, never, never> (+21 overloads)
    pipe
    (
    import Effect

    @since2.0.0

    @since2.0.0

    @since2.0.0

    Effect
    .
    const withSpan: (name: string, options?: SpanOptions | undefined) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, ParentSpan>> (+1 overload)

    Wraps the effect with a new span for tracing.

    @since2.0.0

    withSpan
    (
    name: string
    name
    ))
    const
    const poll: Effect.Effect<void, never, never>
    poll
    =
    const task: (name: string, delay: number, children?: ReadonlyArray<Effect.Effect<void>>) => Effect.Effect<void, never, never>
    task
    ("/poll", 1)
    // Create a program with tasks and subtasks
    const
    const program: Effect.Effect<void, never, never>
    program
    =
    const task: (name: string, delay: number, children?: ReadonlyArray<Effect.Effect<void>>) => Effect.Effect<void, never, never>
    task
    ("client", 2, [
    const task: (name: string, delay: number, children?: ReadonlyArray<Effect.Effect<void>>) => Effect.Effect<void, never, never>
    task
    ("/api", 3, [
    const task: (name: string, delay: number, children?: ReadonlyArray<Effect.Effect<void>>) => Effect.Effect<void, never, never>
    task
    ("/authN", 4, [
    const task: (name: string, delay: number, children?: ReadonlyArray<Effect.Effect<void>>) => Effect.Effect<void, never, never>
    task
    ("/authZ", 5)]),
    const task: (name: string, delay: number, children?: ReadonlyArray<Effect.Effect<void>>) => Effect.Effect<void, never, never>
    task
    ("/payment Gateway", 6, [
    const task: (name: string, delay: number, children?: ReadonlyArray<Effect.Effect<void>>) => Effect.Effect<void, never, never>
    task
    ("DB", 7),
    const task: (name: string, delay: number, children?: ReadonlyArray<Effect.Effect<void>>) => Effect.Effect<void, never, never>
    task
    ("Ext. Merchant", 8)
    ]),
    const task: (name: string, delay: number, children?: ReadonlyArray<Effect.Effect<void>>) => Effect.Effect<void, never, never>
    task
    ("/dispatch", 9, [
    const task: (name: string, delay: number, children?: ReadonlyArray<Effect.Effect<void>>) => Effect.Effect<void, never, never>
    task
    ("/dispatch/search", 10),
    import Effect

    @since2.0.0

    @since2.0.0

    @since2.0.0

    Effect
    .
    const all: <readonly [Effect.Effect<void, never, never>, Effect.Effect<void, never, never>, Effect.Effect<void, never, never>], {
    concurrency: "inherit";
    }>(arg: readonly [Effect.Effect<void, never, never>, Effect.Effect<void, never, never>, Effect.Effect<void, never, never>], options?: {
    concurrency: "inherit";
    } | undefined) => Effect.Effect<[void, void, void], never, never>

    Combines multiple effects into one, returning results based on the input structure.

    Details

    Use this function when you need to run multiple effects and combine their results into a single output. It supports tuples, iterables, structs, and records, making it flexible for different input types.

    For instance, if the input is a tuple:

    // ┌─── a tuple of effects
    // ▼
    Effect.all([effect1, effect2, ...])

    the effects are executed sequentially, and the result is a new effect containing the results as a tuple. The results in the tuple match the order of the effects passed to Effect.all.

    Concurrency

    You can control the execution order (e.g., sequential vs. concurrent) using the concurrency option.

    Short-Circuiting Behavior

    This function stops execution on the first error it encounters, this is called "short-circuiting". If any effect in the collection fails, the remaining effects will not run, and the error will be propagated. To change this behavior, you can use the mode option, which allows all effects to run and collect results as Either or Option.

    The mode option

    The { mode: "either" } option changes the behavior of Effect.all to ensure all effects run, even if some fail. Instead of stopping on the first failure, this mode collects both successes and failures, returning an array of Either instances where each result is either a Right (success) or a Left (failure).

    Similarly, the { mode: "validate" } option uses Option to indicate success or failure. Each effect returns None for success and Some with the error for failure.

    Example (Combining Effects in Tuples)

    import { Effect, Console } from "effect"
    const tupleOfEffects = [
    Effect.succeed(42).pipe(Effect.tap(Console.log)),
    Effect.succeed("Hello").pipe(Effect.tap(Console.log))
    ] as const
    // ┌─── Effect<[number, string], never, never>
    // ▼
    const resultsAsTuple = Effect.all(tupleOfEffects)
    Effect.runPromise(resultsAsTuple).then(console.log)
    // Output:
    // 42
    // Hello
    // [ 42, 'Hello' ]

    Example (Combining Effects in Iterables)

    import { Effect, Console } from "effect"
    const iterableOfEffects: Iterable<Effect.Effect<number>> = [1, 2, 3].map(
    (n) => Effect.succeed(n).pipe(Effect.tap(Console.log))
    )
    // ┌─── Effect<number[], never, never>
    // ▼
    const resultsAsArray = Effect.all(iterableOfEffects)
    Effect.runPromise(resultsAsArray).then(console.log)
    // Output:
    // 1
    // 2
    // 3
    // [ 1, 2, 3 ]

    Example (Combining Effects in Structs)

    import { Effect, Console } from "effect"
    const structOfEffects = {
    a: Effect.succeed(42).pipe(Effect.tap(Console.log)),
    b: Effect.succeed("Hello").pipe(Effect.tap(Console.log))
    }
    // ┌─── Effect<{ a: number; b: string; }, never, never>
    // ▼
    const resultsAsStruct = Effect.all(structOfEffects)
    Effect.runPromise(resultsAsStruct).then(console.log)
    // Output:
    // 42
    // Hello
    // { a: 42, b: 'Hello' }

    Example (Combining Effects in Records)

    import { Effect, Console } from "effect"
    const recordOfEffects: Record<string, Effect.Effect<number>> = {
    key1: Effect.succeed(1).pipe(Effect.tap(Console.log)),
    key2: Effect.succeed(2).pipe(Effect.tap(Console.log))
    }
    // ┌─── Effect<{ [x: string]: number; }, never, never>
    // ▼
    const resultsAsRecord = Effect.all(recordOfEffects)
    Effect.runPromise(resultsAsRecord).then(console.log)
    // Output:
    // 1
    // 2
    // { key1: 1, key2: 2 }

    Example (Short-Circuiting Behavior)

    import { Effect, Console } from "effect"
    const program = Effect.all([
    Effect.succeed("Task1").pipe(Effect.tap(Console.log)),
    Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)),
    // Won't execute due to earlier failure
    Effect.succeed("Task3").pipe(Effect.tap(Console.log))
    ])
    Effect.runPromiseExit(program).then(console.log)
    // Output:
    // Task1
    // {
    // _id: 'Exit',
    // _tag: 'Failure',
    // cause: { _id: 'Cause', _tag: 'Fail', failure: 'Task2: Oh no!' }
    // }

    Example (Collecting Results with mode: "either")

    import { Effect, Console } from "effect"
    const effects = [
    Effect.succeed("Task1").pipe(Effect.tap(Console.log)),
    Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)),
    Effect.succeed("Task3").pipe(Effect.tap(Console.log))
    ]
    const program = Effect.all(effects, { mode: "either" })
    Effect.runPromiseExit(program).then(console.log)
    // Output:
    // Task1
    // Task3
    // {
    // _id: 'Exit',
    // _tag: 'Success',
    // value: [
    // { _id: 'Either', _tag: 'Right', right: 'Task1' },
    // { _id: 'Either', _tag: 'Left', left: 'Task2: Oh no!' },
    // { _id: 'Either', _tag: 'Right', right: 'Task3' }
    // ]
    // }

    Example (Collecting Results with mode: "validate")

    import { Effect, Console } from "effect"
    const effects = [
    Effect.succeed("Task1").pipe(Effect.tap(Console.log)),
    Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)),
    Effect.succeed("Task3").pipe(Effect.tap(Console.log))
    ]
    const program = Effect.all(effects, { mode: "validate" })
    Effect.runPromiseExit(program).then((result) => console.log("%o", result))
    // Output:
    // Task1
    // Task3
    // {
    // _id: 'Exit',
    // _tag: 'Failure',
    // cause: {
    // _id: 'Cause',
    // _tag: 'Fail',
    // failure: [
    // { _id: 'Option', _tag: 'None' },
    // { _id: 'Option', _tag: 'Some', value: 'Task2: Oh no!' },
    // { _id: 'Option', _tag: 'None' }
    // ]
    // }
    // }

    @seeforEach for iterating over elements and applying an effect.

    @seeallWith for a data-last version of this function.

    @since2.0.0

    all
    ([
    const poll: Effect.Effect<void, never, never>
    poll
    ,
    const poll: Effect.Effect<void, never, never>
    poll
    ,
    const poll: Effect.Effect<void, never, never>
    poll
    ], {
    concurrency: "inherit"
    concurrency
    : "inherit" }),
    const task: (name: string, delay: number, children?: ReadonlyArray<Effect.Effect<void>>) => Effect.Effect<void, never, never>
    task
    ("/pollDriver/{id}", 11)
    ])
    ])
    ])
    const
    const NodeSdkLive: Layer<Resource, never, never>
    NodeSdkLive
    =
    import NodeSdk
    NodeSdk
    .
    const layer: (evaluate: LazyArg<NodeSdk.Configuration>) => Layer<Resource> (+1 overload)

    @since1.0.0

    layer
    (() => ({
    Configuration.resource?: {
    readonly serviceName: string;
    readonly serviceVersion?: string;
    readonly attributes?: Attributes;
    } | undefined
    resource
    : {
    serviceName: string
    serviceName
    : "example" },
    Configuration.spanProcessor?: SpanProcessor | readonly SpanProcessor[] | undefined
    spanProcessor
    : new
    new BatchSpanProcessor<BufferConfig>(_exporter: SpanExporter, config?: BufferConfig | undefined): BatchSpanProcessor
    BatchSpanProcessor
    (new
    new OTLPTraceExporter(config?: OTLPExporterNodeConfigBase): OTLPTraceExporter

    Collector Trace Exporter for Node

    OTLPTraceExporter
    ())
    }))
    import Effect

    @since2.0.0

    @since2.0.0

    @since2.0.0

    Effect
    .
    const runPromise: <void, never>(effect: Effect.Effect<void, never, never>, options?: {
    readonly signal?: AbortSignal | undefined;
    } | undefined) => Promise<void>

    Executes an effect and returns the result as a Promise.

    Details

    This function runs an effect and converts its result into a Promise. If the effect succeeds, the Promise will resolve with the successful result. If the effect fails, the Promise will reject with an error, which includes the failure details of the effect.

    The optional options parameter allows you to pass an AbortSignal for cancellation, enabling more fine-grained control over asynchronous tasks.

    When to Use

    Use this function when you need to execute an effect and work with its result in a promise-based system, such as when integrating with third-party libraries that expect Promise results.

    Example (Running a Successful Effect as a Promise)

    import { Effect } from "effect"
    Effect.runPromise(Effect.succeed(1)).then(console.log)
    // Output: 1

    Example (Handling a Failing Effect as a Rejected Promise)

    import { Effect } from "effect"
    Effect.runPromise(Effect.fail("my error")).catch(console.error)
    // Output:
    // (FiberFailure) Error: my error

    @seerunPromiseExit for a version that returns an Exit type instead of rejecting.

    @since2.0.0

    runPromise
    (
    const program: Effect.Effect<void, never, never>
    program
    .
    Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>, Effect.Effect<void, never, never>>(this: Effect.Effect<void, never, never>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>, bc: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>): Effect.Effect<void, never, never> (+21 overloads)
    pipe
    (
    import Effect

    @since2.0.0

    @since2.0.0

    @since2.0.0

    Effect
    .
    const provide: <Resource, never, never>(layer: Layer<Resource, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Resource>> (+9 overloads)

    Provides necessary dependencies to an effect, removing its environmental requirements.

    Details

    This function allows you to supply the required environment for an effect. The environment can be provided in the form of one or more Layers, a Context, a Runtime, or a ManagedRuntime. Once the environment is provided, the effect can run without requiring external dependencies.

    You can compose layers to create a modular and reusable way of setting up the environment for effects. For example, layers can be used to configure databases, logging services, or any other required dependencies.

    Example

    import { Context, Effect, Layer } from "effect"
    class Database extends Context.Tag("Database")<
    Database,
    { readonly query: (sql: string) => Effect.Effect<Array<unknown>> }
    >() {}
    const DatabaseLive = Layer.succeed(
    Database,
    {
    // Simulate a database query
    query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([]))
    }
    )
    // ┌─── Effect<unknown[], never, Database>
    // ▼
    const program = Effect.gen(function*() {
    const database = yield* Database
    const result = yield* database.query("SELECT * FROM users")
    return result
    })
    // ┌─── Effect<unknown[], never, never>
    // ▼
    const runnable = Effect.provide(program, DatabaseLive)
    Effect.runPromise(runnable).then(console.log)
    // Output:
    // timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users"
    // []

    @seeprovideService for providing a service to an effect.

    @since2.0.0

    provide
    (
    const NodeSdkLive: Layer<Resource, never, never>
    NodeSdkLive
    ),
    import Effect

    @since2.0.0

    @since2.0.0

    @since2.0.0

    Effect
    .
    const catchAllCause: <never, void, never, never>(f: (cause: Cause<never>) => Effect.Effect<void, never, never>) => <A, R>(self: Effect.Effect<A, never, R>) => Effect.Effect<void | A, never, R> (+1 overload)

    Handles both recoverable and unrecoverable errors by providing a recovery effect.

    When to Use

    The catchAllCause function allows you to handle all errors, including unrecoverable defects, by providing a recovery effect. The recovery logic is based on the Cause of the error, which provides detailed information about the failure.

    When to Recover from Defects

    Defects are unexpected errors that typically shouldn't be recovered from, as they often indicate serious issues. However, in some cases, such as dynamically loaded plugins, controlled recovery might be needed.

    Example (Recovering from All Errors)

    import { Cause, Effect } from "effect"
    // Define an effect that may fail with a recoverable or unrecoverable error
    const program = Effect.fail("Something went wrong!")
    // Recover from all errors by examining the cause
    const recovered = program.pipe(
    Effect.catchAllCause((cause) =>
    Cause.isFailure(cause)
    ? Effect.succeed("Recovered from a regular error")
    : Effect.succeed("Recovered from a defect")
    )
    )
    Effect.runPromise(recovered).then(console.log)
    // Output: "Recovered from a regular error"

    @since2.0.0

    catchAllCause
    (
    import Effect

    @since2.0.0

    @since2.0.0

    @since2.0.0

    Effect
    .
    const logError: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>

    Logs messages at the ERROR log level.

    Details

    This function logs messages at the ERROR level, suitable for reporting application errors or failures. These logs are typically used for unexpected issues that need immediate attention.

    @since2.0.0

    logError
    )
    )
    )
    /*
    Output:
    timestamp=... level=INFO fiber=#0 message=client
    timestamp=... level=INFO fiber=#0 message=/api
    timestamp=... level=INFO fiber=#0 message=/authN
    timestamp=... level=INFO fiber=#0 message=/authZ
    timestamp=... level=INFO fiber=#0 message="/payment Gateway"
    timestamp=... level=INFO fiber=#0 message=DB
    timestamp=... level=INFO fiber=#0 message="Ext. Merchant"
    timestamp=... level=INFO fiber=#0 message=/dispatch
    timestamp=... level=INFO fiber=#0 message=/dispatch/search
    timestamp=... level=INFO fiber=#3 message=/poll
    timestamp=... level=INFO fiber=#4 message=/poll
    timestamp=... level=INFO fiber=#5 message=/poll
    timestamp=... level=INFO fiber=#0 message=/pollDriver/{id}
    */
  4. Visualize Traces

    Open your web browser and go to http://localhost:3000/explore. You should see the Grafana Tempo TraceQL interface.

    Tempo TraceQL Interface

    To get a list of all available traces, we can select the "Search" query type to get a list of all available traces.

    Tempo Search Selector

    Clicking the generated Trace ID will allow us to inspect the details of the trace.

    Traces in Grafana Tempo

To send span data directly to Sentry for analysis, replace the default span processor with Sentry’s implementation. This allows you to use Sentry as a backend for tracing and debugging.

Example (Configuring Sentry for Tracing)

import {
import NodeSdk
NodeSdk
} from "@effect/opentelemetry"
import {
class SentrySpanProcessor

Converts OpenTelemetry Spans to Sentry Spans and sends them to Sentry via the Sentry SDK.

SentrySpanProcessor
} from "@sentry/opentelemetry"
const
const NodeSdkLive: Layer<Resource, never, never>
NodeSdkLive
=
import NodeSdk
NodeSdk
.
const layer: (evaluate: LazyArg<NodeSdk.Configuration>) => Layer<Resource> (+1 overload)

@since1.0.0

layer
(() => ({
Configuration.resource?: {
readonly serviceName: string;
readonly serviceVersion?: string;
readonly attributes?: Attributes;
} | undefined
resource
: {
serviceName: string
serviceName
: "example" },
Configuration.spanProcessor?: SpanProcessor | readonly SpanProcessor[] | undefined
spanProcessor
: new
new SentrySpanProcessor(options?: {
timeout?: number;
}): SentrySpanProcessor

Converts OpenTelemetry Spans to Sentry Spans and sends them to Sentry via the Sentry SDK.

SentrySpanProcessor
()
}))