Skip to content

Instantly share code, notes, and snippets.

@jonathanws
Last active February 24, 2025 18:48
Show Gist options
  • Save jonathanws/1d9cab43510fc10be5433d03b575dac6 to your computer and use it in GitHub Desktop.
Save jonathanws/1d9cab43510fc10be5433d03b575dac6 to your computer and use it in GitHub Desktop.
Simple Log Framework
/**
* Service file that takes care of importing all environment variables used,
* as well as making sure they're all truthy and correctly typed.
*/
import { LOG_LEVELS } from './log.ts'
const _LOG_LEVEL = Deno.env.get('LOG_LEVEL')
// find() ensures correct typing (don't want just a raw string)
export const LOG_LEVEL = LOG_LEVELS.find((l) => l === _LOG_LEVEL) || 'all'
/**
* A small "log framework", just to see if I could do it.
*
* Includes print functions for all specified logging levels, as well as the ability to
* disable logs considered too granular for the incoming environment variable log level.
*/
import { LOG_LEVEL } from './env.ts'
const PRINTABLE_LOG_LEVELS = [
'debug',
'info',
'warn',
'error'
] as const
type PrintableLogLevel = typeof PRINTABLE_LOG_LEVELS[number]
/**
* 'off' and 'all' are technically log levels, but we don't want the
* developer to be able to use `log.all()`. So we split the arrays.
*/
const LOG_LEVELS = [
'off',
...PRINTABLE_LOG_LEVELS,
'all',
] as const
type LogLevel = typeof LOG_LEVELS[number]
/**
* ANSI escape codes.
*
* Really we could define these strings as an array like above, but I
* don't want to memorize `\x1b[33m` as being `yellow`. So we keep them
* as an object literal with human-readable keys instead.
*/
const RESET_CODE = '\x1b[0m'
const COLOR_CODES = {
CYAN_CODE: '\x1b[36m',
GREEN_CODE: '\x1b[32m',
RED_CODE: '\x1b[31m',
YELLOW_CODE: '\x1b[33m',
} as const
type ColorCode = typeof COLOR_CODES[keyof typeof COLOR_CODES]
// Colored text will remain colored in the output until manually reset.
const getColoredText = (color: ColorCode, message: string) => `${color}${message}${RESET_CODE}`
const cyan = (m: string) => getColoredText(COLOR_CODES.CYAN_CODE, m)
const green = (m: string) => getColoredText(COLOR_CODES.GREEN_CODE, m)
const red = (m: string) => getColoredText(COLOR_CODES.RED_CODE, m)
const yellow = (m: string) => getColoredText(COLOR_CODES.YELLOW_CODE, m)
type LogFunction = (message: string, a?: any) => void
const print = (level: PrintableLogLevel, getColoredText: LogFunction, ...args: [message: string, a?: any]) => {
// Do not print a log if the environment log level is lower
if (LOG_LEVELS.indexOf(LOG_LEVEL) >= LOG_LEVELS.indexOf(level)) {
console.log(
...args.map((arg) => typeof arg === 'string'
? getColoredText(arg)
: arg
))
}
}
const exported: Record<PrintableLogLevel, LogFunction> = {
debug: (...args: [message: string, a?: any]) => print('debug', cyan, ...args),
error: (...args: [message: string, a?: any]) => print('error', red, ...args),
info: (...args: [message: string, a?: any]) => print('info', green, ...args),
warn: (...args: [message: string, a?: any]) => print('warn', yellow, ...args),
}
export default exported
export {
LOG_LEVELS,
type LogLevel,
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment