PailUsage GuidesCustom Types

Custom Types

Create custom log types for semantic logging

Last updated:

Custom Types

Custom log types allow you to create semantic logging methods that better represent your application's domain.

Creating Custom Types

Define custom types when creating a logger:

import { createPail } from "@visulima/pail";

const logger = createPail({
    types: {
        http: {
            badge: "🌐",
            color: "blue",
            label: "HTTP",
            logLevel: "info",
        },
        db: {
            badge: "💾",
            color: "cyan",
            label: "DATABASE",
            logLevel: "debug",
        },
    },
});

logger.http("GET /api/users 200");
logger.db("Query executed", { query: "SELECT * FROM users" });

Type Configuration

Each custom type requires:

  • label (required) - Display label for the log type
  • logLevel (required) - The log level to use
  • color (optional) - ANSI color for styling
  • badge (optional) - Icon or symbol prefix
{
  label: "HTTP",           // Required: Display name
  logLevel: "info",        // Required: Log level
  color: "blue",           // Optional: Color name
  badge: "🌐",            // Optional: Icon/symbol
}

Available Colors

Pail supports ANSI colors from @visulima/colorize:

  • black, red, green, yellow, blue, magenta, cyan, white
  • blackBright, redBright, greenBright, yellowBright, blueBright, magentaBright, cyanBright, whiteBright
  • gray
const logger = createPail({
    types: {
        success: { color: "greenBright", label: "SUCCESS", logLevel: "info" },
        warning: { color: "yellowBright", label: "WARNING", logLevel: "warning" },
    },
});

Overriding Default Types

You can override default types to customize their appearance:

import { createPail } from "@visulima/pail";

const logger = createPail({
    types: {
        error: {
            badge: "❌",
            color: "redBright",
            label: "ERROR",
            logLevel: "error",
        },
        success: {
            badge: "✅",
            color: "greenBright",
            label: "SUCCESS",
            logLevel: "info",
        },
    },
});

logger.error("Custom error style");
logger.success("Custom success style");

Real-World Examples

HTTP Logger

const logger = createPail({
    types: {
        http: {
            badge: "🌐",
            color: "blue",
            label: "HTTP",
            logLevel: "info",
        },
        httpError: {
            badge: "⚠️",
            color: "red",
            label: "HTTP_ERROR",
            logLevel: "error",
        },
    },
});

logger.http("GET /api/users 200", { duration: 45 });
logger.httpError("POST /api/users 500", { error: "Database error" });

Database Logger

const logger = createPail({
    types: {
        db: {
            badge: "💾",
            color: "cyan",
            label: "DATABASE",
            logLevel: "debug",
        },
        dbQuery: {
            badge: "🔍",
            color: "blueBright",
            label: "QUERY",
            logLevel: "debug",
        },
        dbError: {
            badge: "❌",
            color: "red",
            label: "DB_ERROR",
            logLevel: "error",
        },
    },
});

logger.db("Connected to database");
logger.dbQuery("SELECT * FROM users", { duration: 12 });
logger.dbError("Connection failed", error);

Security Logger

const logger = createPail({
    types: {
        security: {
            badge: "🔒",
            color: "yellow",
            label: "SECURITY",
            logLevel: "warning",
        },
        auth: {
            badge: "🔐",
            color: "magenta",
            label: "AUTH",
            logLevel: "info",
        },
    },
});

logger.security("Suspicious activity detected", { ip: "192.168.1.1" });
logger.auth("User logged in", { userId: 123 });

Background Job Logger

const logger = createPail({
    types: {
        job: {
            badge: "⚙️",
            color: "cyan",
            label: "JOB",
            logLevel: "info",
        },
        jobStart: {
            badge: "▶️",
            color: "green",
            label: "JOB_START",
            logLevel: "info",
        },
        jobComplete: {
            badge: "✅",
            color: "greenBright",
            label: "JOB_COMPLETE",
            logLevel: "info",
        },
        jobError: {
            badge: "❌",
            color: "red",
            label: "JOB_ERROR",
            logLevel: "error",
        },
    },
});

logger.jobStart("Processing queue");
logger.job("Processing item", { itemId: 456 });
logger.jobComplete("Queue processed", { itemsProcessed: 100 });
logger.jobError("Job failed", error);

TypeScript Support

Custom types are fully typed:

import { createPail } from "@visulima/pail";

type CustomTypes = "http" | "db" | "cache";

const logger = createPail<CustomTypes>({
    types: {
        http: { label: "HTTP", logLevel: "info" },
        db: { label: "DB", logLevel: "debug" },
        cache: { label: "CACHE", logLevel: "debug" },
    },
});

// TypeScript knows about custom types
logger.http("GET /api/users"); // ✅ Type-safe
logger.db("Query executed"); // ✅ Type-safe
logger.cache("Cache hit"); // ✅ Type-safe
logger.unknown("Test"); // ❌ Type error

Combining with Scopes

Custom types work great with scoped loggers:

const apiLogger = logger.scope("api");

apiLogger.http("GET /users 200");
apiLogger.http("POST /users 201");
// Output: [api] 🌐 HTTP GET /users 200

Best Practices

  1. Use semantic names - Names should reflect their purpose
  2. Consistent styling - Use consistent colors/badges for similar types
  3. Appropriate log levels - Match log levels to severity
  4. Document your types - Keep a reference of custom types
  5. Don't overuse - Too many types can be confusing
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