API Reference
Complete API reference for Logixlysia
Functions
logixlysia
Main plugin function that adds logging capabilities to your Elysia application.
function logixlysia<TFields extends object = LogFields>(
options?: Options
): LogixlysiaPlugin<TFields>
Parameters:
options(optional): Configuration options for Logixlysia
Returns:
LogixlysiaPlugin<TFields>: the Elysia plugin instance (its store carrieslogger,pinoandbeforeTime, and every handler receives a derivedlog) pluswrapWs
Example:
import { Elysia } from 'elysia'
import logixlysia from 'logixlysia'
const app = new Elysia().use(
logixlysia({
config: {
showStartupMessage: true
}
})
)
useLogger
Returns the current request’s RequestScopedLogger. Outside a request, or without useAsyncLocalStorage: true, it returns a no-op logger that writes nothing.
function useLogger<
TFields extends object = LogFields
>(): RequestScopedLogger<TFields>
flushLogixlysia
Drains the transports in options and every file sink, and with close: true also releases them. Pass the same options object you gave the plugin; see graceful shutdown.
function flushLogixlysia(
options: Options,
flags?: { close?: boolean }
): Promise<void>
createLogger
Builds a Logger from Options without registering the plugin. It keeps its own request context, separate from any plugin instance’s.
function createLogger(options?: Options): Logger
resolveOptions
Applies a preset’s defaults under the explicit config and validates the result, the same way the plugin does with the options you pass it. It throws where the plugin would: an unknown preset, or an invalid rotation, sampling, threshold, logFilter or output setting.
function resolveOptions(options?: Options): Options
Also exported: createPluginLogger, createWsHandlerWrapper, getOrCreateRequestId, resolveRequestIdConfig and resolveSampling are the building blocks the plugin is assembled from. They may change between minor versions.
Types
Logixlysia
Elysia instance type with Logixlysia store.
import type { LogixlysiaSingleton } from 'logixlysia'
type Logixlysia = Elysia<'', LogixlysiaSingleton>
The plugin uses an explicit LogixlysiaSingleton: a closed store plus empty decorator / derive / resolve slots that avoid both SingletonBase’s wide Record<string, unknown> and Record<string, never> (the latter would intersect Elysia’s Context keys with never). That keeps Context and WebSocket ws.data precise after .use(logixlysia()).
Options
Configuration options for Logixlysia.
type Options = {
preset?: 'dev' | 'prod' | 'json'
config?: {
showStartupMessage?: boolean
startupMessageFormat?: 'simple' | 'banner'
useColors?: boolean
ip?: boolean
autoRedact?: boolean
redactKeys?: string[]
logErrorPayload?: boolean
timestamp?: {
translateTime?: string
}
customLogFormat?: string
service?: string
slowThreshold?: number
verySlowThreshold?: number
showContextTree?: boolean
contextDepth?: number
logQueryParams?: boolean
transports?: Transport[]
useTransportsOnly?: boolean
disableInternalLogger?: boolean
disableFileLogging?: boolean
onError?: (context: SinkErrorContext) => void
flushTimeoutMs?: number
enrichers?: EnricherLike[]
requestId?: boolean | RequestIdConfig
useAsyncLocalStorage?: boolean
disableWebSocketLogging?: boolean
logFilter?: LogFilter
sampling?: SamplingConfig
logFilePath?: string
logDirMode?: number
logFileMode?: number
logRotation?: LogRotationConfig
pino?: PinoLoggerOptions & { prettyPrint?: boolean | object }
}
}
LogixlysiaStore
Store type available in Elysia context.
type LogixlysiaStore = {
logger: Logger
pino: Pino
beforeTime?: bigint
}
Properties:
logger: Logger instance with helper methodspino: Direct Pino logger instancebeforeTime: Abigintfromprocess.hrtime.bigint(), taken at the start of the most recent request. Elysia shares the store between concurrent requests, so the value is accurate only while requests do not overlap. The plugin’s own durations do not use it.
Keep LogixlysiaStore a closed object type (no index signature). That helps merged handler and WebSocket types stay accurate.
Logger
Logger interface with logging methods.
type Logger = {
pino: Pino
log: (
level: LogLevel,
request: RequestInfo,
data: Record<string, unknown>,
store: StoreData
) => void
handleHttpError: (
request: RequestInfo,
error: unknown,
store: StoreData
) => void
debug: (
request: RequestInfo,
message: string,
context?: Record<string, unknown>
) => void
info: (
request: RequestInfo,
message: string,
context?: Record<string, unknown>
) => void
warn: (
request: RequestInfo,
message: string,
context?: Record<string, unknown>
) => void
error: (
request: RequestInfo,
message: string,
context?: Record<string, unknown>
) => void
mergeContext: (
key: RequestInfo | object,
partial: Record<string, unknown>
) => void
getContext: (key: RequestInfo | object) => Readonly<Record<string, unknown>>
beginRequest: (request: RequestInfo) => void
finalizeRequest: (
request: RequestInfo,
store: StoreData,
status: number
) => void
}
RequestScopedLogger
The log every handler receives, and what useLogger() returns. It is bound to one request, so its methods take no request argument.
type RequestScopedLogger<TFields extends object = LogFields> = {
debug: (message: string, context?: Partial<TFields>) => void
info: (message: string, context?: Partial<TFields>) => void
warn: (message: string, context?: Partial<TFields>) => void
error: (message: string, context?: Partial<TFields>) => void
mergeContext: (partial: Partial<TFields>) => void
}
LogLevel
Log level type.
type LogLevel = 'DEBUG' | 'INFO' | 'WARNING' | 'ERROR'
Transport
Custom transport interface.
type Transport = {
log: (
level: LogLevel,
message: string,
meta?: Record<string, unknown>
) => void | Promise<void>
flush?: () => void | Promise<void>
close?: () => void | Promise<void>
}
flush drains entries the transport has queued or batched; the shutdown flush calls it when the app stops. close releases held sockets, timers and buffers, and is reached only through flushLogixlysia(options, { close: true }).
LogRotationConfig
Log rotation configuration. Importable from logixlysia.
type LogRotationConfig = {
maxSize?: string | number
maxFiles?: number | string
interval?: string
compress?: boolean
compression?: 'gzip'
}
SinkErrorContext
The argument of config.onError, importable from logixlysia.
type SinkErrorContext = {
sink: 'transport' | 'file' | 'rotation' | 'shutdown' | 'enricher' | 'format'
error: unknown
}
LogFilter
The type of config.logFilter, importable from logixlysia. Only the listed levels are logged; a missing or empty list keeps every level.
type LogFilter = {
level?: LogLevel[]
}
Pino
Pino logger type.
type Pino = PinoLogger<never, boolean>
LogixlysiaContext
Context type for request handlers.
type LogixlysiaContext = {
request: Request
store: LogixlysiaStore
}
Classes
HttpError
An HTTP error carrying the context that makes a failure actionable.
class HttpError extends Error {
readonly code?: string
readonly fix?: string
readonly internal?: unknown
readonly link?: string
readonly status: number
readonly why?: string
constructor(status: number, message: string, init?: HttpErrorInit)
toJSON(): HttpErrorPayload
}
interface HttpErrorInit {
code?: string
fix?: string
internal?: unknown
link?: string
why?: string
}
Properties:
status— HTTP status codecode— stable machine-readable identifier the client can branch on, e.g.PAYMENT_DECLINED. Unlikemessage, it is safe to depend on: rewording the message does not break a callerwhy— why the request failed, in plain languagefix— what the caller should do about itlink— documentation URL for this failureinternal— log-only diagnostics. Non-enumerable and excluded fromtoJSON(), so no serializer can put it in a response body
Example:
import { HttpError } from 'logixlysia'
throw new HttpError(402, 'Card declined', {
code: 'PAYMENT_DECLINED',
why: 'The issuing bank rejected the charge.',
fix: 'Try a different card, or contact your bank.',
link: 'https://docs.example.com/errors/payment-declined',
internal: { gatewayCode: 'do_not_honor', chargeId }
})
Response body:
{
"code": "PAYMENT_DECLINED",
"fix": "Try a different card, or contact your bank.",
"link": "https://docs.example.com/errors/payment-declined",
"message": "Card declined",
"status": 402,
"why": "The issuing bank rejected the charge."
}
The log line carries the same fields plus internal, rendered in the context tree as error.code, error.why, error.fix, error.link, and error.internal.
An error with no client-facing fields keeps its previous behaviour exactly — throw new HttpError(404, 'User not found') still responds with the bare message, not JSON. Only an error carrying at least one of code, why, fix, or link responds as JSON.
Usage Examples
Accessing Logger in Route Handlers
app.get('/users/:id', ({ store, params, request }) => {
const { logger, pino } = store
// Use logger helper methods
logger.info(request, 'User accessed', { userId: params.id })
// Or use Pino directly
pino.info({ userId: params.id }, 'User accessed')
return { user: 'data' }
})
Custom Logging
app.post(
'/users',
({ store, body, request }) => {
const { logger } = store
logger.debug(request, 'Creating user', { email: body.email })
// ... create user logic
logger.info(request, 'User created', { userId: newUser.id })
return newUser
},
{ body: t.Object({ email: t.String() }) }
)