kayvee 3.17.0 → 4.0.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/README.md +147 -202
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/kayvee.d.ts +12 -0
- package/dist/kayvee.d.ts.map +1 -0
- package/dist/kayvee.js +50 -0
- package/dist/logger/logger.d.ts +49 -0
- package/dist/logger/logger.d.ts.map +1 -0
- package/dist/logger/logger.js +237 -0
- package/dist/middleware.d.ts +23 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +196 -0
- package/dist/package.json +89 -0
- package/dist/router/index.d.ts +23 -0
- package/dist/router/index.d.ts.map +1 -0
- package/dist/router/index.js +184 -0
- package/package.json +64 -24
- package/.circleci/config.yml +0 -25
- package/.eslintrc.yml +0 -44
- package/.nvmrc +0 -1
- package/.prettierrc.json +0 -1
- package/Makefile +0 -56
- package/benchmarks/data/.keep +0 -1
- package/benchmarks/data/corpus-basic.json +0 -22
- package/benchmarks/data/corpus-pathological.json +0 -22
- package/benchmarks/data/corpus-realistic.json +0 -22
- package/benchmarks/data/kvconfig-basic.yml +0 -7
- package/benchmarks/data/kvconfig-pathological.yml +0 -222
- package/benchmarks/data/kvconfig-realistic.yml +0 -39
- package/benchmarks/routing.js +0 -116
- package/build/lib/kayvee.js +0 -67
- package/build/lib/logger/helpers.js +0 -0
- package/build/lib/logger/logger.js +0 -221
- package/build/lib/middleware.js +0 -302
- package/build/lib/router/index.js +0 -198
- package/build/package.json +0 -49
- package/build/test/context_logger.js +0 -77
- package/build/test/kayvee.js +0 -36
- package/build/test/logger_test.js +0 -334
- package/build/test/middleware.js +0 -557
- package/build/test/router.js +0 -311
- package/index.js +0 -7
- package/lib/kayvee.ts +0 -73
- package/lib/logger/helpers.ts +0 -0
- package/lib/logger/logger.ts +0 -296
- package/lib/middleware.ts +0 -317
- package/lib/router/index.ts +0 -234
- package/lib/router/schema_definitions.json +0 -158
- package/test/context_logger.ts +0 -76
- package/test/kayvee.ts +0 -50
- package/test/kvconfig.yml +0 -14
- package/test/logger_test.ts +0 -378
- package/test/middleware.ts +0 -632
- package/test/router.ts +0 -558
- package/test/static/empty.css +0 -0
- package/test/static/js/empty.js +0 -0
- package/test/tests.json +0 -100
- package/tsconfig.json +0 -10
- package/tslint.json +0 -134
- /package/{build/lib → dist}/router/schema_definitions.json +0 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.Logger = void 0;
|
|
37
|
+
exports.setGlobalRouting = setGlobalRouting;
|
|
38
|
+
exports.getGlobalRouter = getGlobalRouter;
|
|
39
|
+
exports.mockRouting = mockRouting;
|
|
40
|
+
const kv = __importStar(require("../kayvee"));
|
|
41
|
+
const router_1 = require("../router");
|
|
42
|
+
const LEVELS = {
|
|
43
|
+
Trace: "trace",
|
|
44
|
+
Debug: "debug",
|
|
45
|
+
Info: "info",
|
|
46
|
+
Warning: "warning",
|
|
47
|
+
Error: "error",
|
|
48
|
+
Critical: "critical",
|
|
49
|
+
};
|
|
50
|
+
const LOG_LEVEL_ENUM = {
|
|
51
|
+
trace: 0,
|
|
52
|
+
debug: 1,
|
|
53
|
+
info: 2,
|
|
54
|
+
warning: 3,
|
|
55
|
+
error: 4,
|
|
56
|
+
critical: 5,
|
|
57
|
+
};
|
|
58
|
+
let globalRouter;
|
|
59
|
+
function setGlobalRouting(filename) {
|
|
60
|
+
globalRouter = new router_1.Router();
|
|
61
|
+
globalRouter.loadConfig(filename);
|
|
62
|
+
}
|
|
63
|
+
function getGlobalRouter() {
|
|
64
|
+
return globalRouter;
|
|
65
|
+
}
|
|
66
|
+
class Logger {
|
|
67
|
+
static Trace = LEVELS.Trace;
|
|
68
|
+
static Debug = LEVELS.Debug;
|
|
69
|
+
static Info = LEVELS.Info;
|
|
70
|
+
static Warning = LEVELS.Warning;
|
|
71
|
+
static Error = LEVELS.Error;
|
|
72
|
+
static Critical = LEVELS.Critical;
|
|
73
|
+
static LEVELS = ["trace", "debug", "info", "warn", "error", "critical"];
|
|
74
|
+
static METRICS = ["counter", "gauge"];
|
|
75
|
+
formatter;
|
|
76
|
+
logLvl;
|
|
77
|
+
globals;
|
|
78
|
+
logWriter;
|
|
79
|
+
logRouter;
|
|
80
|
+
asyncLocalStorage;
|
|
81
|
+
constructor(source, logLvl = process.env.KAYVEE_LOG_LEVEL, formatter = kv.format, output = console.error) {
|
|
82
|
+
this.formatter = formatter;
|
|
83
|
+
this.logLvl = this._validateLogLvl(logLvl);
|
|
84
|
+
this.globals = {};
|
|
85
|
+
this.globals.source = source;
|
|
86
|
+
this.logWriter = output;
|
|
87
|
+
this.logRouter = null;
|
|
88
|
+
this.asyncLocalStorage = null;
|
|
89
|
+
if (process.env._TEAM_OWNER)
|
|
90
|
+
this.globals.team = process.env._TEAM_OWNER;
|
|
91
|
+
if (process.env._DEPLOY_ENV)
|
|
92
|
+
this.globals.deploy_env = process.env._DEPLOY_ENV;
|
|
93
|
+
if (process.env._EXECUTION_NAME)
|
|
94
|
+
this.globals.wf_id = process.env._EXECUTION_NAME;
|
|
95
|
+
if (process.env._POD_ID)
|
|
96
|
+
this.globals["pod-id"] = process.env._POD_ID;
|
|
97
|
+
if (process.env._POD_SHORTNAME)
|
|
98
|
+
this.globals["pod-shortname"] = process.env._POD_SHORTNAME;
|
|
99
|
+
if (process.env._POD_REGION)
|
|
100
|
+
this.globals["pod-region"] = process.env._POD_REGION;
|
|
101
|
+
if (process.env._POD_ACCOUNT)
|
|
102
|
+
this.globals["pod-account"] = process.env._POD_ACCOUNT;
|
|
103
|
+
}
|
|
104
|
+
setAsyncLocalStorage(asyncLocalStorage) {
|
|
105
|
+
this.asyncLocalStorage = asyncLocalStorage;
|
|
106
|
+
}
|
|
107
|
+
setRouter(r) {
|
|
108
|
+
this.logRouter = r;
|
|
109
|
+
}
|
|
110
|
+
setConfig(source, logLvl, formatter, output) {
|
|
111
|
+
this.globals.source = source;
|
|
112
|
+
this.logLvl = this._validateLogLvl(logLvl);
|
|
113
|
+
this.formatter = formatter;
|
|
114
|
+
this.logWriter = output;
|
|
115
|
+
return this.logWriter;
|
|
116
|
+
}
|
|
117
|
+
_validateLogLvl(logLvl) {
|
|
118
|
+
if (logLvl == null)
|
|
119
|
+
return LEVELS.Debug;
|
|
120
|
+
for (const value of Object.values(LEVELS)) {
|
|
121
|
+
if (logLvl.toLowerCase() === value)
|
|
122
|
+
return value;
|
|
123
|
+
}
|
|
124
|
+
return LEVELS.Debug;
|
|
125
|
+
}
|
|
126
|
+
setLogLevel(logLvl) {
|
|
127
|
+
this.logLvl = this._validateLogLvl(logLvl);
|
|
128
|
+
return this.logLvl;
|
|
129
|
+
}
|
|
130
|
+
setFormatter(formatter) {
|
|
131
|
+
this.formatter = formatter;
|
|
132
|
+
return this.formatter;
|
|
133
|
+
}
|
|
134
|
+
setOutput(output) {
|
|
135
|
+
this.logWriter = output;
|
|
136
|
+
return this.logWriter;
|
|
137
|
+
}
|
|
138
|
+
trace(title) {
|
|
139
|
+
this.traceD(title, {});
|
|
140
|
+
}
|
|
141
|
+
debug(title) {
|
|
142
|
+
this.debugD(title, {});
|
|
143
|
+
}
|
|
144
|
+
info(title) {
|
|
145
|
+
this.infoD(title, {});
|
|
146
|
+
}
|
|
147
|
+
warn(title) {
|
|
148
|
+
this.warnD(title, {});
|
|
149
|
+
}
|
|
150
|
+
error(title) {
|
|
151
|
+
this.errorD(title, {});
|
|
152
|
+
}
|
|
153
|
+
critical(title) {
|
|
154
|
+
this.criticalD(title, {});
|
|
155
|
+
}
|
|
156
|
+
counter(title) {
|
|
157
|
+
this.counterD(title, 1, {});
|
|
158
|
+
}
|
|
159
|
+
gauge(title, value) {
|
|
160
|
+
this.gaugeD(title, value, {});
|
|
161
|
+
}
|
|
162
|
+
traceD(title, data) {
|
|
163
|
+
this._logWithLevel(LEVELS.Trace, { title }, data);
|
|
164
|
+
}
|
|
165
|
+
debugD(title, data) {
|
|
166
|
+
this._logWithLevel(LEVELS.Debug, { title }, data);
|
|
167
|
+
}
|
|
168
|
+
infoD(title, data) {
|
|
169
|
+
this._logWithLevel(LEVELS.Info, { title }, data);
|
|
170
|
+
}
|
|
171
|
+
warnD(title, data) {
|
|
172
|
+
this._logWithLevel(LEVELS.Warning, { title }, data);
|
|
173
|
+
}
|
|
174
|
+
errorD(title, data) {
|
|
175
|
+
this._logWithLevel(LEVELS.Error, { title }, data);
|
|
176
|
+
}
|
|
177
|
+
criticalD(title, data) {
|
|
178
|
+
this._logWithLevel(LEVELS.Critical, { title }, data);
|
|
179
|
+
}
|
|
180
|
+
counterD(title, value, data) {
|
|
181
|
+
this._logWithLevel(LEVELS.Info, { title, value, type: "counter" }, data);
|
|
182
|
+
}
|
|
183
|
+
gaugeD(title, value, data) {
|
|
184
|
+
this._logWithLevel(LEVELS.Info, { title, value, type: "gauge" }, data);
|
|
185
|
+
}
|
|
186
|
+
_logWithLevel(logLvl, metadata, userdata) {
|
|
187
|
+
if (LOG_LEVEL_ENUM[logLvl] < LOG_LEVEL_ENUM[this.logLvl])
|
|
188
|
+
return;
|
|
189
|
+
const store = this.asyncLocalStorage && this.asyncLocalStorage.getStore();
|
|
190
|
+
const storeData = store || { get: () => ({}) };
|
|
191
|
+
const contextData = storeData.get("context") ? storeData.get("context") : {};
|
|
192
|
+
const plainContextData = contextData instanceof Map ? Object.fromEntries(contextData) : contextData;
|
|
193
|
+
const data = Object.assign({ level: logLvl }, this.globals, metadata, plainContextData, userdata);
|
|
194
|
+
if (this.logRouter) {
|
|
195
|
+
data._kvmeta = this.logRouter.route(data);
|
|
196
|
+
}
|
|
197
|
+
else if (globalRouter) {
|
|
198
|
+
data._kvmeta = globalRouter.route(data);
|
|
199
|
+
}
|
|
200
|
+
this.logWriter(this.formatter(data));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
exports.Logger = Logger;
|
|
204
|
+
function mockRouting(cb) {
|
|
205
|
+
const _logWithLevel = Logger.prototype._logWithLevel;
|
|
206
|
+
if (_logWithLevel.isMocked) {
|
|
207
|
+
throw Error("Nested kv.mockRouting calls are not supported");
|
|
208
|
+
}
|
|
209
|
+
const ruleMatches = {};
|
|
210
|
+
Logger.prototype._logWithLevel = function (logLvl, metadata, userdata) {
|
|
211
|
+
const formatter = this.formatter;
|
|
212
|
+
const logWriter = this.logWriter;
|
|
213
|
+
this.formatter = (msg) => msg;
|
|
214
|
+
this.logWriter = (msg) => {
|
|
215
|
+
if (!msg._kvmeta)
|
|
216
|
+
return;
|
|
217
|
+
msg._kvmeta.routes.forEach((route) => {
|
|
218
|
+
ruleMatches[route.rule] = (ruleMatches[route.rule] || []).concat(route);
|
|
219
|
+
});
|
|
220
|
+
};
|
|
221
|
+
_logWithLevel.call(this, logLvl, metadata, userdata);
|
|
222
|
+
this.formatter = formatter;
|
|
223
|
+
this.logWriter = logWriter;
|
|
224
|
+
};
|
|
225
|
+
Logger.prototype._logWithLevel.isMocked = true;
|
|
226
|
+
const done = () => {
|
|
227
|
+
Logger.prototype._logWithLevel = _logWithLevel;
|
|
228
|
+
return ruleMatches;
|
|
229
|
+
};
|
|
230
|
+
cb(done);
|
|
231
|
+
}
|
|
232
|
+
// Expose module-level functions as static members on Logger for backwards compatibility.
|
|
233
|
+
// Tests and consumers that do `const { Logger: KV } = require("kayvee/logger")`
|
|
234
|
+
// can call `KV.setGlobalRouting(...)` and `KV.mockRouting(...)`.
|
|
235
|
+
Logger.setGlobalRouting = setGlobalRouting;
|
|
236
|
+
Logger.getGlobalRouter = getGlobalRouter;
|
|
237
|
+
Logger.mockRouting = mockRouting;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Request, Response, NextFunction } from "express";
|
|
2
|
+
type Handler = (req: Request, res?: Response) => Record<string, unknown>;
|
|
3
|
+
export declare class ContextLogger {
|
|
4
|
+
logger: any;
|
|
5
|
+
handlers: Handler[];
|
|
6
|
+
req: Request;
|
|
7
|
+
res?: Response;
|
|
8
|
+
constructor(logger: any, handlers: Handler[], req: Request, res?: Response);
|
|
9
|
+
_contextualData(data: Record<string, unknown>): Record<string, unknown>;
|
|
10
|
+
}
|
|
11
|
+
export interface MiddlewareOptions {
|
|
12
|
+
source: string;
|
|
13
|
+
headers?: string[];
|
|
14
|
+
handlers?: Handler[];
|
|
15
|
+
base_handlers?: Handler[];
|
|
16
|
+
ignore_dir?: {
|
|
17
|
+
directory: string;
|
|
18
|
+
path: string;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export declare function middleware(clever_options: MiddlewareOptions, secondOpt?: any): (req: Request, res: Response, next: NextFunction) => void;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../lib/middleware.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAyE/D,KAAK,OAAO,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,QAAQ,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAoCzE,qBAAa,aAAa;IACxB,MAAM,EAAE,GAAG,CAAC;IACZ,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,CAAC,EAAE,QAAQ,CAAC;gBAEH,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,QAAQ;IAO1E,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAGxE;AA2BD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,EAAE,CAAC;IAC1B,UAAU,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAClD;AA0CD,wBAAgB,UAAU,CACxB,cAAc,EAAE,iBAAiB,EACjC,SAAS,CAAC,EAAE,GAAG,GACd,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAkC3D"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ContextLogger = void 0;
|
|
7
|
+
exports.middleware = middleware;
|
|
8
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const node_url_1 = require("node:url");
|
|
11
|
+
const morgan_1 = __importDefault(require("morgan"));
|
|
12
|
+
const qs_1 = __importDefault(require("qs"));
|
|
13
|
+
const kayvee_1 = require("./kayvee");
|
|
14
|
+
const logger_1 = require("./logger/logger");
|
|
15
|
+
function walkDirSync(dir, files = []) {
|
|
16
|
+
const list = node_fs_1.default.readdirSync(dir);
|
|
17
|
+
list.forEach((file) => {
|
|
18
|
+
const f = node_path_1.default.join(dir, file);
|
|
19
|
+
if (node_fs_1.default.statSync(node_path_1.default.join(dir, file)).isDirectory()) {
|
|
20
|
+
walkDirSync(f, files);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
files.push(f);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
return files.map((f) => node_path_1.default.relative(dir, f));
|
|
27
|
+
}
|
|
28
|
+
function skip_path(dir, base_path = "/") {
|
|
29
|
+
let files = walkDirSync(dir);
|
|
30
|
+
files = files.map((file) => node_path_1.default.join(base_path, file));
|
|
31
|
+
console.error(`KayveeMiddleware: Skipping successful requests for files in ${dir} at ${base_path}`);
|
|
32
|
+
return (req, res) => files.includes(req.path) && res.statusCode < 400;
|
|
33
|
+
}
|
|
34
|
+
function getBaseUrl(req) {
|
|
35
|
+
const url = req.originalUrl || req.url;
|
|
36
|
+
const parsed = (0, node_url_1.parse)(url, true);
|
|
37
|
+
return parsed.pathname ?? null;
|
|
38
|
+
}
|
|
39
|
+
function getQueryParams(req) {
|
|
40
|
+
const url = req.originalUrl || req.url;
|
|
41
|
+
const parsed = (0, node_url_1.parse)(url, true);
|
|
42
|
+
const parsedQueryString = qs_1.default.parse(parsed.search ?? "", {
|
|
43
|
+
allowPrototypes: false,
|
|
44
|
+
ignoreQueryPrefix: true,
|
|
45
|
+
});
|
|
46
|
+
return `?${qs_1.default.stringify(parsedQueryString)}`;
|
|
47
|
+
}
|
|
48
|
+
function getResponseSize(res) {
|
|
49
|
+
const headers = res.getHeaders ? res.getHeaders() : res._headers;
|
|
50
|
+
if (headers && headers["content-length"]) {
|
|
51
|
+
return Number(headers["content-length"]);
|
|
52
|
+
}
|
|
53
|
+
else if (res.data) {
|
|
54
|
+
return res.data.length;
|
|
55
|
+
}
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
function getResponseTimeNs(req, res) {
|
|
59
|
+
if (!req._startAt || !res._startAt) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
const ns = (res._startAt[0] - req._startAt[0]) * 1e9 +
|
|
63
|
+
(res._startAt[1] - req._startAt[1]);
|
|
64
|
+
return ns;
|
|
65
|
+
}
|
|
66
|
+
function getIp(req) {
|
|
67
|
+
const remoteAddress = req.connection ? req.connection.remoteAddress : undefined;
|
|
68
|
+
return req.ip || remoteAddress;
|
|
69
|
+
}
|
|
70
|
+
function getLogLevel(req, res) {
|
|
71
|
+
const statusCode = res.statusCode;
|
|
72
|
+
if (statusCode >= 499) {
|
|
73
|
+
return logger_1.Logger.Error;
|
|
74
|
+
}
|
|
75
|
+
return logger_1.Logger.Info;
|
|
76
|
+
}
|
|
77
|
+
const defaultHandlers = [
|
|
78
|
+
(req) => ({ method: req.method }),
|
|
79
|
+
(req) => ({ path: getBaseUrl(req) }),
|
|
80
|
+
(req) => ({ params: getQueryParams(req) }),
|
|
81
|
+
(req, res) => ({ "response-size": getResponseSize(res) }),
|
|
82
|
+
(req, res) => ({ "response-time": getResponseTimeNs(req, res) }),
|
|
83
|
+
(req, res) => ({ "status-code": res.statusCode }),
|
|
84
|
+
(req) => ({ ip: getIp(req) }),
|
|
85
|
+
() => ({ via: "kayvee-middleware" }),
|
|
86
|
+
(req, res) => ({ level: getLogLevel(req, res) }),
|
|
87
|
+
() => ({ title: "request-finished" }),
|
|
88
|
+
];
|
|
89
|
+
const defaultContextHandlers = [];
|
|
90
|
+
function handlerData(handlers, req, res) {
|
|
91
|
+
const data = {};
|
|
92
|
+
handlers.forEach((h) => {
|
|
93
|
+
try {
|
|
94
|
+
const handler_data = h(req, res);
|
|
95
|
+
if (handler_data !== null &&
|
|
96
|
+
typeof handler_data === "object" &&
|
|
97
|
+
!Array.isArray(handler_data)) {
|
|
98
|
+
Object.assign(data, handler_data);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
// swallow invalid handler
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
return data;
|
|
106
|
+
}
|
|
107
|
+
class ContextLogger {
|
|
108
|
+
logger;
|
|
109
|
+
handlers;
|
|
110
|
+
req;
|
|
111
|
+
res;
|
|
112
|
+
constructor(logger, handlers, req, res) {
|
|
113
|
+
this.logger = logger;
|
|
114
|
+
this.handlers = handlers;
|
|
115
|
+
this.req = req;
|
|
116
|
+
this.res = res;
|
|
117
|
+
}
|
|
118
|
+
_contextualData(data) {
|
|
119
|
+
return Object.assign(handlerData(this.handlers, this.req, this.res), data);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
exports.ContextLogger = ContextLogger;
|
|
123
|
+
for (const func of logger_1.Logger.LEVELS) {
|
|
124
|
+
ContextLogger.prototype[func] = function (title) {
|
|
125
|
+
this[`${func}D`](title, {});
|
|
126
|
+
};
|
|
127
|
+
ContextLogger.prototype[`${func}D`] = function (title, data) {
|
|
128
|
+
this.logger[`${func}D`](title, this._contextualData(data));
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
for (const func of logger_1.Logger.METRICS) {
|
|
132
|
+
ContextLogger.prototype[func] = function (title, value) {
|
|
133
|
+
this[`${func}D`](title, value, {});
|
|
134
|
+
};
|
|
135
|
+
ContextLogger.prototype[`${func}D`] = function (title, value, data) {
|
|
136
|
+
this.logger[`${func}D`](title, value, this._contextualData(data));
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
const formatLine = (options_arg) => {
|
|
140
|
+
const options = options_arg || {};
|
|
141
|
+
if (!options.source) {
|
|
142
|
+
throw Error("Missing required config for 'source' in Kayvee middleware 'options'");
|
|
143
|
+
}
|
|
144
|
+
const router = (0, logger_1.getGlobalRouter)();
|
|
145
|
+
return (_tokens, req, res) => {
|
|
146
|
+
const data = {};
|
|
147
|
+
const custom_headers = options.headers || [];
|
|
148
|
+
const header_data = {};
|
|
149
|
+
custom_headers.forEach((h) => {
|
|
150
|
+
const lc = h.toLowerCase();
|
|
151
|
+
header_data[lc] = req.headers[lc];
|
|
152
|
+
});
|
|
153
|
+
Object.assign(data, header_data);
|
|
154
|
+
const custom_handlers = options.handlers || [];
|
|
155
|
+
let base_handlers = options.base_handlers || defaultHandlers;
|
|
156
|
+
base_handlers = base_handlers.concat([() => ({ source: options.source })]);
|
|
157
|
+
const all_handlers = custom_handlers.concat(base_handlers);
|
|
158
|
+
Object.assign(data, handlerData(all_handlers, req, res));
|
|
159
|
+
if (router) {
|
|
160
|
+
data._kvmeta = router.route(data);
|
|
161
|
+
}
|
|
162
|
+
return (0, kayvee_1.format)(data);
|
|
163
|
+
};
|
|
164
|
+
};
|
|
165
|
+
const defaultContextLoggerOpts = {
|
|
166
|
+
enabled: true,
|
|
167
|
+
handlers: defaultContextHandlers,
|
|
168
|
+
};
|
|
169
|
+
function middleware(clever_options, secondOpt) {
|
|
170
|
+
if (process.env.NODE_ENV === "test") {
|
|
171
|
+
const morgan_options = secondOpt || { skip: null };
|
|
172
|
+
if (clever_options.ignore_dir) {
|
|
173
|
+
morgan_options.skip = skip_path(clever_options.ignore_dir.directory, clever_options.ignore_dir.path);
|
|
174
|
+
}
|
|
175
|
+
return (0, morgan_1.default)(formatLine(clever_options), morgan_options);
|
|
176
|
+
}
|
|
177
|
+
if (!clever_options.source) {
|
|
178
|
+
throw new Error("Missing required config for 'source' in Kayvee middleware 'options'");
|
|
179
|
+
}
|
|
180
|
+
const context_logger_options = secondOpt || defaultContextLoggerOpts;
|
|
181
|
+
const logger = new logger_1.Logger(clever_options.source);
|
|
182
|
+
const morgan_options = {
|
|
183
|
+
stream: process.stderr,
|
|
184
|
+
skip: null,
|
|
185
|
+
};
|
|
186
|
+
if (clever_options.ignore_dir) {
|
|
187
|
+
morgan_options.skip = skip_path(clever_options.ignore_dir.directory, clever_options.ignore_dir.path);
|
|
188
|
+
}
|
|
189
|
+
const morgan_logger = (0, morgan_1.default)(formatLine(clever_options), morgan_options);
|
|
190
|
+
return (req, res, next) => {
|
|
191
|
+
if (context_logger_options.enabled) {
|
|
192
|
+
req.log = new ContextLogger(logger, context_logger_options.handlers, req);
|
|
193
|
+
}
|
|
194
|
+
morgan_logger(req, res, next);
|
|
195
|
+
};
|
|
196
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "kayvee",
|
|
3
|
+
"description": "Write data to key=val pairs, for human and machine readability",
|
|
4
|
+
"version": "4.0.0",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"require": "./dist/index.js",
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./logger": {
|
|
14
|
+
"require": "./dist/logger/logger.js",
|
|
15
|
+
"import": "./dist/logger/logger.js",
|
|
16
|
+
"types": "./dist/logger/logger.d.ts"
|
|
17
|
+
},
|
|
18
|
+
"./middleware": {
|
|
19
|
+
"require": "./dist/middleware.js",
|
|
20
|
+
"import": "./dist/middleware.js",
|
|
21
|
+
"types": "./dist/middleware.d.ts"
|
|
22
|
+
},
|
|
23
|
+
"./router": {
|
|
24
|
+
"require": "./dist/router/index.js",
|
|
25
|
+
"import": "./dist/router/index.js",
|
|
26
|
+
"types": "./dist/router/index.d.ts"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"typesVersions": {
|
|
30
|
+
"*": {
|
|
31
|
+
"logger": ["dist/logger/logger.d.ts"],
|
|
32
|
+
"middleware": ["dist/middleware.d.ts"],
|
|
33
|
+
"router": ["dist/router/index.d.ts"]
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist/**/*",
|
|
38
|
+
"README.md",
|
|
39
|
+
"LICENSE"
|
|
40
|
+
],
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "git://github.com/Clever/kayvee-js"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"js-yaml": "^4.1.0",
|
|
47
|
+
"jsonschema": "^1.5.0",
|
|
48
|
+
"morgan": "^1.10.0",
|
|
49
|
+
"qs": "^6.13.0"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@clever/prettier-config": "1.0.0",
|
|
53
|
+
"@types/express": "^4.17.23",
|
|
54
|
+
"@types/js-yaml": "^4.0.9",
|
|
55
|
+
"@types/jsonschema": "^1.1.1",
|
|
56
|
+
"@types/mocha": "^10.0.6",
|
|
57
|
+
"@types/morgan": "^1.9.10",
|
|
58
|
+
"@types/node": "^20.11.0",
|
|
59
|
+
"@types/qs": "^6.9.11",
|
|
60
|
+
"@typescript-eslint/eslint-plugin": "^6.19.0",
|
|
61
|
+
"@typescript-eslint/parser": "^6.19.0",
|
|
62
|
+
"benchmark": "^2.1.1",
|
|
63
|
+
"eslint": "^8.56.0",
|
|
64
|
+
"eslint-config-airbnb": "^19.0.4",
|
|
65
|
+
"eslint-config-prettier": "^9.1.0",
|
|
66
|
+
"eslint-formatter-summary": "^1.1.0",
|
|
67
|
+
"express": "^4.18.2",
|
|
68
|
+
"mocha": "^10.2.0",
|
|
69
|
+
"prettier": "^3.2.5",
|
|
70
|
+
"sinon": "^17.0.1",
|
|
71
|
+
"split": "^1.0.0",
|
|
72
|
+
"supertest": "^6.3.4",
|
|
73
|
+
"ts-node": "^10.9.2",
|
|
74
|
+
"typescript": "^5.3.0",
|
|
75
|
+
"underscore": "^1.8.3"
|
|
76
|
+
},
|
|
77
|
+
"scripts": {
|
|
78
|
+
"test": "make -Br test",
|
|
79
|
+
"prepublishOnly": "make build"
|
|
80
|
+
},
|
|
81
|
+
"author": "Clever <tech-notify@clever.com>",
|
|
82
|
+
"license": "BSD-2-Clause",
|
|
83
|
+
"bugs": {
|
|
84
|
+
"url": "https://github.com/Clever/kayvee-js/issues"
|
|
85
|
+
},
|
|
86
|
+
"publishConfig": {
|
|
87
|
+
"registry": "https://registry.npmjs.org"
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export declare class Rule {
|
|
2
|
+
name: string;
|
|
3
|
+
matchers: Record<string, string[]>;
|
|
4
|
+
output: Record<string, unknown>;
|
|
5
|
+
constructor(name: string, matchers: Record<string, string[]>, output: Record<string, unknown>);
|
|
6
|
+
matches(msg: Record<string, unknown>): boolean;
|
|
7
|
+
outputFor(msg: Record<string, unknown>): Record<string, unknown>;
|
|
8
|
+
}
|
|
9
|
+
interface RouteResult {
|
|
10
|
+
team: string;
|
|
11
|
+
kv_version: string;
|
|
12
|
+
kv_language: string;
|
|
13
|
+
routes: Record<string, unknown>[];
|
|
14
|
+
}
|
|
15
|
+
export declare class Router {
|
|
16
|
+
rules: Rule[];
|
|
17
|
+
constructor(rules?: Rule[]);
|
|
18
|
+
loadConfig(filename: string): void;
|
|
19
|
+
_loadConfigString(configStr: string): void;
|
|
20
|
+
route(msg: Record<string, unknown>): RouteResult;
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/router/index.ts"],"names":[],"mappings":"AA2EA,qBAAa,IAAI;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAEpB,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAkC7F,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO;IAS9C,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAsBjE;AA4CD,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;CACnC;AAED,qBAAa,MAAM;IACjB,KAAK,EAAE,IAAI,EAAE,CAAC;gBAEF,KAAK,CAAC,EAAE,IAAI,EAAE;IAI1B,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKlC,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAQ1C,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,WAAW;CAgBjD"}
|