Skip to content

@reliverse/relinka is a modern, minimal logging library that actually feels right. It's not just pretty output — it's a system: smart formatting, file-safe logging, runtime config support, and a fatal mode built for developers who care about correctness.

License

Notifications You must be signed in to change notification settings

reliverse/relinka

Folders and files

NameName
Last commit message
Last commit date

Latest commit

a8ae438 · Apr 12, 2025

History

17 Commits
Jan 13, 2025
Apr 12, 2025
Apr 12, 2025
Apr 12, 2025
Apr 12, 2025
Apr 12, 2025
Apr 12, 2025
Apr 1, 2025
Apr 12, 2025
Apr 1, 2025
Apr 12, 2025
Apr 12, 2025
Apr 12, 2025
Apr 12, 2025
Apr 12, 2025
Mar 17, 2025
Apr 1, 2025

Repository files navigation

Relinka: Logging that Actually Feels Good

💖 GitHub Sponsors💬 Discord✨ Repo📦 NPM

@reliverse/relinka is a modern, minimal logging library that actually feels right. It's not just pretty output — it's a system: smart formatting, file-safe logging, runtime config support, and a fatal mode built for developers who care about correctness. Whether you're building CLI tools, SDKs, or full-stack apps — Relinka helps you log with intention.

Why Relinka

  • 🧙 Drop-in replacement for node:console, consola, or your internal logger
  • 💬 Supports: info, warn, success, error, verbose, fatal, clear
  • 🎨 Terminal output that pops, with automatic color handling
  • 📁 Save logs to file (with daily rotation, cleanup, and max-file limits)
  • 🧠 Structured message formatting (objects, errors, stacks — handled!)
  • ⚙️ Runtime config via relinka.config.ts (powered by reconf)
  • 🚨 fatal logs halt execution and trigger debugger in dev
  • 🧩 Sync-first, async, & CLI-friendly thanks to buffer flushing

Getting Started

1. Install

bun add @reliverse/relinka

2. Use It

Direct Method (Recommended)

  • Place this at the START of your app's main function:
await relinkaConfig;
  • Place this at the END of your app's main function:
await relinkaShutdown();

Usage example:

import {
  relinka,
  relinkaAsync,
  relinkaConfig,
  relinkaShutdown,
} from "@reliverse/relinka";
export async function main() {
  await relinkaAsync(
    // this automatically loads the config
    "verbose",
    "This ASYNC verbose message can be seen only if verbose=true (in user config)",
  );
  await relinkaConfig; // place this at your main function or just at the top of your entry file
  relinka(
    "verbose",
    "This SYNC verbose message can be seen only if verbose=true (in user config) AND config was loaded ",
  );
  relinka("log", "Hello! 👋");
  relinka("log", "Great to see you here!");
  relinka("info", "Everything is running smoothly");
  relinka("warn", "This might be a problem");
  relinka(
    "error", // non-fatal issue level can be recovered
    "Uh oh, something broke",
  );
  // relinka(
  //   "fatal",
  //   "We should never reach this code! This should never happen! (see <anonymous> line)",
  // ); // fatal level throws error and halts execution
  relinka("success", "Thanks for using Relinka!");
  // Make sure to shut down the logger at the end of your program
  // This is important to flush all buffers and close file handles
  await relinkaShutdown();
}
await main();

[🔜 Soon] Singleton Method

const logger = initRelinkaInstance({/* per-project config */}); 
logger("info", "Looks great!");

[🔜 Soon] Object Method

await relinkaConfig;
relinka.info("Looks great!");

Advanced Usage

// Clear terminal:
relinka("clear", "");
// Blank line:
relinka("info", "");
// Async variant:
import { relinkaAsync } from "@reliverse/relinka";
await relinkaAsync("info", "Logged from async context");
// Coming soon:
await relinkaAsync("info", "Something happened", { animate: true });

Config

Create relinka.config.ts:

