effect 4.0.0-beta.10 → 4.0.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Channel.d.ts +7 -7
- package/dist/Effect.d.ts +217 -8
- package/dist/Effect.d.ts.map +1 -1
- package/dist/Effect.js +46 -0
- package/dist/Effect.js.map +1 -1
- package/dist/ErrorReporter.d.ts +376 -0
- package/dist/ErrorReporter.d.ts.map +1 -0
- package/dist/ErrorReporter.js +246 -0
- package/dist/ErrorReporter.js.map +1 -0
- package/dist/LogLevel.d.ts +5 -0
- package/dist/LogLevel.d.ts.map +1 -1
- package/dist/LogLevel.js.map +1 -1
- package/dist/Logger.d.ts +25 -91
- package/dist/Logger.d.ts.map +1 -1
- package/dist/Logger.js +2 -3
- package/dist/Logger.js.map +1 -1
- package/dist/Queue.d.ts.map +1 -1
- package/dist/Queue.js +0 -1
- package/dist/Queue.js.map +1 -1
- package/dist/References.d.ts +3 -3
- package/dist/References.d.ts.map +1 -1
- package/dist/SchemaAST.d.ts.map +1 -1
- package/dist/SchemaAST.js +2 -1
- package/dist/SchemaAST.js.map +1 -1
- package/dist/Stream.d.ts +5 -5
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/effect.js +54 -4
- package/dist/internal/effect.js.map +1 -1
- package/dist/internal/hashMap.js +2 -2
- package/dist/internal/hashMap.js.map +1 -1
- package/dist/unstable/ai/LanguageModel.d.ts.map +1 -1
- package/dist/unstable/ai/LanguageModel.js +41 -0
- package/dist/unstable/ai/LanguageModel.js.map +1 -1
- package/dist/unstable/cli/CliOutput.js +37 -6
- package/dist/unstable/cli/CliOutput.js.map +1 -1
- package/dist/unstable/cli/Command.d.ts +199 -7
- package/dist/unstable/cli/Command.d.ts.map +1 -1
- package/dist/unstable/cli/Command.js +116 -6
- package/dist/unstable/cli/Command.js.map +1 -1
- package/dist/unstable/cli/HelpDoc.d.ts +60 -2
- package/dist/unstable/cli/HelpDoc.d.ts.map +1 -1
- package/dist/unstable/cli/internal/command.d.ts +11 -1
- package/dist/unstable/cli/internal/command.d.ts.map +1 -1
- package/dist/unstable/cli/internal/command.js +33 -8
- package/dist/unstable/cli/internal/command.js.map +1 -1
- package/dist/unstable/cli/internal/completions/CommandDescriptor.js +7 -2
- package/dist/unstable/cli/internal/completions/CommandDescriptor.js.map +1 -1
- package/dist/unstable/cli/internal/parser.js +10 -2
- package/dist/unstable/cli/internal/parser.js.map +1 -1
- package/dist/unstable/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
- package/dist/unstable/http/Headers.d.ts.map +1 -1
- package/dist/unstable/http/Headers.js +27 -10
- package/dist/unstable/http/Headers.js.map +1 -1
- package/dist/unstable/http/HttpEffect.d.ts.map +1 -1
- package/dist/unstable/http/HttpEffect.js +12 -7
- package/dist/unstable/http/HttpEffect.js.map +1 -1
- package/dist/unstable/http/HttpServerError.d.ts +8 -26
- package/dist/unstable/http/HttpServerError.d.ts.map +1 -1
- package/dist/unstable/http/HttpServerError.js +11 -27
- package/dist/unstable/http/HttpServerError.js.map +1 -1
- package/dist/unstable/http/HttpServerRespondable.d.ts +2 -2
- package/dist/unstable/http/HttpServerRespondable.d.ts.map +1 -1
- package/dist/unstable/http/HttpServerRespondable.js +5 -5
- package/dist/unstable/http/HttpServerRespondable.js.map +1 -1
- package/dist/unstable/http/HttpServerResponse.d.ts +2 -1
- package/dist/unstable/http/HttpServerResponse.d.ts.map +1 -1
- package/dist/unstable/http/HttpServerResponse.js +2 -0
- package/dist/unstable/http/HttpServerResponse.js.map +1 -1
- package/dist/unstable/httpapi/HttpApiBuilder.js +1 -1
- package/dist/unstable/httpapi/HttpApiBuilder.js.map +1 -1
- package/dist/unstable/httpapi/HttpApiError.d.ts +11 -0
- package/dist/unstable/httpapi/HttpApiError.d.ts.map +1 -1
- package/dist/unstable/httpapi/HttpApiError.js +29 -9
- package/dist/unstable/httpapi/HttpApiError.js.map +1 -1
- package/dist/unstable/observability/OtlpLogger.d.ts.map +1 -1
- package/dist/unstable/observability/OtlpLogger.js +7 -4
- package/dist/unstable/observability/OtlpLogger.js.map +1 -1
- package/dist/unstable/reactivity/AtomRegistry.d.ts +6 -0
- package/dist/unstable/reactivity/AtomRegistry.d.ts.map +1 -1
- package/dist/unstable/reactivity/AtomRegistry.js +22 -1
- package/dist/unstable/reactivity/AtomRegistry.js.map +1 -1
- package/dist/unstable/rpc/RpcServer.d.ts.map +1 -1
- package/dist/unstable/rpc/RpcServer.js +4 -0
- package/dist/unstable/rpc/RpcServer.js.map +1 -1
- package/dist/unstable/workflow/WorkflowEngine.d.ts +6 -0
- package/dist/unstable/workflow/WorkflowEngine.d.ts.map +1 -1
- package/dist/unstable/workflow/WorkflowEngine.js +131 -0
- package/dist/unstable/workflow/WorkflowEngine.js.map +1 -1
- package/package.json +1 -1
- package/src/Channel.ts +9 -9
- package/src/Effect.ts +235 -8
- package/src/ErrorReporter.ts +459 -0
- package/src/LogLevel.ts +6 -0
- package/src/Logger.ts +28 -95
- package/src/Queue.ts +0 -1
- package/src/References.ts +4 -4
- package/src/SchemaAST.ts +2 -1
- package/src/Stream.ts +7 -7
- package/src/index.ts +5 -0
- package/src/internal/effect.ts +137 -14
- package/src/internal/hashMap.ts +2 -2
- package/src/unstable/ai/LanguageModel.ts +71 -0
- package/src/unstable/cli/CliOutput.ts +45 -6
- package/src/unstable/cli/Command.ts +298 -11
- package/src/unstable/cli/HelpDoc.ts +68 -2
- package/src/unstable/cli/internal/command.ts +47 -11
- package/src/unstable/cli/internal/completions/CommandDescriptor.ts +7 -2
- package/src/unstable/cli/internal/parser.ts +11 -3
- package/src/unstable/http/Headers.ts +28 -13
- package/src/unstable/http/HttpEffect.ts +10 -5
- package/src/unstable/http/HttpServerError.ts +13 -27
- package/src/unstable/http/HttpServerRespondable.ts +6 -6
- package/src/unstable/http/HttpServerResponse.ts +3 -1
- package/src/unstable/httpapi/HttpApiBuilder.ts +1 -0
- package/src/unstable/httpapi/HttpApiError.ts +30 -9
- package/src/unstable/observability/OtlpLogger.ts +9 -5
- package/src/unstable/reactivity/AtomRegistry.ts +29 -1
- package/src/unstable/rpc/RpcServer.ts +4 -0
- package/src/unstable/workflow/WorkflowEngine.ts +178 -0
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pluggable error reporting for Effect programs.
|
|
3
|
+
*
|
|
4
|
+
* Reporting is triggered by `Effect.withErrorReporting`,
|
|
5
|
+
* `ErrorReporter.report`, or built-in reporting boundaries in the HTTP and
|
|
6
|
+
* RPC server modules.
|
|
7
|
+
*
|
|
8
|
+
* Each reporter receives a structured callback with the failing `Cause`, a
|
|
9
|
+
* pretty-printed `Error`, severity, and any extra attributes attached to the
|
|
10
|
+
* original error — making it straightforward to forward failures to Sentry,
|
|
11
|
+
* Datadog, or a custom logging backend.
|
|
12
|
+
*
|
|
13
|
+
* Use the annotation symbols (`ignore`, `severity`, `attributes`) on your
|
|
14
|
+
* error classes to control reporting behavior per-error.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { Data, Effect, ErrorReporter } from "effect"
|
|
19
|
+
*
|
|
20
|
+
* // A reporter that logs to the console
|
|
21
|
+
* const consoleReporter = ErrorReporter.make(({ error, severity }) => {
|
|
22
|
+
* console.error(`[${severity}]`, error.message)
|
|
23
|
+
* })
|
|
24
|
+
*
|
|
25
|
+
* // An error that should be ignored by reporters
|
|
26
|
+
* class NotFoundError extends Data.TaggedError("NotFoundError")<{}> {
|
|
27
|
+
* readonly [ErrorReporter.ignore] = true
|
|
28
|
+
* }
|
|
29
|
+
*
|
|
30
|
+
* // An error with custom severity and attributes
|
|
31
|
+
* class RateLimitError extends Data.TaggedError("RateLimitError")<{
|
|
32
|
+
* readonly retryAfter: number
|
|
33
|
+
* }> {
|
|
34
|
+
* readonly [ErrorReporter.severity] = "Warn" as const
|
|
35
|
+
* readonly [ErrorReporter.attributes] = {
|
|
36
|
+
* retryAfter: this.retryAfter
|
|
37
|
+
* }
|
|
38
|
+
* }
|
|
39
|
+
*
|
|
40
|
+
* // Opt in to error reporting with Effect.withErrorReporting
|
|
41
|
+
* const program = Effect.gen(function*() {
|
|
42
|
+
* yield* new RateLimitError({ retryAfter: 60 })
|
|
43
|
+
* }).pipe(
|
|
44
|
+
* Effect.withErrorReporting,
|
|
45
|
+
* Effect.provide(ErrorReporter.layer([consoleReporter]))
|
|
46
|
+
* )
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @since 4.0.0
|
|
50
|
+
*/
|
|
51
|
+
import type * as Cause from "./Cause.ts"
|
|
52
|
+
import * as Effect from "./Effect.ts"
|
|
53
|
+
import type * as Fiber from "./Fiber.ts"
|
|
54
|
+
import * as effect from "./internal/effect.ts"
|
|
55
|
+
import * as Layer from "./Layer.ts"
|
|
56
|
+
import * as LogLevel from "./LogLevel.ts"
|
|
57
|
+
import type { Severity } from "./LogLevel.ts"
|
|
58
|
+
import type { ReadonlyRecord } from "./Record.ts"
|
|
59
|
+
import type * as Scope from "./Scope.ts"
|
|
60
|
+
import type * as ServiceMap from "./ServiceMap.ts"
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @since 4.0.0
|
|
64
|
+
* @category Type Identifiers
|
|
65
|
+
*/
|
|
66
|
+
export type TypeId = "~effect/ErrorReporter"
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @since 4.0.0
|
|
70
|
+
* @category Type Identifiers
|
|
71
|
+
*/
|
|
72
|
+
export const TypeId: TypeId = "~effect/ErrorReporter"
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* An `ErrorReporter` receives reported failures and forwards them to an
|
|
76
|
+
* external system (logging service, error tracker, etc.).
|
|
77
|
+
*
|
|
78
|
+
* Reporting is triggered by `Effect.withErrorReporting`,
|
|
79
|
+
* `ErrorReporter.report`, or built-in boundaries in the HTTP and RPC server
|
|
80
|
+
* modules. Use {@link make} to create a reporter — it handles deduplication
|
|
81
|
+
* and per-error annotation extraction automatically.
|
|
82
|
+
*
|
|
83
|
+
* @since 4.0.0
|
|
84
|
+
* @category Models
|
|
85
|
+
*/
|
|
86
|
+
export interface ErrorReporter {
|
|
87
|
+
readonly [TypeId]: TypeId
|
|
88
|
+
report(options: {
|
|
89
|
+
readonly cause: Cause.Cause<unknown>
|
|
90
|
+
readonly fiber: Fiber.Fiber<unknown, unknown>
|
|
91
|
+
readonly timestamp: bigint
|
|
92
|
+
}): void
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Creates an `ErrorReporter` from a callback.
|
|
97
|
+
*
|
|
98
|
+
* The returned reporter automatically deduplicates causes and individual
|
|
99
|
+
* errors (the same object is never reported twice), skips interruptions,
|
|
100
|
+
* and resolves the `ignore`, `severity`, and `attributes` annotations on
|
|
101
|
+
* each error before invoking your callback.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```ts
|
|
105
|
+
* import { ErrorReporter } from "effect"
|
|
106
|
+
*
|
|
107
|
+
* // Forward every failure to the console
|
|
108
|
+
* const consoleReporter = ErrorReporter.make(
|
|
109
|
+
* ({ error, severity, attributes }) => {
|
|
110
|
+
* console.error(`[${severity}]`, error.message, attributes)
|
|
111
|
+
* }
|
|
112
|
+
* )
|
|
113
|
+
* ```
|
|
114
|
+
*
|
|
115
|
+
* @since 4.0.0
|
|
116
|
+
* @category Constructors
|
|
117
|
+
*/
|
|
118
|
+
export const make = (
|
|
119
|
+
report: (options: {
|
|
120
|
+
readonly cause: Cause.Cause<unknown>
|
|
121
|
+
readonly error: Error
|
|
122
|
+
readonly attributes: ReadonlyRecord<string, unknown>
|
|
123
|
+
readonly severity: Severity
|
|
124
|
+
readonly fiber: Fiber.Fiber<unknown, unknown>
|
|
125
|
+
readonly timestamp: bigint
|
|
126
|
+
}) => void
|
|
127
|
+
): ErrorReporter => {
|
|
128
|
+
const reported = new WeakSet<Cause.Cause<unknown> | object>()
|
|
129
|
+
return {
|
|
130
|
+
[TypeId]: TypeId,
|
|
131
|
+
report(options) {
|
|
132
|
+
if (reported.has(options.cause)) return
|
|
133
|
+
reported.add(options.cause)
|
|
134
|
+
for (let i = 0; i < options.cause.reasons.length; i++) {
|
|
135
|
+
const reason = options.cause.reasons[i]
|
|
136
|
+
if (reason._tag === "Interrupt") continue
|
|
137
|
+
const original = reason._tag === "Fail" ? reason.error : reason.defect
|
|
138
|
+
const isObject = typeof original === "object" && original !== null
|
|
139
|
+
if (isObject) {
|
|
140
|
+
if (reported.has(original)) continue
|
|
141
|
+
reported.add(original)
|
|
142
|
+
}
|
|
143
|
+
if (isIgnored(original)) continue
|
|
144
|
+
const pretty = effect.causePrettyError(original as any, reason.annotations)
|
|
145
|
+
report({
|
|
146
|
+
...options,
|
|
147
|
+
error: pretty,
|
|
148
|
+
severity: isObject ? getSeverity(original) : "Error",
|
|
149
|
+
attributes: isObject ? getAttributes(original) : emptyAttributes
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* A `ServiceMap.Reference` holding the set of active `ErrorReporter`s for the
|
|
158
|
+
* current fiber. Defaults to an empty set (no reporting).
|
|
159
|
+
*
|
|
160
|
+
* Prefer {@link layer} to configure reporters via the `Layer` API. Use this
|
|
161
|
+
* reference directly only when you need low-level control (e.g. reading the
|
|
162
|
+
* current reporters or swapping them inside a `FiberRef`).
|
|
163
|
+
*
|
|
164
|
+
* @since 4.0.0
|
|
165
|
+
* @category References
|
|
166
|
+
*/
|
|
167
|
+
export const CurrentErrorReporters: ServiceMap.Reference<ReadonlySet<ErrorReporter>> = effect.CurrentErrorReporters
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Creates a `Layer` that registers one or more `ErrorReporter`s.
|
|
171
|
+
*
|
|
172
|
+
* Reporters can be plain `ErrorReporter` values or effectful
|
|
173
|
+
* `Effect<ErrorReporter>` values that are resolved when the layer is built.
|
|
174
|
+
*
|
|
175
|
+
* By default the provided reporters **replace** any previously registered
|
|
176
|
+
* reporters. Set `mergeWithExisting: true` to add them alongside existing
|
|
177
|
+
* ones.
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* ```ts
|
|
181
|
+
* import { Effect, ErrorReporter } from "effect"
|
|
182
|
+
*
|
|
183
|
+
* const consoleReporter = ErrorReporter.make(({ error, severity }) => {
|
|
184
|
+
* console.error(`[${severity}]`, error.message)
|
|
185
|
+
* })
|
|
186
|
+
*
|
|
187
|
+
* const metricsReporter = ErrorReporter.make(({ severity }) => {
|
|
188
|
+
* // increment an error counter by severity
|
|
189
|
+
* })
|
|
190
|
+
*
|
|
191
|
+
* // Replace all existing reporters
|
|
192
|
+
* const ReporterLive = ErrorReporter.layer([
|
|
193
|
+
* consoleReporter,
|
|
194
|
+
* metricsReporter
|
|
195
|
+
* ])
|
|
196
|
+
*
|
|
197
|
+
* // Add to existing reporters instead of replacing
|
|
198
|
+
* const ReporterMerged = ErrorReporter.layer(
|
|
199
|
+
* [metricsReporter],
|
|
200
|
+
* { mergeWithExisting: true }
|
|
201
|
+
* )
|
|
202
|
+
*
|
|
203
|
+
* const program = Effect.gen(function*() {
|
|
204
|
+
* yield* Effect.fail("boom")
|
|
205
|
+
* }).pipe(
|
|
206
|
+
* Effect.withErrorReporting,
|
|
207
|
+
* Effect.provide(ReporterLive)
|
|
208
|
+
* )
|
|
209
|
+
* ```
|
|
210
|
+
*
|
|
211
|
+
* @since 4.0.0
|
|
212
|
+
* @category Layers
|
|
213
|
+
*/
|
|
214
|
+
export const layer = <
|
|
215
|
+
const Reporters extends ReadonlyArray<ErrorReporter | Effect.Effect<ErrorReporter, any, any>>
|
|
216
|
+
>(
|
|
217
|
+
reporters: Reporters,
|
|
218
|
+
options?: { readonly mergeWithExisting?: boolean | undefined } | undefined
|
|
219
|
+
): Layer.Layer<
|
|
220
|
+
never,
|
|
221
|
+
Reporters extends readonly [] ? never : Effect.Error<Reporters[number]>,
|
|
222
|
+
Exclude<
|
|
223
|
+
Reporters extends readonly [] ? never : Effect.Services<Reporters[number]>,
|
|
224
|
+
Scope.Scope
|
|
225
|
+
>
|
|
226
|
+
> =>
|
|
227
|
+
Layer.effect(
|
|
228
|
+
CurrentErrorReporters,
|
|
229
|
+
Effect.withFiber(Effect.fnUntraced(function*(fiber) {
|
|
230
|
+
const currentReporters = new Set(
|
|
231
|
+
options?.mergeWithExisting === true ? fiber.getRef(effect.CurrentErrorReporters) : []
|
|
232
|
+
)
|
|
233
|
+
for (const reporter of reporters) {
|
|
234
|
+
currentReporters.add(Effect.isEffect(reporter) ? yield* reporter : reporter)
|
|
235
|
+
}
|
|
236
|
+
return currentReporters
|
|
237
|
+
}))
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Manually report a `Cause` to all registered `ErrorReporter`s on the
|
|
242
|
+
* current fiber.
|
|
243
|
+
*
|
|
244
|
+
* This is useful when you want to report an error for observability without
|
|
245
|
+
* actually failing the fiber.
|
|
246
|
+
*
|
|
247
|
+
* @example
|
|
248
|
+
* ```ts
|
|
249
|
+
* import { Cause, Effect, ErrorReporter } from "effect"
|
|
250
|
+
*
|
|
251
|
+
* // Log the cause for monitoring, then continue with a fallback
|
|
252
|
+
* const program = Effect.gen(function*() {
|
|
253
|
+
* const cause = Cause.fail("something went wrong")
|
|
254
|
+
* yield* ErrorReporter.report(cause)
|
|
255
|
+
* return "fallback value"
|
|
256
|
+
* })
|
|
257
|
+
* ```
|
|
258
|
+
*
|
|
259
|
+
* @since 4.0.0
|
|
260
|
+
* @category Reporting
|
|
261
|
+
*/
|
|
262
|
+
export const report = <E>(cause: Cause.Cause<E>): Effect.Effect<void> =>
|
|
263
|
+
Effect.withFiber((fiber) => {
|
|
264
|
+
effect.reportCauseUnsafe(fiber, cause)
|
|
265
|
+
return Effect.void
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Interface that errors can implement to control reporting behavior.
|
|
270
|
+
*
|
|
271
|
+
* All three annotation properties are optional:
|
|
272
|
+
* - `[ErrorReporter.ignore]` — when `true`, the error is never reported
|
|
273
|
+
* - `[ErrorReporter.severity]` — overrides the default `"Error"` severity
|
|
274
|
+
* - `[ErrorReporter.attributes]` — extra key/value pairs forwarded to reporters
|
|
275
|
+
*
|
|
276
|
+
* The global `Error` interface is augmented with `Reportable`, so these
|
|
277
|
+
* properties are available on all `Error` instances.
|
|
278
|
+
*
|
|
279
|
+
* @since 4.0.0
|
|
280
|
+
* @category Annotations
|
|
281
|
+
*/
|
|
282
|
+
export interface Reportable {
|
|
283
|
+
readonly [ignore]?: boolean
|
|
284
|
+
readonly [severity]?: Severity
|
|
285
|
+
readonly [attributes]?: ReadonlyRecord<string, unknown>
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
declare global {
|
|
289
|
+
interface Error extends Reportable {}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Symbol key used to mark an error as unreportable.
|
|
294
|
+
*
|
|
295
|
+
* Set this property to `true` on any error class to prevent it from being
|
|
296
|
+
* forwarded to reporters. Useful for expected errors such as HTTP 404s.
|
|
297
|
+
*
|
|
298
|
+
* @example
|
|
299
|
+
* ```ts
|
|
300
|
+
* import { Data, ErrorReporter } from "effect"
|
|
301
|
+
*
|
|
302
|
+
* class NotFoundError extends Data.TaggedError("NotFoundError")<{}> {
|
|
303
|
+
* readonly [ErrorReporter.ignore] = true
|
|
304
|
+
* }
|
|
305
|
+
* ```
|
|
306
|
+
*
|
|
307
|
+
* @since 4.0.0
|
|
308
|
+
* @category Annotations
|
|
309
|
+
*/
|
|
310
|
+
export type ignore = "~effect/ErrorReporter/ignore"
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Symbol key used to mark an error as unreportable.
|
|
314
|
+
*
|
|
315
|
+
* Set this property to `true` on any error class to prevent it from being
|
|
316
|
+
* forwarded to reporters. Useful for expected errors such as HTTP 404s.
|
|
317
|
+
*
|
|
318
|
+
* @example
|
|
319
|
+
* ```ts
|
|
320
|
+
* import { Data, ErrorReporter } from "effect"
|
|
321
|
+
*
|
|
322
|
+
* class NotFoundError extends Data.TaggedError("NotFoundError")<{}> {
|
|
323
|
+
* readonly [ErrorReporter.ignore] = true
|
|
324
|
+
* }
|
|
325
|
+
* ```
|
|
326
|
+
*
|
|
327
|
+
* @since 4.0.0
|
|
328
|
+
* @category Annotations
|
|
329
|
+
*/
|
|
330
|
+
export const ignore: ignore = "~effect/ErrorReporter/ignore"
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Returns `true` if the given value has the `ErrorReporter.ignore` annotation
|
|
334
|
+
* set to `true`.
|
|
335
|
+
*
|
|
336
|
+
* @since 4.0.0
|
|
337
|
+
* @category Annotations
|
|
338
|
+
*/
|
|
339
|
+
export const isIgnored = (u: unknown): boolean =>
|
|
340
|
+
typeof u === "object" && u !== null && ignore in u && u[ignore] === true
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Symbol key used to override the severity level of an error.
|
|
344
|
+
*
|
|
345
|
+
* When set, the reporter callback receives this value as `severity` instead
|
|
346
|
+
* of the default `"Error"`. Accepted values are the `LogLevel.Severity`
|
|
347
|
+
* literals: `"Trace"`, `"Debug"`, `"Info"`, `"Warn"`, `"Error"`, `"Fatal"`.
|
|
348
|
+
*
|
|
349
|
+
* @example
|
|
350
|
+
* ```ts
|
|
351
|
+
* import { Data, ErrorReporter } from "effect"
|
|
352
|
+
*
|
|
353
|
+
* class DeprecationWarning extends Data.TaggedError("DeprecationWarning")<{}> {
|
|
354
|
+
* readonly [ErrorReporter.severity] = "Warn" as const
|
|
355
|
+
* }
|
|
356
|
+
* ```
|
|
357
|
+
*
|
|
358
|
+
* @since 4.0.0
|
|
359
|
+
* @category Annotations
|
|
360
|
+
*/
|
|
361
|
+
export type severity = "~effect/ErrorReporter/severity"
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Symbol key used to override the severity level of an error.
|
|
365
|
+
*
|
|
366
|
+
* When set, the reporter callback receives this value as `severity` instead
|
|
367
|
+
* of the default `"Error"`. Accepted values are the `LogLevel.Severity`
|
|
368
|
+
* literals: `"Trace"`, `"Debug"`, `"Info"`, `"Warn"`, `"Error"`, `"Fatal"`.
|
|
369
|
+
*
|
|
370
|
+
* @example
|
|
371
|
+
* ```ts
|
|
372
|
+
* import { Data, ErrorReporter } from "effect"
|
|
373
|
+
*
|
|
374
|
+
* class DeprecationWarning extends Data.TaggedError("DeprecationWarning")<{}> {
|
|
375
|
+
* readonly [ErrorReporter.severity] = "Warn" as const
|
|
376
|
+
* }
|
|
377
|
+
* ```
|
|
378
|
+
*
|
|
379
|
+
* @since 4.0.0
|
|
380
|
+
* @category Annotations
|
|
381
|
+
*/
|
|
382
|
+
export const severity: severity = "~effect/ErrorReporter/severity"
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Reads the `ErrorReporter.severity` annotation from an error object,
|
|
386
|
+
* falling back to `"Error"` when unset or invalid.
|
|
387
|
+
*
|
|
388
|
+
* @since 4.0.0
|
|
389
|
+
* @category Annotations
|
|
390
|
+
*/
|
|
391
|
+
export const getSeverity = (error: object): Severity => {
|
|
392
|
+
if (severity in error && LogLevel.values.includes(error[severity] as Severity)) {
|
|
393
|
+
return error[severity] as Severity
|
|
394
|
+
}
|
|
395
|
+
return "Error"
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Symbol key used to attach extra key/value metadata to an error report.
|
|
400
|
+
*
|
|
401
|
+
* Reporters receive these attributes alongside the error, making it easy to
|
|
402
|
+
* include contextual information such as user IDs, request IDs, or any
|
|
403
|
+
* domain-specific data useful for debugging.
|
|
404
|
+
*
|
|
405
|
+
* @example
|
|
406
|
+
* ```ts
|
|
407
|
+
* import { Data, ErrorReporter } from "effect"
|
|
408
|
+
*
|
|
409
|
+
* class PaymentError extends Data.TaggedError("PaymentError")<{
|
|
410
|
+
* readonly orderId: string
|
|
411
|
+
* }> {
|
|
412
|
+
* readonly [ErrorReporter.attributes] = {
|
|
413
|
+
* orderId: this.orderId
|
|
414
|
+
* }
|
|
415
|
+
* }
|
|
416
|
+
* ```
|
|
417
|
+
*
|
|
418
|
+
* @since 4.0.0
|
|
419
|
+
* @category Annotations
|
|
420
|
+
*/
|
|
421
|
+
export type attributes = "~effect/ErrorReporter/attributes"
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Symbol key used to attach extra key/value metadata to an error report.
|
|
425
|
+
*
|
|
426
|
+
* Reporters receive these attributes alongside the error, making it easy to
|
|
427
|
+
* include contextual information such as user IDs, request IDs, or any
|
|
428
|
+
* domain-specific data useful for debugging.
|
|
429
|
+
*
|
|
430
|
+
* @example
|
|
431
|
+
* ```ts
|
|
432
|
+
* import { Data, ErrorReporter } from "effect"
|
|
433
|
+
*
|
|
434
|
+
* class PaymentError extends Data.TaggedError("PaymentError")<{
|
|
435
|
+
* readonly orderId: string
|
|
436
|
+
* }> {
|
|
437
|
+
* readonly [ErrorReporter.attributes] = {
|
|
438
|
+
* orderId: this.orderId
|
|
439
|
+
* }
|
|
440
|
+
* }
|
|
441
|
+
* ```
|
|
442
|
+
*
|
|
443
|
+
* @since 4.0.0
|
|
444
|
+
* @category Annotations
|
|
445
|
+
*/
|
|
446
|
+
export const attributes: attributes = "~effect/ErrorReporter/attributes"
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Reads the `ErrorReporter.attributes` annotation from an error object,
|
|
450
|
+
* returning an empty record when unset.
|
|
451
|
+
*
|
|
452
|
+
* @since 4.0.0
|
|
453
|
+
* @category Annotations
|
|
454
|
+
*/
|
|
455
|
+
export const getAttributes = (error: object): ReadonlyRecord<string, unknown> => {
|
|
456
|
+
return attributes in error ? error[attributes] as any : emptyAttributes
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
const emptyAttributes: ReadonlyRecord<string, unknown> = {}
|
package/src/LogLevel.ts
CHANGED
|
@@ -142,6 +142,12 @@ import * as References from "./References.ts"
|
|
|
142
142
|
*/
|
|
143
143
|
export type LogLevel = "All" | "Fatal" | "Error" | "Warn" | "Info" | "Debug" | "Trace" | "None"
|
|
144
144
|
|
|
145
|
+
/**
|
|
146
|
+
* @since 4.0.0
|
|
147
|
+
* @category models
|
|
148
|
+
*/
|
|
149
|
+
export type Severity = "Fatal" | "Error" | "Warn" | "Info" | "Debug" | "Trace"
|
|
150
|
+
|
|
145
151
|
/**
|
|
146
152
|
* @since 4.0.0
|
|
147
153
|
* @category models
|
package/src/Logger.ts
CHANGED
|
@@ -115,8 +115,7 @@ import type { PlatformError } from "./PlatformError.ts"
|
|
|
115
115
|
import * as Predicate from "./Predicate.ts"
|
|
116
116
|
import { CurrentLogAnnotations, CurrentLogSpans } from "./References.ts"
|
|
117
117
|
import type * as Scope from "./Scope.ts"
|
|
118
|
-
import * as ServiceMap from "./ServiceMap.ts"
|
|
119
|
-
import type * as Types from "./Types.ts"
|
|
118
|
+
import type * as ServiceMap from "./ServiceMap.ts"
|
|
120
119
|
|
|
121
120
|
const TypeId = "~effect/Logger"
|
|
122
121
|
|
|
@@ -144,8 +143,9 @@ const TypeId = "~effect/Logger"
|
|
|
144
143
|
* @since 2.0.0
|
|
145
144
|
* @category models
|
|
146
145
|
*/
|
|
147
|
-
export interface Logger<in Message, out Output> extends
|
|
148
|
-
|
|
146
|
+
export interface Logger<in Message, out Output> extends Pipeable {
|
|
147
|
+
readonly [TypeId]: typeof TypeId
|
|
148
|
+
log(options: Options<Message>): Output
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
/**
|
|
@@ -153,100 +153,32 @@ export interface Logger<in Message, out Output> extends Logger.Variance<Message,
|
|
|
153
153
|
* ```ts
|
|
154
154
|
* import { Effect, Logger } from "effect"
|
|
155
155
|
*
|
|
156
|
-
* //
|
|
157
|
-
* const
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
156
|
+
* // Options interface provides all logging context
|
|
157
|
+
* const detailedLogger = Logger.make((options) => {
|
|
158
|
+
* const output = {
|
|
159
|
+
* message: options.message,
|
|
160
|
+
* level: options.logLevel,
|
|
161
|
+
* timestamp: options.date.toISOString(),
|
|
162
|
+
* fiberId: options.fiber.id,
|
|
163
|
+
* hasCause: options.cause !== undefined
|
|
164
|
+
* }
|
|
165
|
+
* console.log(JSON.stringify(output))
|
|
162
166
|
* })
|
|
163
167
|
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
* Effect.provide(Logger.layer([customLogger]))
|
|
168
|
+
* const program = Effect.log("Processing request").pipe(
|
|
169
|
+
* Effect.provide(Logger.layer([detailedLogger]))
|
|
167
170
|
* )
|
|
168
171
|
* ```
|
|
169
172
|
*
|
|
170
173
|
* @since 2.0.0
|
|
171
174
|
* @category models
|
|
172
175
|
*/
|
|
173
|
-
export
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
* // Variance interface defines contravariance for Message and covariance for Output
|
|
180
|
-
* const customLogger = Logger.make<unknown, void>((options) => {
|
|
181
|
-
* console.log(options.message)
|
|
182
|
-
* })
|
|
183
|
-
*
|
|
184
|
-
* // The logger can accept more specific message types (contravariance)
|
|
185
|
-
* // and can be used where less specific output types are expected (covariance)
|
|
186
|
-
* ```
|
|
187
|
-
*
|
|
188
|
-
* @since 2.0.0
|
|
189
|
-
* @category models
|
|
190
|
-
*/
|
|
191
|
-
export interface Variance<in Message, out Output> {
|
|
192
|
-
readonly [TypeId]: VarianceStruct<Message, Output>
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* @example
|
|
197
|
-
* ```ts
|
|
198
|
-
* import { Logger } from "effect"
|
|
199
|
-
*
|
|
200
|
-
* // VarianceStruct defines the actual variance structure used internally
|
|
201
|
-
* // This structure ensures proper typing and variance behavior
|
|
202
|
-
* const logger = Logger.make<unknown, void>((options) => {
|
|
203
|
-
* console.log(options.message)
|
|
204
|
-
* })
|
|
205
|
-
*
|
|
206
|
-
* // The variance structure handles contravariance for input Message type
|
|
207
|
-
* // and covariance for output Output type
|
|
208
|
-
* ```
|
|
209
|
-
*
|
|
210
|
-
* @since 4.0.0
|
|
211
|
-
* @category models
|
|
212
|
-
*/
|
|
213
|
-
export interface VarianceStruct<in Message, out Output> {
|
|
214
|
-
_Message: Types.Contravariant<Message>
|
|
215
|
-
_Output: Types.Covariant<Output>
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* @example
|
|
220
|
-
* ```ts
|
|
221
|
-
* import { Effect, Logger } from "effect"
|
|
222
|
-
*
|
|
223
|
-
* // Options interface provides all logging context
|
|
224
|
-
* const detailedLogger = Logger.make((options) => {
|
|
225
|
-
* const output = {
|
|
226
|
-
* message: options.message,
|
|
227
|
-
* level: options.logLevel,
|
|
228
|
-
* timestamp: options.date.toISOString(),
|
|
229
|
-
* fiberId: options.fiber.id,
|
|
230
|
-
* hasCause: options.cause !== undefined
|
|
231
|
-
* }
|
|
232
|
-
* console.log(JSON.stringify(output))
|
|
233
|
-
* })
|
|
234
|
-
*
|
|
235
|
-
* const program = Effect.log("Processing request").pipe(
|
|
236
|
-
* Effect.provide(Logger.layer([detailedLogger]))
|
|
237
|
-
* )
|
|
238
|
-
* ```
|
|
239
|
-
*
|
|
240
|
-
* @since 2.0.0
|
|
241
|
-
* @category models
|
|
242
|
-
*/
|
|
243
|
-
export interface Options<out Message> {
|
|
244
|
-
readonly message: Message
|
|
245
|
-
readonly logLevel: LogLevel.LogLevel
|
|
246
|
-
readonly cause: Cause.Cause<unknown>
|
|
247
|
-
readonly fiber: Fiber.Fiber<unknown, unknown>
|
|
248
|
-
readonly date: Date
|
|
249
|
-
}
|
|
176
|
+
export interface Options<out Message> {
|
|
177
|
+
readonly message: Message
|
|
178
|
+
readonly logLevel: LogLevel.LogLevel
|
|
179
|
+
readonly cause: Cause.Cause<unknown>
|
|
180
|
+
readonly fiber: Fiber.Fiber<unknown, unknown>
|
|
181
|
+
readonly date: Date
|
|
250
182
|
}
|
|
251
183
|
|
|
252
184
|
/**
|
|
@@ -562,7 +494,7 @@ const format = (
|
|
|
562
494
|
quoteValue: (s: string) => string,
|
|
563
495
|
space?: number | string | undefined
|
|
564
496
|
) =>
|
|
565
|
-
({ cause, date, fiber, logLevel, message }:
|
|
497
|
+
({ cause, date, fiber, logLevel, message }: Options<unknown>): string => {
|
|
566
498
|
const formatValue = (value: string): string => value.match(textOnly) ? value : quoteValue(value)
|
|
567
499
|
const format = (label: string, value: string): string => `${effect.formatLabel(label)}=${formatValue(value)}`
|
|
568
500
|
const append = (label: string, value: string): string => " " + format(label, value)
|
|
@@ -636,7 +568,7 @@ const format = (
|
|
|
636
568
|
* @category constructors
|
|
637
569
|
*/
|
|
638
570
|
export const make: <Message, Output>(
|
|
639
|
-
log: (options:
|
|
571
|
+
log: (options: Options<Message>) => Output
|
|
640
572
|
) => Logger<Message, Output> = effect.loggerMake
|
|
641
573
|
|
|
642
574
|
/**
|
|
@@ -1389,7 +1321,7 @@ export const layer = <
|
|
|
1389
1321
|
const Loggers extends ReadonlyArray<Logger<unknown, unknown> | Effect.Effect<Logger<unknown, unknown>, any, any>>
|
|
1390
1322
|
>(
|
|
1391
1323
|
loggers: Loggers,
|
|
1392
|
-
options?: { mergeWithExisting
|
|
1324
|
+
options?: { readonly mergeWithExisting?: boolean | undefined } | undefined
|
|
1393
1325
|
): Layer.Layer<
|
|
1394
1326
|
never,
|
|
1395
1327
|
Loggers extends readonly [] ? never : Effect.Error<Loggers[number]>,
|
|
@@ -1398,13 +1330,14 @@ export const layer = <
|
|
|
1398
1330
|
Scope.Scope
|
|
1399
1331
|
>
|
|
1400
1332
|
> =>
|
|
1401
|
-
Layer.
|
|
1333
|
+
Layer.effect(
|
|
1334
|
+
CurrentLoggers,
|
|
1402
1335
|
withFiber(effect.fnUntraced(function*(fiber) {
|
|
1403
1336
|
const currentLoggers = new Set(options?.mergeWithExisting === true ? fiber.getRef(effect.CurrentLoggers) : [])
|
|
1404
1337
|
for (const logger of loggers) {
|
|
1405
1338
|
currentLoggers.add(isEffect(logger) ? yield* logger : logger)
|
|
1406
1339
|
}
|
|
1407
|
-
return
|
|
1340
|
+
return currentLoggers
|
|
1408
1341
|
}))
|
|
1409
1342
|
)
|
|
1410
1343
|
|
package/src/Queue.ts
CHANGED
|
@@ -1113,7 +1113,6 @@ export const collect = <A, E>(self: Dequeue<A, E | Done>): Effect<Array<A>, Pull
|
|
|
1113
1113
|
while: constTrue,
|
|
1114
1114
|
body: constant(takeAll(self)),
|
|
1115
1115
|
step(items: Arr.NonEmptyArray<A>) {
|
|
1116
|
-
out.push(...items)
|
|
1117
1116
|
for (let i = 0; i < items.length; i++) {
|
|
1118
1117
|
out.push(items[i])
|
|
1119
1118
|
}
|
package/src/References.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* @since 4.0.0
|
|
12
12
|
*/
|
|
13
13
|
import { constTrue, constUndefined } from "./Function.ts"
|
|
14
|
-
import type { LogLevel } from "./LogLevel.ts"
|
|
14
|
+
import type { LogLevel, Severity } from "./LogLevel.ts"
|
|
15
15
|
import type { ReadonlyRecord } from "./Record.ts"
|
|
16
16
|
import { MaxOpsBeforeYield } from "./Scheduler.ts"
|
|
17
17
|
import * as ServiceMap from "./ServiceMap.ts"
|
|
@@ -451,7 +451,7 @@ export const CurrentLogAnnotations = ServiceMap.Reference<ReadonlyRecord<string,
|
|
|
451
451
|
* @category references
|
|
452
452
|
* @since 4.0.0
|
|
453
453
|
*/
|
|
454
|
-
export const CurrentLogLevel: ServiceMap.Reference<
|
|
454
|
+
export const CurrentLogLevel: ServiceMap.Reference<Severity> = ServiceMap.Reference<Severity>(
|
|
455
455
|
"effect/References/CurrentLogLevel",
|
|
456
456
|
{ defaultValue: () => "Info" }
|
|
457
457
|
)
|
|
@@ -516,9 +516,9 @@ export const MinimumLogLevel = ServiceMap.Reference<
|
|
|
516
516
|
* @category references
|
|
517
517
|
* @since 4.0.0
|
|
518
518
|
*/
|
|
519
|
-
export const UnhandledLogLevel: ServiceMap.Reference<
|
|
519
|
+
export const UnhandledLogLevel: ServiceMap.Reference<Severity | undefined> = ServiceMap.Reference(
|
|
520
520
|
"effect/References/UnhandledLogLevel",
|
|
521
|
-
{ defaultValue: ():
|
|
521
|
+
{ defaultValue: (): Severity | undefined => "Error" }
|
|
522
522
|
)
|
|
523
523
|
|
|
524
524
|
/**
|