@sap/xsodata
Version:
Expose data from a HANA database as OData V2 service with help of .xsodata files.
311 lines (256 loc) • 9.98 kB
JavaScript
'use strict';
const logMemory = process.env.XSODATA_LOG_MEMORY_CONSUMPTION >= 1;
// PREREQUISITE
// This logging api logs only if XS_APP_LOG_LEVEL = debug
// 0 error
// 1 warn
// 2 info
// 3 verbose
// 4 debug
// 5 silly
let XSODATA_LOG_LEVEL = process.env.XSODATA_LOG_LEVEL || 4;
// Logging for request time
// Requires XSODATA_LOG_LEVEL >= 4
// 0: no Request times are logged
// 1: Request times are logged
let XSODATA_LOG_REQUEST_TIME = process.env.XSODATA_LOG_REQUEST_TIME || 0;
// Log long requests
// Requires XSODATA_LOG_LEVEL >= 2
// Requires request length > XSODATA_FORCE_LOG_LONG_REQUEST
let XSODATA_FORCE_LOG_LONG_REQUEST = process.env.XSODATA_FORCE_LOG_LONG_REQUEST || 2;
// Log sql commands
// 0-1: no SQL query commands are logged
// 2: SQL query commands are logged ( and time if XSODATA_LOG_SQL_TIME is > 1)
let XSODATA_LOG_SQL_COMMAND = process.env.XSODATA_LOG_SQL_COMMAND || 2;
// Logging for sql commands execution time
// Requires XSODATA_LOG_SQL_COMMAND >= 2
// 0: no SQL times are logged
// 1: SQL times are logged
let XSODATA_LOG_SQL_TIME = process.env.XSODATA_LOG_SQL_TIME || 0;
// Log long sql commands
// Requires request length > XSODATA_FORCE_LOG_LONG_SQL
let XSODATA_FORCE_LOG_LONG_SQL = process.env.XSODATA_FORCE_LOG_LONG_SQL || 2;
// Log long sql query parameter
// Requires XSODATA_LOG_SQL_COMMAND >= 2
// 0-1: no SQL query parameters are logged
// 2: SQL query parameters are logged
let XSODATA_LOG_SQL_PARAMETERS = process.env.XSODATA_LOG_SQL_PARAMETERS || 2;
// XSODATA_LOG_SQL_PARAM_VALUE_SIZE: sets the length of the parameter value loggged out
let XSODATA_LOG_SQL_PARAM_VALUE_SIZE = process.env.XSODATA_LOG_SQL_PARAM_VALUE_SIZE || 80;
let XSODATA_LOG_SQL_PARAM_ARRAY_SIZE = process.env.XSODATA_LOG_SQL_PARAM_ARRAY_SIZE || 80;
// Log long sql results
// Requires XSODATA_LOG_SQL_COMMAND >= 2
// 0-1: no SQL results are logged
// 2: SQL results are logged
let XSODATA_LOG_SQL_DATA = process.env.XSODATA_LOG_SQL_DATA || 0;
let XSODATA_LOG_SQL_DATA_VALUE_SIZE = process.env.XSODATA_LOG_SQL_DATA_VALUE_SIZE || 20;
let XSODATA_LOG_SQL_DATA_ARRAY_SIZE = process.env.XSODATA_LOG_SQL_DATA_ARRAY_SIZE || 30;
//XSODATA_LOG_LEVEL = 0;
//XSODATA_LOG_REQUEST_TIME = 1;
//XSODATA_FORCE_LOG_LONG_REQUEST = 1;
//XSODATA_LOG_SQL_COMMAND = 0;
//XSODATA_LOG_SQL_TIME = 0;
//XSODATA_FORCE_LOG_LONG_SQL = 2;
//XSODATA_LOG_SQL_PARAMETERS = 0;
//XSODATA_LOG_SQL_DATA = 0;
var logLevels = {
"error": 0,
"warn": 1,
"info": 2,
"verbose": 3,
"debug": 4,
"silly": 5
};
function printSqlData(array) {
let ret = '';
for (const value of array) {
if (ret.length) {
ret += ',';
}
if (typeof value === 'string' && value.length > XSODATA_LOG_SQL_DATA_VALUE_SIZE) {
ret += value.substr(0, XSODATA_LOG_SQL_DATA_VALUE_SIZE) + '.LEN:' + value.length;
continue;
}
if (Array.isArray(value) && value.length > XSODATA_LOG_SQL_DATA_ARRAY_SIZE) {
ret += value.slice(0, XSODATA_LOG_SQL_DATA_ARRAY_SIZE);
continue;
}
if (Buffer.isBuffer(value) && value.length > XSODATA_LOG_SQL_DATA_VALUE_SIZE) {
ret += value.slice(0, XSODATA_LOG_SQL_DATA_VALUE_SIZE).toString('hex') + '.LEN:' + value.length;
continue;
}
if (typeof value === 'object') {
ret += JSON.stringify(value);
continue;
}
ret += value;
}
return ret;
}
function printSqlParameters(array) {
let ret = '';
if (array && Array.isArray(array)) {
for (const value of array) {
if (ret.length) {
ret += ',';
}
if (typeof value === 'string' && value.length > XSODATA_LOG_SQL_PARAM_VALUE_SIZE) {
ret += value.substr(0, XSODATA_LOG_SQL_PARAM_VALUE_SIZE) + '<' + value.length + '>';
continue;
}
if (Array.isArray(value) && value.length > XSODATA_LOG_SQL_PARAM_ARRAY_SIZE) {
ret += value.slice(0, XSODATA_LOG_SQL_PARAM_VALUE_SIZE);
continue;
}
if (Buffer.isBuffer(value) && value.length > XSODATA_LOG_SQL_PARAM_VALUE_SIZE) {
ret += value.slice(0, XSODATA_LOG_SQL_PARAM_VALUE_SIZE).toString('hex') + '.LEN:' + value.length;
continue;
}
ret += value;
}
}
return ret;
}
//Code
var EmptyLogger = function () {
};
EmptyLogger.prototype.cloneWithContext = function () {
return new EmptyLogger();
};
Object.keys(logLevels).forEach(function (levelKey) {
EmptyLogger.prototype[levelKey] = function () {};
});
function getMemStats() {
const used = process.memoryUsage();
let rssMB = (used.rss / 1024 / 1024).toFixed(2);
let heapTotalMB = (used.heapTotal / 1024 / 1024).toFixed(2);
let heapUsedMB = (used.heapUsed / 1024 / 1024).toFixed(2);
return `rss (MB): ${rssMB}, heapTotal (MB): ${heapTotalMB}, heapUsed (MB): ${heapUsedMB}`;
}
function Logger(logger, context) {
this.logger = logger || new EmptyLogger();
this.context = context || { callId: 0, uniqueNetworkRequestID: 0, uniqueRequestID: 0 };
this.info('Logger', 'Logger created for request');
//this.XSODATA_LOG_SQL_TIME = XSODATA_LOG_SQL_TIME;
//this.XSODATA_LOG_REQUEST_TIME = XSODATA_LOG_REQUEST_TIME;
}
Logger.prototype.cloneWithContext = function (context) {
this.info('Logger', 'cloneWithContext');
return new Logger(this.logger, context);
};
Logger.prototype.getKey = function () {
return '[' + this.context.uniqueNetworkRequestID + '][' + this.context.uniqueRequestID + '] ';
};
Logger.prototype.error = function (scope, text) {
//level 0
this.logger.error(this.getKey() + scope + '::' + text);
};
Logger.prototype.warn = function (scope, text) {
//level 1
this.logger.warn(this.getKey() + scope + '::' + text);
};
Logger.prototype.info = function (scope, text, textIndent) {
if (XSODATA_LOG_LEVEL >= 2) {
//level 2
if (textIndent) {
textIndent = '\n ' + textIndent.replace('\n', '\n ');
} else {
textIndent = '';
}
this.logger.info(this.getKey() + scope + '::' + text + textIndent);
}
};
Logger.prototype.verbose = function (scope, text) {
//level 3
if (XSODATA_LOG_LEVEL >= 3) {
this.logger.verbose(this.getKey() + scope + '::' + text);
}
};
Logger.prototype.debug = function (scope, text) {
//level 4
if (XSODATA_LOG_LEVEL >= 4) {
const out = !logMemory ? text : text + ' --- ' + getMemStats();
this.logger.debug(this.getKey() + scope + '::' + out);
}
};
Logger.prototype.silly = function (scope, text) {
//level 5
if (XSODATA_LOG_LEVEL >= 5) {
const out = !logMemory ? text : text + ' --- ' + getMemStats();
this.logger.debug(this.getKey() + scope + '::' + out);
}
};
Logger.prototype.logSqlData = function (data) {
if (XSODATA_LOG_SQL_COMMAND >= 2 && XSODATA_LOG_SQL_DATA >= 2) {
let out = "[]";
if (Array.isArray(data) && data.length > 0) {
out = printSqlData(data);
}
this.logger.debug(this.getKey() + 'SQL data: ' + out);
}
};
Logger.prototype.logSqlCommand = function (sql) {
if (XSODATA_LOG_SQL_COMMAND >= 2) {
this.logger.debug(this.getKey() + 'SQL command: ' + sql);
}
};
Logger.prototype.logSqlParameters = function (parameters, force, asError) {
if (XSODATA_LOG_SQL_COMMAND >= 2 && (XSODATA_LOG_SQL_PARAMETERS >= 2 || force || asError)) {
let out = printSqlParameters(parameters);
if (asError) {
this.logger.error(this.getKey() + 'SQL param: ' + out);
} else {
this.logger.debug(this.getKey() + 'SQL param: ' + out);
}
}
};
Logger.prototype.getStartTimeSql = function () {
if (XSODATA_LOG_SQL_TIME || XSODATA_FORCE_LOG_LONG_SQL) {
return process.hrtime();
}
return null;
};
Logger.prototype.logSqlTime = function (text, startTime, sql) {
const padZeroMS = (value) => {
while (value.length < 6) {
value = '0' + value;
}
return value;
};
if (startTime) {
const hrtime = process.hrtime(startTime);
const ms = padZeroMS('' + Math.round(hrtime[1] / 1000));
if (XSODATA_LOG_SQL_COMMAND >= 2 && XSODATA_LOG_SQL_TIME) {
// sql is already logged for same request (don't log twice)
this.logger.debug(this.getKey() + 'SQL ' + text + ' time: ' + hrtime[0] + '.' + ms + ' s');
} else if (XSODATA_FORCE_LOG_LONG_SQL && hrtime[0] >= XSODATA_FORCE_LOG_LONG_SQL) {
this.logger.debug(this.getKey() + 'SQL command: ' + sql);
this.logger.debug(this.getKey() + 'SQL ' + text + ' time: ' + hrtime[0] + '.' + ms + ' s');
}
}
};
Logger.prototype.getStartTimeRequest = function () {
if (XSODATA_LOG_REQUEST_TIME || XSODATA_FORCE_LOG_LONG_REQUEST) {
return process.hrtime();
}
return null;
};
Logger.prototype.logRequestTime = function (text, startTime, url) {
const padZeroMS = (value) => {
while (value.length < 6) {
value = '0' + value;
}
return value;
};
if (startTime) {
const hrtime = process.hrtime(startTime);
const ms = padZeroMS('' + Math.round(hrtime[1] / 1000));
if (XSODATA_LOG_LEVEL >= 2) {
// sql is already logged for same request (don't log twice)
this.logger.debug(this.getKey() + 'Request ' + text + ' time: ' + hrtime[0] + '.' + ms + ' s');
} else if (XSODATA_FORCE_LOG_LONG_REQUEST && hrtime[0] > XSODATA_FORCE_LOG_LONG_REQUEST) {
this.logger.debug(this.getKey() + 'Request ' + text + ' time: ' + hrtime[0] + '.' + ms + ' s (' + url + ')');
}
}
};
module.exports = Logger;