import { defineConfig } from "@reliverse/relinka";
/**
 * RELINKA CONFIGURATION FILE
 * - Hover over a field to see the information
 * - Use intellisense to see available options
 * @see https://github.com/reliverse/relinka
 */
export default defineConfig({
  // Enable to see verbose logs
  verbose: false,

  // Timestamp configuration
  timestamp: {
    enabled: false,
    format: "HH:mm:ss",
  },

  // Control whether logs are saved to a file
  saveLogsToFile: true,

  // Disable colors in the console
  disableColors: false,

  // Log file path
  logFilePath: "relinka.log",

  levels: {
    success: {
      symbol: "✓",
      fallbackSymbol: "[OK]",
      color: "greenBright",
      spacing: 3,
    },
    info: {
      symbol: "i",
      fallbackSymbol: "[i]",
      color: "cyanBright",
      spacing: 3,
    },
    error: {
      symbol: "✖",
      fallbackSymbol: "[ERR]",
      color: "redBright",
      spacing: 3,
    },
    warn: {
      symbol: "⚠",
      fallbackSymbol: "[WARN]",
      color: "yellowBright",
      spacing: 3,
    },
    fatal: {
      symbol: "‼",
      fallbackSymbol: "[FATAL]",
      color: "redBright",
      spacing: 3,
    },
    verbose: {
      symbol: "✧",
      fallbackSymbol: "[VERBOSE]",
      color: "gray",
      spacing: 3,
    },
    log: { symbol: "│", fallbackSymbol: "|", color: "dim", spacing: 3 },
  },

  // Directory settings
  dirs: {
    dailyLogs: true,
    logDir: "logs", // store logs in a custom folder
    maxLogFiles: 5, // keep only the 5 most recent log files
    specialDirs: {
      distDirNames: [],
      useParentConfigInDist: true,
    },
  },
});

Supported files:

  • relinka.config.ts
  • 🔜 other formats, supported by reconf, are coming soon

Log Files

  • Default: logs/relinka.log
  • Daily mode: 2025-04-11-relinka.log
  • Auto-cleanup: keep latest N logs

API Summary

relinka("info", "message", optionalDetails);
relinka("fatal", "something broke"); // throws
relinka("clear", ""); // clears terminal

await relinkaAsync("warn", "something async");
defineConfig({ ... }) // helper for relinka.config.ts

Built-in Utilities

  • ✅ Timestamping
  • ✅ File-safe formatting
  • ✅ Log rotation
  • ✅ Fatal logging (with debugger)
  • ✅ Colorized terminal output

FAQ

Why relinka.config.ts doesn't works for me?

→ You forget to load user's config by using await relinkaConfig; at the START of your app's main function.

Why my terminal stucks after last relinka() usage?

→ You forget to flush the buffer. Place await relinkaShutdown(); at the END of your app's main function.

Why does TS linter tells that something wrong with relinka("info", args)?

→ Add empty string: relinka("info", "", args)

Does fatal throw?

→ Yes, always. It will halt execution and trigger debugger in dev mode.

What's coming next?

  • Relinka is designed to be used in the different ways:
  • Use relinka(level, message, ...args) (recommended).
  • 🔜 Or, just relinka.level(message, ...args)
  • 🔜 Both designed to work with both sync (default) and async/await.
  • 🔜 Both designed to work with both direct and wrapper methods.
  • 🔜 Use the async logger if you want some advanced features (like typing text streaming animation).

Tips

Roadmap

  • File logging
  • Timestamps
  • Daily logs
  • Log rotation
  • fatal type
  • Runtime config
  • Implement per-project config redefinition
  • Plugin support (custom formatters, hooks)
  • CLI interface (to manage logs, config, etc)

Shoutouts

Relinka wouldn't exist without these gems:

License

💖 MIT © 2025 blefnk Nazar Kornienko

About

@reliverse/relinka is a modern, minimal logging library that actually feels right. It's not just pretty output — it's a system: smart formatting, file-safe logging, runtime config support, and a fatal mode built for developers who care about correctness.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published