# Modifiers

Once you have an Adze log instance you can now start applying modifiers. Modifiers are methods that alter the log in some way and then return the log instance so that you may chain more modifiers or terminate the instance. Keep in mind, some modifiers have a dependency on the presence of a label and labels rely on Shed.

# assert

This modifier accepts an assertion boolean expression and will only print if the boolean expression fails (is a falsy value).

MDN Docs (opens new window)

# Interface

class BaseLog {
  public assert(assertion: boolean): this;
}

# Example

import { adze } from 'adze';

const x = 2;
const y = 3;

// Let's assert that x and y should be equal
adze()
  .assert(x === y)
  .log('X does not equal Y');

// This log will not print because the assertion passes
adze()
  .assert(x === 2)
  .log('X does not equal 2');

// Let's look at the output with emoji's enabled
adze({ useEmoji: true })
  .assert(x === y)
  .log('X does not equal Y');

# Output

assert modifier example output

assert modifier example terminal output

# count

The count modifier tells the log to increment a counter associated to the log's label.

MDN Docs (opens new window)

# Interface

class BaseLog {
  public get count(): this;
}

# Example

import { adze, createShed } from 'adze';

// A shed is required for labels and modifiers that depend on them
createShed();

for (let i = 0; i < 5; i += 1) {
  adze().label('my-counter').count.log('Counting iterations.');
}

# Output

Count modifier output

Count modifier terminal output

# countClear

The countClear modifier completely clears the count from a label. Rather than setting the count to 0 it instead becomes null.

NOTE: This method is deliberately a modifier rather than a terminator because it forces you to write a log that gives you insight into when a counter was cleared. It also makes the countClear log recallable from a bundle or the Shed in the order it was created.

This is not a standard API.

# Interface

class BaseLog {
  public get countClear(): this;
}

# Example

import { adze, createShed } from 'adze';

// A shed is required for labels and modifiers that depend on them
createShed();

for (let i = 0; i < 4; i += 1) {
  adze().label('my-counter').count.log('Counting iterations.');
}

adze().label('my-counter').countClear.log('Clearing the counter.');

adze().label('my-counter').log('A log with the my-counter label but no count.');

# Output

count clear modifier example output

# countReset

The countReset modifier resets the counter associated to the log's label to 0.

NOTE: This method is deliberately a modifier rather than a terminator because it forces you to write a log that gives you insight into when a counter was reset. It also makes the countReset log recallable from a bundle or the Shed in the order it was created.

MDN Docs (opens new window)

# Interface

class BaseLog {
  public get countReset(): this;
}

# Example

import { adze, createShed } from 'adze';

// A shed is required for labels and modifiers that depend on them
createShed();

for (let i = 0; i < 4; i += 1) {
  adze().label('my-counter').count.log('Counting iterations.');
}

adze().label('my-counter').countReset.log('Resetting the counter.');

for (let i = 0; i < 4; i += 1) {
  adze().label('my-counter').count.log('Counting iterations again.');
}

# Output

count reset modifier example output

count reset modifier example terminal output

# dir

The dir modifier transforms the output of the log by directing it to use the console.dir() method for printing purposes only.

NOTE: Logs that use dir as a modifier should only be given a single argument which is usually an object. If multiple arguments are given, behavior may differ between browser and node environments. Refer to the MDN docs for more details.

MDN Docs (opens new window)

# Interface

class BaseLog {
  public get dir(): this;
}

# Example

import { adze } from 'adze';

adze().dir.log({ foo: 'bar' });

# Output

dir modifier output

dir modifier terminal output

# dirxml

The dirxml modifier transforms the output of the log by directing it to use the console.dirxml() method for printing purposes only. This is mainly useful for logging out DOM elements.

NOTE: Logs that use dirxml as a modifier should only be given a single argument which is usually a DOM Element or other XML object. If multiple arguments are given, behavior may differ between browser and node environments. Refer to the MDN docs for more details.

MDN Docs (opens new window)

# Interface

class BaseLog {
  public get dirxml(): this;
}

# Example

import { adze } from 'adze';

