Blyp Docs

Basic Usage

In your terminal, log levels are color-coded: INFO is blue, SUCCESS is green, WARNING is yellow, ERROR is red, and CRITICAL is bold red.

Root logger

The root logger export is a proxy around a default standalone logger instance.

import { logger } from "@blyp/core";

logger.info("server started on port 3000");
logger.success("database connection established");
logger.warning("rate limit approaching for user 42");
logger.error("failed to reach payment provider");

Terminal output:

[INFO]    server started on port 3000
[SUCCESS] database connection established
[WARNING] rate limit approaching for user 42
[ERROR]   failed to reach payment provider

SUCCESS appears in green, WARNING in yellow, and ERROR in red in a real terminal session.

Log levels

Use the full set of Blyp log levels when you want severity to stay obvious at a glance.

logger.debug("cache lookup: key=session:abc123");
logger.info("server started on port 3000");
logger.success("database connection established");
logger.warning("rate limit approaching", {
  userId: 42,
  remaining: 10,
});
logger.error("failed to reach payment provider", {
  timeoutMs: 5000,
});
logger.critical("out of memory", {
  heapUsedPercent: 98,
});

Terminal output:

[DEBUG]    cache lookup: key=session:abc123
[INFO]     server started on port 3000
[SUCCESS]  database connection established
[WARNING]  rate limit approaching userId=42 remaining=10
[ERROR]    failed to reach payment provider timeoutMs=5000
[CRITICAL] out of memory heapUsedPercent=98

Structured messages and metadata

Every log method accepts a message and optional extra arguments.

logger.info("user login", {
  userId: "usr_123",
  tenantId: "tenant_456",
});

logger.table("feature flags", {
  betaCheckout: true,
  useEdgeCache: false,
});

Terminal output:

[INFO] user login userId=usr_123 tenantId=tenant_456
[TABLE] feature flags
  betaCheckout=true
  useEdgeCache=false

Child loggers

Use child() when you want stable bindings on every log line.

const paymentsLog = logger.child({
  service: "payments",
  region: "eu-west-1",
});

paymentsLog.info("authorized");
paymentsLog.error("capture failed", { provider: "stripe" });

Terminal output:

[INFO]  authorized service=payments region=eu-west-1
[ERROR] capture failed service=payments region=eu-west-1 provider=stripe

Structured request batches

Use createStructuredLog() when a request or workflow should produce one final structured payload instead of many unrelated lines.

import { createStructuredLog } from "@blyp/core";

const structuredLog = createStructuredLog("checkout", {
  service: "web-api",
  timestamp: new Date().toISOString(),
});

structuredLog.set({
  user: { id: 1, plan: "pro" },
  cart: { items: 3, total: 9999 },
  payment: { method: "card", status: "success" },
});

structuredLog.emit({
  status: 200,
  message: "POST /checkout",
});

Terminal output on .emit():

[INFO] POST /checkout
  service=web-api
  user.id=1 user.plan=pro
  cart.items=3 cart.total=9999
  payment.method=card payment.status=success
  status=200

Without structured logs - scattered output, hard to correlate:

[INFO] user logged in
[INFO] item added to cart
[INFO] payment processing
[INFO] order created

With structured logs - one rich event on .emit():

[INFO] POST /checkout
  service=web-api
  user.id=1 user.plan=pro
  cart.items=3 cart.total=9999
  payment.method=card payment.status=success
  status=200

Nothing is logged until .emit() is called. All .set() calls accumulate context silently. The final emitted event contains everything in one line or structured pretty block.

This is especially useful inside framework handlers because the same root import automatically binds to the active request logger. See Structured Logs for the typed generic form, emit options, and request-scoped behavior.

Dedicated standalone instances

If you need a logger with different level, output directory, or file options, create an instance explicitly.

import { createStandaloneLogger } from "@blyp/core";

const log = createStandaloneLogger({
  level: "debug",
  pretty: true,
  logDir: "logs/payments",
  clientLogging: {
    enabled: true,
    path: "/client-logs",
  },
});

log.info("standalone logger ready");

Terminal output:

[INFO] standalone logger ready

Root import vs @blyp/core/standalone

Both of these are valid:

import { logger, createStandaloneLogger } from "@blyp/core";

Terminal output:

(no terminal output - import only)
import type { StandaloneLogger, StandaloneLoggerConfig } from "@blyp/core/standalone";

Terminal output:

(no terminal output - type import only)

Use the root import for app code and the subpath import when you specifically want standalone type surfaces.