Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework documentation around formats and custom format functions. #125

Closed
wants to merge 5 commits into from
Closed
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 104 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,39 @@ var morgan = require('morgan')

Create a new morgan logger middleware function using the given `format` and `options`.
The `format` argument may be a string of a predefined name (see below for the names),
a string of a format string, or a function that will produce a log entry.
a string of a format string, or a format function that will produce a log entry.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the wording is in the format "a ". Can we keep that wording for the function as well? Perhaps "or a function that will format a log entry"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Changed this in 1c9416c. Not sure why this Github comment wasn't hidden automatically because the line was changed.


Format functions accept three arguments `tokens`, `req`, and `res` where `tokens` represents
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And then probably start this with "The function will be called with three arguments: [...]"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Changed this in 1c9416c. Not sure why this Github comment wasn't hidden automatically because the line was changed.

an object with all known tokens. It is expected to return a string. For the sake of example, the
following four code snippets are equivalent.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is missing the information on the log-skipping behavior.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Changed this in 1c9416c. Not sure why this Github comment wasn't hidden automatically because the line was changed.


##### Using a [predefined format string](#predefined-formats)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this skipped a level of heading by accident.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Changed this in 1c9416c. Not sure why this Github comment wasn't hidden automatically because the line was changed.

```
morgan(':tiny')
```

##### Using format string of [predefined tokens](#tokens)
```js
morgan(':method :url :status :res[content-length] - :response-time ms')
```

##### Using a format function [from `morgan.compile`](#morgancompileformat)
``` js
morgan(morgan.compile(':method :url :status :res[content-length] - :response-time ms'))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if I want to explain what the difference is between this example and the one above is. I would just leave out this example.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Changed this in 1c9416c. Not sure why this Github comment wasn't hidden automatically because the line was changed.

```

##### Using a custom format function
``` js
morgan(function (tokens, req, res) {
return [
tokens.method(req, res),
tokens.url(req, res),
tokens.status(req, res),
tokens.res(req, res, 'content-length'), '-',
tokens['response-time'](req, res), 'ms'
].join(' ')
})
```

#### Options