// create a new div element
const newDiv = document.createElement('div');
newDiv.setAttribute('id', 'test');
// and give it some content
const newContent = document.createTextNode('Hi there and greetings!');
// add the text node to the newly created div
newDiv.appendChild(newContent);

adze().dirxml.log(newDiv);

# Output

dirxml modifier output

dirxml modifier terminal output

# dump

This modifier instructs the labeled log to print the context values from a thread.

Refer to the Mapped Diagnostic Context (MDC) page for more information about the purpose of MDC.

This modifier is dependent upon having a label and a Shed.

This is not a standard API.

# Interface

class BaseLog {
  public get dump(): this;
}

# Example

import { adze, createShed } from 'adze';

const shed = createShed();

// Creating a shed listener is a great way to get meta data from your
// threaded logs to write to disk or pass to another plugin, library,
// or service.
shed.addListener([1, 2, 3, 4, 5, 6, 7, 8], (log) => {
  // Do something with `log.context.added` or `log.context.subtracted`.
});

function add(a, b) {
  const answer = a + b;
  adze().label('foo').thread('added', { a, b, answer });
  return answer;
}

function subtract(x, y) {
  const answer = x - y;
  adze().label('foo').thread('subtracted', { x, y, answer });
  return answer;
}

add(1, 2);
subtract(4, 3);

adze().label('foo').dump.info('Results from our thread');

# Output

dump modifier example output

dump modifier terminal example output

# group

The group modifier starts an uncollapsed group of logs. This means that all subsequent logs will be nested beneath this log until a groupEnd log occurs.

MDN Docs (opens new window)

# Interface

class BaseLog {
  public get group(): this;
}

# Example

import { adze } from 'adze';

// Some info about our app.
const version = 'v1.0.0';
const browser = 'firefox';

adze().group.info('App Information');
adze().info(`Version: ${version}`);
adze().info(`Browser: ${browser}`);
adze().groupEnd.info();

# Output

group modifier example output

group modifier terminal example output

# groupCollapsed

The groupCollapsed modifier starts an collapsed group of logs. This means that all subsequent logs will be nested beneath this log until a groupEnd log occurs.

Note: This will not be collapsed in a terminal environment since there is no way to uncollapse it.

MDN Docs

# Interface

class BaseLog {
  public get groupCollapsed(): this;
}

# Example

import { adze } from 'adze';

// Some info about our app.
const version = 'v1.0.0';
const browser = 'firefox';

adze().groupCollapsed.info('App Information');
adze().info(`Version: ${version}`);
adze().info(`Browser: ${browser}`);
adze().groupEnd.info();

# Output

groupCollapsed modifier example output

groupCollapsed modifier terminal example output

# groupEnd

The groupEnd modifier ends a log group. Any logs following a groupEnd will no longer be grouped.

MDN Docs (opens new window)

# Interface

class BaseLog {
  public get groupEnd(): this;
}

# Example

import { adze } from 'adze';

// Some info about our app.
const version = 'v1.0.0';
const browser = 'firefox';

adze().group.info('App Information');
adze().info(`Version: ${version}`);
adze().info(`Browser: ${browser}`);
adze().groupEnd.info(); // <-- Ends the group

adze().info('Some other information...');

# Output

groupEnd modifier example output

groupEnd modifier terminal example output

# label

Applies an identifying label to a log. If a Shed is present, all logs that share the same label will be linked together behind the scenes. This enables global tracking for modifiers that require a label as a prerequisite.

These are the modifiers that require a label and a Shed to be useful:

This is not a standard API.

# Interface

class BaseLog {
  public label(name: string): this;
}

# Example

import { adze, createShed } from 'adze';

createShed();

// Labels can be applied in any order in a modifier chain
adze().count.label('foo').log('Bar');
adze().label('foo').count.log('Foo');

# Output

label modifier example output

label modifier terminal example output

# meta

The meta modifier allows you to attach meta data to your log instance. You can then retrieve it at a later time from within a log listener or by calling the data() method on a log instance.

This is not a standard API.

# Interface

The interface of meta<KV extends [string, any]>(...[key, val]: KV): this; is available for Adze versions >= 1.2.0

