forked from toshihirock/node-elb-log-parser
-
Notifications
You must be signed in to change notification settings - Fork 9
/
index.js
executable file
·133 lines (122 loc) · 4.1 KB
/
index.js
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#! /usr/bin/env node
/**
* Field names, in order of appearance in the ALB log lines
*/
const fields = [
'type', 'timestamp', 'elb', 'client:port',
'target:port', 'request_processing_time', 'target_processing_time', 'response_processing_time',
'elb_status_code', 'target_status_code', 'received_bytes', 'sent_bytes',
'request', 'user_agent', 'ssl_cipher', 'ssl_protocol',
'target_group_arn', 'trace_id', 'domain_name', 'chosen_cert_arn',
'matched_rule_priority', 'request_creation_time', 'actions_executed', 'redirect_url',
'error_reason', 'target:port_list', 'target_status_code_list', 'classification',
'classification_reason'
]
module.exports = function (line) {
//
// Trailing newline? NOTHX
//
if (line.match(/\n$/)) {
line = line.slice(0, line.length - 1);
}
const parsed = parseAlbLogLine(line)
return parsed
};
if (require.main === module) {
var split = require('split');
var Transform = require('stream').Transform;
process.stdin
.pipe(split())
.pipe(new Transform({
decodeStrings: false,
transform: function (line, encoding, callback) {
if (line) {
this.push(JSON.stringify(module.exports(line)) + '\n');
}
callback();
}
}))
.pipe(process.stdout);
}
/**
* Parse one line of an AWS Application Load Balancer log
*
* @param {string} line
*/
function parseAlbLogLine(line) {
const parsed = {}
let counter = 0
let finished = false
let quoteSeen = false
let element = ''
for (const c of line + ' ') {
if (finished) {
if (element) {
let fieldName = fields[counter]
// Convert all numeric strings to numbers
if (element.match(/^-?\d+.?\d*$/)) {
element = Number(element)
}
if (fieldName === 'request') {
_decorateFromRequest(element, parsed)
}
// H/T @jason-linthwaite (https://github.com/jason-linthwaite)
if (!fieldName) continue
if (fieldName.match(/^\S+?:port$/)) {
_decorateFromPortField(fieldName, element, parsed)
} else {
parsed[fieldName] = element
}
element = ''
counter++
}
finished = false
}
// treat whitespace as a delimiter *except* when inside of quotes
if (c.match(/^\s$/) && !quoteSeen) finished = true
if (c === '"') { // beginning or end of a quote delimited string
if (quoteSeen) finished = true // if we've seen one quote, this closes the quote delimited string
quoteSeen = !quoteSeen // Toggle the quote flag
} else {
// Append the character to the element unless this character terminates the element
if (!finished) element += c
}
}
return parsed
}
function _decorateFromPortField(fieldName, element, parsed) {
// We don't actually send back 'client:port' and 'target:port'; we send back
// 'client', 'client_port', 'target', and 'target_port'
const field = fieldName.match(/^(\S+?):port/)[1]
const sepIndex = element.lastIndexOf(':')
if (sepIndex === -1) {
parsed[field] = '-'
parsed[`${field}_port`] = -1
} else {
parsed[field] = element.substring(0, sepIndex)
parsed[`${field}_port`] = parseInt(element.substring(sepIndex + 1, element.length))
}
return parsed
}
/**
* Helper for parseAlbLogLine
*
* @param {string} element
* @param {object} parsed
*/
function _decorateFromRequest(element, parsed) {
const url = require('url');
const [request_method, request_uri, request_http_version] = element.split(/\s+/)
parsed.request_method = request_method
parsed.request_uri = request_uri
parsed.request_http_version = request_http_version
const parsedUrl = url.parse(request_uri)
parsed.request_uri_scheme = parsedUrl.protocol
parsed.request_uri_host = parsedUrl.hostname
if (parsedUrl.port) {
parsed.request_uri_port = parseInt(parsedUrl.port)
}
parsed.request_uri_path = parsedUrl.pathname
parsed.request_uri_query = parsedUrl.query
return parsed
}