---
title: '05 Logging with Morgan'
disqus: hackmd
---
05 Logging with Morgan
===
<style>
img{
/* border: 2px solid red; */
margin-left: auto;
margin-right: auto;
width: 90%;
display: block;
}
</style>
## Table of Contents
[TOC]
Logging
---
- collect and store data over time for analysis
- gain insights
- resolve bugs
- detect probs
- simplest form is `console.log` to log data to cmd
- why log?
- debug
- document steps for error
- security audits
- detect and log suspicious activities/events
- complexity of tracking and detecting
### What to Log
- timestamp/log entry
- timing data for req
- request endpt data
- eg. paths /users
- eg. verbs - GET, POST etc.
- ip of req
- exceptions
### How to Log
- libs
- morgan
- winson
- log4js
Morgan
---
- http req middleware for nodejs
- simplifies logging reqs for app
- https://www.npmjs.com/package/morgan
- http://expressjs.com/en/resources/middleware/morgan.html

- `npm install morgan --save`
- `var morgan = require('morgan')`
- api - `morgan(format, options)`
- create morgan logger middleware func with given format and options
- format str can be string of predefined name, string of format str orfunc to produce a log entry
- format func is called with 3 args - tokens, req and res
- token is obj will all defined tokens
- req is http req
- res is http resp
- func expected to return str which is log line
- or undefined or null to skip logging
### Pre-defined Tokens

```javascript
...
app.use(morgan(':method :url :date'));
...
```
### Pre-defined Log Formats

```javascript
var morgan = require('morgan')
...
app.use(morgan('combined'))
...
```
### Custom Tokens
```javascript
// function returns some val representing token output in log
morgan.token('myToken', (req, res) => {
...
return ...;
})
```
#### Applying Custom Tokens
- `app.use(morgan(":myToken" :method :url :date));`
#### Examples
**custom json token**
```javascript
morgan.token("json", function(req, res) {
return JSON.stringify({
date: nDate,
url: req.url,
status: res.statusCode,
method: req.method,
httpVersion: req.httpVersion
})
})
// eg. used with format :json
app.use(morgan(':remote-addr ===> :method :url => :status header count => :req-headers-length --> :date --> :response-time :json', {stream: appLogStream}));
// sample output with :json
::1 ===> GET /profile.html => 404 header count => 14 --> Tue, 01 Dec 2020 16:44:20 GMT --> 2.661 {"date":"12/2/2020, 12:44:18 AM","url":"/profile.html","status":404,"method":"GET","httpVersion":"1.1"}
```
### Logging to File
- use fs lib to create file stream and apply to morgan
```javscript
var fs = require('fs')
...
// flag = a - append mode to file
const appLogStream = fs.createWriteStream(path.join(__dirname__, 'app.log'), {flags: "a"});
...
app.use(morgan("combined", {stream: appLogStream}));
...
```
#### Examples
**App logging stream**
```javascript
var appLogStream = rfs.createStream('access.log', {
interval: '1d', // rotate daily
path: path.join(__dirname, 'logs') //write to a subdir log using path module to use parent dir
})
app.use(morgan(':remote-addr ===> :method :url => :status header count => :req-headers-length --> :date --> :response-time :json', {stream: appLogStream}));
// eg. output to access.log
::1 ===> GET /profile.html => 404 header count => 14 --> Tue, 01 Dec 2020 16:44:20 GMT --> 2.661 {"date":"12/2/2020, 12:44:18 AM","url":"/profile.html","status":404,"method":"GET","httpVersion":"1.1"}
```
**Error logging stream**
```javascript
var errorLogStream = rfs.createStream('error.log', {
interval: '1d', // rotate daily
path: path.join(__dirname, 'logs') //write to a subdir log
})
app.use((morgan(':remote-addr ===> :method :url => :status :exception => :date --> :response-time :exception-json', {
skip: function (req, res) { return res.statusCode < 400 },
stream: errorLogStream
})));
// eg. output to error.log
::1 ===> GET /profile.html => 404 Not Found => Tue, 01 Dec 2020 16:44:20 GMT --> 2.661 {"exception":"Not Found","method":"GET","url":"/profile.html","ip":"::1","date":"12/2/2020, 12:44:18 AM"}
```
### Log File Rotation
- log file can grow to large size for apps on cloud
- need to create multiple log files
- eg. one for ea day
- use `rotating-file-stream` module
- `npm install rotating-file-stream --save`
```javascript
var rfs = require('rotating-file-stream');
// create rotating write stream
var appLogStream = rfs.createStream('access.log', {
interval: '1d', // rotate daily
path: path.join(__dirname, 'log') //write to a subdir log
})
...
app.use(morgan('combined', {stream: appLogStream}));
```
#### More Examples
```javascript
const rfs = require("rotating-file-stream");
const stream = rfs.createStream("file.log", {
// other eg. 300B, 300K, 1G
size: "10M", // rotate every 10 MegaBytes written
// other eg. 5s, 5m, 2h, 1M (rotate every midmight between 2 distinct months)
interval: "1d", // rotate daily
compress: "gzip" // compress rotated files
});
```
###### tags: `SC` `DISM` `School` `Notes`