Repository navigation
Expand file tree
/
Copy pathformat.js
More file actions
113 lines (89 loc) · 3.37 KB
/
Copy pathformat.js
File metadata and controls
113 lines (89 loc) · 3.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
module.exports = ApacheHttpdFormatter
var Hoek = require('hoek')
var debug = require('debug')('good:apache:format')
var Stream = require('stream')
var moment = require('moment')
var querystring = require('querystring')
var Pkg = require('./package.json')
var FORMAT_RE = /%(\{.*?\}|>)?[%a-zA-Z]/g
var MOMENT_FORMAT = '[[]DD/MMM/YYYY:HH:mm:ss Z[]]'
var DEFAULT = {format:'combined', separator:'\n'}
var FORMATS = { 'combined': '%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"'
, 'common' : '%h %l %u %t \"%r\" %>s %b'
, 'referer' : '%{Referer}i -> %U'
}
Hoek.inherits(ApacheHttpdFormatter, Stream.Transform)
function ApacheHttpdFormatter (options, transformOptions) {
if (!(this instanceof ApacheHttpdFormatter))
return new ApacheHttpdFormatter(options, transformOptions)
debug('Initialize formatter')
options = options || {}
options.objectMode = true
Stream.Transform.call(this, options)
transformOptions = transformOptions || {}
var config = Hoek.applyToDefaults(DEFAULT, transformOptions)
this.separator = config.separator
this.format = FORMATS[config.format] || config.format
debug('Formatter config', {separator:this.separator, format:this.format})
}
ApacheHttpdFormatter.prototype._transform = function (data, _encoding, next) {
debug('ApacheHttpdFormatter transform', data)
var timestamp = moment(data.timestamp)
var source = data.source || {}
var replacements =
{ '%%': '%'
, '%h': source.remoteAddress || '-'
, '%l': '-'
, '%u': '-'
, '%U': data.path
, '%t': timestamp.format(MOMENT_FORMAT)
, '%r': mkRequestLine(data)
, '%s': data.statusCode
, '%>s': data.statusCode
, '%b': responseBytes(data)
, '%{Referer}i': source.referer || '-'
, '%{User-agent}i': source.userAgent || '-'
}
var line = this.format.replace(FORMAT_RE, replacer)
debug('Log line: %s', line)
this.push(line + this.separator)
next(null)
function replacer(match, param) {
var val = replacements[match]
if (!val) {
console.error('WARNING: Format %j not implemented; please submit an issue or PR: %s', match, Pkg.bugs.url)
val = '-'
}
debug('Replace %s (%s): %s', match, val)
return val
}
}
//
// Utilities
//
// Return the response payload size in bytes.
// TODO: The payload size is only known if the user sets responsePayload:true in the Good options.
// TODO: If the payload is an object (something for Hapi to JSON.stringify), then this will stringify it again to determine the length.
function responseBytes(data) {
var payload = data.responsePayload
if (!payload)
return '-'
if (typeof payload == 'string' || Buffer.isBuffer(payload))
return payload.length
return JSON.stringify(payload).length
}
// Return the first line of the request.
// TODO: This line is faked, generated from data about the request. Worse, the HTTP version is hard-coded.
function mkRequestLine(data) {
var method = data.method || 'get'
var version = 'HTTP/1.1'
var firstLog = data.log && data.log[0]
if (firstLog && ~firstLog.tags.indexOf('received')) {
debug('Pull the request line from the first "received" log')
var url = firstLog.data.url
} else {
debug('Ascertain request line manually from the path and query')
var url = data.path + '?' + querystring.stringify(data.query)
}
return method.toUpperCase() + ' ' + url + ' ' + version
}