UNPKG

veffect

Version:

powerful TypeScript validation library built on the robust foundation of Effect combining exceptional type safety, high performance, and developer experience. Taking inspiration from Effect's functional principles, VEffect delivers a balanced approach tha

240 lines 7.01 kB
import { constVoid, dual, pipe } from "../Function.js"; import * as HashMap from "../HashMap.js"; import * as Inspectable from "../Inspectable.js"; import * as List from "../List.js"; import * as LogSpan from "../LogSpan.js"; import * as Option from "../Option.js"; import { pipeArguments } from "../Pipeable.js"; import * as Cause from "./cause.js"; import * as _fiberId from "./fiberId.js"; /** @internal */ const LoggerSymbolKey = "effect/Logger"; /** @internal */ export const LoggerTypeId = /*#__PURE__*/Symbol.for(LoggerSymbolKey); const loggerVariance = { /* c8 ignore next */ _Message: _ => _, /* c8 ignore next */ _Output: _ => _ }; /** @internal */ export const makeLogger = log => ({ [LoggerTypeId]: loggerVariance, log, pipe() { return pipeArguments(this, arguments); } }); /** @internal */ export const mapInput = /*#__PURE__*/dual(2, (self, f) => makeLogger(options => self.log({ ...options, message: f(options.message) }))); /** @internal */ export const mapInputOptions = /*#__PURE__*/dual(2, (self, f) => makeLogger(options => self.log(f(options)))); /** @internal */ export const filterLogLevel = /*#__PURE__*/dual(2, (self, f) => makeLogger(options => f(options.logLevel) ? Option.some(self.log(options)) : Option.none())); /** @internal */ export const map = /*#__PURE__*/dual(2, (self, f) => makeLogger(options => f(self.log(options)))); /** @internal */ export const none = { [LoggerTypeId]: loggerVariance, log: constVoid, pipe() { return pipeArguments(this, arguments); } }; /** @internal */ export const simple = log => ({ [LoggerTypeId]: loggerVariance, log: ({ message }) => log(message), pipe() { return pipeArguments(this, arguments); } }); /** @internal */ export const succeed = value => { return simple(() => value); }; /** @internal */ export const sync = evaluate => { return simple(evaluate); }; /** @internal */ export const zip = /*#__PURE__*/dual(2, (self, that) => makeLogger(options => [self.log(options), that.log(options)])); /** @internal */ export const zipLeft = /*#__PURE__*/dual(2, (self, that) => map(zip(self, that), tuple => tuple[0])); /** @internal */ export const zipRight = /*#__PURE__*/dual(2, (self, that) => map(zip(self, that), tuple => tuple[1])); /** @internal */ export const stringLogger = /*#__PURE__*/makeLogger(({ annotations, cause, date, fiberId, logLevel, message, spans }) => { const nowMillis = date.getTime(); const outputArray = [`timestamp=${date.toISOString()}`, `level=${logLevel.label}`, `fiber=${_fiberId.threadName(fiberId)}`]; let output = outputArray.join(" "); const stringMessage = Inspectable.toStringUnknown(message); if (stringMessage.length > 0) { output = output + " message="; output = appendQuoted(stringMessage, output); } if (cause != null && cause._tag !== "Empty") { output = output + " cause="; output = appendQuoted(Cause.pretty(cause), output); } if (List.isCons(spans)) { output = output + " "; let first = true; for (const span of spans) { if (first) { first = false; } else { output = output + " "; } output = output + pipe(span, LogSpan.render(nowMillis)); } } if (pipe(annotations, HashMap.size) > 0) { output = output + " "; let first = true; for (const [key, value] of annotations) { if (first) { first = false; } else { output = output + " "; } output = output + filterKeyName(key); output = output + "="; output = appendQuoted(Inspectable.toStringUnknown(value), output); } } return output; }); /** @internal */ const escapeDoubleQuotes = str => `"${str.replace(/\\([\s\S])|(")/g, "\\$1$2")}"`; const textOnly = /^[^\s"=]+$/; /** @internal */ const appendQuoted = (label, output) => output + (label.match(textOnly) ? label : escapeDoubleQuotes(label)); /** @internal */ export const logfmtLogger = /*#__PURE__*/makeLogger(({ annotations, cause, date, fiberId, logLevel, message, spans }) => { const nowMillis = date.getTime(); const outputArray = [`timestamp=${date.toISOString()}`, `level=${logLevel.label}`, `fiber=${_fiberId.threadName(fiberId)}`]; let output = outputArray.join(" "); const stringMessage = Inspectable.toStringUnknown(message, 0); if (stringMessage.length > 0) { output = output + " message="; output = appendQuotedLogfmt(stringMessage, output); } if (cause != null && cause._tag !== "Empty") { output = output + " cause="; output = appendQuotedLogfmt(Cause.pretty(cause), output); } if (List.isCons(spans)) { output = output + " "; let first = true; for (const span of spans) { if (first) { first = false; } else { output = output + " "; } output = output + pipe(span, renderLogSpanLogfmt(nowMillis)); } } if (pipe(annotations, HashMap.size) > 0) { output = output + " "; let first = true; for (const [key, value] of annotations) { if (first) { first = false; } else { output = output + " "; } output = output + filterKeyName(key); output = output + "="; output = appendQuotedLogfmt(Inspectable.toStringUnknown(value, 0), output); } } return output; }); /** @internal */ export const structuredLogger = /*#__PURE__*/makeLogger(({ annotations, cause, date, fiberId, logLevel, message, spans }) => { const now = date.getTime(); const annotationsObj = {}; const spansObj = {}; if (HashMap.size(annotations) > 0) { for (const [k, v] of annotations) { annotationsObj[k] = structuredMessage(v); } } if (List.isCons(spans)) { for (const span of spans) { spansObj[span.label] = now - span.startTime; } } return { message: structuredMessage(message), logLevel: logLevel.label, timestamp: date.toISOString(), cause: Cause.isEmpty(cause) ? undefined : Cause.pretty(cause), annotations: annotationsObj, spans: spansObj, fiberId: _fiberId.threadName(fiberId) }; }); export const structuredMessage = u => { switch (typeof u) { case "bigint": case "function": case "symbol": { return String(u); } default: { return u; } } }; /** @internal */ export const jsonLogger = /*#__PURE__*/map(structuredLogger, Inspectable.stringifyCircular); /** @internal */ const filterKeyName = key => key.replace(/[\s="]/g, "_"); /** @internal */ const escapeDoubleQuotesLogfmt = str => JSON.stringify(str); /** @internal */ const appendQuotedLogfmt = (label, output) => output + (label.match(textOnly) ? label : escapeDoubleQuotesLogfmt(label)); /** @internal */ const renderLogSpanLogfmt = now => self => { const label = filterKeyName(self.label); return `${label}=${now - self.startTime}ms`; }; /** @internal */ export const isLogger = u => { return typeof u === "object" && u != null && LoggerTypeId in u; }; //# sourceMappingURL=logger.js.map