Expand Down Expand Up @@ -103,7 +135,20 @@ To define a token, simply invoke `morgan.token()` with the name and a callback f
morgan.token('type', function (req, res) { return req.headers['content-type'] })
```

Calling `morgan.token()` using the same name as an existing token will overwrite that token definition.
There are a few pieces of behavior you should be aware of when using tokens:

- `morgan.token('name', callback)` corresponds to `:name` in any string passed to `morgan(format, options)`.
Copy link
Contributor

@dougwilson dougwilson Oct 12, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the Express.js readmes, we usually format the bullet lists as "<space><space>*<space>"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, let's not call the function callback, as that has a significance in the Node.js land, and this is not a function that is in the form of a callback (it's sync and isn't called with err as the first argument).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Changed this in 1c9416c. Not sure why this Github comment wasn't hidden automatically because the line was changed.

- `morgan.token('name', callback)` defines the function `morgan.name(req, res, arg)` which may be used in any functions passed to `morgan(format, options)`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I read this a few times, but I think it's a bit unclear what is means, if you could expand on this a bit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Changed this in 1c9416c. Not sure why this Github comment wasn't hidden automatically because the line was changed.

- Falsey values returned from the `callback` function will be replaced with `-` in your log output.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: Falsey -> Falsy

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Changed this in 1c9416c. Not sure why this Github comment wasn't hidden automatically because the line was changed.

- Calling `morgan.token()` using the same name as an existing token will overwrite that token definition.
- Tokens can accept a string argument passed in from `[]` brackets by specifying
a third argument `arg`. In this way we could define a more generic `header` token that
outputs an arbitrary `req` header. For example:
```js
morgan.token('header', function (req, res, arg) { return req.headers[arg] })
```
Using the above example `:header[content-type]` would be the equivalent to the less generic
`:type` in the first example.

##### :date[format]

Expand Down Expand Up @@ -169,14 +214,20 @@ The contents of the User-Agent header of the request.

### morgan.compile(format)

Compile a format string into a function for use by `morgan`. A format string
Compile a format string into a format function for use by `morgan`. A format string
is a string that represents a single log line and can utilize token syntax.
Tokens are references by `:token-name`. If tokens accept arguments, they can
be passed using `[]`, for example: `:token-name[pretty]` would pass the string
`'pretty'` as an argument to the token `token-name`.

The function returned from `morgan.compile` takes three arguments `tokens` , `req`, and `res`
where `tokens` represents an object with all known tokens. If a log should be skipped the
function will return `null`.

Normally formats are defined using `morgan.format(name, format)`, but for certain
advanced uses, this compile function is directly available.
advanced uses, this compile function is directly available. The function returned can be passed directly to morgan using `morgan(morgan.compile(format))`. In other words, `morgan.compile` is a quick short-hand to turn format strings into format functions.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these two new sentences don't quite fit in with the subject of this paragraph. Is there a better place to put them?

Copy link
Contributor Author

@indexzero indexzero Oct 13, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Changed this in 1c9416c. Not sure why this Github comment wasn't hidden automatically because the line was changed.


In some rare cases (such as [outputting JSON logs from `morgan`](#output-json-logs)) you may want to write your own custom format function. These functions should have the same API as functions returned from `morgan.compile` accepting three arguments: `tokens`, `req`, and `res`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line (and the one two above) need to be wrapped with line breaks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this sentence is probably unnecessary with the added information now found at the top of the readme.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Changed this in 1c9416c. Not sure why this Github comment wasn't hidden automatically because the line was changed.


## Examples

Expand Down Expand Up @@ -310,6 +361,55 @@ function assignId (req, res, next) {
}
```

### arguments to custom token formats

Example of a custom token format that uses an argument. It will output the
property from `process` related to the argument passed to the token. If that property
is a function then it will return the value returned from that function.

```js
var express = require('express')
var morgan = require('morgan')

morgan.token('process', function getId (req, res, arg) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think "getId" is a typo here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Changed this in 1c9416c. Not sure why this Github comment wasn't hidden automatically because the line was changed.

if (typeof process[arg] === 'function') {
return String(process[arg]())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this line misses the functionality for taking advantage of the built-in falsy behavior,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Changed this in 1c9416c. Not sure why this Github comment wasn't hidden automatically because the line was changed.

} else if (process[arg]) {
return String(process[arg])
}
})
```

### output JSON logs

``` js
var express = require('express')
var morgan = require('morgan')

var route = morgan.compile(':method :url')
var outputJson = function (tokens, req, res) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not used a named function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Changed this in 1c9416c. Not sure why this Github comment wasn't hidden automatically because the line was changed.

return JSON.stringify({
route: route(tokens, req, res),
status: morgan.status(req, res),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this a typo: "morgan" should probably be "tokens" on this line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Changed this in 1c9416c. Not sure why this Github comment wasn't hidden automatically because the line was changed.

'content-length': morgan.res(req, res, 'content-length')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same morgan -> tokens typo on this line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Changed this in 1c9416c. Not sure why this Github comment wasn't hidden automatically because the line was changed.

})
}

var app = express()

app.use(morgan(outputJson))

app.get('/', function (req, res) {
res.send('hello, world!')
})
```

A request to `GET /` would cause `morgan` to log the following JSON:

``` json
{ "route": "GET /", "status": 200, "content-length": 13 }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we don't have any examples of the output for any other example apps above. If we include an example, shouldn't it at least be exactly what the user would see? I don't think JSON.stringify includes those space characters.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Changed this in 1c9416c. Not sure why this Github comment wasn't hidden automatically because the line was changed.

```

## License

[MIT](LICENSE)
Expand Down