@livy/contracts
v1.1.2
Published
Conceptual types and structures for the Livy logger
Downloads
848
Maintainers
Readme
@livy/contracts
This package (primarily) contains types representing the core concepts of the Livy logger. Those are especially useful when you're building Livy components using TypeScript. For this reason, code blocks in this documentation are written in TypeScript.
Table of Contents:
LogLevel
LogRecord
LoggerInterface
HandlerInterface
ResettableInterface
FormattableHandlerInterface
ProcessableHandlerInterface
ClosableHandlerInterface
FormatterInterface
ProcessorInterface
/ProcessorFunction
LogLevel
This module contains the available log levels and their corresponding severities:
LogLevel
is a type representing any valid RFC 5424 log level whilelogLevels
is an array containing all those level strings, sorted from least (debug
) to most serious (emergency
):import { LogLevel, logLevels } from '@livy/contracts' function printLevel(level: LogLevel) { if (!logLevels.includes(level)) { throw Error('Invalidlog log level') } console.log(level) }
The
SeverityLevel
type represents log level severity as an integer from0
through7
. TheSeverityMap
object maps log levels to their corresponding severity (debug → 7, ..., emergency → 0
):import { LogLevel, SeverityMap } from '@livy/contracts' /** * Sort a list of log levels by severity ("debug" first, "emergency" last) */ function sortBySeverity(levels: LogLevel[]) { return [...levels].sort( (levelA, levelB) => SeverityMap[levelB] - SeverityMap[levelA] ) }
LogRecord
Exposes the LogRecord
interface which describes the structure of a Livy log record. This is useful for writing, for example, a custom formatter in TypeScript:
import { FormatterInterface } from '@livy/contracts'
import { LogRecord } from '@livy/contracts'
class QueryStringFormatter implements FormatterInterface {
/*
* Format properties of a record as level=debug&severity=7&message=...
*/
public format(record: LogRecord) {
return new URLSearchParams(Object.entries(record)).toString()
}
/*
* Format properties of multiple records as level[]=debug&severity[]=7&message[]=...
*/
public formatBatch(records: LogRecord[]) {
return new URLSearchParams(
records.reduce(
(carry, record) => [
...carry,
...Object.entries(record).map(([key, value]) => [`${key}[]`, value])
],
[]
)
)
.toString()
.replace(/%5B%5D/g, '[]')
}
}
LoggerInterface
Describes the abstract structure of a Livy logger instance (LoggerInterface
) as well as two variations, AsyncLoggerInterface
and SyncLoggerInterface
, which extend LoggerInterface
and additionally define concrete return types (instead of unknown
) for the log methods.
import {
LoggerInterface,
AsyncLoggerInterface,
SyncLoggerInterface
} from '@livy/contracts'
HandlerInterface
Describes the minimum viable structure of a Livy handler as HandlerInterface
. Additionally, a SyncHandlerInterface
is provided which represents a handler that has synchronous logging methods in addition to the asynchronous ones.
import { HandlerInterface, SyncHandlerInterface } from '@livy/contracts'
ResettableInterface
Describes the structure of a resettable handler or processor — a component able to reset its internal state (e.g. the ArrayHandler
which can clear its own buffer).
import { ResettableInterface } from '@livy/contracts'
Handlers implementing this interface expose a reset
method to trigger the reset:
const resettableHandler = new SomeResettableHandler()
resettableHandler.reset()
Calling this method on a handler should not only reset its own state but also the state of all components attached to it (e.g. processors or wrapped handlers).
FormattableHandlerInterface
Describes the structure of a handler which has a configurable formatter.
import { FormattableHandlerInterface } from '@livy/contracts'
ProcessableHandlerInterface
Describes the structure of a handler with support for processors.
import { ProcessableHandlerInterface } from '@livy/contracts'
Handlers implementing this interface expose a Set of processors as their processors
property:
const processableHandler = new SomeProcessableHandler()
processableHandler.processors
.add(new SomeProcessor())
.add(new OtherProcessor())
ClosableHandlerInterface
Describes the structure of a handler which wants to do cleanup tasks when the process exits.
If you want to implement such a handler, please be aware that there is often no spare time left when the close()
method is invoked (because it is triggered when the process exits/the web page is left), i.e. asynchronous cleanup actions usually won't work.
import { ClosableHandlerInterface } from '@livy/contracts'
FormatterInterface
Describes the structure of a formatter.
import { FormatterInterface } from '@livy/contracts'
ProcessorInterface
/ProcessorFunction
Describes the structure of a processor.
import { ProcessorInterfaceOrFunction } from '@livy/contracts'
A processor can either be stateless or stateful:
Stateless Processors
A stateless processor is just a bare function taking a log record and returning a log record.
import { ProcessorFunction } from '@livy/contracts'
Stateful Processors
A stateful processor is a class with a process
method. That method then does the job of accepting and returning a log record.
import { ProcessorInterface } from '@livy/contracts'
Writing a processor in a stateful is usually done...
- ...if it needs to take options (which are usually taken to the processor's constructor).
- ...if it needs to retain state between several processed records.