kayvee 3.17.0 → 3.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +124 -0
- package/.github/workflows/notify-ci-status.yml +20 -0
- package/.nvmrc +1 -1
- package/Makefile +0 -1
- package/build/lib/kayvee.js +13 -17
- package/build/lib/logger/logger.js +84 -76
- package/build/lib/middleware.js +56 -84
- package/build/lib/router/index.js +61 -63
- package/build/package.json +10 -6
- package/build/test/context_logger.js +36 -44
- package/build/test/kayvee.js +16 -16
- package/build/test/logger_test.js +112 -101
- package/build/test/middleware.js +81 -82
- package/build/test/router.js +232 -92
- package/lib/logger/logger.ts +17 -1
- package/lib/middleware.ts +1 -1
- package/package.json +10 -6
- package/test/middleware.ts +1 -1
- package/tsconfig.json +1 -1
- package/.eslintrc.yml +0 -44
- package/tslint.json +0 -134
package/build/lib/middleware.js
CHANGED
|
@@ -2,13 +2,6 @@
|
|
|
2
2
|
* Module dependencies.
|
|
3
3
|
* @private
|
|
4
4
|
*/
|
|
5
|
-
var __spreadArrays = (this && this.__spreadArrays) || function () {
|
|
6
|
-
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
|
|
7
|
-
for (var r = Array(s), k = 0, i = 0; i < il; i++)
|
|
8
|
-
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
|
|
9
|
-
r[k] = a[j];
|
|
10
|
-
return r;
|
|
11
|
-
};
|
|
12
5
|
var fs = require("fs");
|
|
13
6
|
var path = require("path");
|
|
14
7
|
var kayvee = require("../lib/kayvee");
|
|
@@ -18,11 +11,10 @@ var _ = require("underscore");
|
|
|
18
11
|
/**
|
|
19
12
|
* all relative files path in a directory
|
|
20
13
|
*/
|
|
21
|
-
function walkDirSync(dir, files) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
var f = path.join(dir, file);
|
|
14
|
+
function walkDirSync(dir, files = []) {
|
|
15
|
+
const list = fs.readdirSync(dir);
|
|
16
|
+
list.forEach((file) => {
|
|
17
|
+
const f = path.join(dir, file);
|
|
26
18
|
if (fs.statSync(path.join(dir, file)).isDirectory()) {
|
|
27
19
|
walkDirSync(f, files);
|
|
28
20
|
}
|
|
@@ -30,7 +22,7 @@ function walkDirSync(dir, files) {
|
|
|
30
22
|
files.push(f);
|
|
31
23
|
}
|
|
32
24
|
});
|
|
33
|
-
return files.map(
|
|
25
|
+
return files.map((f) => path.relative(dir, f));
|
|
34
26
|
}
|
|
35
27
|
/**
|
|
36
28
|
* returns a middleware function that checks if path exists in dir.
|
|
@@ -38,12 +30,11 @@ function walkDirSync(dir, files) {
|
|
|
38
30
|
* Files in the directory are prefixed by base_path and compared to
|
|
39
31
|
* req.path
|
|
40
32
|
*/
|
|
41
|
-
function skip_path(dir, base_path) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
return function (req, res) { return _(files).contains(req.path) && res.statusCode < 400; };
|
|
33
|
+
function skip_path(dir, base_path = "/") {
|
|
34
|
+
let files = walkDirSync(dir);
|
|
35
|
+
files = files.map((file) => path.join(base_path, file));
|
|
36
|
+
console.error(`KayveeMiddleware: Skipping successful requests for files in ${dir} at ${base_path}`);
|
|
37
|
+
return (req, res) => _(files).contains(req.path) && res.statusCode < 400;
|
|
47
38
|
}
|
|
48
39
|
/**
|
|
49
40
|
* request path
|
|
@@ -63,7 +54,7 @@ function getQueryParams(req) {
|
|
|
63
54
|
allowPrototypes: false,
|
|
64
55
|
ignoreQueryPrefix: true,
|
|
65
56
|
});
|
|
66
|
-
return
|
|
57
|
+
return `?${require("qs").stringify(parsedQueryString)}`;
|
|
67
58
|
}
|
|
68
59
|
/**
|
|
69
60
|
* response size
|
|
@@ -104,8 +95,8 @@ function getIp(req) {
|
|
|
104
95
|
* Log level
|
|
105
96
|
*/
|
|
106
97
|
function getLogLevel(req, res) {
|
|
107
|
-
|
|
108
|
-
|
|
98
|
+
const statusCode = res.statusCode;
|
|
99
|
+
let result;
|
|
109
100
|
if (statusCode >= 499) {
|
|
110
101
|
result = KayveeLogger.Error;
|
|
111
102
|
}
|
|
@@ -119,53 +110,45 @@ function getLogLevel(req, res) {
|
|
|
119
110
|
*/
|
|
120
111
|
var defaultHandlers = [
|
|
121
112
|
// Request method
|
|
122
|
-
|
|
113
|
+
(req) => ({ method: req.method }),
|
|
123
114
|
// Path (URL without query params)
|
|
124
|
-
|
|
115
|
+
(req) => ({ path: getBaseUrl(req) }),
|
|
125
116
|
// Query params
|
|
126
|
-
|
|
117
|
+
(req) => ({ params: getQueryParams(req) }),
|
|
127
118
|
// Response size
|
|
128
|
-
|
|
119
|
+
(req, res) => ({ "response-size": getResponseSize(res) }),
|
|
129
120
|
// Response time (ns)
|
|
130
|
-
|
|
121
|
+
(req, res) => ({ "response-time": getResponseTimeNs(req, res) }),
|
|
131
122
|
// Status code
|
|
132
|
-
|
|
123
|
+
(req, res) => ({ "status-code": res.statusCode }),
|
|
133
124
|
// Ip address
|
|
134
|
-
|
|
125
|
+
(req) => ({ ip: getIp(req) }),
|
|
135
126
|
// Via -- what library/code produced this log?
|
|
136
|
-
|
|
127
|
+
() => ({ via: "kayvee-middleware" }),
|
|
137
128
|
// Kayvee's reserved fields
|
|
138
129
|
// Log level
|
|
139
|
-
|
|
130
|
+
(req, res) => ({ level: getLogLevel(req, res) }),
|
|
140
131
|
// Source -- which app emitted this log?
|
|
141
132
|
// -> Gets passed in among `options` during library initialization
|
|
142
133
|
// Title
|
|
143
|
-
|
|
134
|
+
() => ({ title: "request-finished" }),
|
|
144
135
|
];
|
|
145
|
-
|
|
146
|
-
function handlerData(handlers) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
args[_i - 1] = arguments[_i];
|
|
150
|
-
}
|
|
151
|
-
var data = {};
|
|
152
|
-
handlers.forEach(function (h) {
|
|
136
|
+
const defaultContextHandlers = [];
|
|
137
|
+
function handlerData(handlers, ...args) {
|
|
138
|
+
const data = {};
|
|
139
|
+
handlers.forEach((h) => {
|
|
153
140
|
try {
|
|
154
|
-
|
|
141
|
+
const handler_data = h(...args);
|
|
155
142
|
_.extend(data, handler_data);
|
|
156
143
|
}
|
|
157
144
|
catch (e) {
|
|
158
|
-
//
|
|
145
|
+
// swallow invalid handler
|
|
159
146
|
}
|
|
160
147
|
});
|
|
161
148
|
return data;
|
|
162
149
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
var args = [];
|
|
166
|
-
for (var _i = 2; _i < arguments.length; _i++) {
|
|
167
|
-
args[_i - 2] = arguments[_i];
|
|
168
|
-
}
|
|
150
|
+
class ContextLogger {
|
|
151
|
+
constructor(logger, handlers, ...args) {
|
|
169
152
|
this.logger = null;
|
|
170
153
|
this.handlers = [];
|
|
171
154
|
this.args = [];
|
|
@@ -173,34 +156,25 @@ var ContextLogger = /** @class */ (function () {
|
|
|
173
156
|
this.handlers = handlers;
|
|
174
157
|
this.args = args;
|
|
175
158
|
}
|
|
176
|
-
|
|
177
|
-
return _.extend(handlerData
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
var _loop_1 = function (func) {
|
|
159
|
+
_contextualData(data) {
|
|
160
|
+
return _.extend(handlerData(this.handlers, ...this.args), data);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
for (const func of KayveeLogger.LEVELS) {
|
|
182
164
|
ContextLogger.prototype[func] = function (title) {
|
|
183
|
-
this[func
|
|
165
|
+
this[`${func}D`](title, {});
|
|
184
166
|
};
|
|
185
|
-
ContextLogger.prototype[func
|
|
186
|
-
this.logger[func
|
|
167
|
+
ContextLogger.prototype[`${func}D`] = function (title, data) {
|
|
168
|
+
this.logger[`${func}D`](title, this._contextualData(data));
|
|
187
169
|
};
|
|
188
|
-
};
|
|
189
|
-
for (var _i = 0, _a = KayveeLogger.LEVELS; _i < _a.length; _i++) {
|
|
190
|
-
var func = _a[_i];
|
|
191
|
-
_loop_1(func);
|
|
192
170
|
}
|
|
193
|
-
|
|
171
|
+
for (const func of KayveeLogger.METRICS) {
|
|
194
172
|
ContextLogger.prototype[func] = function (title, value) {
|
|
195
|
-
this[func
|
|
173
|
+
this[`${func}D`](title, value, {});
|
|
196
174
|
};
|
|
197
|
-
ContextLogger.prototype[func
|
|
198
|
-
this.logger[func
|
|
175
|
+
ContextLogger.prototype[`${func}D`] = function (title, value, data) {
|
|
176
|
+
this.logger[`${func}D`](title, value, this._contextualData(data));
|
|
199
177
|
};
|
|
200
|
-
};
|
|
201
|
-
for (var _b = 0, _c = KayveeLogger.METRICS; _b < _c.length; _b++) {
|
|
202
|
-
var func = _c[_b];
|
|
203
|
-
_loop_2(func);
|
|
204
178
|
}
|
|
205
179
|
/*
|
|
206
180
|
* User configuration is passed via an `options` object.
|
|
@@ -225,20 +199,20 @@ for (var _b = 0, _c = KayveeLogger.METRICS; _b < _c.length; _b++) {
|
|
|
225
199
|
* base_handlers: e.g. [function(request, response) { return {"key":"val"}]
|
|
226
200
|
*
|
|
227
201
|
*/
|
|
228
|
-
var formatLine =
|
|
202
|
+
var formatLine = (options_arg) => {
|
|
229
203
|
var options = options_arg || {};
|
|
230
204
|
// `source` is the one required field
|
|
231
205
|
if (!options.source) {
|
|
232
206
|
throw Error("Missing required config for 'source' in Kayvee middleware 'options'");
|
|
233
207
|
}
|
|
234
|
-
|
|
235
|
-
return
|
|
208
|
+
const router = KayveeLogger.getGlobalRouter();
|
|
209
|
+
return (tokens, req, res) => {
|
|
236
210
|
// Build a dict of data to log
|
|
237
211
|
var data = { _kvmeta: undefined }; // Adding _kvmeta here to make typescript compile happy
|
|
238
212
|
// Add user-configured request headers
|
|
239
213
|
var custom_headers = options.headers || [];
|
|
240
214
|
var header_data = {};
|
|
241
|
-
custom_headers.forEach(
|
|
215
|
+
custom_headers.forEach((h) => {
|
|
242
216
|
// Header field names are case insensitive, so let's be consistent
|
|
243
217
|
var lc = h.toLowerCase();
|
|
244
218
|
header_data[lc] = req.headers[lc];
|
|
@@ -248,9 +222,9 @@ var formatLine = function (options_arg) {
|
|
|
248
222
|
var custom_handlers = options.handlers || [];
|
|
249
223
|
// Allow user to override `base_handlers`; provide sane default set of handlers
|
|
250
224
|
var base_handlers = options.base_handlers || defaultHandlers;
|
|
251
|
-
base_handlers = base_handlers.concat([
|
|
225
|
+
base_handlers = base_handlers.concat([() => ({ source: options.source })]);
|
|
252
226
|
// Execute custom-handlers THEN base-handlers
|
|
253
|
-
|
|
227
|
+
const all_handlers = custom_handlers.concat(base_handlers);
|
|
254
228
|
_.extend(data, handlerData(all_handlers, req, res));
|
|
255
229
|
if (router) {
|
|
256
230
|
data._kvmeta = router.route(data);
|
|
@@ -258,7 +232,7 @@ var formatLine = function (options_arg) {
|
|
|
258
232
|
return kayvee.format(data);
|
|
259
233
|
};
|
|
260
234
|
};
|
|
261
|
-
|
|
235
|
+
const defaultContextLoggerOpts = {
|
|
262
236
|
enabled: true,
|
|
263
237
|
handlers: defaultContextHandlers,
|
|
264
238
|
};
|
|
@@ -267,8 +241,7 @@ var defaultContextLoggerOpts = {
|
|
|
267
241
|
* @public
|
|
268
242
|
*/
|
|
269
243
|
if (process.env.NODE_ENV === "test") {
|
|
270
|
-
module.exports =
|
|
271
|
-
if (morgan_options === void 0) { morgan_options = { skip: null }; }
|
|
244
|
+
module.exports = (clever_options, morgan_options = { skip: null }) => {
|
|
272
245
|
if (clever_options.ignore_dir) {
|
|
273
246
|
morgan_options.skip = skip_path(clever_options.ignore_dir.directory, clever_options.ignore_dir.path);
|
|
274
247
|
}
|
|
@@ -277,22 +250,21 @@ if (process.env.NODE_ENV === "test") {
|
|
|
277
250
|
module.exports.ContextLogger = ContextLogger;
|
|
278
251
|
}
|
|
279
252
|
else {
|
|
280
|
-
module.exports =
|
|
281
|
-
if (context_logger_options === void 0) { context_logger_options = defaultContextLoggerOpts; }
|
|
253
|
+
module.exports = (clever_options, context_logger_options = defaultContextLoggerOpts) => {
|
|
282
254
|
// `source` is the one required field
|
|
283
255
|
if (!clever_options.source) {
|
|
284
256
|
throw new Error("Missing required config for 'source' in Kayvee middleware 'options'");
|
|
285
257
|
}
|
|
286
|
-
|
|
287
|
-
|
|
258
|
+
const logger = new KayveeLogger(clever_options.source);
|
|
259
|
+
const morgan_options = {
|
|
288
260
|
stream: process.stderr,
|
|
289
261
|
skip: null,
|
|
290
262
|
};
|
|
291
263
|
if (clever_options.ignore_dir) {
|
|
292
264
|
morgan_options.skip = skip_path(clever_options.ignore_dir.directory, clever_options.ignore_dir.path);
|
|
293
265
|
}
|
|
294
|
-
|
|
295
|
-
return
|
|
266
|
+
const morgan_logger = morgan(formatLine(clever_options), morgan_options);
|
|
267
|
+
return (req, res, next) => {
|
|
296
268
|
if (context_logger_options.enabled) {
|
|
297
269
|
req.log = new ContextLogger(logger, context_logger_options.handlers, req);
|
|
298
270
|
}
|
|
@@ -4,20 +4,20 @@ var schema = require("./schema_definitions");
|
|
|
4
4
|
var yaml = require("js-yaml");
|
|
5
5
|
var _ = require("underscore");
|
|
6
6
|
var packageJson = require("../../package.json");
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
const kvVersion = packageJson.version;
|
|
8
|
+
const teamName = process.env._TEAM_OWNER || "UNSET";
|
|
9
|
+
const reEnvvarTokens = new RegExp("\\$\\{(.+?)\\}", "g");
|
|
10
|
+
const reFieldTokens = new RegExp("%\\{(.+?)\\}", "g");
|
|
11
11
|
// For performance reason this code is intentionally redundant and not-inlined.
|
|
12
12
|
// Removing redundancy and inlining this function some how makes performance worst.
|
|
13
13
|
function substituteEnvVars(obj, subber) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
for (
|
|
17
|
-
|
|
14
|
+
const rtn = {};
|
|
15
|
+
const replacer = (s) => s.replace(reEnvvarTokens, (__, p1) => subber(p1));
|
|
16
|
+
for (const key in obj) {
|
|
17
|
+
const val = obj[key];
|
|
18
18
|
if (Array.isArray(val)) {
|
|
19
|
-
|
|
20
|
-
for (
|
|
19
|
+
const updatedVals = Array(val.length);
|
|
20
|
+
for (let i = 0; i < val.length; i++) {
|
|
21
21
|
updatedVals[i] = replacer(val[i]);
|
|
22
22
|
}
|
|
23
23
|
rtn[key] = updatedVals;
|
|
@@ -29,51 +29,51 @@ function substituteEnvVars(obj, subber) {
|
|
|
29
29
|
return rtn;
|
|
30
30
|
}
|
|
31
31
|
function deepKey(obj, key) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
const path = key.split(".");
|
|
33
|
+
let idx = 0;
|
|
34
|
+
let val = obj;
|
|
35
35
|
do {
|
|
36
36
|
val = val[path[idx++]];
|
|
37
37
|
} while (val && idx < path.length);
|
|
38
38
|
return val;
|
|
39
39
|
}
|
|
40
40
|
function fieldMatches(obj, field, values) {
|
|
41
|
-
|
|
41
|
+
const val = obj[field] || deepKey(obj, field);
|
|
42
42
|
if (val == null || val === "") {
|
|
43
43
|
return false;
|
|
44
44
|
}
|
|
45
45
|
if (values[0] === "*") {
|
|
46
46
|
return true;
|
|
47
47
|
}
|
|
48
|
-
for (
|
|
48
|
+
for (let i = 0; i < values.length; i++) {
|
|
49
49
|
if (values[i] === val) {
|
|
50
50
|
return true;
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
return false;
|
|
54
54
|
}
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
class Rule {
|
|
56
|
+
constructor(name, matchers, output) {
|
|
57
57
|
this.name = null;
|
|
58
58
|
this.matchers = null;
|
|
59
59
|
this.output = null;
|
|
60
60
|
this.name = name;
|
|
61
61
|
this.matchers = matchers;
|
|
62
|
-
|
|
63
|
-
this.output = substituteEnvVars(output,
|
|
64
|
-
|
|
62
|
+
const envMissing = [];
|
|
63
|
+
this.output = substituteEnvVars(output, (k) => {
|
|
64
|
+
const val = process.env[k];
|
|
65
65
|
if (val == null) {
|
|
66
66
|
envMissing.push(k);
|
|
67
67
|
}
|
|
68
68
|
return val;
|
|
69
69
|
});
|
|
70
70
|
if (envMissing.length > 0) {
|
|
71
|
-
throw new Error(
|
|
71
|
+
throw new Error(`Missing env var(s): ${envMissing.join(", ")}`);
|
|
72
72
|
}
|
|
73
|
-
Object.keys(matchers).forEach(
|
|
74
|
-
|
|
73
|
+
Object.keys(matchers).forEach((field) => {
|
|
74
|
+
const fieldVals = matchers[field];
|
|
75
75
|
if (fieldVals.indexOf("*") !== -1 && fieldVals.length > 1) {
|
|
76
|
-
throw new Error(
|
|
76
|
+
throw new Error(`Invalid matcher values in ${name}.${field}.\n` +
|
|
77
77
|
"Wildcard matcher can't co-exist with other matchers.");
|
|
78
78
|
}
|
|
79
79
|
});
|
|
@@ -83,24 +83,24 @@ var Rule = /** @class */ (function () {
|
|
|
83
83
|
this.output.rule = this.name;
|
|
84
84
|
}
|
|
85
85
|
// matches returns true if `msg` matches against this rule
|
|
86
|
-
|
|
87
|
-
for (
|
|
86
|
+
matches(msg) {
|
|
87
|
+
for (const field in this.matchers) {
|
|
88
88
|
if (!fieldMatches(msg, field, this.matchers[field])) {
|
|
89
89
|
return false;
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
return true;
|
|
93
|
-
}
|
|
93
|
+
}
|
|
94
94
|
// returns the output with kv substitutions performed
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
for (
|
|
100
|
-
|
|
95
|
+
outputFor(msg) {
|
|
96
|
+
const rtn = {};
|
|
97
|
+
const subst = (__, k) => msg[k] || deepKey(msg, k) || "KEY_NOT_FOUND";
|
|
98
|
+
const replacer = (s) => s.replace(reFieldTokens, subst);
|
|
99
|
+
for (const key in this.output) {
|
|
100
|
+
const val = this.output[key];
|
|
101
101
|
if (Array.isArray(val)) {
|
|
102
|
-
|
|
103
|
-
for (
|
|
102
|
+
const updatedVals = Array(val.length);
|
|
103
|
+
for (let i = 0; i < val.length; i++) {
|
|
104
104
|
updatedVals[i] = replacer(val[i]);
|
|
105
105
|
}
|
|
106
106
|
rtn[key] = updatedVals;
|
|
@@ -110,9 +110,8 @@ var Rule = /** @class */ (function () {
|
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
return rtn;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
}());
|
|
113
|
+
}
|
|
114
|
+
}
|
|
116
115
|
// validateKVConfig ensures that `routes` matches the config schema. We have this
|
|
117
116
|
// function instead of just doing a plain jsonschema.validate in order to get
|
|
118
117
|
// better error messages for the "output" object (by default jsonschema would
|
|
@@ -120,11 +119,11 @@ var Rule = /** @class */ (function () {
|
|
|
120
119
|
// formats, but won't tell you what's wrong because it doesn't let you
|
|
121
120
|
// condition on the output.type property).
|
|
122
121
|
function validateKVConfig(config) {
|
|
123
|
-
|
|
124
|
-
|
|
122
|
+
const validator = new jsonschema.Validator();
|
|
123
|
+
const results = validator.validate(config, schema);
|
|
125
124
|
return {
|
|
126
125
|
valid: results.valid,
|
|
127
|
-
errors: results.errors.map(
|
|
126
|
+
errors: results.errors.map((err) => err.stack),
|
|
128
127
|
};
|
|
129
128
|
}
|
|
130
129
|
// parseConfig parses and validates the configuration passed as a string. It
|
|
@@ -132,53 +131,53 @@ function validateKVConfig(config) {
|
|
|
132
131
|
// it was successfully parsed, rules is an array of rules, and errors is an
|
|
133
132
|
// array of errors.
|
|
134
133
|
function parseConfig(fileString) {
|
|
135
|
-
|
|
134
|
+
let config;
|
|
136
135
|
try {
|
|
137
136
|
config = yaml.safeLoad(fileString);
|
|
138
137
|
}
|
|
139
138
|
catch (e) {
|
|
140
139
|
return { valid: false, rules: [], errors: [e] };
|
|
141
140
|
}
|
|
142
|
-
|
|
141
|
+
const validateRes = validateKVConfig(config);
|
|
143
142
|
if (!validateRes.valid) {
|
|
144
143
|
return _.assign(validateRes, { rules: [] });
|
|
145
144
|
}
|
|
146
145
|
try {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
return { valid: true, rules
|
|
146
|
+
const rulesObj = _.mapObject(config.routes, (elem, name) => new Rule(name, elem.matchers, elem.output));
|
|
147
|
+
const rules = _.values(rulesObj);
|
|
148
|
+
return { valid: true, rules, errors: [] };
|
|
150
149
|
}
|
|
151
150
|
catch (e) {
|
|
152
151
|
return { valid: false, rules: [], errors: [e] };
|
|
153
152
|
}
|
|
154
153
|
}
|
|
155
|
-
|
|
156
|
-
|
|
154
|
+
class Router {
|
|
155
|
+
constructor(rules) {
|
|
157
156
|
this.rules = null;
|
|
158
157
|
this.rules = rules || [];
|
|
159
158
|
}
|
|
160
159
|
// loadConfig reads in the config located at `filename` and sets the routing
|
|
161
160
|
// rules to what it finds there. It should be a YAML-formatted file with
|
|
162
161
|
// routing rules placed under the `routes` key on the root object.
|
|
163
|
-
|
|
164
|
-
|
|
162
|
+
loadConfig(filename) {
|
|
163
|
+
const data = fs.readFileSync(filename, "utf8");
|
|
165
164
|
this._loadConfigString(data);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
|
|
165
|
+
}
|
|
166
|
+
_loadConfigString(configStr) {
|
|
167
|
+
const parsedRules = parseConfig(configStr);
|
|
169
168
|
if (!parsedRules.valid) {
|
|
170
169
|
throw new Error(parsedRules.errors);
|
|
171
170
|
}
|
|
172
171
|
this.rules = parsedRules.rules;
|
|
173
|
-
}
|
|
172
|
+
}
|
|
174
173
|
// route matches the log line `msg` against all loaded rules and returns a
|
|
175
174
|
// metadata object describing the outputs it should be sent to based on that
|
|
176
175
|
// matching. logger.ts will attach this to log lines under the `_kvmeta`
|
|
177
176
|
// property.
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
for (
|
|
181
|
-
|
|
177
|
+
route(msg) {
|
|
178
|
+
const outputs = [];
|
|
179
|
+
for (let i = 0; i < this.rules.length; i++) {
|
|
180
|
+
const rule = this.rules[i];
|
|
182
181
|
if (rule.matches(msg)) {
|
|
183
182
|
outputs.push(rule.outputFor(msg));
|
|
184
183
|
}
|
|
@@ -189,10 +188,9 @@ var Router = /** @class */ (function () {
|
|
|
189
188
|
kv_language: "js",
|
|
190
189
|
routes: outputs,
|
|
191
190
|
};
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
}());
|
|
191
|
+
}
|
|
192
|
+
}
|
|
195
193
|
module.exports = {
|
|
196
|
-
Router
|
|
197
|
-
Rule
|
|
194
|
+
Router,
|
|
195
|
+
Rule,
|
|
198
196
|
};
|
package/build/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kayvee",
|
|
3
3
|
"description": "Write data to key=val pairs, for human and machine readability",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.18.0",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -19,20 +19,24 @@
|
|
|
19
19
|
"@clever/prettier-config": "1.0.0",
|
|
20
20
|
"@types/mocha": "^8.0.3",
|
|
21
21
|
"@types/node": "^12.12.68",
|
|
22
|
+
"@typescript-eslint/eslint-plugin": "^5.2.0",
|
|
23
|
+
"@typescript-eslint/parser": "^5.2.0",
|
|
22
24
|
"babel-eslint": "^6.0.2",
|
|
23
25
|
"benchmark": "^2.1.1",
|
|
24
|
-
"eslint": "^
|
|
26
|
+
"eslint": "^7.11.0",
|
|
25
27
|
"eslint-config-airbnb": "^7.0.0",
|
|
26
|
-
"eslint-
|
|
27
|
-
"eslint-
|
|
28
|
+
"eslint-config-prettier": "^6.12.0",
|
|
29
|
+
"eslint-formatter-summary": "^1.1.0",
|
|
30
|
+
"eslint-plugin-jsx-a11y": "^6.3.1",
|
|
31
|
+
"eslint-plugin-react": "^7.21.5",
|
|
32
|
+
"eslint-plugin-react-hooks": "^4.1.2",
|
|
28
33
|
"express": "^4.13.4",
|
|
29
34
|
"mocha": "^3.5.3",
|
|
30
35
|
"prettier": "2.1.2",
|
|
31
36
|
"sinon": "^1.17.4",
|
|
32
37
|
"supertest": "^1.2.0",
|
|
33
38
|
"ts-node": "^9.0.0",
|
|
34
|
-
"
|
|
35
|
-
"typescript": "^4.0.3"
|
|
39
|
+
"typescript": "^3.9.10"
|
|
36
40
|
},
|
|
37
41
|
"scripts": {
|
|
38
42
|
"test": "make -Br test",
|