Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/rijvi-mahmud/shaddy/llms.txt

Use this file to discover all available pages before exploring further.

useLogger is a fully-featured logging hook for React components. It replaces scattered console.log calls with a structured logger that respects minimum log levels, adds timestamps and prefixes, renders colour-coded output in the browser console, and automatically suppresses logs in production when devOnly is enabled. The hook also provides advanced utilities like table, group, time/timeEnd, assert, and trace — a complete developer-console toolkit available inside any component.

Installation

npx shadcn@latest add https://shaddy-docs.vercel.app/r/use-logger

Signature

export enum LogLevel {
  DEBUG = 0,
  INFO  = 1,
  WARN  = 2,
  ERROR = 3,
  NONE  = 4,
}

export interface LoggerConfig {
  level?:                    LogLevel
  enabled?:                  boolean
  showTimestamp?:            boolean
  timestampFormat?:          'iso' | 'locale' | 'time' | 'custom'
  customTimestampFormatter?: () => string
  prefix?:                   string
  colored?:                  boolean
  showStackTrace?:           boolean
  customHandler?:            <T = unknown>(level: string, message: string, data?: T[]) => void
  devOnly?:                  boolean
  groupName?:                string
}

export const useLogger: (config?: LoggerConfig) => {
  debug:   <T = unknown>(message: string, ...optionalParams: T[]) => void
  info:    <T = unknown>(message: string, ...optionalParams: T[]) => void
  warn:    <T = unknown>(message: string, ...optionalParams: T[]) => void
  error:   <T = unknown>(message: string, ...optionalParams: T[]) => void
  success: <T = unknown>(message: string, ...optionalParams: T[]) => void
  table:   (data: unknown, columns?: string[]) => void
  group:   (label: string, callback: () => void, collapsed?: boolean) => void
  time:    (label: string) => void
  timeEnd: (label: string) => void
  assert:  <T = unknown>(condition: boolean, message: string, ...optionalParams: T[]) => void
  trace:   <T = unknown>(message: string, ...optionalParams: T[]) => void
  clear:   () => void
  config:  LoggerConfig
}

Parameters

config
LoggerConfig
Optional configuration object. All properties are optional; omitting the argument entirely uses safe defaults (debug level, timestamps on, colours on, devOnly off).

Return Value

debug
(message, ...data?) => void
Logs at LogLevel.DEBUG. Rendered in indigo in the browser when colored is true.
info
(message, ...data?) => void
Logs at LogLevel.INFO. Rendered in blue when colored is true.
warn
(message, ...data?) => void
Logs at LogLevel.WARN using console.warn. Always rendered in the browser’s native warning style.
error
(message, ...data?) => void
Logs at LogLevel.ERROR using console.error. Appends the stack trace when showStackTrace is true and the first extra param is an Error.
success
(message, ...data?) => void
Logs at LogLevel.INFO using green colour. Useful for confirming successful operations without cluttering error/warn channels.
table
(data, columns?) => void
Renders structured data using console.table (browser only). Falls back to console.log in server environments.
group
(label, callback, collapsed?) => void
Wraps callback output in a console.group / console.groupCollapsed block. Pass collapsed = true to start the group folded.
time
(label) => void
Starts a console.time timer with the given label.
timeEnd
(label) => void
Stops and prints the elapsed time for the timer started with the same label.
assert
(condition, message, ...data?) => void
Calls console.assert. The message is only printed when condition is false.
trace
(message, ...data?) => void
Logs a message with a stack trace using console.trace.
clear
() => void
Clears the console. Respects the enabled setting.
config
LoggerConfig
The merged configuration object actually in use (defaults merged with your overrides). Useful for debugging logger setup.

Usage

Basic Component Logging

import { useLogger, LogLevel } from "@/hooks/use-logger"

export function UserCard({ userId }: { userId: string }) {
  const logger = useLogger({
    prefix: "UserCard",
    level:  LogLevel.INFO,
    devOnly: true, // Suppress logs in production automatically
  })

  useEffect(() => {
    logger.info("Component mounted", { userId })
    return () => {
      logger.debug("Component unmounted", { userId })
    }
  }, [userId])

  const handleDelete = async () => {
    logger.warn("Attempting to delete user", { userId })
    try {
      await deleteUser(userId)
      logger.success("User deleted successfully")
    } catch (err) {
      logger.error("Failed to delete user", err)
    }
  }

  return (
    <div>
      <p>User ID: {userId}</p>
      <button onClick={handleDelete}>Delete</button>
    </div>
  )
}

Performance Measurement

import { useLogger } from "@/hooks/use-logger"

export function DataProcessor({ items }: { items: unknown[] }) {
  const logger = useLogger({ prefix: "DataProcessor" })

  const processItems = () => {
    logger.time("processItems")
    const result = items.map(expensiveTransform)
    logger.timeEnd("processItems")
    logger.table(result, ["id", "name", "value"])
    return result
  }

  return <button onClick={processItems}>Process {items.length} items</button>
}

Grouped Logs

import { useLogger } from "@/hooks/use-logger"

export function AuthFlow() {
  const logger = useLogger()

  const handleLogin = async (email: string, password: string) => {
    logger.group("Login Flow", () => {
      logger.info("Validating credentials", { email })
      logger.debug("Password length", password.length)
    })

    try {
      await login(email, password)
      logger.success("Login successful")
    } catch (err) {
      logger.error("Login failed", err)
    }
  }

  return <LoginForm onSubmit={handleLogin} />
}

Custom Remote Log Handler

import { useLogger, LogLevel } from "@/hooks/use-logger"

export function TrackedComponent() {
  const logger = useLogger({
    level: LogLevel.WARN,
    customHandler: (level, message, data) => {
      // Send warnings and errors to your observability platform
      fetch("/api/logs", {
        method: "POST",
        body: JSON.stringify({ level, message, data, timestamp: Date.now() }),
      })
    },
  })

  const handleRiskyAction = () => {
    logger.warn("User performed a risky action")
  }

  return <button onClick={handleRiskyAction}>Risky Action</button>
}

Notes

  • All logging methods are memoised with useCallback and return stable function references, so they are safe to pass as props or include in useEffect dependency arrays.
  • When devOnly: true, all methods are no-ops in production. No logs, no overhead.
  • The colored option only applies in browser environments — in Node.js (SSR) the hook falls back to plain console methods with formatted text.
  • The hook exports LogLevel as a named enum so you can use it for comparisons and configuration without hard-coding numbers.

Build docs developers (and LLMs) love