# @darkobits/log

> The logger that @darkobits uses.

Latest version **2.0.0-beta.20** (published 2024-12-02) · WTFPL license · 0 weekly downloads

## Install

```sh
npm install @darkobits/log
pnpm add @darkobits/log
yarn add @darkobits/log
bun add @darkobits/log
```

## Health

**Score 45/100 (D)** — status: stable.

Positive: has types; esm support; no vulnerabilities.

Warnings: low downloads.

Negative: stale.

## Facts

| | |
|---|---|
| Version | 2.0.0-beta.20 |
| Published | 2024-12-02 |
| First published | 2017-11-10 |
| Weekly downloads | 0 |
| License | WTFPL |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 11 |
| Unpacked size | 33.1 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 1 |
| Author | darkobits |
| Maintainers | darkobits |
| Keywords | log, npm, unique |

## Links

- npm: https://www.npmjs.com/package/@darkobits/log
- Repository: https://github.com/darkobits/log
- Homepage: https://github.com/darkobits/log#readme
- Issues: https://github.com/darkobits/log/issues
- npm.io page: https://npm.io/package/@darkobits/log

## Dependencies (11)

- [ms](https://npm.io/package/ms.md) ^2.1.3
- [ora](https://npm.io/package/ora.md) ^8.1.1
- [chalk](https://npm.io/package/chalk.md) ^4.1.2
- [consola](https://npm.io/package/consola.md) ^3.2.3
- [p-queue](https://npm.io/package/p-queue.md) ^8.0.1
- [deepmerge](https://npm.io/package/deepmerge.md) ^4.3.1
- [p-wait-for](https://npm.io/package/p-wait-for.md) ^5.0.2
- [cli-spinners](https://npm.io/package/cli-spinners.md) ^3.2.0
- [@darkobits/env](https://npm.io/package/@darkobits/env.md) ^2.0.0
- [@darkobits/sleep](https://npm.io/package/@darkobits/sleep.md) ^3.0.0
- [@darkobits/mask-string](https://npm.io/package/@darkobits/mask-string.md) ^3.0.0

## Alternatives

- [cli-color](https://npm.io/package/cli-color.md) — 3.4M weekly downloads
- [log](https://npm.io/package/log.md) — 1.3M weekly downloads
- [logstash-client](https://npm.io/package/logstash-client.md) — 4.5K weekly downloads
- [@nocobase/plugin-logger](https://npm.io/package/@nocobase/plugin-logger.md) — 2.0K weekly downloads
- [child-process-debug](https://npm.io/package/child-process-debug.md) — 695 weekly downloads

## Recent versions

- 2.0.0-beta.20 (latest) — 2024-12-02
- 2.0.0-beta.30 (beta) — 2025-02-27
- 2.0.0-beta.29 — 2025-02-15
- 2.0.0-beta.28 — 2024-12-07
- 2.0.0-beta.27 — 2024-12-06
- 2.0.0-beta.26 — 2024-12-06
- 2.0.0-beta.25 — 2024-12-04
- 2.0.0-beta.24 — 2024-12-04
- 2.0.0-beta.23 — 2024-12-03
- 2.0.0-beta.22 — 2024-12-03
- 2.0.0-beta.21 — 2024-12-02
- 2.0.0-beta.19 — 2024-12-02
- 2.0.0-beta.18 — 2024-12-01
- 2.0.0-beta.17 — 2024-12-01
- 2.0.0-beta.16 — 2021-05-11
- … 27 more at https://npm.io/package/@darkobits/log/versions

## README

<a href="#top" id="top">
  <img src="https://user-images.githubusercontent.com/441546/104720607-e97f5a80-56e1-11eb-89e5-5eee4dc9b17e.png" style="max-width: 100%">
</a>
<p align="center">
  <a href="https://www.npmjs.com/package/@darkobits/log"><img src="https://img.shields.io/npm/v/@darkobits/log.svg?style=flat-square"></a>
  <a href="https://github.com/darkobits/log/actions"><img src="https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Fdarkobits%2Flog%2Fbadge%3Fref%3Dmaster&style=flat-square&label=build&logo=none"></a>
  <a href="https://app.codecov.io/gh/darkobits/log/branch/master"><img src="https://img.shields.io/codecov/c/github/darkobits/log/master?style=flat-square"></a>
  <a href="https://david-dm.org/darkobits/log"><img src="https://img.shields.io/david/darkobits/log.svg?style=flat-square"></a>
  <a href="https://conventionalcommits.org"><img src="https://img.shields.io/badge/conventional%20commits-1.0.0-027dc6.svg?style=flat-square"></a>
</p>

A logger for CLIs. Noop.

## Contents

* [Features](#features)
* [Install](#install)
* [Basic Usage](#basic-usage)
* [API](#api)
  * [`.chalk`](#chalk)
  * [`#configure`](#configureconfig-partiallogoptions-void)
  * [`#getLevel`](#getlevel-leveldescriptor)
  * [`#getLevels`](#getlevels-key-string-leveldescriptor)
  * [`#isLevelAtLeast`](#islevelatleastname-string-boolean)
  * [`#prefix`](#prefixprefix-primitive-prefix)
  * [`#addSecret`](#addsecretsecret-primitive--regexp-maskchar---void)
  * [`#createPipe`](#createpipelevel-string-nodejswritablestream)
  * [`#beginInteractive`](#begininteractivemessagefn--begininteractiveoptions-endinteractivefn)
  * [`#createTimer`](#createtimeroptions-timeroptions-timer)
  * [`#createProgressBar`](#createprogressbaroptions-progressbaroptions-progressbar)
  * [`#createSpinner`](#createspinneroptions-spinneroptions-spinner)
* [Debug Support](#debug-support)
* [Caveats](#caveats)

## Features

* Highly Configurable
* Chalk-included
* Interactive Mode
* Timers
* Spinners
* Progress Bars

## Install

```
$ npm i @darkobits/log
```

## Basic Usage

This package's default export is a factory function that accepts an [options object](/src/etc/types.ts#L119-L189).

If the `level` option is omitted, the log level will be set to `process.env.LOG_LEVEL` if set. Otherwise, it will be set to `info`.

**Example:**

```ts
import LogFactory from '@darkobits/log';

const log = LogFactory({heading: 'myApp'});

log.info(`Now you're thinking with ${log.chalk.bold('Portals')}!`);
```

<p align="center">
  <img src="https://user-images.githubusercontent.com/441546/64509568-ddd18780-d294-11e9-961a-16f1f203db20.png" max-width="100%">
</p>

## API

This section documents the properties and methods of each logger instance. The examples below assume a logger (referred to as `log`) has already been created.

<a href="#top"><img src="https://user-images.githubusercontent.com/441546/63230477-f5e84680-c1c1-11e9-8c2d-6d2079cee662.png"></a>
<h3><code>.chalk</code></h3>

To afford a convenient way to style log messages, the logger creates a custom [Chalk](https://github.com/chalk/chalk) instance for each logger, the options for which are configurable. By creating a custom Chalk instance, the logger avoids conflicting with the default/global Chalk instance that may be in use by other parts of an application.

**Example:**

```ts
log.info(`Have a ${log.chalk.bold.pink('fabulous')} day!`);
```

<p align="center">
  <img src="https://user-images.githubusercontent.com/441546/64509839-7831cb00-d295-11e9-9993-4bb65e1d0a9c.png" max-width="100%">
</p>

<a href="#top"><img src="https://user-images.githubusercontent.com/441546/63230477-f5e84680-c1c1-11e9-8c2d-6d2079cee662.png"></a>
<h3><code>configure(config: Partial<<a href="/src/etc/types.ts#L119-L189">LogOptions</a>>): void</code></h3>

Configure/re-configure the logger instance. The provided object will be deep-merged with the logger's existing configuration. This method can therefore be used to accomplish things like:

* Adding log levels.
* Changing the styling for existing log levels and other tokens.
* Changing the log level.

**Example:**

```ts
// Change the log level.
log.configure({level: 'verbose'});

// Add a new log level.
log.configure({
  levels: {
    foo: {
      level: 5000,
      label: 'FOO!',
      style: (token, chalk) => chalk.keyword('blue')(token)
    }
  }
});
```

<a href="#top"><img src="https://user-images.githubusercontent.com/441546/63230477-f5e84680-c1c1-11e9-8c2d-6d2079cee662.png"></a>
<h3><code>getLevel(): <a href="/src/etc/types.ts#L37-L57">LevelDescriptor</a></code></h3>

Returns a `LevelDescriptor` object for the current log level.

**Example:**

Assuming the current level is `info`:

```ts
const curLevel = log.getLevel();

curLevel.label //=> 'info'
curLevel.level //=> 6000
curLevel.style //=> StyleFunction
```

<a href="#top"><img src="https://user-images.githubusercontent.com/441546/63230477-f5e84680-c1c1-11e9-8c2d-6d2079cee662.png"></a>
<h3><code>getLevels(): {[key: string]: <a href="/src/etc/types.ts#L37-L57">LevelDescriptor</a>}</code></h3>

Returns an object mapping log level names (ex: `info`) to `LevelDescriptor` objects for each configured level. Note: The logger does not implement a method for the `silent` level.

<a href="#top"><img src="https://user-images.githubusercontent.com/441546/63230477-f5e84680-c1c1-11e9-8c2d-6d2079cee662.png"></a>
<h3><code>isLevelAtLeast(name: string): boolean</code></h3>

Returns `true` if a message written at the provided log level would be written to the output stream based on the current log level.

**Example:**

```ts
log.configure({level: 'info'});
log.isLevelAtLeast('error') //=> true
log.isLevelAtLeast('silly') //=> false
```

<a href="#top"><img src="https://user-images.githubusercontent.com/441546/63230477-f5e84680-c1c1-11e9-8c2d-6d2079cee662.png"></a>
<h3><code>prefix(prefix: <a href="/src/etc/types.ts#L10-L13">Primitive</a>): <a href="/src/etc/types.ts#L66-L75">Prefix</a></code></h3>


Applies a prefix, styled according to the logger's `style.prefix` options, to each line written to the output stream for the current call.

**Example:**

```ts
log.info(log.prefix('someFunction'), 'Hello\nworld.');
```

<p align="center">
  <img src="https://user-images.githubusercontent.com/441546/64510094-20e02a80-d296-11e9-88fe-a04099676c25.png" max-width="100%">
</p>

<a href="#top"><img src="https://user-images.githubusercontent.com/441546/63230477-f5e84680-c1c1-11e9-8c2d-6d2079cee662.png"></a>
<h3><code>addSecret(secret: <a href="/src/etc/types.ts#L10-L13">Primitive</a> | RegExp, maskChar = '*'): void</code></h3>

This method may be used to ensure passwords and other sensitive information are not inadvertently written to the output stream. It accepts either a string literal or a regular expression and an optional mask character. By default, secrets are masked using `*`.

**Example:**

```ts
const user = {
  name: 'Frodo',
  password: 'shire'
};

log.addSecret(user.password);
log.info('User data:', user);
```

<p align="center">
  <img src="https://user-images.githubusercontent.com/441546/64510491-24c07c80-d297-11e9-935a-3e1f2cb4e38e.png" max-width="100%">
</p>

<a href="#top"><img src="https://user-images.githubusercontent.com/441546/63230477-f5e84680-c1c1-11e9-8c2d-6d2079cee662.png"></a>
<h3><code>createPipe(level: string): <a href="https://nodejs.org/api/stream.html#stream_writable_streams">NodeJS.WritableStream</a></code></h3>

Creates a writable stream that will output any data written to it as log messages at the indicated level. Useful for displaying the output of a child process, for example.

In the following example, all output written to `process.stderr` by the child process will be written as log messages at the `verbose` level.

**Example:**

```ts
import execa from 'execa';

log.info('Starting child process...');

const childProcess = execa('echo', ['"I am a banana!"'], {stdout: 'pipe'});
childProcess.stdout.pipe(log.createPipe('verbose'));

await childProcess;

log.info('Done.');
```

<p align="center">
  <img src="https://user-images.githubusercontent.com/441546/64511027-466e3380-d298-11e9-8dd7-a496cd7a459c.png" max-width="100%">
</p>

<a href="#top"><img src="https://user-images.githubusercontent.com/441546/63230477-f5e84680-c1c1-11e9-8c2d-6d2079cee662.png"></a>
<h3><code>beginInteractive(<a href="/src/etc/types.ts#L80-L85">MessageFn</a> | <a href="/src/etc/types.ts#L88-L100">BeginInteractiveOptions</a>): <a href="/src/etc/types.ts#L98">EndInteractiveFn</a></code></h3>

Begins a new interactive session and returns a function that may be invoked to end the interactive session. This method accepts either an options object or a function that will be invoked to render each update during the interactive session. If a custom interval is not being used, the shorthand (message function only) form is recommended.

The function returned by `beginInteractive` accepts a function that will be invoked to produce the final content written to the interactive line(s).

**Example:**

```ts
const spinner = log.createSpinner();
const time = log.createTimer();
const endInteractive = log.beginInteractive(() => log.info(`${spinner} Please stand by...`));

// Some time later...

endInteractive(() => log.info(`Done in ${time}.`));
```

> screenshot(s) here

<a href="#top"><img src="https://user-images.githubusercontent.com/441546/63230477-f5e84680-c1c1-11e9-8c2d-6d2079cee662.png"></a>
<h3><code>createTimer(options?: <a href="https://github.com/sindresorhus/pretty-ms/blob/master/index.d.ts#L2-L64">TimerOptions</a>): <a href="/src/lib/timer.ts#L15-L28">Timer</a></code></h3>

Creates a timer (chronograph) that starts immediately. The timer object may be placed directly into an interpolated string literal and will render its current value. Formatting is facilitated using [`pretty-ms`](https://github.com/sindresorhus/pretty-ms), and this method's options are identical to those of `pretty-ms`.

Additionally, the timer object has a `#reset()` method that may be invoked to reset the timer to zero.

**Example:**

```ts
const timer = log.createTimer();

// Some time later...

log.info(`Done in ${timer}.`);
```

> screenshot(s) here.

<a href="#top"><img src="https://user-images.githubusercontent.com/441546/63230477-f5e84680-c1c1-11e9-8c2d-6d2079cee662.png"></a>
<h3><code>createProgressBar(options: <a href="/src/lib/progress-bar.ts#L7-L88">ProgressBarOptions</a>): <a href="/src/lib/progress-bar.ts#L91-L96">ProgressBar</a></code></h3>

Creates a progress bar. The progress bar object may be placed directly into an interpolated string literal and will render its current value. The only required option for this method is `getProgress`, a function that will be invoked every time the progress bar is rendered, and should return a number between `0` and `1` indicating how full the bar should be.

**Example:**

```ts
import axios from 'axios';

let completed = 0;

const progressBar = log.createProgressBar({
  // `getProgress` can simply return the value of `completed`.
  getProgress: () => completed
});

// Begin an interactive session that will continuously render our progress bar
// while the download is outstanding.
const endInteractive = log.beginInteractive(() => log.info(`Downloading file: ${progressBar}`));

// Download a file with Axios.
const download = await axios({
  url: 'https://my.domain.com/some-file.zip',
  onDownloadProgress: (progressEvent) => {
    // On each progress event, update our `completed` variable.
    completed = progressEvent.loaded / progressEvent.total;
  }
});

// Finally, end our interactive session.
endInteractive(() => log.info('Download complete.'));
```

<a href="#top"><img src="https://user-images.githubusercontent.com/441546/63230477-f5e84680-c1c1-11e9-8c2d-6d2079cee662.png"></a>
<h3><code>createSpinner(options?: <a href="/src/lib/spinner.ts#L7-L19">SpinnerOptions</a>): <a href="/src/lib/spinner.ts#L22-L27">Spinner</a></code></h3>

Creates a spinner. The spinner object may be placed directly into an interpolated string literal and will render its current value. The only option this method accepts is `name`, which should be a valid [`cli-spinners`](https://github.com/sindresorhus/cli-spinners) [spinner name](https://jsfiddle.net/sindresorhus/2eLtsbey/embedded/result/). If no options are provided, the `dots` spinner will be used.

**Example:**

```ts
const spinner = log.createSpinner();

const endInteractive = log.beginInteractive(() => log.info(`${spinner} Reticulating splines...`));

// Once all splines have been reticulated...

endInteractive(() => log.info(`Done.`));
```

## Debug Support

...

## Caveats

...

## &nbsp;
<p align="center">
  <br>
  <img width="22" height="22" src="https://cloud.githubusercontent.com/assets/441546/25318539/db2f4cf2-2845-11e7-8e10-ef97d91cd538.png">
</p>

---
_Source: https://npm.io/package/@darkobits/log · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