class BaseLog {
  // Types are Overloaded
  public meta<T>(key: string, val: T): this;
  public meta<KV extends [string, any]>(...[key, val]: KV): this;
}

# Example

import { adze, createShed } from 'adze';

// Let's optionally create a shed to show the use of meta data on listeners
const shed = createShed();

// We'll listen only to logs of level 6 which is "log"
shed.addListener([6], (data) => {
  adze().info("My log's meta data!", data.meta);
});

// Let's create a super important message to attach as meta data
const info = 'Hello World!';

adze().meta('message', info).log('This log contains an important message.');
import { adze, createShed } from 'adze';

// Let's optionally create a shed to show the use of meta data on listeners
const shed = createShed();

// We'll listen only to logs of level 6 which is "log"
shed.addListener([6], (data) => {
  adze().info("My log's meta data!", data.meta);
});

// Let's create a super important message to attach as meta data
const info = 'Hello World!';

adze().meta('message', info).log('This log contains an important message.');

# Output

meta modifier output with listener output

meta modifier terminal output with listener output

# namespace / ns

This modifier adds one or more namespaces to a log. Multiple calls to the namespace modifier are additive by nature and will not overwrite previously applied namespaces. These are mainly used as human readable group identifiers but are also useful for filtering recalled logs and for identifying logs from a log listener. This modifier does not do any special grouping under the hood. The ns() method is just a shorter alias for namespace().

As of version 1.7.0, Adze now supports passing a Constraints type to the log factory that will allow you to centrally specify what namespaces are allowed to be used. This is beneficial because it will force users to add any new namespace that they might want to add to the central allowedNamespaces type property. This will make it easier to filter namespaces throughout your application because you will only have a single place to look to understand what namespaces are being used.

Rest-of operator for namespace/ns available in Adze >= v1.5.0

Namespace constraint type available in Adze >= 1.7.0

Namespaces became additive by nature in Adze >= 1.8.0

This is not a standard API.

# Interface

class BaseLog {
  public namespace(ns: string | string[]): this;
  public ns(ns: string | string[]): this;
  // Or alternatively with the restof operator (versions >= 1.5.0)
  public namespace(...ns: string[]): this;
  public ns(...ns: string[]): this;
}

# Example

import { adze } from 'adze';

adze().namespace('tix-123').log('Important info for a feature.');
adze()
  .namespace(['tix-123', 'tix-456'])
  .log('Important info for multiple features.');
adze()
  .namespace('tix-123', 'tix-456', 'tix-789')
  .log('Multiple namespace entry simplified by the restof operator.');
// ns() is a shorthand alias for namespace()
adze().ns('tix-456').log('More info');
// Multiple calls to namespace/ns are additive
adze().ns('foo', 'bar').ns('baz').log('This log has all applied namespaces.');

//----- Example with TS Constraints -----//
import adze, { Constraints } from 'adze';

// First we will create our app constraints by extending the Constraint interface
interface MyAppConstraints extends Constraints {
  allowedNamespaces: 'foo' | 'bar' | 'hello' | 'world';
}

// Now we apply the constraints to our app's logger factory
const logger = adze<MyAppConstraints>().seal();

// Now when we define namespaces for a log a type error will be thrown if the 
// namespace provided isn't in the allowedNamespaces union type.
logger().ns('foo', 'bar', 'baz').fail('This is not allowed.');
//                        ^^^^^
// Argument of type '"baz"' is not assignable to parameter of type '"foo" | "bar" | "hello" | "world"'.

# Output

namespace modifier example output

namespace modifier terminal example output

# silent

The silent modifier allows a log to be terminated and cached but prevents it from printing to the console. This can be useful for providing a log to a log listener that you do not want to have printed.

This is not a standard API.

# Interface

class BaseLog {
  public get silent(): this;
}

# Example

import { adze } from 'adze';

adze().log('Hello World!');
adze().silent.log('Crickets...');
adze().log('I guess nobody is home :(');

# Output

example of silent log output

example of silent log terminal output

# table

The table modifier transforms the output of the log by directing it to use the console.table() method for printing purposes only.

MDN Docs (opens new window)

# Interface

class BaseLog {
  public get table(): this;
}

# Example

