Skip to content

Commit

Permalink
output log groups from Logger.prettyLogger
Browse files Browse the repository at this point in the history
  • Loading branch information
tim-smart committed Jul 3, 2024
1 parent 3be50fe commit d32caa8
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 31 deletions.
12 changes: 11 additions & 1 deletion .changeset/nervous-cougars-taste.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,14 @@
"effect": minor
---

add Logger.prettyLogger, and make it the default
add Logger.prettyLogger and Logger.pretty

`Logger.pretty` is a new logger that leverages the features of the `console` APIs to provide a more visually appealing output.

To try it out, provide it to your program:

```ts
import { Effect, Logger } from "effect"

Effect.log("Hello, World!").pipe(Effect.provide(Logger.pretty))
```
8 changes: 4 additions & 4 deletions packages/effect/src/Logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,9 +366,9 @@ export const stringLogger: Logger<unknown, string> = internal.stringLogger
* @since 3.5.0
* @category constructors
*/
export const prettyLogger: (options?: {
readonly colors?: "auto" | boolean
}) => Logger<unknown, string> = internal.prettyLogger
export const prettyLogger: (
options?: { readonly colors?: "auto" | boolean }
) => Logger<unknown, Array<Array<unknown>>> = internal.prettyLogger

/**
* @since 2.0.0
Expand Down Expand Up @@ -409,7 +409,7 @@ export const logFmt: Layer.Layer<never> = replace(fiberRuntime.defaultLogger, fi
* @since 3.5.0
* @category constructors
*/
export const string: Layer.Layer<never> = replace(fiberRuntime.defaultLogger, fiberRuntime.stringLogger)
export const pretty: Layer.Layer<never> = replace(fiberRuntime.defaultLogger, fiberRuntime.prettyLogger)

/**
* @since 2.0.0
Expand Down
22 changes: 18 additions & 4 deletions packages/effect/src/internal/fiberRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1406,7 +1406,7 @@ export const loggerWithConsoleError = <M, O>(self: Logger<M, O>): Logger<M, void
/** @internal */
export const defaultLogger: Logger<unknown, void> = globalValue(
Symbol.for("effect/Logger/defaultLogger"),
() => loggerWithConsoleLog(internalLogger.prettyLogger())
() => loggerWithConsoleLog(internalLogger.stringLogger)
)

/** @internal */
Expand All @@ -1422,9 +1422,23 @@ export const logFmtLogger: Logger<unknown, void> = globalValue(
)

/** @internal */
export const stringLogger: Logger<unknown, void> = globalValue(
Symbol.for("effect/Logger/stringLogger"),
() => loggerWithConsoleLog(internalLogger.stringLogger)
export const prettyLogger: Logger<unknown, void> = globalValue(
Symbol.for("effect/Logger/prettyLogger"),
() => {
const logger = internalLogger.prettyLogger()
return internalLogger.makeLogger((opts) => {
const services = FiberRefs.getOrDefault(opts.context, defaultServices.currentServices)
const console = Context.get(services, consoleTag).unsafe
const groups = logger.log(opts)
console.log(...groups[0])
if (groups.length <= 1) return
for (let i = 1; i < groups.length; i++) {
console.group()
console.log(...groups[i])
console.groupEnd()
}
})
}
)

/** @internal */
Expand Down
45 changes: 23 additions & 22 deletions packages/effect/src/internal/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ export const isLogger = (u: unknown): u is Logger.Logger<unknown, unknown> => {
}

const processStdoutIsTTY = typeof process === "object" && "stdout" in process && process.stdout.isTTY === true
const hasWindow = typeof window === "object"

const withColor = (text: string, ...colors: ReadonlyArray<string>) => {
let out = ""
Expand All @@ -382,10 +383,14 @@ const colors = {
green: "32",
yellow: "33",
blue: "34",
magenta: "35",
magenta: "95",
cyan: "36",
white: "37",
gray: "90"
gray: "90",
black: "30",

bgRed: "41",
bgBrightRed: "101"
} as const

const logLevelColors: Record<LogLevel.LogLevel["_tag"], ReadonlyArray<string>> = {
Expand All @@ -396,21 +401,23 @@ const logLevelColors: Record<LogLevel.LogLevel["_tag"], ReadonlyArray<string>> =
Info: [colors.green],
Warning: [colors.yellow],
Error: [colors.red],
Fatal: [colors.bright, colors.red]
Fatal: [colors.bgBrightRed, colors.black]
}

/** @internal */
export const prettyLogger = (options?: {
readonly colors?: "auto" | boolean
}) =>
makeLogger<unknown, string>(
makeLogger<unknown, Array<Array<unknown>>>(
({ annotations, cause, date, fiberId, logLevel, message: message_, spans }) => {
const showColors = typeof options?.colors === "boolean" ? options.colors : processStdoutIsTTY
const showColors = typeof options?.colors === "boolean" ? options.colors : processStdoutIsTTY || hasWindow
const color = showColors ? withColor : withColorNoop

const message = Arr.ensure(message_)
const groups: Array<Array<unknown>> = []
const firstParams: Array<unknown> = []

let logMessage = color(
let firstLine = color(
`[${date.getHours().toString().padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}:${
date.getSeconds().toString().padStart(2, "0")
}.${date.getMilliseconds().toString().padStart(3, "0")}]`,
Expand All @@ -422,46 +429,40 @@ export const prettyLogger = (options?: {
const now = date.getTime()
const render = renderLogSpanLogfmt(now)
for (const span of spans) {
logMessage += " " + render(span)
firstLine += " " + render(span)
}
}

logMessage += ":"
firstLine += ":"
let messageIndex = 0
if (message.length > 0) {
const firstMaybeString = structuredMessage(message[0])
if (typeof firstMaybeString === "string") {
logMessage += " " + color(firstMaybeString, colors.bright, colors.cyan)
firstLine += " " + color(firstMaybeString, colors.bright, colors.cyan)
messageIndex++
}
}
groups.push([firstLine, ...firstParams])

if (!Cause.isEmpty(cause)) {
const lines = Cause.pretty(cause).split("\n")
for (let i = 0; i < lines.length; i++) {
logMessage += "\n " + lines[i]
const errors = Cause.prettyErrors(cause)
for (let i = 0; i < errors.length; i++) {
groups.push(hasWindow ? [errors[i]] : [errors[i].stack])
}
}

if (messageIndex < message.length) {
for (; messageIndex < message.length; messageIndex++) {
const lines = Inspectable.stringifyCircular(message[messageIndex], 2).split("\n")
for (let i = 0; i < lines.length; i++) {
logMessage += "\n " + lines[i]
}
groups.push([message[messageIndex]])
}
}

if (HashMap.size(annotations) > 0) {
for (const [key, value] of annotations) {
logMessage += "\n " + color(`${key}:`, colors.bright, colors.white) + " "
const lines = Inspectable.stringifyCircular(value, 2).split("\n")
for (let i = 0; i < lines.length; i++) {
logMessage += (i > 0 ? "\n " : "") + lines[i]
}
groups.push([color(`${key}:`, colors.bright, colors.white) + " %O", value])
}
}

return logMessage
return groups
}
)

0 comments on commit d32caa8

Please sign in to comment.