Skip to content

Commit

Permalink
feat: control log levels
Browse files Browse the repository at this point in the history
  • Loading branch information
patroza committed Oct 4, 2024
1 parent 6ec5687 commit 550ba43
Show file tree
Hide file tree
Showing 29 changed files with 144 additions and 46 deletions.
8 changes: 8 additions & 0 deletions .changeset/rich-yaks-hide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@effect-app/infra-adapters": patch
"effect-app": patch
"@effect-app/infra": patch
"@effect-app/core": patch
---

control log levels
10 changes: 10 additions & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,16 @@
"default": "./_cjs/utils/extend.cjs"
}
},
"./utils/logger": {
"import": {
"types": "./dist/utils/logger.d.ts",
"default": "./dist/utils/logger.js"
},
"require": {
"types": "./dist/utils/logger.d.ts",
"default": "./_cjs/utils/logger.cjs"
}
},
"./validation": {
"import": {
"types": "./dist/validation.d.ts",
Expand Down
23 changes: 23 additions & 0 deletions packages/core/src/utils/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Effect, FiberRef } from "../index.js"

type Levels = "info" | "debug" | "warn" | "error"
export const LogLevels = FiberRef.unsafeMake(new Map<string, Levels>())
export const makeLog = (namespace: string, defaultLevel: Levels = "warn") => {
const level = LogLevels.pipe(Effect.andThen((levels) => levels.get(namespace) ?? defaultLevel))
return {
logWarning: (...message: ReadonlyArray<any>) =>
level.pipe(
Effect.andThen((l) =>
l === "info" || l === "debug" || l === "warn" ? Effect.logWarning(...message) : Effect.void
)
),
logError: Effect.logError,
logFatal: Effect.logFatal,
logInfo: (...message: ReadonlyArray<any>) =>
level.pipe(Effect.andThen((l) => l === "info" || l === "debug" ? Effect.logInfo(...message) : Effect.void)),
logDebug: (...message: ReadonlyArray<any>) =>
level.pipe(Effect.andThen((l) => l === "debug" ? Effect.logDebug(...message) : Effect.void))
}
}
10 changes: 10 additions & 0 deletions packages/infra-adapters/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,16 @@
"default": "./_cjs/fileUtil.cjs"
}
},
"./logger": {
"import": {
"types": "./dist/logger.d.ts",
"default": "./dist/logger.js"
},
"require": {
"types": "./dist/logger.d.ts",
"default": "./_cjs/logger.cjs"
}
},
"./memQueue": {
"import": {
"types": "./dist/memQueue.d.ts",
Expand Down
5 changes: 3 additions & 2 deletions packages/infra-adapters/src/CUPS/fake.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { pretty } from "@effect-app/core/utils"
import { Effect } from "effect-app"
import { InfraLogger } from "../logger.js"
import { CUPS } from "./service.js"

/**
Expand All @@ -8,7 +9,7 @@ import { CUPS } from "./service.js"
export const FAKECups = CUPS.toLayer(Effect.sync(() => {
return {
print: (buffer, printerId, ...options) =>
Effect
InfraLogger
.logInfo("Printing to fake printer")
.pipe(
Effect.zipRight(Effect.sync(() => ({ stdout: "fake", stderr: "" }))),
Expand All @@ -20,7 +21,7 @@ export const FAKECups = CUPS.toLayer(Effect.sync(() => {
})
),
printFile: (filePath, printerId, ...options) =>
Effect
InfraLogger
.logInfo("Printing to fake printer")
.pipe(
Effect.zipRight(Effect.sync(() => ({ stdout: "fake", stderr: "" }))),
Expand Down
6 changes: 3 additions & 3 deletions packages/infra-adapters/src/CUPS/live.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import path from "path"
import util from "util"
import type { FileOptions } from "../fileUtil.js"
import { tempFile } from "../fileUtil.js"
import { InfraLogger } from "../logger.js"
import { CUPS } from "./service.js"
import type { PrinterId } from "./service.js"

Expand Down Expand Up @@ -42,12 +43,11 @@ export function makeCUPS(cupsServer?: URL) {
const exec_ = util.promisify(cp.exec)
const exec = (command: string) =>
Effect.andThen(
Effect
.logDebug(`Executing: ${command}`),
InfraLogger.logDebug(`Executing: ${command}`),
Effect.tap(
Effect
.tryPromise(() => exec_(command)),
(r) => (Effect.logDebug(`Executed`).pipe(Effect.annotateLogs("result", pretty(r))))
(r) => (InfraLogger.logDebug(`Executed`).pipe(Effect.annotateLogs("result", pretty(r))))
)
)
type PrinterConfig = { url?: URL | undefined; id: string }
Expand Down
3 changes: 2 additions & 1 deletion packages/infra-adapters/src/RequestFiberSet.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { Tracer } from "@effect-app/core"
import { Context, Effect, Fiber, FiberSet, Option } from "@effect-app/core"
import { InfraLogger } from "./logger.js"

const make = Effect.gen(function*() {
const set = yield* FiberSet.make<any, any>()
Expand All @@ -9,7 +10,7 @@ const make = Effect.gen(function*() {
const addAll = (fibers: readonly Fiber.RuntimeFiber<any, any>[]) =>
Effect.sync(() => fibers.forEach((_) => FiberSet.unsafeAdd(set, _)))
const join = FiberSet.size(set).pipe(
Effect.andThen((count) => Effect.logInfo(`Joining ${count} current fibers on the RequestFiberSet`)),
Effect.andThen((count) => InfraLogger.logInfo(`Joining ${count} current fibers on the RequestFiberSet`)),
Effect.andThen(FiberSet.join(set))
)
const run = FiberSet.run(set)
Expand Down
3 changes: 2 additions & 1 deletion packages/infra-adapters/src/ServiceBus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {
import { ServiceBusClient } from "@azure/service-bus"
import type { Scope } from "effect-app"
import { Cause, Context, Effect, Exit, FiberSet, Layer } from "effect-app"
import { InfraLogger } from "./logger.js"
import { RequestFiberSet } from "./RequestFiberSet.js"

function makeClient(url: string) {
Expand Down Expand Up @@ -84,7 +85,7 @@ export function subscribe<RMsg, RErr>(hndlr: MessageHandlers<RMsg, RErr>, sessio
const fr = yield* FiberSet.runtime(fs)<RMsg | RErr>()
const wait = Effect.gen(function*() {
if ((yield* FiberSet.size(fs)) > 0) {
yield* Effect.logDebug("Waiting ServiceBusFiberSet to be empty: " + (yield* FiberSet.size(fs)))
yield* InfraLogger.logDebug("Waiting ServiceBusFiberSet to be empty: " + (yield* FiberSet.size(fs)))
}
while ((yield* FiberSet.size(fs)) > 0) yield* Effect.sleep("250 millis")
})
Expand Down
3 changes: 3 additions & 0 deletions packages/infra-adapters/src/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { makeLog } from "@effect-app/core/utils/logger"

export const InfraLogger = makeLog("@effect-app/infra", "info")
10 changes: 10 additions & 0 deletions packages/infra/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,16 @@
"default": "./_cjs/filter/types/validator.cjs"
}
},
"./logger": {
"import": {
"types": "./dist/logger.d.ts",
"default": "./dist/logger.js"
},
"require": {
"types": "./dist/logger.d.ts",
"default": "./_cjs/logger.cjs"
}
},
"./logger/jsonLogger": {
"import": {
"types": "./dist/logger/jsonLogger.d.ts",
Expand Down
3 changes: 2 additions & 1 deletion packages/infra/src/api/internal/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { setupRequestContext } from "@effect-app/infra/api/setupRequest"
import { reportError } from "@effect-app/infra/errorReporter"
import { Duration, Effect, pipe, S, Schedule, Stream } from "effect-app"
import { HttpHeaders, HttpServerResponse } from "effect-app/http"
import { InfraLogger } from "src/logger.js"

// Tell the client to retry every 10 seconds if connectivity is lost
const setRetry = Stream.succeed("retry: 10000")
Expand All @@ -13,7 +14,7 @@ export const makeSSE = <A extends { id: any }, E, R, SI, SR>(
) =>
Effect
.gen(function*() {
yield* Effect.logInfo("$ start listening to events")
yield* InfraLogger.logInfo("$ start listening to events")

const enc = new TextEncoder()

Expand Down
5 changes: 3 additions & 2 deletions packages/infra/src/api/internal/middlewares.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import * as FiberRef from "effect/FiberRef"
import { pipe } from "effect/Function"
import * as HashMap from "effect/HashMap"
import * as Metric from "effect/Metric"
import { InfraLogger } from "src/logger.js"
import type * as Middlewares from "../middlewares.js"

export const accessLog = (level: "Info" | "Warning" | "Debug" = "Info") =>
Expand Down Expand Up @@ -67,13 +68,13 @@ export const errorLog = Middleware.make((app) =>

if (response.status >= 400 && response.status < 500) {
yield* _(
Effect.logWarning(
InfraLogger.logWarning(
`${request.method.toUpperCase()} ${request.url} client error ${response.status}`
)
)
} else if (response.status >= 500) {
yield* _(
Effect.logError(
InfraLogger.logError(
`${request.method.toUpperCase()} ${request.url} server error ${response.status}`
)
)
Expand Down
5 changes: 3 additions & 2 deletions packages/infra/src/api/routing/defaultErrorHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import type {
InvalidTokenError,
UnauthorizedError as JWTUnauthorizedError
} from "express-oauth2-jwt-bearer"
import { InfraLogger } from "src/logger.js"

export class JWTError extends Data.TaggedClass("JWTError")<{
error:
Expand All @@ -43,7 +44,7 @@ export function defaultBasicErrorHandler<R>(
Effect
// final catch all; expecting never so that unhandled known errors will show up
.catchAll((err: never) =>
Effect
InfraLogger
.logError(
"Program error, compiler probably silenced, got an unsupported Error in Error Channel of Effect" + err
)
Expand Down Expand Up @@ -126,7 +127,7 @@ export function defaultErrorHandler<R, A extends { _tag: string } = never>(
Effect
// final catch all; expecting never so that unhandled known errors will show up
.catchAll((err: never) =>
Effect
InfraLogger
.logError(
"Program error, compiler probably silenced, got an unsupported Error in Error Channel of Effect" + err
)
Expand Down
7 changes: 4 additions & 3 deletions packages/infra/src/api/routing/makeRequestHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import type { HttpServerError } from "effect-app/http"
import { HttpBody, HttpRouter, HttpServerRequest, HttpServerResponse } from "effect-app/http"
import { NonEmptyString255 } from "effect-app/schema"
import type { REST } from "effect-app/schema"
import { InfraLogger } from "src/logger.js"
import { updateRequestContext } from "../setupRequest.js"
import { makeRequestParsers, parseRequestParams } from "./base.js"
import type { RequestHandler, RequestHandlerBase } from "./base.js"
Expand Down Expand Up @@ -182,7 +183,7 @@ export function makeRequestHandler<

const eff =
// TODO: we don;t have access to user id here cause context is not yet created
Effect
InfraLogger
.logInfo("Incoming request")
.pipe(
Effect.annotateLogs({
Expand Down Expand Up @@ -281,7 +282,7 @@ export function makeRequestHandler<
}),
Effect.suspend(() => {
const headers = res.headers
return Effect
return InfraLogger
.logError("Finished request", cause)
.pipe(Effect.annotateLogs({
method: req.method,
Expand Down Expand Up @@ -312,7 +313,7 @@ export function makeRequestHandler<
),
Effect
.tap((res) =>
Effect
InfraLogger
.logInfo("Finished request")
.pipe(Effect.annotateLogs({
method: req.method,
Expand Down
2 changes: 1 addition & 1 deletion packages/infra/src/api/writeDocs.ts.bak
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ export function writeOpenapiDocsI(rdescs: readonly RouteDescriptorAny[]) {
]
}))
.flatMap((_) => writeTextFile("./openapi.json", JSON.stringify(_, undefined, 2)).orDie)
.flatMap(() => Effect.logDebug("OpenAPI spec written to './openapi.json'"))
.flatMap(() => InfraLogger.logDebug("OpenAPI spec written to './openapi.json'"))
}
17 changes: 9 additions & 8 deletions packages/infra/src/errorReporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { dropUndefined } from "@effect-app/core/utils"
import * as Sentry from "@sentry/node"
import { Cause, Effect, Option } from "effect-app"
import { annotateSpanWithError, CauseException, ErrorReported } from "./errors.js"
import { InfraLogger } from "./logger.js"
import { RequestContextContainer } from "./services/RequestContextContainer.js"

const tryToJson = <T>(error: CauseException<T>) => {
Expand All @@ -27,22 +28,22 @@ export function reportError(
Effect.gen(function*() {
yield* annotateSpanWithError(cause, name)
if (Cause.isInterrupted(cause)) {
yield* Effect.logDebug("Interrupted").pipe(Effect.annotateLogs("extras", JSON.stringify(extras ?? {})))
yield* InfraLogger.logDebug("Interrupted").pipe(Effect.annotateLogs("extras", JSON.stringify(extras ?? {})))
return
}
const error = new CauseException(cause, name)

yield* reportSentry(error, extras)
yield* Effect
yield* InfraLogger
.logError("Reporting error", cause)
.pipe(
Effect.annotateLogs(dropUndefined({
extras,
__cause__: tryToJson(error),
__error_name__: name
})),
Effect.catchAllCause((cause) => Effect.logError("Failed to log error", cause)),
Effect.catchAllCause(() => Effect.logError("Failed to log error cause"))
Effect.catchAllCause((cause) => InfraLogger.logError("Failed to log error", cause)),
Effect.catchAllCause(() => InfraLogger.logError("Failed to log error cause"))
)

error[ErrorReported] = true
Expand Down Expand Up @@ -70,20 +71,20 @@ export function logError<E>(
return (cause: Cause<E>, extras?: Record<string, unknown>) =>
Effect.gen(function*() {
if (Cause.isInterrupted(cause)) {
yield* Effect.logDebug("Interrupted").pipe(Effect.annotateLogs(dropUndefined({ extras })))
yield* InfraLogger.logDebug("Interrupted").pipe(Effect.annotateLogs(dropUndefined({ extras })))
return
}
const error = new CauseException(cause, name)
yield* Effect
yield* InfraLogger
.logWarning("Logging error", cause)
.pipe(
Effect.annotateLogs(dropUndefined({
extras,
__cause__: tryToJson(error),
__error_name__: name
})),
Effect.catchAllCause((cause) => Effect.logError("Failed to log error", cause)),
Effect.catchAllCause(() => Effect.logError("Failed to log error cause"))
Effect.catchAllCause((cause) => InfraLogger.logError("Failed to log error", cause)),
Effect.catchAllCause(() => InfraLogger.logError("Failed to log error cause"))
)
})
}
Expand Down
3 changes: 3 additions & 0 deletions packages/infra/src/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { makeLog } from "@effect-app/core/utils/logger"

export const InfraLogger = makeLog("@effect-app/infra", "info")
5 changes: 3 additions & 2 deletions packages/infra/src/services/Emailer/Sendgrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { dropUndefinedT } from "@effect-app/core/utils"
import type { EmailData } from "@sendgrid/helpers/classes/email-address.js"
import sgMail from "@sendgrid/mail"
import { Array, Effect, Equivalence, Secret } from "effect-app"
import { InfraLogger } from "src/logger.js"
import { inspect } from "util"
import { Emailer } from "./service.js"
import type { EmailMsg, EmailMsgOptionalFrom, SendgridConfig } from "./service.js"
Expand All @@ -22,7 +23,7 @@ const makeSendgrid = ({ apiKey, defaultFrom, defaultReplyTo, realMail, subjectPr

const renderedMsg_ = render(msg)
const renderedMsg = { ...renderedMsg_, subject: `${subjectPrefix}${renderedMsg_.subject}` }
yield* Effect.logDebug("Sending email").pipe(Effect.annotateLogs("msg", inspect(renderedMsg, false, 5)))
yield* InfraLogger.logDebug("Sending email").pipe(Effect.annotateLogs("msg", inspect(renderedMsg, false, 5)))

const ret = yield* Effect.async<
[sgMail.ClientResponse, Record<string, unknown>],
Expand All @@ -41,7 +42,7 @@ const makeSendgrid = ({ apiKey, defaultFrom, defaultReplyTo, realMail, subjectPr
// templateId: msg.templateId
// }
// }
// yield* Effect.logDebug("Tracking email event").annotateLogs("event", event.$$.pretty)
// yield* InfraLogger.logDebug("Tracking email event").annotateLogs("event", event.$$.pretty)
// const { trackEvent } = yield* AiContextService
// trackEvent(event)
return ret
Expand Down
7 changes: 4 additions & 3 deletions packages/infra/src/services/Emailer/fake.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { Effect } from "effect-app"
import { pretty } from "effect-app/utils"
import { InfraLogger } from "src/logger.js"
import { Emailer } from "./service.js"

const makeFake = Effect
.logDebug("FAKE Emailer Service enabled")
const makeFake = InfraLogger
.logInfo("FAKE Emailer Service enabled")
.pipe(Effect.map(() =>
Emailer.of({
sendMail(msg) {
return Effect
return InfraLogger
.logDebug(`Fake send mail`)
.pipe(Effect.annotateLogs("msg", pretty(msg)))
}
Expand Down
Loading

0 comments on commit 550ba43

Please sign in to comment.