import { adze } from 'adze';

const tabular_data = [
  { firstName: 'Andrew', lastName: 'Stacy' },
  { firstName: 'Jim', lastName: 'Bob' },
];

adze().table.log(tabular_data);

# Output

table modifier output

table modifier terminal output

# test

This modifier accepts a boolean expression and will only print if the boolean expression passes (is a truthy value).

This is not a standard API.

# Interface

class BaseLog {
  public test(expression: boolean): this;
}

# Example

import { adze } from 'adze';

const x = 2;
const y = 3;

// Let's test that x equals 2
adze()
  .test(x === 2)
  .log('X equals 2');

// This log will not print because the test fails
adze()
  .test(x === y)
  .log('X does not equal Y');

// Let's look at the output with emoji's enabled
adze({ useEmoji: true })
  .test(y === 3)
  .log('Y equals 3');

# Output

test modifier example output

test modifier terminal example output

# time

This modifier starts a timer associated to the log's label. This is useful for taking performance measurements. A log with a time modifier must be followed by a log with a timeEnd modifier in order to get the final measurement.

This modifier is dependent upon having a label and a Shed.

MDN Docs (opens new window)

# Interface

class BaseLog {
  public get time(): this;
}

# Example

import { adze, createShed } from 'adze';

createShed();

// Let's create a timer for performance
adze().label('loop').time.log('Starting a timer.');

for (let i = 0; i < 10000; i += 1) {
  // Do a lot of stuff that takes time
}

// End the timer to get the loop performance
adze().label('loop').timeEnd.log('Performance of our loop.');

// Let's see the output with emoji's
adze({ useEmoji: true }).label('loop').timeEnd.log('Performance of our loop.');

# Output

time modifier example output

time modifier terminal example output

# timeEnd

This modifier ends a timer associated to the log's label. This is useful for taking performance measurements. A log with a timeEnd modifier must be preceded by a log with a time modifier in order to get the final measurement.

This modifier is dependent upon having a label and a Shed.

MDN Docs (opens new window)

# Interface

class BaseLog {
  public get time(): this;
}

# Example

import { adze, createShed } from 'adze';

createShed();

// Let's create a timer for performance
adze().label('loop').time.log('Starting a timer.');

for (let i = 0; i < 10000; i += 1) {
  // Do a lot of stuff that takes time
}

// End the timer to get the loop performance
adze().label('loop').timeEnd.log('Performance of our loop.');

// Let's see the output with emoji's
adze({ useEmoji: true }).label('loop').timeEnd.log('Performance of our loop.');

# Output

time end modifier example output

time end modifier example output

# timeNow

This modifier logs the time ellapsed since the page has loaded. This is useful for measuring page load performance rather than performance of a particular piece of code. This modifier is not dependent upon a label or Shed.

This is not a standard API.

# Interface

class BaseLog {
  public get timeNow(): this;
}

# Example

import { adze } from 'adze';

for (let i = 0; i < 10000; i += 1) {
  // Do a lot of stuff that takes time
}

// Let's create a timer for performance
adze().timeNow.log('Recording the time ellapsed since page load.');

// Let's see what it looks like with emoji's enabled.
adze({ useEmoji: true }).timeNow.log(
  'Recording the time ellapsed since page load.'
);

# Output

time now modifier example output

time now modifier terminal example output

# timestamp

This modifier instructs the log to render an ISO 8601 (opens new window) timestamp.

This is not a standard API.

Version >= 1.1

# Interface

class BaseLog {
  public get timestamp(): this;
}

# Example

import { adze } from 'adze';

adze().label('timestamped').timestamp.log('This log has a timestamp.');

# Output

timestamp modifier example output

timestamp modifier terminal example output

# trace

This modifier instructs the log to print a stacktrace using the standard console.trace() method.

NOTE: The styling for logs using this modifier varies by browser. Chrome will render the log message with proper styling while Firefox will only render the message unstyled.

MDN Docs (opens new window)

# Interface

class BaseLog {
  public get trace(): this;
}

# Example

import { adze } from 'adze';

adze().trace.log('Trying to find an issue...');

# Output

trace modifier example output

trace modifier example terminal output