Zero-dependency logging with a focus on developer experience and modern backend runtimes.
When you're developering for NodeJS (ie. not browsers) on a modern runtime (ie. FaaS / Lambda / containers) and you care about structured logs (ie. as JSON)
- Serialized to JSON (by default)
- Stamped with RFC3339 (by default)
- Writes to stdout (by default)
- Easy to emit with context
- Typescript
- Extensible
npm i --save dexlog
import { StandardLogger } from 'dexlog'
StandardLogger.debug('this is for troubleshooting')
// > {"message":"this is for troubleshooting","level":"DEBUG","timestamp":"2020-06-23T06:46:11.799Z"}
StandardLogger.info('success')
// > {"message":"success","level":"INFO","timestamp":"2020-06-23T06:46:11.799Z"}
StandardLogger.warn("something happened, but i'm able to continue")
// > {"message":"something happened, but i'm able to continue","level":"WARN","timestamp":"2020-06-23T06:46:11.799Z"}
StandardLogger.error('failed to do that thing')
// > {"message":"failed to do that thing","level":"ERROR","timestamp":"2020-06-23T06:46:11.799Z"}
const user_id = 'dave'
const error = new Error('not found')
StandardLogger.error('failed to log in', { error, user_id })
// > {"message":"failed to log in","level":"ERROR","error":"Error: not found","id":"dave","timestamp":"2020-06-23T06:46:11.799Z"}
const user_id = 'dave'
const logger = StandardLogger.with({ user_id })
// use as normal:
const error = new Error('not found')
logger.error('failed to log in', { error })
// > {"message":"failed to log in","level":"ERROR","error":"Error: not found","id":"dave","timestamp":"2020-06-23T06:46:11.799Z"}
RECOMMENDED:
The StandardLogger
uses the environment variable LOG_LEVEL
- set it as needed:
$ LOG_LEVEL=INFO node .
OR:
you can set it programmatically:
import { LogLevel, Logger } from 'dexlog'
const logger = new Logger(LogLevel.DEBUG)
Lets say you are using lambda, you might want to add context to your logger like this:
import { StandardLogger } from 'dexlog'
export async function lambda_handler(event: any, context: LambdaContext): Promise<any> {
const logger = StandardLogger.with({ request_id: context.awsRequestId })
logger.debug('event recieved', { event })
}
Most of the time you'll want to use the StandardLogger, but just in case you need some customization
You can bring a writer, it just has to be a function which takes an object and returns nothing.
Interface:
export type Writer = (msg: any) => void
Example implementation which writes to S3:
import { LogLevel, Logger, Writer } from "dexlog"
// S3Writer writes to S3
class S3Writer {
constructor(
public Bucket: string,
public Key: string,
public s3: AWS.S3 = new AWS.S3(),
) {}
public write: Writer = (Body: any) => {
s3.putObject({ Body, Bucket: this.Bucket, Key: this.Key }) // this is an async function, don't actually do this
}
}
const writer = new S3Writer("examplebucket", "examplekey")
const logger = new Logger( LogLevel.INFO, writer.write )
A Serializer takes anything and returns a string.
Interface:
export type Serializer = (msg: any) => string
Example implementation which returns everything in CAPS!
import { LogLevel, Logger, StdOutWriter, Serializer } from 'dexlog'
const AngrySerializer: Serializer = (msg: any) => JSON.stringify(msg).toUpperCase()
const logger = new Logger(LogLevel.DEBUG, StdOutWriter, AngrySerializer)
logger.error('what?!') // {"MESSAGE":"WHAT?!","LEVEL":"ERROR","TIMESTAMP":"2020-06-23T10:02:03.765Z"}
A Stamper returns an object which is appended to your log.
Interface:
export type Stamper = () => any
Example implementation which stamps messages with "foo" and a backwards timestamp:
import { DefaultSerializer, Logger, LogLevel, Stamper, StdOutWriter } from 'dexlog'
// timestamper
const locale = new Intl.DateTimeFormat('en-US', {
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
timeZone: 'America/New_York',
})
const FreedomStamper: Stamper = () => ({ time: locale.format(new Date()) })
// foo stamper
const FooStamper: Stamper = () => ({ foo: 'bar' })
// logger
const logger = new Logger(LogLevel.DEBUG, StdOutWriter, DefaultSerializer, [
FreedomStamper,
FooStamper,
])
// usage
logger.info('Hello, World!') // {"message":"Hello, World!","level":"INFO","time":"6/23/2020","foo":"bar"}