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 🙏

© 2026 – Pkg Stats / Ryan Hefner

sofie-logger

v0.0.1

Published

Library for unified logging across Sofie Automation projects, based on LogTape.

Readme

Sofie: The Modern TV News Studio Automation System (Logging library)

npm

This is a part of the Sofie TV News Studio Automation System.

What is it?

This is a thin wrapper around the LogTape library (https://logtape.org) with some Sofie-recommended defaults and restrictions.

The reason for using this package is:

  • To have a unified logging setup across the Sofie Automation projects
  • To ensure logs are easily parsable by log collectors such as Elasticsearch by avoiding logging arbitrary data structures.

Usage

Note: The official LogTape documentation applies to this as well, see https://logtape.org

In application: Configuration

Configure and initialize logging at startup

It is mandatory that the application sets the configuration upon standup

import { loggingConfigureWithDefault, getDefaultConfiguration, loggingConfigure } from 'sofie-logger'

await loggingConfigureWithDefault() // Sets up logging with Sofie-recommended defaults

// or:

await loggingConfigureWithDefault({
	logLevel: 'debug', // Set a log level
	logPath: '/var/logs/my-application', // Enable logging to disk
})

// or:

// This is equivalent to calling loggingConfigureWithDefault():
const config = getDefaultConfiguration()
await loggingConfigure(config)

Reconfigure logging at runtime

import { loggingConfigureWithDefault } from 'sofie-logger'

// Example: Change the log level:
await loggingConfigureWithDefault({
	reset: true, // Reset previous configuration
	logLevel: 'debug', // Set a log level
})

// Note: If you have a custom logging configuration, you have to instead modify modify it and pass it into loggingConfigure() again.

Logging

import { getLogger, SofieLogger } from 'sofie-logger'

class MyLibraryClass {
	logger: SofieLogger
	constructor() {
		// Setup a logger for this class.
		// Set the category so that the origin of the logs can be identified:
		this.logger = getLogger(['my-library', 'MyLibraryClass'])
	}
	logAMessage() {
		logger.info('Hello world!')
	}
}

It is possible to provide the logger with additional context data. By default, only the data field is allowed:

const logger = getLogger(['my-test-category'])
logger.info('got some data', { data: myDataObject }) // The `data` field is always converted to JSON-string before logged.

If you want to log some custom data fields, you need to extend the SofieLogger type to allow those fields:

declare module 'sofie-logger' {
	interface SofieLoggerContext {
		userId?: string
		sessionId?: string
	}
}

const logger = getLogger(['my-test-category'])
logger.info('user logged in', {
	// These fields are now allowed:
	userId: 'user-1234',
	session: 'session-5678',
})

The reason for not allowing any data in the context (as is the LogTape way), it turns out that logging arbitrary data structures can lead to issues with log collectors, as they may not be able to parse and index all data structures correctly.

Inheritance and contextual loggers

import { getLogger } from 'sofie-logger'
declare module 'sofie-logger' {
	interface SofieLoggerContext {
		userId?: string
	}
}

const parentLogger = getLogger('my-library')

// Example of creating a child logger with a sub-category:
const childLogger = parentLogger.getChild('child-category')
childLogger.info('This is from the child logger') // outputs category "my-library.child-category"

// Example of creating a contextual logger:
const withContextLogger = parentLogger.with({ userId: 'user-1234' })
withContextLogger.info('User did something') // outputs with userId in the log context

Advanced: Custom filters

An application may implement custom log filters, for example to omit logs from certain categories.

import { getLogger, getDefaultConfiguration, loggingConfigure } from 'sofie-logger'

const config = getDefaultConfiguration({
	reset: true,
	logLevel: 'debug', // debug and above
})

// Add a filter:
const filters = (config.filters = config.filters ?? {})
filters.myCustomFilter = (log) => {
	if (log.category.includes('special-category')) return false // Don't log this
	return true
}

// Assign the filter to all loggers:
config.loggers.forEach((logger) => (logger.filters = [...(logger.filters || []), 'myCustomFilter']))

await loggingConfigure(config)

const logger = getLogger('my-category')
const specialLogger = logger.getChild('special-category')

logger.info('This message will appear')
specialLogger.info('This message will NOT appear')