PailConceptsReporters

Reporters

Understanding reporters in Pail

Last updated:

Reporters

Reporters are responsible for writing log messages to various destinations. They receive processed log metadata and format it for output.

Built-in Reporters

JsonReporter

Outputs structured JSON logs. Available for both browser and server.

Server:

import { createPail } from "@visulima/pail";
import { JsonReporter } from "@visulima/pail/reporter/json";

const logger = createPail({
    reporters: [new JsonReporter()],
});

logger.info("Server started", { port: 3000 });
// Output: {"type":{"name":"info","level":"informational"},"message":"Server started","context":[{"port":3000}],"date":"2024-01-01T12:00:00.000Z"}

Browser:

import { createPail } from "@visulima/pail/browser";
import { JsonReporter } from "@visulima/pail/reporter/json";

const logger = createPail({
    reporters: [new JsonReporter()],
});

PrettyReporter

Beautiful formatted console output with colors and styling. Available for both browser and server.

Server:

import { createPail } from "@visulima/pail";
import { PrettyReporter } from "@visulima/pail/reporter/pretty";

const logger = createPail({
    reporters: [new PrettyReporter()],
});

logger.success("Operation completed");
// Output: ✓ success Operation completed

Browser:

import { createPail } from "@visulima/pail/browser";
import { PrettyReporter } from "@visulima/pail/reporter/pretty";

const logger = createPail({
    reporters: [new PrettyReporter()],
});

SimpleReporter

Simple formatted output with error inspection. Server only.

import { createPail } from "@visulima/pail";
import { SimpleReporter } from "@visulima/pail/reporter/simple";

const logger = createPail({
    reporters: [new SimpleReporter()],
});

FileReporter (JsonFileReporter)

Writes logs to rotating files. Server only. Requires rotating-file-stream package.

import { createPail } from "@visulima/pail";
import { JsonFileReporter } from "@visulima/pail/reporter/file";

const logger = createPail({
    reporters: [
        new JsonFileReporter({
            filePath: "/var/log/app.log",
            interval: "1d", // Rotate daily
            size: "10M", // Rotate when file reaches 10MB
            compress: "gzip",
        }),
    ],
});

Reporter Comparison

ReporterBrowserServerOutput FormatUse Case
JsonReporterJSONStructured logging, log aggregation
PrettyReporterFormatted textDevelopment, debugging
SimpleReporterSimple textMinimal output
FileReporterJSON filesProduction logging

Using Multiple Reporters

You can use multiple reporters simultaneously:

import { createPail } from "@visulima/pail";
import { JsonReporter } from "@visulima/pail/reporter/json";
import { PrettyReporter } from "@visulima/pail/reporter/pretty";
import { JsonFileReporter } from "@visulima/pail/reporter/file";

const logger = createPail({
    reporters: [
        new PrettyReporter(), // Console output
        new JsonFileReporter({ filePath: "./logs/app.log" }), // File output
    ],
});

logger.info("Message"); // Sent to both reporters

Creating Custom Reporters

Implement the Reporter interface:

import type { Reporter, ReadonlyMeta } from "@visulima/pail";

class CustomReporter<L extends string = string> implements Reporter<L> {
    public log(meta: ReadonlyMeta<L>): void {
        // Your custom logic here
        console.log(`[${meta.type.name}] ${meta.message}`);
    }
}

const logger = createPail({
    reporters: [new CustomReporter()],
});

Stream-Aware Reporter (Server)

For server-side reporters that need stdout/stderr:

import type { StreamAwareReporter } from "@visulima/pail";

class StreamReporter<L extends string = string> implements StreamAwareReporter<L> {
    #stdout: NodeJS.WriteStream;
    #stderr: NodeJS.WriteStream;

    public setStdout(stdout: NodeJS.WriteStream): void {
        this.#stdout = stdout;
    }

    public setStderr(stderr: NodeJS.WriteStream): void {
        this.#stderr = stderr;
    }

    public log(meta: ReadonlyMeta<L>): void {
        const stream = meta.type.level === "error" ? this.#stderr : this.#stdout;
        stream.write(`${JSON.stringify(meta)}\n`);
    }
}

Logger Types Aware Reporter

To customize output based on logger types:

import type { LoggerTypesAwareReporter, LoggerTypesConfig } from "@visulima/pail";

class TypesAwareReporter<T extends string, L extends string = string> implements LoggerTypesAwareReporter<T, L> {
    private types: LoggerTypesConfig<T, L> = {};

    public setLoggerTypes(types: LoggerTypesConfig<T, L>): void {
        this.types = types;
    }

    public log(meta: ReadonlyMeta<L>): void {
        const typeConfig = this.types[meta.type.name];
        // Use typeConfig for custom formatting
    }
}

Reporter Options

JsonReporter Options

import { JsonReporter } from "@visulima/pail/reporter/json";

new JsonReporter({
    error: {
        // Error serialization options
        includeStack: true,
        includeCause: true,
    },
});

PrettyReporter Options

import { PrettyReporter } from "@visulima/pail/reporter/pretty";

new PrettyReporter({
    uppercase: {
        label: true, // Uppercase labels
    },
    bold: {
        label: false,
    },
    underline: {
        label: false,
        message: false,
    },
});

FileReporter Options

import { JsonFileReporter } from "@visulima/pail/reporter/file";

new JsonFileReporter({
    filePath: "./logs/app.log",
    interval: "1d", // Daily rotation
    size: "10M", // Rotate at 10MB
    compress: "gzip", // Compress old files
    writeImmediately: false, // Buffer writes
});

Raw Reporter

The raw reporter bypasses normal processing and is used internally for direct output:

const logger = createPail({
    rawReporter: new CustomRawReporter(),
});

logger.raw("Direct message"); // Uses rawReporter
Support

Contribute to our work and keep us going

Community is the heart of open source. The success of our packages wouldn't be possible without the incredible contributions of users, testers, and developers who collaborate with us every day.Want to get involved? Here are some tips on how you can make a meaningful impact on our open source projects.

Ready to help us out?

Be sure to check out the package's contribution guidelines first. They'll walk you through the process on how to properly submit an issue or pull request to our repositories.

Submit a pull request

Found something to improve? Fork the repo, make your changes, and open a PR. We review every contribution and provide feedback to help you get merged.

Good first issues

Simple issues suited for people new to open source development, and often a good place to start working on a package.
View good first issues