Skip to content

connectedcars/node-logutil

Repository files navigation

node-logutil

Build Status Coverage Status

Installation

npm install https://github.com/connectedcars/node-logutil#v1.1.3

API

log.debug(message[, context])

Logs the provided message with the optional context as a JSON string, if the log level is set to output debug.

The method takes most input, but the combination described above is the recommended one.

message

Type: string

Descriptive log message

context

Type: object

Object hash to provide log context.

log.statistic(message[, context])

Logs the provided message with the optional context as a JSON string, if the log level is set to output statistic.

The method takes most input, but the combination described above is the recommended one.

message

Type: string

Descriptive log message

context

Type: object

Object hash to provide log context.

log.info(message[, context])

Logs the provided message with the optional context as a JSON string, if the log level is set to output info.

The method takes most input, but the combination described above is the recommended one.

message

Type: string

Descriptive log message

context

Type: object

Object hash to provide log context.

log.warn(message[, context])

Logs the provided message with the optional context as a JSON string, if the log level is set to output warnings.

The method takes most input, but the combination described above is the recommended one.

message

Type: string

Descriptive log message

context

Type: object

Object hash to provide log context.

log.error(message[, context])

Logs the provided message with the optional context as a JSON string, if the log level is set to output errors.

The method takes most input, but the combination described above is the recommended one.

message

Type: string

Descriptive log message

context

Type: object

Object hash to provide log context.

log.critical(message[, context])

Logs the provided message with the optional context as a JSON string, if the log level is set to output critical.

The method takes most input, but the combination described above is the recommended one.

message

Type: string

Descriptive log message

context

Type: object

Object hash to provide log context.

log.MetricRegistry()

A singleton instance that holds the state of all metrics in the application at a given point in time. The class should be instantiated globally and kept through the process lifetime.

log.MetricsRegistry.prototype.cumulative(name, value[, labels])

A monotically increasing number that. E.g. the number of requests since the process started.

name

Type: string Name of the metric to write. The recommended format is [namespace]/[metric-name]. E.g. ingester/queue-size

value

Type: number A value to write. It's worth noting that we're always using floating-point precision for these values.

labels

Type: object An optional label map that denotes some specific properties you want to group by / filter on later. Please note that this map must have hashable values. Thus, you're not allowed to nest objects. It's also worth noting that the MetricRegistry will log all permutations of the label, so please only use it to store categorical types and not, say carIds. Example: {tableName: 'LatestCarPositions'}

Scenarios where you'd want to use this metric type

Generally every time you're interested in monitoring:

  • the relative change in a value (marginal difference)
  • or the value relative to the time period

E.g.

  • Inserted rows since last time
  • Incoming HTTP requests

log.MetricsRegistry.prototype.gauge(name, value[, labels, reducerFn])

Please refer to log.MetricsRegistry.prototype.cumulative() for a definition of the arguments name, value and labels

An instantaneous measurement of a varying number. Per default, we will only store the value and timestamp of the latest inserted value. So if you insert two values, e.g. gauge('foo', 2) at time 0 and gauge('foo', 4) at time 2, and the metrics are scraped at time 3, we will report value=4,time=2 to the log. If you for some reason don't want this, you can specify an optional reducerFn argument:

// Function that takes the mean over all values in that timespan
const fn = (arr) => arr.reduce((a, b) => a+b)) / arr.length

// Sample some data
registry.gauge('foo', 10, null, fn)
registry.gauge('foo', 20, null, fn)

// logMetric reports value=30 and generates a timestamp
registry.logMetrics()
Scenarios where you'd want to use this metric type

Every time you want to capture a state at a particular time. E.g.:

  • Size of a queue at a particular time
  • CPU utilization

A rule of thumb: If a value can go vary (i.e. go up and down), and it should be captured at a specific time, then it's a good candidate for a gauge.

log.MetricRegistry.prototype.logMetrics()

Captures a snapshot of the image state and adds endTime=Date.now() to all objects. Afterwards all metrics are dumped to stdout using node-logutil's log.statistic function. All metrics are dumped using LOG_LEVEL=INFO, so make sure your application uses at least that log level.

This function is intended to be used together with metrics-subscriber-api

log.MetricRegistry.prototype.getMetrics()

Returns all metrics as an array of objects. Example:

{
  name: 'gauge-metric',
  type: 'GAUGE',
  value: 50,
  labels: { brand: 'vw' }
}

log.MetricRegistry.prototype.getPrometheusMetrics()

Returns an array of strings formatted using the Prometheus exposition format The format should follow their EBNF definition, but is not tested against a parser as of this moment.

This function is intended to be exposed through a small HTTP server and used in conjunction with Prometheus in the future.

Usage

const log = require('logutil')

log.debug('This is a debug message')
// Outputs to stdout: {"message":"This is a debug message","severity":"DEBUG","timestamp":"2017-09-01T13:37:42Z"}
log.debug('This is a statistic value', { foo: 42, bar: 1337 })
// Outputs to stdout: {"message":"Statistics","severity":"STATISTIC","timestamp":"2017-09-01T13:37:42Z", "content":{"foo":42,"bar":1337}}
log.info('This is an info message')
// Outputs to stdout: {"message":"This is an info message","severity":"INFO","timestamp":"2017-09-01T13:37:42Z"}
log.warn('This is a warning message', { type: 'missing-item' })
// Outputs to stderr: {"message":"This is a warning message","severity":"WARNING","timestamp":"2017-09-01T13:37:42Z","context":{"type":"missing-item"}}
log.error('This is an error message', { context: { items: ['foo', 'bar'] } })
// Outputs to stderr: {"message":"This is an error message","severity":"ERROR","timestamp":"2017-09-01T13:37:42Z","context":{"items":["foo","bar"]}}
log.critical('This is a critical message', { context: { items: ['foo', 'bar'] } })
// Outputs to stderr: {"message":"This is a critical message","severity":"CRITICAL","timestamp":"2017-09-01T13:37:42Z","context":{"items":["foo","bar"]}}

log.debug(() => {
  // Only runs if log level is debug
  return Promise.resolve('This is a debug message')
})
// Outputs to stdout: {"message":"This is a debug message","severity":"DEBUBG","timestamp":"2017-09-01T13:37:42Z"}
log.info(() => {
  // Only runs if log level is info
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('This is an info message')
    }, 500)
  })
})
// Outputs to stdout (after 500 ms): {"message":"This is an info message","severity":"INFO","timestamp":"2017-09-01T13:37:42Z"}

// Instantiate as a singleton
const registry = log.MetricRegistry()

// Write some data
await registry.gauge('namespace/metric-name', 20, {brand: 'vw'})
await registry.cumulative('namespace/cumulative-metric-name', 40, {brand: 'seat'})

// In case you want to do aggregations more granular than the regular dump, you can pass in a reducer function taking an array of numbers.
await registry.gauge('namespace/metric-name', 20, {brand: 'vw'}, (arr) => arr.reduce((a, b) => a+b)) / arr.length

// Dump metrics to stdout regularly
setInterval(registry.logMetrics, 30000)

Configuration

Determining what to output depends on the environment variable LOG_LEVEL. This variable can be DEBUG, STATISTIC, INFO, WARN, ERROR, or CRITICAL but defaults to WARN.