Hyperlinkv0.8.0-beta.28

Logger

Logger.formatStructuredconsteffect/Logger.ts:626
Logger<
  unknown,
  {
    readonly level: string
    readonly fiberId: string
    readonly timestamp: string
    readonly message: unknown
    readonly cause: string | undefined
    readonly annotations: Record<string, unknown>
    readonly spans: Record<string, number>
  }
>

A Logger which outputs logs using a structured format.

Details

For example, a structured entry can contain message: [ "hello" ], level: "INFO", timestamp: "2025-01-03T14:25:39.666Z", annotations: { key: "value" }, spans: { label: 0 }, and fiberId: "#1".

Example (Formatting logs as structured objects)

import { Effect, Logger } from "effect"

// Use the structured format logger
const structuredLoggerProgram = Effect.log("Hello Structured Format").pipe(
  Effect.provide(Logger.layer([Logger.formatStructured]))
)

// Perfect for JSON processing and analytics
const analyticsProgram = Effect.gen(function*() {
  yield* Effect.log("User action", { action: "click", element: "button" })
  yield* Effect.logInfo("API call", { endpoint: "/users", duration: 150 })
}).pipe(
  Effect.annotateLogs("sessionId", "abc123"),
  Effect.withLogSpan("request"),
  Effect.provide(Logger.layer([Logger.formatStructured]))
)

// Process structured output
const processingLogger = Logger.map(Logger.formatStructured, (output) => {
  // Process the structured object
  const enhanced = { ...output, processed: true }
  return enhanced
})
constructors
Source effect/Logger.ts:62636 lines
export const formatStructured: Logger<unknown, {
  readonly level: string
  readonly fiberId: string
  readonly timestamp: string
  readonly message: unknown
  readonly cause: string | undefined
  readonly annotations: Record<string, unknown>
  readonly spans: Record<string, number>
}> = effect.loggerMake(({ cause, date, fiber, logLevel, message }) => {
  const annotationsObj: Record<string, unknown> = {}
  const spansObj: Record<string, number> = {}

  const annotations = fiber.getRef(CurrentLogAnnotations)
  for (const [key, value] of Object.entries(annotations)) {
    annotationsObj[key] = effect.structuredMessage(value)
  }

  const now = date.getTime()
  const spans = fiber.getRef(CurrentLogSpans)
  for (const [label, timestamp] of spans) {
    spansObj[label] = now - timestamp
  }

  const messageArr = Array.ensure(message)
  return {
    message: messageArr.length === 1
      ? effect.structuredMessage(messageArr[0])
      : messageArr.map(effect.structuredMessage),
    level: logLevel.toUpperCase(),
    timestamp: date.toISOString(),
    cause: cause.reasons.length > 0 ? effect.causePretty(cause) : undefined,
    annotations: annotationsObj,
    spans: spansObj,
    fiberId: formatFiberId(fiber.id)
  }
})
Referenced by 2 symbols