Skip to content

Commit

Permalink
support variadic arguments in Effect.log (#2452)
Browse files Browse the repository at this point in the history
  • Loading branch information
tim-smart committed Apr 16, 2024
1 parent 42a986d commit a16cebb
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 76 deletions.
11 changes: 11 additions & 0 deletions .changeset/selfish-bottles-yell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"effect": minor
---

support variadic arguments in Effect.log

This makes Effect.log more similar to console.log:

```ts
Effect.log("hello", { foo: "bar" }, Cause.fail("error"));
```
46 changes: 18 additions & 28 deletions packages/effect/src/Effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4336,76 +4336,66 @@ export const matchEffect: {
* @since 2.0.0
* @category logging
*/
export const log: <A>(
messageOrCause: A,
supplementary?: A extends Cause.Cause<any> ? unknown : Cause.Cause<unknown>
) => Effect<void> = effect.log
export const log: (...message: ReadonlyArray<any>) => Effect<void, never, never> = effect.log

/**
* Logs the specified message or cause at the specified log level.
*
* @since 2.0.0
* @category logging
*/
export const logWithLevel = (
level: LogLevel,
...message: ReadonlyArray<any>
): Effect<void> => effect.logWithLevel(level)(...message)

/**
* Logs the specified message or cause at the Trace log level.
*
* @since 2.0.0
* @category logging
*/
export const logTrace: <A>(
messageOrCause: A,
supplementary?: A extends Cause.Cause<any> ? unknown : Cause.Cause<unknown>
) => Effect<void> = effect.logTrace
export const logTrace: (...message: ReadonlyArray<any>) => Effect<void, never, never> = effect.logTrace

/**
* Logs the specified message or cause at the Debug log level.
*
* @since 2.0.0
* @category logging
*/
export const logDebug: <A>(
messageOrCause: A,
supplementary?: A extends Cause.Cause<any> ? unknown : Cause.Cause<unknown>
) => Effect<void> = effect.logDebug
export const logDebug: (...message: ReadonlyArray<any>) => Effect<void, never, never> = effect.logDebug

/**
* Logs the specified message or cause at the Info log level.
*
* @since 2.0.0
* @category logging
*/
export const logInfo: <A>(
messageOrCause: A,
supplementary?: A extends Cause.Cause<any> ? unknown : Cause.Cause<unknown>
) => Effect<void> = effect.logInfo
export const logInfo: (...message: ReadonlyArray<any>) => Effect<void, never, never> = effect.logInfo

/**
* Logs the specified message or cause at the Warning log level.
*
* @since 2.0.0
* @category logging
*/
export const logWarning: <A>(
messageOrCause: A,
supplementary?: A extends Cause.Cause<any> ? unknown : Cause.Cause<unknown>
) => Effect<void> = effect.logWarning
export const logWarning: (...message: ReadonlyArray<any>) => Effect<void, never, never> = effect.logWarning

/**
* Logs the specified message or cause at the Error log level.
*
* @since 2.0.0
* @category logging
*/
export const logError: <A>(
messageOrCause: A,
supplementary?: A extends Cause.Cause<any> ? unknown : Cause.Cause<unknown>
) => Effect<void> = effect.logError
export const logError: (...message: ReadonlyArray<any>) => Effect<void, never, never> = effect.logError

/**
* Logs the specified message or cause at the Fatal log level.
*
* @since 2.0.0
* @category logging
*/
export const logFatal: <A>(
messageOrCause: A,
supplementary?: A extends Cause.Cause<any> ? unknown : Cause.Cause<unknown>
) => Effect<void> = effect.logFatal
export const logFatal: (...message: ReadonlyArray<any>) => Effect<void, never, never> = effect.logFatal

/**
* Adjusts the label for the current logging span.
Expand Down
83 changes: 43 additions & 40 deletions packages/effect/src/internal/core-effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -887,20 +887,32 @@ export const iterate: {
return core.succeed(initial)
})

const logWithLevel = (level?: LogLevel.LogLevel) =>
<A>(
messageOrCause: A,
supplementary?: A extends Cause.Cause<any> ? unknown : Cause.Cause<unknown>
/** @internal */
export const logWithLevel = (level?: LogLevel.LogLevel) =>
(
...message: ReadonlyArray<any>
): Effect.Effect<void> => {
const levelOption = Option.fromNullable(level)
let message: unknown
let cause: Cause.Cause<unknown>
if (internalCause.isCause(messageOrCause)) {
cause = messageOrCause
message = (supplementary as unknown) ?? ""
} else {
message = messageOrCause
cause = (supplementary as Cause.Cause<unknown>) ?? internalCause.empty
let cause: Cause.Cause<unknown> | undefined = undefined
for (let i = 0, len = message.length; i < len; i++) {
const msg = message[i]
if (internalCause.isCause(msg)) {
if (cause !== undefined) {
cause = internalCause.sequential(cause, msg)
} else {
cause = msg
}
message = [...message.slice(0, i), ...message.slice(i + 1)]
i--
}
}
if (message.length === 0) {
message = "" as any
} else if (message.length === 1) {
message = message[0]
}
if (cause === undefined) {
cause = internalCause.empty
}
return core.withFiberRuntime((fiberState) => {
fiberState.log(message, cause, levelOption)
Expand All @@ -909,46 +921,37 @@ const logWithLevel = (level?: LogLevel.LogLevel) =>
}

/** @internal */
export const log: <A>(
messageOrCause: A,
supplementary?: A extends Cause.Cause<any> ? unknown : Cause.Cause<unknown>
) => Effect.Effect<void> = logWithLevel()
export const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never> = logWithLevel()

/** @internal */
export const logTrace: <A>(
messageOrCause: A,
supplementary?: A extends Cause.Cause<any> ? unknown : Cause.Cause<unknown>
) => Effect.Effect<void> = logWithLevel(LogLevel.Trace)
export const logTrace: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never> = logWithLevel(
LogLevel.Trace
)

/** @internal */
export const logDebug: <A>(
messageOrCause: A,
supplementary?: A extends Cause.Cause<any> ? unknown : Cause.Cause<unknown>
) => Effect.Effect<void> = logWithLevel(LogLevel.Debug)
export const logDebug: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never> = logWithLevel(
LogLevel.Debug
)

/** @internal */
export const logInfo: <A>(
messageOrCause: A,
supplementary?: A extends Cause.Cause<any> ? unknown : Cause.Cause<unknown>
) => Effect.Effect<void> = logWithLevel(LogLevel.Info)
export const logInfo: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never> = logWithLevel(
LogLevel.Info
)

/** @internal */
export const logWarning: <A>(
messageOrCause: A,
supplementary?: A extends Cause.Cause<any> ? unknown : Cause.Cause<unknown>
) => Effect.Effect<void> = logWithLevel(LogLevel.Warning)
export const logWarning: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never> = logWithLevel(
LogLevel.Warning
)

/** @internal */
export const logError: <A>(
messageOrCause: A,
supplementary?: A extends Cause.Cause<any> ? unknown : Cause.Cause<unknown>
) => Effect.Effect<void> = logWithLevel(LogLevel.Error)
export const logError: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never> = logWithLevel(
LogLevel.Error
)

/** @internal */
export const logFatal: <A>(
messageOrCause: A,
supplementary?: A extends Cause.Cause<any> ? unknown : Cause.Cause<unknown>
) => Effect.Effect<void> = logWithLevel(LogLevel.Fatal)
export const logFatal: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never> = logWithLevel(
LogLevel.Fatal
)

/* @internal */
export const withLogSpan = dual<
Expand Down
36 changes: 28 additions & 8 deletions packages/effect/src/internal/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,21 @@ export const stringLogger: Logger.Logger<unknown, string> = makeLogger<unknown,
]

let output = outputArray.join(" ")
const stringMessage = Inspectable.toStringUnknown(message)

if (stringMessage.length > 0) {
output = output + " message="
output = appendQuoted(stringMessage, output)
if (Array.isArray(message)) {
for (let i = 0; i < message.length; i++) {
const stringMessage = Inspectable.toStringUnknown(message[i])
if (stringMessage.length > 0) {
output = output + " message="
output = appendQuoted(stringMessage, output)
}
}
} else {
const stringMessage = Inspectable.toStringUnknown(message)
if (stringMessage.length > 0) {
output = output + " message="
output = appendQuoted(stringMessage, output)
}
}

if (cause != null && cause._tag !== "Empty") {
Expand Down Expand Up @@ -235,11 +245,21 @@ export const logfmtLogger = makeLogger<unknown, string>(
]

let output = outputArray.join(" ")
const stringMessage = Inspectable.toStringUnknown(message, 0)

if (stringMessage.length > 0) {
output = output + " message="
output = appendQuotedLogfmt(stringMessage, output)
if (Array.isArray(message)) {
for (let i = 0; i < message.length; i++) {
const stringMessage = Inspectable.toStringUnknown(message[i], 0)
if (stringMessage.length > 0) {
output = output + " message="
output = appendQuotedLogfmt(stringMessage, output)
}
}
} else {
const stringMessage = Inspectable.toStringUnknown(message, 0)
if (stringMessage.length > 0) {
output = output + " message="
output = appendQuotedLogfmt(stringMessage, output)
}
}

if (cause != null && cause._tag !== "Empty") {
Expand Down
40 changes: 40 additions & 0 deletions packages/effect/test/Logger.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,26 @@ message" imma_span__=7ms I_am_also_a_bad_key_name="{
with line breaks" good_key3="I_have=a"`
)
})

it("multiple messages", () => {
const date = new Date()
vi.setSystemTime(date)

const result = Logger.stringLogger.log({
fiberId: FiberId.none,
logLevel: logLevelInfo,
message: ["a", "b", "c"],
cause: Cause.empty,
context: FiberRefs.unsafeMake(new Map()),
spans: List.empty(),
annotations: HashMap.empty(),
date
})

expect(result).toEqual(
`timestamp=${date.toJSON()} level=INFO fiber= message=a message=b message=c`
)
})
})

describe("logfmtLogger", () => {
Expand Down Expand Up @@ -310,6 +330,26 @@ describe("logfmtLogger", () => {
]
])
}).pipe(Effect.scoped, Effect.runPromise))

it("multiple messages", () => {
const date = new Date()
vi.setSystemTime(date)

const result = Logger.logfmtLogger.log({
fiberId: FiberId.none,
logLevel: logLevelInfo,
message: ["a", "b", "c"],
cause: Cause.empty,
context: FiberRefs.unsafeMake(new Map()),
spans: List.empty(),
annotations: HashMap.empty(),
date
})

expect(result).toEqual(
`timestamp=${date.toJSON()} level=INFO fiber= message=a message=b message=c`
)
})
})

describe("jsonLogger", () => {
Expand Down

0 comments on commit a16cebb

Please sign in to comment.