npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@livy/contracts

v1.1.2

Published

Conceptual types and structures for the Livy logger

Downloads

848

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

This module contains the available log levels and their corresponding severities:

  • LogLevel is a type representing any valid RFC 5424 log level while logLevels 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 from 0 through 7. The SeverityMap 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.