girok
v0.4.0
Published
girok is a lightweight and highly customizable JavaScript logger
Maintainers
Readme
girok
girok is a lightweight and highly customizable logger library.
Install
Using npm:
npm install girokUsing bun:
bun add girokUsage
import { logger } from "girok"
import { formatText } from "girok/formatters"
let log = logger({
level: "info",
formatter: formatText("[%lvl%] %ctx% %args%"),
outputs: ["stdout", "file://./logs"],
})
log.info("Hello World!") // [INFO] Hello World!
log = log.context({ key: "value" })
log.info("Hello again!") // [INFO] key="value" Hello again!Documentation
Basics
Instanciate a logger
To instanciate a logger you can use the logger function:
import { logger } from "girok"
const log = logger()
log.info("Hello World!")Level
The level option allows you to set the minimum level that will be logged. By default, the level option is set to info.
import { logger } from "girok"
const log = logger({
level: "warn",
})
log.trace("trace") // Not printed
log.debug("debug") // Not printed
log.info("info") // Not printed
log.warn("warn") // prints "warn"
log.error("error") // prints "error"
log.fatal("fatal") // prints "fatal" and exit processThe following levels are available:
trace < debug < info < warn < error < fatalContext
To add context properties to your logs, you can use the logger context function. This function takes a new contex in entry and returns a new logger with the defined context.
import { logger } from "girok"
let log = logger()
log.info("Message without context") // [INFO] Message without context
log = log.context({ foo: "bar" })
log.info("Message with context") // [INFO] foo="bar" Message with context
log = log.context({ test: 42 })
log.info("Message with context") // [INFO] foo="bar", test=42 Message with contextFormatting
Predefined formatters
You can use the formatter option to define the format of your logs.
There are two predefined formatters, text and json. The text formatter is the default one.
import { logger } from "girok"
let logTxt = logger({ formatter: "text" })
let logJson = logger({ formatter: "json" })
logTxt.info("Hello World")
// [INFO] 1970-01-01 00:00:00.000 (index.ts:6:8) Hello World
logJson.info("Hello World")
// {"level":"INFO","caller":"index.ts:7:9","ts":0,"message":"Hello World"}Custom formatters
You can use the formatter option to define your own formatter function. Here is the signature of the formatter function:
type LogMeta = {
level: Level
caller?: string
ts: number
context: Record<string, any>
}
type Formatter = (meta: LogMeta, ...args: any[]) => stringThere are two predefined formatters functions, formatText and formatJson. Those are the formatters used by the default text and json formatters, respectively.
Each of these can be customized.
import { logger } from "girok"
import { formatText, formatJson } from "girok/formatters"
const logTxt = logger({
formatter: formatText(), // alias for 'text'
})
const logJson = logger({
formatter: formatJson(), // alias for 'json'
})formatText()
Format log message as text.
Signature:
type FormatText = (
fmt: string,
meta: { ansi?: boolean; inline?: boolean; depth?: number | null }
) => FormatterExample:
let log = formatText("[%lvl%] %date% (%caller%) %args%", {
depth: 4,
ansi: false,
inline: true,
})
log.info("Hello World!")
// [INFO] 2022-01-01 00:00:00.000 (index.js) Hello World!
log = formatText(
"[%lvl%] %date.format(YYYY-MM-DD HH:mm:ss.SSS).utc% %ctx% %args%"
)
log.warn("Hello World!")
// [WARN] 2022-01-01 00:00:00.000 Hello World!formatJson()
Format log as JSON object. Each argument is treated as a sequence of alternating keys and values. If there is only one argument passed, it gets the default "message" key.
Signature:
type FormatJson = (
filter?: string[], // default is ['level', 'caller', 'ts', 'context', 'args']
opt?: { tsFormat?: string; utc?: boolean }
) => FormatterExample:
const log = formatJson(["level", "ts"])
log.info("key1", "val1", "key2", 42, "key3", { foo: "bar" })
// {"level":"info","ts":123456789,"key1":"val1","key2":42,"key3":{"foo":"bar"}}
log.info("Hey!")
// {"level":"info","ts":123456790,"message":"Hey!"}Outputs
The outputs option allows you to define a list of target outputs for your logs. The default output is ["stdout"].
Acceptable values are:
stdout- write logs to standard outputfile://<filePath>- appends logs to a file located at<filePath>- Transporter function - see next section for more details
import { logger } from "girok"
const log = logger({
outputs: ["stdout", "file://./logs"],
})Transporters
You can alson define a Transporter function as an output. This allows you to send logs to custom destinations.
The signature of a Transporter function is:
type Transporter = (buffer: string[]) => voidGirok provides the following default Transporter functions:
stdout
This is the default transporter. It writes logs to the standard output. This is the transporter used by the "stdout" alias.
import { logger } from "girok"
import { stdout } from "girok/transporters"
const log = logger({
outputs: [stdout], // same as ["stdout"]
})file
This transporter write logs to a file. This is the transporter used by the "file" alias.
path- path to the fileflag- flag to open the file. The default is"a", which means append.
import { logger } from "girok"
import { file } from "girok/transporters"
const log = logger({
outputs: [file({ path: "./logs", flag: "a" })], // same as ["file://./logs"]
})http
This transporter sends logs to an HTTP server. By default the logs in the buffer are concatened and written in the body of the request. You can configure the parser option to parse the response before sending it.
Signature:
type HttpTransporter = (config: {
url: string
method?: string // default is POST
headers?: Record<string, string>
onError?: (error: any) => void
parser?: (data: string[]) => any // tr
}) => Transporterhere is an example of using the http transporter:
import { logger } from "girok"
import { http } from "girok/transporters"
const log = logger({
outputs: [http({ url: "http://localhost:7357" })],
})logstash
This transporter sends logs to a Logstash server.
Signature:
type LogstashTransporter = (config: {
url?: string // default is http://localhost:5044
onError?: (error: any) => void
})Example:
import { logger } from "girok"
import { logstash } from "girok/transporters"
const log = logger({
outputs: [logstash()],
})splunk
This transporter sends logs to a Splunk server.
Signature:
type SplunkTransporter = (config: {
url?: string // default is http://localhost:8088/services/collector
token?: string
metadata?: {
time?: number
host?: string
source?: string
sourcetype?: string
index?: string
}
onError?: (e: Error) => void
})Example:
import { logger } from "girok"
import { splunk } from "girok/transporters"
const log = logger({
outputs: [splunk()],
})Other options
Buffer size
The bufferSize option defines the maximum number of logs in the buffer before flushing. The default is 1, which means logs will be flushed after each log.
import { logger } from "girok"
const log = logger({
bufferSize: 5,
})
log.info("1") // No output
log.info("2") // No output
log.info("3") // No output
log.info("4") // No output
log.info("5") // output: 1\n2\n3\n4\n5\nFlush interval
The flushInterval option defines the interval in milliseconds between two flushes. The default is undefined. Meaning that logs will be flushed after each buffer completion.
import { logger } from "girok"
const log = logger({
flushInterval: 10_000, // logs are flushed every 10 seconds
})Override console
The overrideConsole option defines whether the console object should be overridden by the current logger. The default is false.
import { logger } from "girok"
const log = logger({
overrideConsole: true,
})
console.log("Hello, World!") // alias for log.info("Hello World")
// [INFO] 1970-01-01 00:00:00.000 (index.ts:7:9) Hello World!
console.warn("Test", 42)
// [WARN] 1970-01-01 00:00:00.000 (index.ts:9:9) Test 42