@wnqueiroz/ecs-winston
Version:
A formatter for the winston logger compatible with Elastic Common Schema (ECS) 🚀
169 lines (168 loc) • 6.34 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ecsWinstonFormat = exports.getECSLogParsed = exports.getErrorData = exports.getMetadata = exports.getHttpRequestData = exports.stringify = void 0;
const fast_json_stringify_1 = __importDefault(require("fast-json-stringify"));
const lodash_merge_1 = __importDefault(require("lodash.merge"));
const lodash_unset_1 = __importDefault(require("lodash.unset"));
const qs_1 = __importDefault(require("qs"));
const winston = __importStar(require("winston"));
const ecs_schema_1 = require("./ecs-schema");
const { combine, timestamp, printf } = winston.format;
exports.stringify = (0, fast_json_stringify_1.default)(ecs_schema_1.ecsSchema);
function getHttpRequestData({ req, res, requestId, }) {
var _a;
if (!req || !res)
return null;
const { httpVersion, method, body } = req;
const request = {
id: requestId,
method,
body: {
bytes: Number(req.get('content-length')),
content: body,
},
mime_type: req.get('content-type'),
};
const response = {
status_code: res.statusCode,
mime_type: res.get('content-type'),
body: {
bytes: Number(res.get('content-length')),
content: res.locals.body,
},
};
const user_agent = {
original: req.get('user-agent'),
};
const http = {
version: httpVersion,
request,
response,
};
const { hostname, url, query, protocol } = req;
const ecsUrl = {};
if (hostname) {
const [host, port] = hostname.split(':');
ecsUrl.domain = host;
ecsUrl.port = Number(port);
}
const hasQuery = url.indexOf('?');
if (hasQuery)
ecsUrl.query = qs_1.default.stringify(query);
return {
http,
user_agent,
url: {
domain: ecsUrl.domain || undefined,
path: ((_a = req === null || req === void 0 ? void 0 : req.route) === null || _a === void 0 ? void 0 : _a.path) || undefined,
port: ecsUrl.port || undefined,
query: ecsUrl.query || undefined,
scheme: ['http', 'https'].includes(protocol) ? protocol : undefined,
},
};
}
exports.getHttpRequestData = getHttpRequestData;
function getMetadata({ rest, config, message }) {
const exclude = {
config: (config === null || config === void 0 ? void 0 : config.exclude) || [],
message: message.exclude || rest.exclude || [],
};
return {
req: message.req || rest.req,
res: message.res || rest.res,
ecs: message.ecs || rest.ecs,
error: message.error || rest.error || null,
exclude: [...exclude.config, ...exclude.message],
};
}
exports.getMetadata = getMetadata;
function getErrorData(error) {
if (!error || !(error instanceof Error))
return undefined;
return {
type: Object.prototype.toString.call(error.constructor) === '[object Function]'
? error.constructor.name
: error.name,
message: error.message,
stack_trace: error.stack,
};
}
exports.getErrorData = getErrorData;
function getECSLogParsed({ config, level, message, timestamp, rest, }) {
var _a;
const { req, res, ecs, exclude, error } = getMetadata({
rest: rest,
config,
message: message,
});
const messageIsString = typeof message === 'string';
const traceId = ((_a = config === null || config === void 0 ? void 0 : config.setTraceId) === null || _a === void 0 ? void 0 : _a.call(config)) || null;
const httpRequestData = getHttpRequestData({
req,
res,
requestId: traceId,
});
let ecsLogData = Object.assign(Object.assign({ '@timestamp': timestamp, log: { level: String(level) }, message: messageIsString ? message : null, ecs: {
version: '1.12.0',
} }, (httpRequestData ? httpRequestData : {})), (traceId
? {
trace: {
id: traceId,
},
}
: {}));
ecsLogData.error = getErrorData(error);
if (ecs)
ecsLogData = (0, lodash_merge_1.default)(ecsLogData, ecs);
// Excluding properties by paths in "exclude" option
exclude.forEach((path = '') => {
const splittedPath = path.split('.');
(0, lodash_unset_1.default)(ecsLogData, splittedPath);
});
return (0, exports.stringify)(ecsLogData);
}
exports.getECSLogParsed = getECSLogParsed;
const ecsWinstonFormat = (config) => combine(timestamp(), printf((_a) => {
var { level, message, timestamp } = _a, rest = __rest(_a, ["level", "message", "timestamp"]);
return getECSLogParsed({
config,
level,
message,
timestamp,
rest,
});
}));
exports.ecsWinstonFormat = ecsWinstonFormat;