npm package: @financial-times/n-auto-logger
Description: an opinionated [enhancer](https://github.com/Financial-Times/n-express-enhancer) to log function calls in the operation/action model > using [n-logger](https://github.com/Financial-Times/n-logger) by default, can be set to any logger instance
Latest version: 4.1.2

# n-auto-logger 

an opinionated [enhancer](https://github.com/Financial-Times/n-express-enhancer) to log function calls in the operation/action model
> using [n-logger](https://github.com/Financial-Times/n-logger) by default, can be set to any logger instance

[![npm version](https://badge.fury.io/js/%40financial-times%2Fn-auto-logger.svg)](https://badge.fury.io/js/%40financial-times%2Fn-auto-logger)
![npm download](https://img.shields.io/npm/dm/@financial-times/n-auto-logger.svg)
![node version](https://img.shields.io/node/v/@financial-times/n-auto-logger.svg)
[![gitter chat](https://badges.gitter.im/Financial-Times/n-auto-logger.svg)](https://gitter.im/Financial-Times/n-auto-logger?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)


[![CircleCI](https://circleci.com/gh/Financial-Times/n-auto-logger.svg?style=shield)](https://circleci.com/gh/Financial-Times/n-auto-logger)
[![Coverage Status](https://coveralls.io/repos/github/Financial-Times/n-auto-logger/badge.svg?branch=master)](https://coveralls.io/github/Financial-Times/n-auto-logger?branch=master)
[![Known Vulnerabilities](https://snyk.io/test/github/Financial-Times/n-auto-logger/badge.svg)](https://snyk.io/test/github/Financial-Times/n-auto-logger)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/Financial-Times/n-auto-logger/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/Financial-Times/n-auto-logger/?branch=master)
[![Dependencies](https://david-dm.org/Financial-Times/n-auto-logger.svg)](https://david-dm.org/Financial-Times/n-auto-logger)
[![devDependencies](https://david-dm.org/Financial-Times/n-auto-logger/dev-status.svg)](https://david-dm.org/Financial-Times/n-auto-logger?type=dev)

<br>

- [Install](#install)
- [Usage](#usage)
  * [log an Action](#log-an-action)
  * [log an Operation](#log-an-operation)
  * [auto log level](#auto-log-level)
  * [mute logger fields](#mute-logger-fields)
  * [customise logger instance](#customise-logger-instance)
  * [requestId](#requestid)
- [Gotcha](#gotcha)
  * [reserved fields](#reserved-fields)
  * [ignored fields](#ignored-fields)
  * [error auto parse](#error-auto-parse)
  * [log auto trim](#log-auto-trim)
  * [mute logger in test](#mute-logger-in-test)
- [Licence](#licence)

<br>

## Install
```shell
npm install @financial-times/n-auto-logger
```

## Usage

### log an Action

automatically log the start, success/failure state with necessary metadata including function name as `action`, it can be applied to both individual action function or an action function bundle.

```js
import { logAction, tagService, compose } from '@financial-times/n-auto-logger';

const result = logAction(someFunction)({...params, meta}); // action function

export default compose(
 tagService('service-name'), // optional
 logAction,
)({ 
 methodA, 
 methodB, 
 methodC 
}); // action function bundle
```

> more details on [action function](https://github.com/financial-Times/n-express-monitor#action-function)

### log an Operation

automatically log the start, success/failure state with necessary metadata including function name as `operation`, it can be applied to both individual operation function or an operation function bundle.

```js
import { logOperation, errorToHanlder, compose } from '@financial-times/n-auto-logger';

const operationFunction = (meta, req, res) => {}; // operation function
const someMiddleware = compose(
 errorToHandler, 
 logOperation
)(operationFunction);

export default compose(
 errorToHandler, 
 logOperation
)({ 
 operationFunctionA, 
 operationFuncitonB 
}); // operation function bundle
```

> more details on [operation function](https://github.com/financial-Times/n-express-monitor#operatoin-function)

### auto log level

set auto log level in `.env` with 3 options: `verbose`(default) | `concise` | `error`.

```js
AUTO_LOG_LEVEL=concise
```

* `verbose` would log every stage(start, success/failure) of operation and action
* `concise` would log success/failure of operation and only failure of action
* `error` would log only failure of operation and action

You can override the ENV_VAR with a flag value as well if you would like to switch log level in production for debugging.

### mute logger fields

set key names of fields to be muted in .env to reduce log for development or filter fields in production.

```js
LOGGER_MUTE_FIELDS=transactionId, userId
```

### customise logger instance

```js
import { setupLoggerInstance } from '@financial-times/n-auto-logger';
import winston from 'winston'; // you can use any instance as long as it has .info, .warn, .error method

setupLoggerInstance(winston); // set the logger instance before using the enhancer
```

### requestId

use the requestIdMiddleware to ensure the logs are easy to thread when debugging, and this would work well with [n-api-factory](https://github.com/Financial-Times/n-api-factory) to pass it to up stream services.

```js
import { requestIdMiddleware } from '@financial-times/n-auto-logger';

// you might want to exclude `__*` path from log
app.use(/^\/(?!_{2}).*$/, [
 // use it before any other middleware to be logged
 requestIdMiddleware,
 //...other middlewares
]);
```

## Gotcha

### reserved fields
`n-auto-logger` will append values to following reserved fields automatically, the values would be overriden by the key value of the same name in your `args/params/meta` or error object, be cautious not to override them unintentionally.

| fields    | default                                                                            | convention used in     |
|-----------|------------------------------------------------------------------------------------|------------------------|
| operation | operationFunction.name                                                             | n-auto-logger/metrics  |
| action    | actionFunction.name                                                                | n-auto-logger/metrics  |
| service   | tagService('service-name')                                                         | n-auto-metrics         |
| result    | 'success'<br>'failure'                                                                | n-auto-logger          |
| category  | 'FETCH_RESPONSE_ERROR'<br>'FETCH_NETWORK_ERROR'<br>'NODE_SYSTEM_ERROR'<br>'CUSTOM_ERROR' | n-auto-metrics/n-error |
| type      | specify the unique error type for debugging and error handling                     | n-auto-metrics/n-error |
| status    | recorded for service action call failure                                           | n-error/n-api-factory  |
| stack     | error stack trace                                                                  | n-error                |


### ignored fields
`user`, `handler`, `_locals` fields from `error` or `meta` object would not be logged by default.

sensitive personal data could be put in `meta.user` and would not be logged
```js
const meta = { ...meta, user: { id, email } };
```

UI but not debugger facing data could be put in `error.user` and would not be logged
e.g. app error status (> API call error status), user message (> error message from API for debugging)

```js
throw nError({ status, message }).extend({ user: { status, message } });
````

`.handler` field would not be logged, as it is only useful for error handler
```js
throw nError({ status: 404 }).extend({ handler: 'REDIRECT_TO_INDEX' });
```

`_locals` field would not be logged as it is verbose and not relevant to debug
```js
// in case you didn't clone the error object in error handler
function(err, req, res, next) {
  const e = {...err}; // clone the error object to avoid mutate the input
  res.render('template', e); // res.render is not a pure function, it would assign _locals to e
}
```

### error auto parse

`n-auto-logger` would parse different forms of the following error objects to logger-suitable format automatically([detail](src/failure.js)), while it still logs plain object and string message.

* Fetch Response Error `content-type`:`application/json`,`text/plain`,`text/html`
* Fetch (Network) Error
* Node native Error objects
* Custom objects extends native Error object
* [NError](https://github.com/Financial-Times/n-error)

### log auto trim

`n-auto-logger` would trim any empty fields and method fields in the input meta or error objects automatically to concise log ([detail](src/index.js)), you shouldn't be concerned about passing excessive meta fields or extend Error object with methods.

### mute logger in test

stub the logger instance instead of the whole module

```js
import logger from '@financial-times/n-auto-logger'; // the underlying logger instance (`n-logger`)

// sinon sandbox
sandbox.stub(logger);

// jest
logger.info = jest.fn();
logger.warn = jest.fn();
logger.error = jest.fn();
```

## Licence
[MIT](/LICENSE)