Merge pull request #1171 from CartoDB/dgaubert/ch78384/maps-api-replace-log4js-logger-by-pino-bis

Do not bind logger to global object
This commit is contained in:
Daniel G. Aubert
2020-06-04 12:14:21 +02:00
committed by GitHub
69 changed files with 262 additions and 807 deletions
+31 -41
View File
@@ -3,21 +3,11 @@
const http = require('http');
const https = require('https');
const path = require('path');
const fs = require('fs');
const semver = require('semver');
const pino = require('pino');
// TODO: research it it's still needed
const setICUEnvVariable = require('./lib/utils/icu-data-env-setter');
global.logger = pino({ base: null, level: process.env.NODE_ENV === 'test' ? 'fatal' : 'info' }, pino.destination({ sync: false }));
const { engines } = require('./package.json');
if (!semver.satisfies(process.versions.node, engines.node)) {
global.logger.fatal(new Error(`Node version ${process.versions.node} is not supported, please use Node.js ${engines.node}.`));
process.exit(1);
}
// This function should be called before the require('yargs').
setICUEnvVariable();
@@ -37,27 +27,9 @@ const argv = require('yargs')
const environmentArg = argv._[0] || process.env.NODE_ENV || 'development';
const configurationFile = path.resolve(argv.config || `./config/environments/${environmentArg}.js`);
if (!fs.existsSync(configurationFile)) {
global.logger.fatal(new Error(`Configuration file ${configurationFile} does not exist`));
process.exit(1);
}
global.environment = require(configurationFile);
const ENVIRONMENT = argv._[0] || process.env.NODE_ENV || global.environment.environment;
process.env.NODE_ENV = ENVIRONMENT;
process.env.NODE_ENV = argv._[0] || process.env.NODE_ENV || global.environment.environment;
const availableEnvironments = {
production: true,
staging: true,
development: true
};
if (!availableEnvironments[ENVIRONMENT]) {
global.logger.fatal(new Error(`Invalid environment argument, valid ones: ${Object.keys(availableEnvironments).join(', ')}`));
process.exit(1);
}
process.env.NODE_ENV = ENVIRONMENT;
if (global.environment.uv_threadpool_size) {
process.env.UV_THREADPOOL_SIZE = global.environment.uv_threadpool_size;
}
@@ -76,10 +48,28 @@ https.globalAgent = new https.Agent(agentOptions);
// Include cartodb_windshaft only _after_ the "global" variable is set
// See https://github.com/Vizzuality/Windshaft-cartodb/issues/28
const cartodbWindshaft = require('./lib/server');
const createServer = require('./lib/server');
const serverOptions = require('./lib/server-options');
const { logger } = serverOptions;
const server = cartodbWindshaft(serverOptions);
const availableEnvironments = {
production: true,
staging: true,
development: true
};
if (!availableEnvironments[process.env.NODE_ENV]) {
logger.fatal(new Error(`Invalid environment argument, valid ones: ${Object.keys(availableEnvironments).join(', ')}`));
process.exit(1);
}
const { engines } = require('./package.json');
if (!semver.satisfies(process.versions.node, engines.node)) {
logger.fatal(new Error(`Node version ${process.versions.node} is not supported, please use Node.js ${engines.node}.`));
process.exit(1);
}
const server = createServer(serverOptions);
// Specify the maximum length of the queue of pending connections for the HTTP server.
// The actual length will be determined by the OS through sysctl settings such as tcp_max_syn_backlog and somaxconn on Linux.
@@ -91,10 +81,10 @@ const listener = server.listen(serverOptions.bind.port, serverOptions.bind.host,
const version = require('./package').version;
listener.on('listening', function () {
global.logger.info(`Using Node.js ${process.version}`);
global.logger.info(`Using configuration file ${configurationFile}`);
logger.info(`Using Node.js ${process.version}`);
logger.info(`Using configuration file ${configurationFile}`);
const { address, port } = listener.address();
global.logger.info(`Windshaft tileserver ${version} started on ${address}:${port} PID=${process.pid} (${ENVIRONMENT})`);
logger.info(`Windshaft tileserver ${version} started on ${address}:${port} PID=${process.pid} (${process.env.NODE_ENV})`);
});
function getCPUUsage (oldUsage) {
@@ -189,19 +179,19 @@ function getGCTypeValue (type) {
return value;
}
const exitProcess = pino.final(global.logger, (err, logger, listener, signal, killTimeout) => {
scheduleForcedExit(killTimeout, logger);
const exitProcess = logger.finish((err, finalLogger, listener, signal, killTimeout) => {
scheduleForcedExit(killTimeout, finalLogger);
logger.info(`Process has received signal: ${signal}`);
finalLogger.info(`Process has received signal: ${signal}`);
let code = 0;
if (err) {
code = 1;
logger.fatal(err);
finalLogger.fatal(err);
}
logger.info(`Process is going to exit with code: ${code}`);
finalLogger.info(`Process is going to exit with code: ${code}`);
listener.close(() => process.exit(code));
});
@@ -215,10 +205,10 @@ function addHandlers (listener, killTimeout) {
addHandlers(listener, 45000);
function scheduleForcedExit (killTimeout, logger) {
function scheduleForcedExit (killTimeout, finalLogger) {
// Schedule exit if there is still ongoing work to deal with
const killTimer = setTimeout(() => {
global.logger.info('Process didn\'t close on time. Force exit');
finalLogger.info('Process didn\'t close on time. Force exit');
process.exit(1);
}, killTimeout);
+9 -9
View File
@@ -47,10 +47,10 @@ const LayergroupMetadata = require('../utils/layergroup-metadata');
const RendererStatsReporter = require('../stats/reporter/renderer');
const initializeStatusCode = require('./middlewares/initialize-status-code');
const logger = require('./middlewares/logger');
const initLogger = require('./middlewares/logger');
const bodyParser = require('body-parser');
const servedByHostHeader = require('./middlewares/served-by-host-header');
const stats = require('./middlewares/stats');
const profiler = require('./middlewares/profiler');
const lzmaMiddleware = require('./middlewares/lzma');
const cors = require('./middlewares/cors');
const user = require('./middlewares/user');
@@ -87,7 +87,7 @@ module.exports = class ApiRouter {
rendererOptions: serverOptions,
redisPool,
onTileErrorStrategy: getOnTileErrorStrategy({ enabled: environmentOptions.enabledFeatures.onTileErrorStrategy }),
logger: global.logger
logger: this.serverOptions.logger
});
const rendererStatsReporter = new RendererStatsReporter(rendererCache, serverOptions.renderCache.statsInterval);
@@ -98,7 +98,7 @@ module.exports = class ApiRouter {
const surrogateKeysCacheBackends = createSurrogateKeysCacheBackends(serverOptions);
const surrogateKeysCache = new SurrogateKeysCache(surrogateKeysCacheBackends);
const templateMaps = createTemplateMaps({ redisPool, surrogateKeysCache });
const templateMaps = createTemplateMaps({ redisPool, surrogateKeysCache, logger: this.serverOptions.logger });
const analysisStatusBackend = new AnalysisStatusBackend();
const analysisBackend = new AnalysisBackend(metadataBackend, serverOptions.analysis);
@@ -201,12 +201,12 @@ module.exports = class ApiRouter {
middlewares.forEach(middleware => apiRouter.use(middleware()));
apiRouter.use(logger());
apiRouter.use(initLogger({ logger: this.serverOptions.logger }));
apiRouter.use(initializeStatusCode());
apiRouter.use(bodyParser.json());
apiRouter.use(servedByHostHeader());
apiRouter.use(clientHeader());
apiRouter.use(stats({
apiRouter.use(profiler({
enabled: this.serverOptions.useProfiler,
statsClient: global.statsClient
}));
@@ -226,7 +226,7 @@ module.exports = class ApiRouter {
}
};
function createTemplateMaps ({ redisPool, surrogateKeysCache }) {
function createTemplateMaps ({ redisPool, surrogateKeysCache, logger }) {
const templateMaps = new TemplateMaps(redisPool, {
max_user_templates: global.environment.maxUserTemplates
});
@@ -235,10 +235,10 @@ function createTemplateMaps ({ redisPool, surrogateKeysCache }) {
const startTime = Date.now();
surrogateKeysCache.invalidate(new NamedMapsCacheEntry(user, templateName), (err) => {
if (err) {
return global.logger.error(err);
return logger.error(err, `Named map (${templateName}) invalidation failed, user: ${user}`);
}
global.logger.info({ user, type: 'named_map_invalidation', elapsed: Date.now() - startTime });
logger.info({ user, type: 'named_map_invalidation', elapsed: Date.now() - startTime }, `Named map (${templateName}) invalidation success, user: ${user}`);
});
}
+3 -11
View File
@@ -7,7 +7,6 @@ const cleanUpQueryParams = require('../middlewares/clean-up-query-params');
const credentials = require('../middlewares/credentials');
const dbConnSetup = require('../middlewares/db-conn-setup');
const authorize = require('../middlewares/authorize');
const initProfiler = require('../middlewares/init-profiler');
const checkJsonContentType = require('../middlewares/check-json-content-type');
const incrementMapViewCount = require('../middlewares/increment-map-view-count');
const augmentLayergroupData = require('../middlewares/augment-layergroup-data');
@@ -76,7 +75,6 @@ module.exports = class AnonymousMapController {
}
middlewares () {
const isTemplateInstantiation = false;
const useTemplateHash = false;
const includeQuery = true;
const label = 'ANONYMOUS LAYERGROUP';
@@ -95,7 +93,6 @@ module.exports = class AnonymousMapController {
metrics({
enabled: this.config.pubSubMetrics.enabled,
metricsBackend: this.metricsBackend,
logger: global.logger,
tags: metricsTags
}),
credentials(),
@@ -103,7 +100,6 @@ module.exports = class AnonymousMapController {
dbConnSetup(this.pgConnection),
rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.ANONYMOUS),
cleanUpQueryParams(['aggregation']),
initProfiler(isTemplateInstantiation),
checkJsonContentType(),
checkCreateLayergroup(),
prepareAdapterMapConfig(this.mapConfigAdapter),
@@ -144,7 +140,6 @@ function checkCreateLayergroup () {
}
}
req.profiler.done('checkCreateLayergroup');
return next();
};
}
@@ -153,6 +148,7 @@ function prepareAdapterMapConfig (mapConfigAdapter) {
return function prepareAdapterMapConfigMiddleware (req, res, next) {
const requestMapConfig = req.body;
const { logger } = res.locals;
const { user, api_key: apiKey } = res.locals;
const { dbuser, dbname, dbpassword, dbhost, dbport } = res.locals;
const params = Object.assign({ dbuser, dbname, dbpassword, dbhost, dbport }, req.query);
@@ -160,6 +156,7 @@ function prepareAdapterMapConfig (mapConfigAdapter) {
const context = {
analysisConfiguration: {
user,
logger,
db: {
host: dbhost,
port: dbport,
@@ -178,12 +175,7 @@ function prepareAdapterMapConfig (mapConfigAdapter) {
requestMapConfig,
params,
context,
(err, requestMapConfig, stats = { overviewsAddedToMapconfig: false }) => {
req.profiler.done('anonymous.getMapConfig');
stats.mapType = 'anonymous';
req.profiler.add(stats);
(err, requestMapConfig) => {
if (err) {
return next(err);
}
@@ -61,8 +61,6 @@ module.exports = class AttributesLayergroupController {
function getFeatureAttributes (attributesBackend) {
return function getFeatureAttributesMiddleware (req, res, next) {
req.profiler.start('windshaft.maplayer_attribute');
const { mapConfigProvider } = res.locals;
const { token } = res.locals;
const { dbuser, dbname, dbpassword, dbhost, dbport } = res.locals;
@@ -62,8 +62,6 @@ module.exports = class AggregatedFeaturesLayergroupController {
function getClusteredFeatures (clusterBackend) {
return function getFeatureAttributesMiddleware (req, res, next) {
req.profiler.start('windshaft.maplayer_cluster_features');
const { mapConfigProvider } = res.locals;
const { user, token } = res.locals;
const { dbuser, dbname, dbpassword, dbhost, dbport } = res.locals;
@@ -100,7 +100,6 @@ function getPreviewImageByCenter (previewBackend) {
const options = { mapConfigProvider, format, width, height, zoom, center };
previewBackend.getImage(options, (err, image, stats = {}) => {
req.profiler.done(`render-${format}`);
req.profiler.add(stats);
if (err) {
@@ -133,7 +132,6 @@ function getPreviewImageByBoundingBox (previewBackend) {
const options = { mapConfigProvider, format, width, height, bbox };
previewBackend.getImage(options, (err, image, stats = {}) => {
req.profiler.done(`render-${format}`);
req.profiler.add(stats);
if (err) {
+7 -11
View File
@@ -70,7 +70,6 @@ module.exports = class PreviewTemplateController {
metrics({
enabled: this.config.pubSubMetrics.enabled,
metricsBackend: this.metricsBackend,
logger: global.logger,
tags: metricsTags
}),
credentials(),
@@ -293,7 +292,7 @@ function getImage ({ previewBackend, label }) {
if (zoom !== undefined && center) {
const options = { mapConfigProvider, format, width, height, zoom, center };
return previewBackend.getImage(options, (err, image, stats) => {
return previewBackend.getImage(options, (err, image, stats = {}) => {
req.profiler.add(stats);
if (err) {
@@ -310,9 +309,8 @@ function getImage ({ previewBackend, label }) {
const options = { mapConfigProvider, format, width, height, bbox };
previewBackend.getImage(options, (err, image, stats) => {
previewBackend.getImage(options, (err, image, stats = {}) => {
req.profiler.add(stats);
req.profiler.done('render-' + format);
if (err) {
err.label = label;
@@ -337,17 +335,14 @@ function setContentTypeHeader () {
};
}
function incrementMapViewsError (ctx) {
return `ERROR: failed to increment mapview count for user '${ctx.user}': ${ctx.err}`;
}
function incrementMapViews ({ metadataBackend }) {
return function incrementMapViewsMiddleware (req, res, next) {
const { user, mapConfigProvider } = res.locals;
const { user, mapConfigProvider, logger } = res.locals;
mapConfigProvider.getMapConfig((err, mapConfig) => {
if (err) {
global.logger.info(incrementMapViewsError({ user, err }));
err.message = `Failed to increment mapview count for user '${user}'. ${err.message}`;
logger.warn({ error: err });
return next();
}
@@ -359,7 +354,8 @@ function incrementMapViews ({ metadataBackend }) {
metadataBackend.incMapviewCount(user, statTag, (err) => {
if (err) {
global.logger.info(incrementMapViewsError({ user, err }));
err.message = `Failed to increment mapview count for user '${user}'. ${err.message}`;
logger.warn({ error: err });
}
next();
@@ -96,8 +96,6 @@ function getStatusCode (tile, format) {
function getTile (tileBackend) {
return function getTileMiddleware (req, res, next) {
req.profiler.start(`windshaft.${req.params.layer ? 'maplayer_tile' : 'map_tile'}`);
const { mapConfigProvider } = res.locals;
const { token } = res.locals;
const { layer, z, x, y, format } = req.params;
-2
View File
@@ -3,8 +3,6 @@
module.exports = function authorize (authBackend) {
return function authorizeMiddleware (req, res, next) {
authBackend.authorize(req, res, (err, authorized) => {
req.profiler.done('authorize');
if (err) {
return next(err);
}
+3 -2
View File
@@ -6,11 +6,12 @@ module.exports = function setCacheChannelHeader () {
return next();
}
const { mapConfigProvider } = res.locals;
const { mapConfigProvider, logger } = res.locals;
mapConfigProvider.getAffectedTables((err, affectedTables) => {
if (err) {
global.logger.warn(err, 'ERROR generating Cache Channel Header');
err.message = `Error generating Cache Channel Header. ${err.message}`;
logger.warn({ error: err });
return next();
}
+3 -2
View File
@@ -40,11 +40,12 @@ module.exports = function setCacheControlHeader ({
return next();
}
const { mapConfigProvider = { getAffectedTables: callback => callback() } } = res.locals;
const { mapConfigProvider = { getAffectedTables: callback => callback() }, logger } = res.locals;
mapConfigProvider.getAffectedTables((err, affectedTables) => {
if (err) {
global.logger.warn(err, 'ERROR generating Cache Control Header');
err.message = `Error generating Cache Control Header. ${err.message}`;
logger.warn({ error: err });
return next();
}
@@ -6,8 +6,6 @@ module.exports = function checkJsonContentType () {
return next(new Error('POST data must be of type application/json'));
}
req.profiler.done('checkJsonContentTypeMiddleware');
next();
};
};
-2
View File
@@ -7,8 +7,6 @@ module.exports = function dbConnSetup (pgConnection) {
const { user } = res.locals;
pgConnection.setDBConn(user, res.locals, (err) => {
req.profiler.done('dbConnSetup');
if (err) {
if (err.message && err.message.indexOf('name not found') !== -1) {
err.http_status = 404;
+10 -75
View File
@@ -1,34 +1,19 @@
'use strict';
const _ = require('underscore');
const debug = require('debug')('windshaft:cartodb:error-middleware');
module.exports = function errorMiddleware (/* options */) {
return function error (err, req, res, next) {
var allErrors = Array.isArray(err) ? err : [err];
const { logger } = res.locals;
const errors = populateLimitErrors(Array.isArray(err) ? err : [err]);
allErrors = populateLimitErrors(allErrors);
logger.error({ error: errors });
const label = err.label || 'UNKNOWN';
err = allErrors[0] || new Error(label);
allErrors[0] = err;
var statusCode = findStatusCode(err);
setErrorHeader(allErrors, statusCode, res);
debug('[%s ERROR] -- %d: %s, %s', label, statusCode, err, err.stack);
// If a callback was requested, force status to 200
if (req.query && req.query.callback) {
statusCode = 200;
}
var errorResponseBody = {
errors: allErrors.map(errorMessage),
errors_with_context: allErrors.map(errorMessageWithContext)
const errorResponseBody = {
errors: errors.map(errorMessage),
errors_with_context: errors.map(errorMessageWithContext)
};
res.status(statusCode);
// If a callback was requested, force status to 200
res.status(req.query.callback ? 200 : findStatusCode(errors[0]));
if (req.query && req.query.callback) {
res.jsonp(errorResponseBody);
@@ -135,7 +120,7 @@ function statusFromErrorMessage (errMsg) {
function errorMessage (err) {
// See https://github.com/Vizzuality/Windshaft-cartodb/issues/68
var message = (_.isString(err) ? err : err.message) || 'Unknown error';
var message = (typeof err === 'string' ? err : err.message) || 'Unknown error';
return stripConnectionInfo(message);
}
@@ -165,7 +150,7 @@ function shouldBeExposed (prop) {
function errorMessageWithContext (err) {
// See https://github.com/Vizzuality/Windshaft-cartodb/issues/68
var message = (_.isString(err) ? err : err.message) || 'Unknown error';
var message = (typeof err === 'string' ? err : err.message) || 'Unknown error';
var error = {
type: err.type || 'unknown',
@@ -181,53 +166,3 @@ function errorMessageWithContext (err) {
return error;
}
function setErrorHeader (errors, statusCode, res) {
const errorsCopy = errors.slice(0);
const mainError = errorsCopy.shift();
const errorsLog = {
mainError: {
statusCode: statusCode || 200,
message: mainError.message,
name: mainError.name,
label: mainError.label,
type: mainError.type,
subtype: mainError.subtype
}
};
errorsLog.moreErrors = errorsCopy.map(error => {
return {
message: error.message,
name: error.name,
label: error.label,
type: error.type,
subtype: error.subtype
};
});
res.set('X-Tiler-Errors', stringifyForLogs(errorsLog));
}
/**
* Remove problematic nested characters
* from object for logs RegEx
*
* @param {Object} object
*/
function stringifyForLogs (object) {
Object.keys(object).map(key => {
if (typeof object[key] === 'string') {
object[key] = object[key].replace(/[^a-zA-Z0-9]/g, ' ');
} else if (typeof object[key] === 'object') {
stringifyForLogs(object[key]);
} else if (object[key] instanceof Array) {
for (const element of object[key]) {
stringifyForLogs(element);
}
}
});
return JSON.stringify(object);
}
@@ -2,7 +2,7 @@
module.exports = function incrementMapViewCount (metadataBackend) {
return function incrementMapViewCountMiddleware (req, res, next) {
const { mapConfig, user } = res.locals;
const { mapConfig, user, logger } = res.locals;
const statTag = mapConfig.obj().stat_tag;
if (statTag) {
@@ -11,10 +11,9 @@ module.exports = function incrementMapViewCount (metadataBackend) {
// Error won't blow up, just be logged.
metadataBackend.incMapviewCount(user, statTag, (err) => {
req.profiler.done('incMapviewCount');
if (err) {
global.logger.warn(err, `ERROR: failed to increment mapview count for user '${user}'`);
err.message = `Failed to increment mapview count for user '${user}'. ${err.message}`;
logger.warn({ error: err });
}
next();
-11
View File
@@ -1,11 +0,0 @@
'use strict';
module.exports = function initProfiler (isTemplateInstantiation) {
const operation = isTemplateInstantiation ? 'instance_template' : 'createmap';
return function initProfilerMiddleware (req, res, next) {
req.profiler.start(`windshaft-cartodb.${operation}_${req.method.toLowerCase()}`);
req.profiler.done(`${operation}.initProfilerMiddleware`);
next();
};
};
+3 -2
View File
@@ -6,7 +6,7 @@ module.exports = function setLastModifiedHeader () {
return next();
}
const { mapConfigProvider, cache_buster: cacheBuster } = res.locals;
const { mapConfigProvider, cache_buster: cacheBuster, logger } = res.locals;
if (cacheBuster) {
const cacheBusterTimestamp = parseInt(cacheBuster, 10);
@@ -21,7 +21,8 @@ module.exports = function setLastModifiedHeader () {
mapConfigProvider.getAffectedTables((err, affectedTables) => {
if (err) {
global.logger.warn(err, 'ERROR generating Last Modified Header');
err.message = `Error generating Last Modified Header. ${err.message}`;
logger.warn({ error: err });
return next();
}
+5 -5
View File
@@ -2,13 +2,13 @@
const uuid = require('uuid');
module.exports = function logger () {
return function loggerMiddleware (req, res, next) {
module.exports = function initLogger ({ logger }) {
return function initLoggerMiddleware (req, res, next) {
const id = req.get('X-Request-Id') || uuid.v4();
res.locals.logger = global.logger.child({ id });
res.locals.logger = logger.child({ id });
res.locals.logger.info(req);
res.on('finish', () => res.locals.logger.info(res));
res.locals.logger.info({ request: req });
res.on('finish', () => res.locals.logger.info({ response: res }));
next();
};
-2
View File
@@ -24,8 +24,6 @@ module.exports = function lzma () {
delete req.query.lzma;
Object.assign(req.query, JSON.parse(result));
req.profiler.done('lzma');
next();
} catch (err) {
next(new Error('Error parsing lzma as JSON: ' + err));
-1
View File
@@ -4,7 +4,6 @@ module.exports = function mapError (options) {
const { addContext = false, label = 'MAPS CONTROLLER' } = options;
return function mapErrorMiddleware (err, req, res, next) {
req.profiler.done('error');
const { mapConfig } = res.locals;
if (addContext) {
+9 -6
View File
@@ -3,7 +3,7 @@
const EVENT_VERSION = '1';
const MAX_LENGTH = 100;
module.exports = function metrics ({ enabled, tags, metricsBackend, logger }) {
module.exports = function metrics ({ enabled, tags, metricsBackend }) {
if (!enabled) {
return function metricsDisabledMiddleware (req, res, next) {
next();
@@ -15,6 +15,10 @@ module.exports = function metrics ({ enabled, tags, metricsBackend, logger }) {
}
return function metricsMiddleware (req, res, next) {
// FIXME: use parent logger as we don't want bind the error to the request
// but we still want to know if an error is thrown
const { logger } = res.locals;
res.on('finish', () => {
const { event, attributes } = getEventData(req, res, tags);
@@ -51,7 +55,7 @@ function getEventData (req, res, tags) {
template_hash: getTemplateHash({ res }),
stat_tag: getStatTag({ res }),
response_code: res.statusCode.toString(),
response_time: getResponseTime(res),
response_time: getResponseTime(req),
source_domain: req.hostname,
event_version: EVENT_VERSION
}, tags.attributes, extra);
@@ -121,13 +125,12 @@ function getStatTag ({ res }) {
}
}
// FIXME: 'X-Tiler-Profiler' might not be accurate enough
function getResponseTime (res) {
const profiler = res.get('X-Tiler-Profiler');
// FIXME: 'Profiler' might not be accurate enough
function getResponseTime (req) {
let stats;
try {
stats = JSON.parse(profiler);
stats = req.profiler.toJSON();
} catch (e) {
return undefined;
}
@@ -2,20 +2,26 @@
const Profiler = require('../../stats/profiler-proxy');
const debug = require('debug')('windshaft:cartodb:stats');
const onHeaders = require('on-headers');
module.exports = function stats (options) {
module.exports = function profiler (options) {
const { enabled = true, statsClient } = options;
return function statsMiddleware (req, res, next) {
return function profilerMiddleware (req, res, next) {
const { logger } = res.locals;
const { id } = logger.bindings();
// TODO: stop using profiler and log stats instead of adding them to the profiler
req.profiler = new Profiler({
statsd_client: statsClient,
profile: enabled
});
onHeaders(res, () => res.set('X-Tiler-Profiler', req.profiler.toJSONString()));
req.profiler.start(id);
res.on('finish', () => {
req.profiler.done('response');
logger.info({ stats: req.profiler.toJSON() });
try {
// May throw due to dns, see: http://github.com/CartoDB/Windshaft/issues/166
req.profiler.sendStats();
-2
View File
@@ -2,8 +2,6 @@
module.exports = function sendResponse () {
return function sendResponseMiddleware (req, res, next) {
req.profiler.done('res');
res.status(res.statusCode);
if (Buffer.isBuffer(res.body)) {
+3 -2
View File
@@ -5,7 +5,7 @@ const NamedMapMapConfigProvider = require('../../models/mapconfig/provider/named
module.exports = function setSurrogateKeyHeader ({ surrogateKeysCache }) {
return function setSurrogateKeyHeaderMiddleware (req, res, next) {
const { user, mapConfigProvider } = res.locals;
const { user, mapConfigProvider, logger } = res.locals;
if (mapConfigProvider instanceof NamedMapMapConfigProvider) {
surrogateKeysCache.tag(res, new NamedMapsCacheEntry(user, mapConfigProvider.getTemplateName()));
@@ -17,7 +17,8 @@ module.exports = function setSurrogateKeyHeader ({ surrogateKeysCache }) {
mapConfigProvider.getAffectedTables((err, affectedTables) => {
if (err) {
global.logger.warn(err, 'ERROR generating Surrogate Key Header');
err.message = `Erros generating Surrogate Key Header. ${err.message}`;
logger.warn({ error: err });
return next();
}
+5 -1
View File
@@ -6,7 +6,11 @@ module.exports = function user (metadataBackend) {
const cdbRequest = new CdbRequest();
return function userMiddleware (req, res, next) {
res.locals.user = getUserNameFromRequest(req, cdbRequest);
try {
res.locals.user = getUserNameFromRequest(req, cdbRequest);
} catch (err) {
return next(err);
}
metadataBackend.getUserId(res.locals.user, (err, userId) => {
if (err || !userId) {
@@ -166,8 +166,6 @@ function updateTemplate ({ templateMaps }) {
function retrieveTemplate ({ templateMaps }) {
return function retrieveTemplateMiddleware (req, res, next) {
req.profiler.start('windshaft-cartodb.get_template');
const { user } = res.locals;
const templateId = templateName(req.params.template_id);
@@ -195,8 +193,6 @@ function retrieveTemplate ({ templateMaps }) {
function destroyTemplate ({ templateMaps }) {
return function destroyTemplateMiddleware (req, res, next) {
req.profiler.start('windshaft-cartodb.delete_template');
const { user } = res.locals;
const templateId = templateName(req.params.template_id);
@@ -215,8 +211,6 @@ function destroyTemplate ({ templateMaps }) {
function listTemplates ({ templateMaps }) {
return function listTemplatesMiddleware (req, res, next) {
req.profiler.start('windshaft-cartodb.get_template_list');
const { user } = res.locals;
templateMaps.listTemplates(user, (err, templateIds) => {
@@ -4,7 +4,6 @@ const cleanUpQueryParams = require('../middlewares/clean-up-query-params');
const credentials = require('../middlewares/credentials');
const dbConnSetup = require('../middlewares/db-conn-setup');
const authorize = require('../middlewares/authorize');
const initProfiler = require('../middlewares/init-profiler');
const checkJsonContentType = require('../middlewares/check-json-content-type');
const incrementMapViewCount = require('../middlewares/increment-map-view-count');
const augmentLayergroupData = require('../middlewares/augment-layergroup-data');
@@ -74,7 +73,6 @@ module.exports = class NamedMapController {
}
middlewares () {
const isTemplateInstantiation = true;
const useTemplateHash = true;
const includeQuery = false;
const label = 'NAMED MAP LAYERGROUP';
@@ -93,7 +91,6 @@ module.exports = class NamedMapController {
metrics({
enabled: this.config.pubSubMetrics.enabled,
metricsBackend: this.metricsBackend,
logger: global.logger,
tags: metricsTags
}),
credentials(),
@@ -101,7 +98,6 @@ module.exports = class NamedMapController {
dbConnSetup(this.pgConnection),
rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.NAMED),
cleanUpQueryParams(['aggregation']),
initProfiler(isTemplateInstantiation),
checkJsonContentType(),
checkInstantiteLayergroup(),
getTemplate(
@@ -151,8 +147,6 @@ function checkInstantiteLayergroup () {
}
}
req.profiler.done('checkInstantiteLayergroup');
return next();
};
}
@@ -188,9 +182,6 @@ function getTemplate (
);
mapConfigProvider.getMapConfig((err, mapConfig, rendererParams, context, stats = {}) => {
req.profiler.done('named.getMapConfig');
stats.mapType = 'named';
req.profiler.add(stats);
if (err) {
+1 -2
View File
@@ -67,9 +67,8 @@ function getTile ({ tileBackend, label }) {
const { layer, z, x, y, format } = req.params;
const params = { layer, z, x, y, format };
tileBackend.getTile(mapConfigProvider, params, (err, tile, headers, stats) => {
tileBackend.getTile(mapConfigProvider, params, (err, tile, headers, stats = {}) => {
req.profiler.add(stats);
req.profiler.done('render-' + format);
if (err) {
err.label = label;
-2
View File
@@ -30,8 +30,6 @@ AnalysisBackend.prototype.create = function (analysisConfiguration, analysisDefi
analysisConfiguration.batch.inlineExecution = this.batchConfig.inlineExecution;
analysisConfiguration.batch.hostHeaderTemplate = this.batchConfig.hostHeaderTemplate;
analysisConfiguration.logger = global.logger;
this.getAnalysesLimits(analysisConfiguration.user, function (err, limits) {
if (err) {}
analysisConfiguration.limits = limits || {};
-6
View File
@@ -133,8 +133,6 @@ AuthBackend.prototype.authorize = function (req, res, callback) {
if (isAuthorizedByApikey) {
return this.pgConnection.setDBAuth(user, res.locals, 'regular', function (err) {
req.profiler.done('setDBAuth');
if (err) {
return callback(err);
}
@@ -150,8 +148,6 @@ AuthBackend.prototype.authorize = function (req, res, callback) {
if (isAuthorizedBySigner) {
return this.pgConnection.setDBAuth(user, res.locals, 'master', function (err) {
req.profiler.done('setDBAuth');
if (err) {
return callback(err);
}
@@ -163,8 +159,6 @@ AuthBackend.prototype.authorize = function (req, res, callback) {
// if no signer name was given, use default api key
if (!res.locals.signer) {
return this.pgConnection.setDBAuth(user, res.locals, 'default', function (err) {
req.profiler.done('setDBAuth');
if (err) {
return callback(err);
}
+17 -22
View File
@@ -1,29 +1,24 @@
'use strict';
function CdbRequest () {
this.RE_USER_FROM_HOST = new RegExp(global.environment.user_from_host ||
'^([^\\.]+)\\.' // would extract "strk" from "strk.cartodb.com"
);
}
module.exports = CdbRequest;
CdbRequest.prototype.userByReq = function (req) {
var host = req.headers.host || '';
if (req.params.user) {
return req.params.user;
module.exports = class CdbRequest {
constructor () {
// would extract "strk" from "strk.cartodb.com"
this.RE_USER_FROM_HOST = new RegExp(global.environment.user_from_host || '^([^\\.]+)\\.');
}
var mat = host.match(this.RE_USER_FROM_HOST);
userByReq (req) {
const host = req.headers.host || '';
if (!mat) {
return global.logger.error(new Error(`Pattern '${this.RE_USER_FROM_HOST}' does not match hostname '${host}'`));
if (req.params.user) {
return req.params.user;
}
const mat = host.match(this.RE_USER_FROM_HOST);
if (!mat || mat.length !== 2) {
throw new Error(`No username found in hostname '${host}'`);
}
return mat[1];
}
if (mat.length !== 2) {
return global.logger.error(new Error(`Pattern '${this.RE_USER_FROM_HOST}' gave unexpected matches against '${host}': ${mat}`));
}
return mat[1];
};
+2 -15
View File
@@ -23,7 +23,7 @@ function getPGTypeName (pgType) {
module.exports = class BaseDataview {
getResult (psql, override, callback) {
this.sql(psql, override, (err, query, flags = null) => {
this.sql(psql, override, (err, query) => {
if (err) {
return callback(err);
}
@@ -36,20 +36,7 @@ module.exports = class BaseDataview {
result = this.format(result, override);
result.type = this.getType();
// Overviews logging
const stats = {};
if (flags && flags.usesOverviews !== undefined) {
stats.usesOverviews = flags.usesOverviews;
} else {
stats.usesOverviews = false;
}
if (this.getType) {
stats.dataviewType = this.getType();
}
return callback(null, result, stats);
return callback(null, result);
}, true); // use read-only transaction
});
}
+1 -1
View File
@@ -213,7 +213,7 @@ Aggregation.prototype.sql = function (psql, override, callback) {
debug(aggregationSql);
return callback(null, aggregationSql, { usesOverviews: true });
return callback(null, aggregationSql);
};
var aggregationFnQueryTpl = {
+1 -1
View File
@@ -76,5 +76,5 @@ Formula.prototype.sql = function (psql, override, callback) {
debug(formulaSql);
return callback(null, formulaSql, { usesOverviews: true });
return callback(null, formulaSql);
};
+1 -1
View File
@@ -179,7 +179,7 @@ Histogram.prototype.sql = function (psql, override, callback) {
var histogramSql = this._buildQuery(override);
return callback(null, histogramSql, { usesOverviews: true });
return callback(null, histogramSql);
};
Histogram.prototype._buildQuery = function (override) {
@@ -25,58 +25,50 @@ MapConfigOverviewsAdapter.prototype.getMapConfig = function (user, requestMapCon
layers.forEach(layer => augmentLayersQueue.defer(this._augmentLayer.bind(this), user, layer, analysesResults));
augmentLayersQueue.awaitAll(function layersAugmentQueueFinish (err, results) {
augmentLayersQueue.awaitAll(function layersAugmentQueueFinish (err, layers) {
if (err) {
return callback(err);
}
const layers = results.map(result => result.layer);
const overviewsAddedToMapconfig = results.some(result => result.overviewsAddedToMapconfig);
if (!layers || layers.length === 0) {
return callback(new Error('Missing layers array from layergroup config'));
}
requestMapConfig.layers = layers;
const stats = { overviewsAddedToMapconfig };
return callback(null, requestMapConfig, stats);
return callback(null, requestMapConfig);
});
};
MapConfigOverviewsAdapter.prototype._augmentLayer = function (user, layer, analysesResults, callback) {
let overviewsAddedToMapconfig = false;
if (layer.type !== 'mapnik' && layer.type !== 'cartodb') {
return callback(null, { layer, overviewsAddedToMapconfig });
return callback(null, layer);
}
this.overviewsMetadataBackend.getOverviewsMetadata(user, layer.options.sql, (err, metadata) => {
if (err) {
return callback(err, { layer, overviewsAddedToMapconfig });
return callback(err);
}
if (_.isEmpty(metadata)) {
return callback(null, { layer, overviewsAddedToMapconfig });
return callback(null, layer);
}
var filters = getFilters(analysesResults, layer);
overviewsAddedToMapconfig = true;
if (!filters) {
layer.options = Object.assign({}, layer.options, getQueryRewriteData(layer, analysesResults, {
overviews: metadata
}));
return callback(null, { layer, overviewsAddedToMapconfig });
return callback(null, layer);
}
var unfilteredQuery = getUnfilteredQuery(analysesResults, layer);
this.filterStatsBackend.getFilterStats(user, unfilteredQuery, filters, function (err, stats) {
if (err) {
return callback(null, { layer, overviewsAddedToMapconfig });
return callback(null, layer);
}
layer.options = Object.assign({}, layer.options, getQueryRewriteData(layer, analysesResults, {
@@ -84,7 +76,7 @@ MapConfigOverviewsAdapter.prototype._augmentLayer = function (user, layer, analy
filter_stats: stats
}));
return callback(null, { layer, overviewsAddedToMapconfig });
return callback(null, layer);
});
});
};
+3 -2
View File
@@ -3,6 +3,7 @@
const fqdn = require('@carto/fqdn-sync');
var _ = require('underscore');
var OverviewsQueryRewriter = require('./utils/overviews-query-rewriter');
const Logger = require('./utils/logger');
var rendererConfig = _.defaults(global.environment.renderer || {}, {
cache_ttl: 60000, // milliseconds
@@ -127,7 +128,7 @@ module.exports = {
varnish_purge_enabled: global.environment.varnish.purge_enabled,
fastly: global.environment.fastly || {},
cache_enabled: global.environment.cache_enabled,
log_format: global.environment.log_format,
useProfiler: global.environment.useProfiler,
pubSubMetrics: Object.assign({ enabled: false }, global.environment.pubSubMetrics)
pubSubMetrics: Object.assign({ enabled: false }, global.environment.pubSubMetrics),
logger: new Logger()
};
+4
View File
@@ -52,4 +52,8 @@ ProfilerProxy.prototype.toJSONString = function () {
return this.profile ? this.profiler.toJSONString() : '{}';
};
ProfilerProxy.prototype.toJSON = function () {
return this.profile ? JSON.parse(this.profiler.toJSONString()) : {};
};
module.exports = ProfilerProxy;
+55
View File
@@ -0,0 +1,55 @@
'use strict';
const pino = require('pino');
const { req: requestSerializer, res: responseSerializer, err: errorSerializer } = pino.stdSerializers;
module.exports = class Logger {
constructor () {
const { LOG_LEVEL, NODE_ENV } = process.env;
const logLevelFromNodeEnv = NODE_ENV === 'test' ? 'fatal' : 'info';
const options = {
base: null, // Do not bind hostname, pid and friends by default
level: LOG_LEVEL || logLevelFromNodeEnv,
serializers: {
request: requestSerializer,
response: responseSerializer,
error: (error) => Array.isArray(error) ? error.map((err) => errorSerializer(err)) : [errorSerializer(error)]
}
};
const dest = pino.destination({ sync: false }); // stdout
this._logger = pino(options, dest);
}
trace (...args) {
this._logger.trace(...args);
}
debug (...args) {
this._logger.debug(...args);
}
info (...args) {
this._logger.info(...args);
}
warn (...args) {
this._logger.warn(...args);
}
error (...args) {
this._logger.error(...args);
}
fatal (...args) {
this._logger.fatal(...args);
}
child (...args) {
return this._logger.child(...args);
}
finish (callback) {
return pino.final(this._logger, callback);
}
};
-5
View File
@@ -4920,11 +4920,6 @@
"ee-first": "1.1.1"
}
},
"on-headers": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz",
"integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c="
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
-1
View File
@@ -51,7 +51,6 @@
"lru-cache": "4.1.3",
"lzma": "2.3.2",
"node-statsd": "0.1.1",
"on-headers": "1.0.1",
"pino": "^6.3.1",
"queue-async": "1.1.0",
"redis-mpool": "^0.8.0",
+2 -2
View File
@@ -4,7 +4,7 @@ var assert = require('../../support/assert');
var helper = require('../../support/test-helper');
var CartodbWindshaft = require('../../../lib/server');
const createServer = require('../../../lib/server');
var serverOptions = require('../../../lib/server-options');
var TestClient = require('../../support/test-client');
@@ -14,7 +14,7 @@ describe('named-maps analysis', function () {
var server;
before(function () {
server = new CartodbWindshaft(serverOptions);
server = createServer(serverOptions);
});
var IMAGE_TOLERANCE_PER_MIL = 20;
@@ -2,7 +2,7 @@
const assert = require('../../support/assert');
const testHelper = require('../../support/test-helper');
const CartodbWindshaft = require('../../../lib/server');
const createServer = require('../../../lib/server');
const serverOptions = require('../../../lib/server-options');
var LayergroupToken = require('../../../lib/models/layergroup-token');
@@ -47,7 +47,7 @@ describe('Basic authorization use cases', function () {
var server;
before(function () {
server = new CartodbWindshaft(serverOptions);
server = createServer(serverOptions);
});
beforeEach(function () {
+2 -2
View File
@@ -5,7 +5,7 @@ var testHelper = require('../../support/test-helper');
var assert = require('../../support/assert');
var qs = require('querystring');
var CartodbWindshaft = require('../../../lib/server');
const createServer = require('../../../lib/server');
var serverOptions = require('../../../lib/server-options');
var LayergroupToken = require('../../../lib/models/layergroup-token');
@@ -14,7 +14,7 @@ describe('get requests with cache headers', function () {
var server;
before(function () {
server = new CartodbWindshaft(serverOptions);
server = createServer(serverOptions);
server.setMaxListeners(0);
});
+2 -2
View File
@@ -7,7 +7,7 @@ var step = require('step');
var FastlyPurge = require('fastly-purge');
var _ = require('underscore');
var NamedMapsCacheEntry = require('../../../lib/cache/model/named-maps-entry');
var CartodbWindshaft = require('../../../lib/server');
const createServer = require('../../../lib/server');
var nock = require('nock');
describe('templates surrogate keys', function () {
@@ -33,7 +33,7 @@ describe('templates surrogate keys', function () {
var server;
before(function () {
server = new CartodbWindshaft(serverOptions);
server = createServer(serverOptions);
nock.disableNetConnect();
nock.enableNetConnect(/(127.0.0.1|cartocdn.com)/);
});
+1 -23
View File
@@ -55,7 +55,6 @@ describe('dataviews using tables without overviews', function () {
return done(err);
}
assert.deepStrictEqual(formulaResult, { operation: 'count', result: 7313, nulls: 0, type: 'formula' });
assert(getUsesOverviewsFromHeaders(headers) === false); // Overviews logging
testClient.drain(done);
});
@@ -269,8 +268,6 @@ describe('dataviews using tables with overviews', function () {
nulls: 0,
type: 'formula'
});
assert.ok(getUsesOverviewsFromHeaders(headers)); // Overviews logging
assert(getDataviewTypeFromHeaders(headers) === 'formula'); // Overviews logging
testClient.drain(done);
});
@@ -290,8 +287,6 @@ describe('dataviews using tables with overviews', function () {
infinities: 0,
nans: 0
});
assert.ok(getUsesOverviewsFromHeaders(headers)); // Overviews logging
assert(getDataviewTypeFromHeaders(headers) === 'formula'); // Overviews logging
testClient.drain(done);
});
@@ -311,8 +306,6 @@ describe('dataviews using tables with overviews', function () {
infinities: 0,
nans: 0
});
assert.ok(getUsesOverviewsFromHeaders(headers)); // Overviews logging
assert(getDataviewTypeFromHeaders(headers) === 'formula'); // Overviews logging
testClient.drain(done);
});
@@ -387,8 +380,6 @@ describe('dataviews using tables with overviews', function () {
assert.ok(histogram);
assert.strictEqual(histogram.type, 'histogram');
assert.ok(Array.isArray(histogram.bins));
assert.ok(getUsesOverviewsFromHeaders(headers)); // Overviews logging
assert(getDataviewTypeFromHeaders(headers) === 'histogram'); // Overviews logging
testClient.drain(done);
});
@@ -480,7 +471,7 @@ describe('dataviews using tables with overviews', function () {
nans: 0,
type: 'formula'
});
assert.ok(getUsesOverviewsFromHeaders(headers)); // Overviews logging
testClient.drain(done);
});
});
@@ -499,7 +490,6 @@ describe('dataviews using tables with overviews', function () {
nans: 0,
type: 'formula'
});
assert.ok(getUsesOverviewsFromHeaders(headers)); // Overviews logging
testClient.drain(done);
});
@@ -519,7 +509,6 @@ describe('dataviews using tables with overviews', function () {
nulls: 0,
type: 'formula'
});
assert.ok(getUsesOverviewsFromHeaders(headers)); // Overviews logging
testClient.drain(done);
});
@@ -611,9 +600,6 @@ describe('dataviews using tables with overviews', function () {
type: 'aggregation'
});
assert.ok(getUsesOverviewsFromHeaders(headers)); // Overviews logging
assert(getDataviewTypeFromHeaders(headers) === 'aggregation'); // Overviews logging
testClient.drain(done);
});
});
@@ -830,11 +816,3 @@ describe('dataviews using tables with overviews', function () {
});
});
});
function getUsesOverviewsFromHeaders (headers) {
return headers && headers['x-tiler-profiler'] && JSON.parse(headers['x-tiler-profiler']).usesOverviews;
}
function getDataviewTypeFromHeaders (headers) {
return headers && headers['x-tiler-profiler'] && JSON.parse(headers['x-tiler-profiler']).dataviewType;
}
@@ -4,14 +4,14 @@ var assert = require('../support/assert');
var step = require('step');
var LayergroupToken = require('../../lib/models/layergroup-token');
var testHelper = require('../support/test-helper');
var CartodbWindshaft = require('../../lib/server');
var createServer = require('../../lib/server');
var serverOptions = require('../../lib/server-options');
describe('dynamic styling for named maps', function () {
var server;
before(function () {
server = new CartodbWindshaft(serverOptions);
server = createServer(serverOptions);
});
var keysToDelete;
-44
View File
@@ -1,44 +0,0 @@
'use strict';
const assert = require('../support/assert');
const TestClient = require('../support/test-client');
describe('error middleware', function () {
it('should returns a errors header', function (done) {
const mapConfig = {
version: '1.6.0',
layers: [{
type: 'mapnik',
options: {}
}]
};
const errorHeader = {
mainError: {
statusCode: 400,
message: 'Missing cartocss for layer 0 options',
name: 'Error',
label: 'ANONYMOUS LAYERGROUP',
type: 'layer'
},
moreErrors: []
};
this.testClient = new TestClient(mapConfig, 1234);
const params = {
response: {
status: 400,
headers: {
'Content-Type': 'application/json; charset=utf-8',
'X-Tiler-Errors': JSON.stringify(errorHeader)
}
}
};
this.testClient.getLayergroup(params, (err) => {
assert.ifError(err);
done();
});
});
});
+2 -2
View File
@@ -1,14 +1,14 @@
'use strict';
var assert = require('../support/assert');
var CartodbWindshaft = require('../../lib/server');
var createServer = require('../../lib/server');
var serverOptions = require('../../lib/server-options');
describe('error with context', function () {
var server;
before(function () {
server = new CartodbWindshaft(serverOptions);
server = createServer(serverOptions);
});
var layerOK = {
+5 -5
View File
@@ -5,7 +5,7 @@ require('../support/test-helper');
var fs = require('fs');
var assert = require('../support/assert');
var CartodbWindshaft = require('../../lib/server');
const createServer = require('../../lib/server');
var serverOptions = require('../../lib/server-options');
describe('health checks', function () {
@@ -41,7 +41,7 @@ describe('health checks', function () {
};
it('returns 200 and ok=true with enabled configuration', function (done) {
var server = new CartodbWindshaft(serverOptions);
var server = createServer(serverOptions);
assert.response(server, healthCheckRequest, RESPONSE_OK, function (res, err) {
assert.ok(!err);
@@ -62,7 +62,7 @@ describe('health checks', function () {
fs.readFile = function (filename, callback) {
callback(null, errorMessage);
};
var server = new CartodbWindshaft(serverOptions);
var server = createServer(serverOptions);
assert.response(server, healthCheckRequest, RESPONSE_FAIL, function (res, err) {
fs.readFile = readFileFn;
@@ -82,7 +82,7 @@ describe('health checks', function () {
fs.readFile = function (filename, callback) {
callback(null, '');
};
var server = new CartodbWindshaft(serverOptions);
var server = createServer(serverOptions);
assert.response(server, healthCheckRequest, RESPONSE_FAIL, function (res, err) {
fs.readFile = readFileFn;
@@ -100,7 +100,7 @@ describe('health checks', function () {
it('not err if disabled file does not exist', function (done) {
global.environment.disabled_file = '/tmp/ftreftrgtrccre';
var server = new CartodbWindshaft(serverOptions);
var server = createServer(serverOptions);
assert.response(server, healthCheckRequest, RESPONSE_OK, function (res, err) {
assert.ok(!err);
+2 -2
View File
@@ -10,14 +10,14 @@ var LayergroupToken = require('../../lib/models/layergroup-token');
var PgQueryRunner = require('../../lib/backends/pg-query-runner');
var QueryTables = require('cartodb-query-tables').queryTables;
var CartodbWindshaft = require('../../lib/server');
const createServer = require('../../lib/server');
var serverOptions = require('../../lib/server-options');
describe('tests from old api translated to multilayer', function () {
var server;
before(function () {
server = new CartodbWindshaft(serverOptions);
server = createServer(serverOptions);
server.setMaxListeners(0);
});
+5 -5
View File
@@ -19,7 +19,7 @@ var windshaftFixtures = path.join(__dirname, '/../../node_modules/windshaft/test
var IMAGE_EQUALS_TOLERANCE_PER_MIL = 20;
var IMAGE_EQUALS_HIGHER_TOLERANCE_PER_MIL = 25;
var CartodbWindshaft = require('../../lib/server');
const createServer = require('../../lib/server');
var serverOptions = require('../../lib/server-options');
var QueryTables = require('cartodb-query-tables').queryTables;
@@ -30,7 +30,7 @@ var QueryTables = require('cartodb-query-tables').queryTables;
var server;
before(function () {
server = new CartodbWindshaft(serverOptions);
server = createServer(serverOptions);
server.setMaxListeners(0);
});
@@ -851,7 +851,7 @@ var QueryTables = require('cartodb-query-tables').queryTables;
function doRestartServer (err/*, res */) {
assert.ifError(err);
// hack simulating restart...
server = new CartodbWindshaft(serverOptions);
server = createServer(serverOptions);
return null;
},
function doGet1 (err) {
@@ -1274,7 +1274,7 @@ var QueryTables = require('cartodb-query-tables').queryTables;
it('cache control for layergroup default value', function (done) {
global.environment.varnish.layergroupTtl = null;
var server = new CartodbWindshaft(serverOptions);
var server = createServer(serverOptions);
assert.response(server, layergroupTtlRequest, layergroupTtlResponseExpectation,
function (res) {
@@ -1291,7 +1291,7 @@ var QueryTables = require('cartodb-query-tables').queryTables;
var layergroupTtl = 300;
global.environment.varnish.layergroupTtl = layergroupTtl;
var server = new CartodbWindshaft(serverOptions);
var server = createServer(serverOptions);
assert.response(server, layergroupTtlRequest, layergroupTtlResponseExpectation,
function (res) {
+2 -2
View File
@@ -3,7 +3,7 @@
var testHelper = require('../support/test-helper');
var assert = require('../support/assert');
var CartodbWindshaft = require('../../lib/server');
const createServer = require('../../lib/server');
var serverOptions = require('../../lib/server-options');
var LayergroupToken = require('../../lib/models/layergroup-token');
@@ -17,7 +17,7 @@ describe('named_layers', function () {
var server;
before(function () {
server = new CartodbWindshaft(serverOptions);
server = createServer(serverOptions);
});
// configure redis pool instance to use in tests
@@ -4,7 +4,7 @@ var step = require('step');
var testHelper = require('../support/test-helper');
var assert = require('../support/assert');
var CartodbWindshaft = require('../../lib/server');
const createServer = require('../../lib/server');
var serverOptions = require('../../lib/server-options');
var RedisPool = require('redis-mpool');
@@ -17,7 +17,7 @@ describe('layers visibility for previews', function () {
var server;
before(function () {
server = new CartodbWindshaft(serverOptions);
server = createServer(serverOptions);
});
// configure redis pool instance to use in tests
@@ -6,7 +6,7 @@ var querystring = require('querystring');
var assert = require('../support/assert');
const mapnik = require('@carto/mapnik');
var CartodbWindshaft = require('../../lib/server');
const createServer = require('../../lib/server');
var serverOptions = require('../../lib/server-options');
var TemplateMaps = require('../../lib/backends/template-maps');
var NamedMapsCacheEntry = require('../../lib/cache/model/named-maps-entry');
@@ -15,7 +15,7 @@ describe('named maps authentication', function () {
var server;
before(function () {
server = new CartodbWindshaft(serverOptions);
server = createServer(serverOptions);
});
// configure redis pool instance to use in tests
+2 -2
View File
@@ -5,14 +5,14 @@ require('../support/test-helper');
const helper = require('../support/test-helper');
var assert = require('../support/assert');
const mapnik = require('@carto/mapnik');
var CartodbWindshaft = require('../../lib/server');
const createServer = require('../../lib/server');
var serverOptions = require('../../lib/server-options');
describe('named maps provider cache', function () {
var server;
before(function () {
server = new CartodbWindshaft(serverOptions);
server = createServer(serverOptions);
});
var username = 'localhost';
@@ -6,7 +6,7 @@ var RedisPool = require('redis-mpool');
var assert = require('../support/assert');
const mapnik = require('@carto/mapnik');
var CartodbWindshaft = require('../../lib/server');
const createServer = require('../../lib/server');
var serverOptions = require('../../lib/server-options');
var TemplateMaps = require('../../lib/backends/template-maps');
@@ -86,7 +86,7 @@ describe('named maps static view', function () {
};
// this could be removed once named maps are invalidated, otherwise you hits the cache
var server = new CartodbWindshaft(serverOptions);
var server = createServer(serverOptions);
assert.response(server, requestOptions, expectedResponse, function (res, err) {
testHelper.deleteRedisKeys({ 'user:localhost:mapviews:global': 5 }, function () {
@@ -323,7 +323,7 @@ describe('named maps static view', function () {
};
// this could be removed once named maps are invalidated, otherwise you hits the cache
var server = new CartodbWindshaft(serverOptions);
var server = createServer(serverOptions);
assert.response(server, requestOptions, expectedResponse, function (res, err) {
assert.ifError(err);
+2 -2
View File
@@ -6,7 +6,7 @@ var querystring = require('querystring');
var assert = require('../support/assert');
const mapnik = require('@carto/mapnik');
var CartodbWindshaft = require('../../lib/server');
const createServer = require('../../lib/server');
var serverOptions = require('../../lib/server-options');
var TemplateMaps = require('../../lib/backends/template-maps');
var NamedMapsCacheEntry = require('../../lib/cache/model/named-maps-entry');
@@ -15,7 +15,7 @@ describe('named maps preview stats', function () {
var server;
before(function () {
server = new CartodbWindshaft(serverOptions);
server = createServer(serverOptions);
});
var redisPool = new RedisPool(global.environment.redis);
@@ -3,7 +3,7 @@
var testHelper = require('../support/test-helper');
var assert = require('../support/assert');
var CartodbWindshaft = require('../../lib/server');
const createServer = require('../../lib/server');
var serverOptions = require('../../lib/server-options');
var LayergroupToken = require('../../lib/models/layergroup-token');
@@ -18,7 +18,7 @@ describe('overviews metadata for named maps', function () {
var server;
before(function () {
server = new CartodbWindshaft(serverOptions);
server = createServer(serverOptions);
});
// configure redis pool instance to use in tests
@@ -172,126 +172,4 @@ describe('overviews metadata for named maps', function () {
}
);
});
describe('Overviews Flags', function () {
it('Overviews used', function (done) {
step(
function postTemplate () {
var next = this;
assert.response(server, {
url: '/api/v1/map/named?api_key=1234',
method: 'POST',
headers: { host: 'localhost', 'Content-Type': 'application/json' },
data: JSON.stringify(template)
}, {}, function (res, err) {
next(err, res);
});
},
function instantiateTemplate (err) {
assert.ifError(err);
var next = this;
assert.response(server, {
url: '/api/v1/map/named/' + templateId,
method: 'POST',
headers: {
host: 'localhost',
'Content-Type': 'application/json'
}
}, {},
function (res, err) {
return next(err, res);
});
},
function checkFlags (err, res) {
assert.ifError(err);
var next = this;
var parsedBody = JSON.parse(res.body);
keysToDelete['map_cfg|' + LayergroupToken.parse(parsedBody.layergroupid).token] = 0;
keysToDelete['user:localhost:mapviews:global'] = 5;
const headers = JSON.parse(res.headers['x-tiler-profiler']);
assert.ok(headers.overviewsAddedToMapconfig);
assert.strictEqual(headers.mapType, 'named');
next();
},
function finish (err) {
done(err);
}
);
});
it('Overviews NOT used', function (done) {
const nonOverviewsTemplateId = 'non-overviews-template';
var nonOverviewsTemplate = {
version: '0.0.1',
name: nonOverviewsTemplateId,
auth: { method: 'open' },
layergroup: {
version: '1.0.0',
layers: [nonOverviewsLayer]
}
};
step(
function postTemplate () {
var next = this;
assert.response(server, {
url: '/api/v1/map/named?api_key=1234',
method: 'POST',
headers: { host: 'localhost', 'Content-Type': 'application/json' },
data: JSON.stringify(nonOverviewsTemplate)
}, {}, function (res, err) {
next(err, res);
});
},
function instantiateTemplate (err) {
assert.ifError(err);
var next = this;
assert.response(server, {
url: '/api/v1/map/named/' + nonOverviewsTemplateId,
method: 'POST',
headers: {
host: 'localhost',
'Content-Type': 'application/json'
}
}, {},
function (res, err) {
return next(err, res);
});
},
function checkFlags (err, res) {
assert.ifError(err);
var next = this;
var parsedBody = JSON.parse(res.body);
keysToDelete['map_cfg|' + LayergroupToken.parse(parsedBody.layergroupid).token] = 0;
keysToDelete['user:localhost:mapviews:global'] = 5;
const headers = JSON.parse(res.headers['x-tiler-profiler']);
assert.strictEqual(headers.overviewsAddedToMapconfig, false);
assert.strictEqual(headers.mapType, 'named');
next();
},
function finish (err) {
done(err);
}
);
});
});
});
+3 -80
View File
@@ -3,7 +3,7 @@
var testHelper = require('../support/test-helper');
var assert = require('../support/assert');
var CartodbWindshaft = require('../../lib/server');
const createServer = require('../../lib/server');
var serverOptions = require('../../lib/server-options');
var LayergroupToken = require('../../lib/models/layergroup-token');
@@ -18,7 +18,7 @@ describe('overviews metadata', function () {
var server;
before(function () {
server = new CartodbWindshaft(serverOptions);
server = createServer(serverOptions);
});
// configure redis pool instance to use in tests
@@ -110,90 +110,13 @@ describe('overviews metadata', function () {
}
);
});
describe('Overviews Flags', function () {
it('Overviews used', function (done) {
var layergroup = {
version: '1.0.0',
layers: [overviewsLayer, nonOverviewsLayer]
};
var layergroupUrl = '/api/v1/map';
var expectedToken;
step(
function doPost () {
var next = this;
assert.response(server, {
url: layergroupUrl,
method: 'POST',
headers: { host: 'localhost', 'Content-Type': 'application/json' },
data: JSON.stringify(layergroup)
}, {}, function (res) {
assert.strictEqual(res.statusCode, 200, res.body);
const headers = JSON.parse(res.headers['x-tiler-profiler']);
assert.ok(headers.overviewsAddedToMapconfig);
assert.strictEqual(headers.mapType, 'anonymous');
const parsedBody = JSON.parse(res.body);
expectedToken = parsedBody.layergroupid;
next();
});
},
function finish (err) {
keysToDelete['map_cfg|' + LayergroupToken.parse(expectedToken).token] = 0;
keysToDelete['user:localhost:mapviews:global'] = 5;
done(err);
}
);
});
it('Overviews NOT used', function (done) {
var layergroup = {
version: '1.0.0',
layers: [nonOverviewsLayer]
};
var layergroupUrl = '/api/v1/map';
var expectedToken;
step(
function doPost () {
var next = this;
assert.response(server, {
url: layergroupUrl,
method: 'POST',
headers: { host: 'localhost', 'Content-Type': 'application/json' },
data: JSON.stringify(layergroup)
}, {}, function (res) {
assert.strictEqual(res.statusCode, 200, res.body);
const headers = JSON.parse(res.headers['x-tiler-profiler']);
assert.strictEqual(headers.overviewsAddedToMapconfig, false);
assert.strictEqual(headers.mapType, 'anonymous');
const parsedBody = JSON.parse(res.body);
expectedToken = parsedBody.layergroupid;
next();
});
},
function finish (err) {
keysToDelete['map_cfg|' + LayergroupToken.parse(expectedToken).token] = 0;
keysToDelete['user:localhost:mapviews:global'] = 5;
done(err);
}
);
});
});
});
describe('overviews metadata with filters', function () {
var server;
before(function () {
server = new CartodbWindshaft(serverOptions);
server = createServer(serverOptions);
});
// configure redis pool instance to use in tests
+2 -2
View File
@@ -5,7 +5,7 @@ var assert = require('../support/assert');
const helper = require('../support/test-helper');
var TestClient = require('../support/test-client');
const LayergroupToken = require('../../lib/models/layergroup-token');
const CartodbWindshaft = require('../../lib/server');
const createServer = require('../../lib/server');
const serverOptions = require('../../lib/server-options');
describe('regressions', function () {
@@ -44,7 +44,7 @@ describe('regressions', function () {
// See: https://github.com/CartoDB/Windshaft-cartodb/pull/956
it('"/user/localhost/api/v1/map" should create an anonymous map', function (done) {
const server = new CartodbWindshaft(serverOptions);
const server = createServer(serverOptions);
const layergroup = {
version: '1.7.0',
layers: [
+3 -3
View File
@@ -6,14 +6,14 @@ var assert = require('../support/assert');
var querystring = require('querystring');
var step = require('step');
var CartodbWindshaft = require('../../lib/server');
const createServer = require('../../lib/server');
var serverOptions = require('../../lib/server-options');
describe('server', function () {
var server;
before(function () {
server = new CartodbWindshaft(serverOptions);
server = createServer(serverOptions);
server.setMaxListeners(0);
});
@@ -45,7 +45,7 @@ describe('server old_api', function () {
var server;
before(function () {
server = new CartodbWindshaft(serverOptions);
server = createServer(serverOptions);
server.setMaxListeners(0);
});
+2 -2
View File
@@ -21,7 +21,7 @@ var http = require('http');
var helper = require('../support/test-helper');
var CartodbWindshaft = require('../../lib/server');
const createServer = require('../../lib/server');
var serverOptions = require('../../lib/server-options');
var LayergroupToken = require('../../lib/models/layergroup-token');
@@ -30,7 +30,7 @@ describe('template_api', function () {
var server;
before(function () {
server = new CartodbWindshaft(serverOptions);
server = createServer(serverOptions);
server.setMaxListeners(0);
// FIXME: we need a better way to reset cache while running tests
server.layergroupAffectedTablesCache.cache.reset();
@@ -4,7 +4,7 @@ var assert = require('../../support/assert');
var step = require('step');
var LayergroupToken = require('../../../lib/models/layergroup-token');
var testHelper = require('../../support/test-helper');
var CartodbWindshaft = require('../../../lib/server');
const createServer = require('../../../lib/server');
var serverOptions = require('../../../lib/server-options');
const mapnik = require('@carto/mapnik');
var IMAGE_TOLERANCE_PER_MIL = 10;
@@ -13,7 +13,7 @@ describe('turbo-carto for named maps', function () {
var server;
before(function () {
server = new CartodbWindshaft(serverOptions);
server = createServer(serverOptions);
});
var keysToDelete;
+2 -2
View File
@@ -8,7 +8,7 @@ var queue = require('queue-async');
var helper = require('../../support/test-helper');
var CartodbWindshaft = require('../../../lib/server');
const createServer = require('../../../lib/server');
var serverOptions = require('../../../lib/server-options');
var LayergroupToken = require('../../../lib/models/layergroup-token');
@@ -17,7 +17,7 @@ describe('named-maps widgets', function () {
var server;
before(function () {
server = new CartodbWindshaft(serverOptions);
server = createServer(serverOptions);
});
var username = 'localhost';
+4 -4
View File
@@ -12,7 +12,7 @@ var LayergroupToken = require('../../lib/models/layergroup-token');
var assert = require('./assert');
var helper = require('./test-helper');
var CartodbWindshaft = require('../../lib/server');
const createServer = require('../../lib/server');
var serverOptions = require('../../lib/server-options');
serverOptions.analysis.batch.inlineExecution = true;
@@ -30,7 +30,7 @@ function TestClient (config, apiKey, extraHeaders = {}, overrideServerOptions =
this.extraHeaders = extraHeaders;
this.keysToDelete = {};
this.serverOptions = Object.assign({}, serverOptions, overrideServerOptions);
this.server = new CartodbWindshaft(this.serverOptions);
this.server = createServer(this.serverOptions);
}
module.exports = TestClient;
@@ -1348,7 +1348,7 @@ TestClient.prototype.drain = function (callback) {
module.exports.getStaticMap = function getStaticMap (templateName, params, callback) {
var self = this;
self.server = new CartodbWindshaft(serverOptions);
self.server = createServer(serverOptions);
if (!callback) {
callback = params;
@@ -1378,7 +1378,7 @@ module.exports.getStaticMap = function getStaticMap (templateName, params, callb
};
// this could be removed once named maps are invalidated, otherwise you hits the cache
var server = new CartodbWindshaft(serverOptions);
var server = createServer(serverOptions);
assert.response(server, requestOptions, expectedResponse, function (res, err) {
helper.deleteRedisKeys({ 'user:localhost:mapviews:global': 5 }, function () {
-10
View File
@@ -1,12 +1,5 @@
'use strict';
/**
* User: simon
* Date: 30/08/2011
* Time: 13:52
* Desc: Loads test specific variables
*/
var assert = require('assert');
var fs = require('fs');
var LZMA = require('lzma').LZMA;
@@ -14,7 +7,6 @@ var LZMA = require('lzma').LZMA;
var lzmaWorker = new LZMA();
var redis = require('redis');
const pino = require('pino');
const setICUEnvVariable = require('../../lib/utils/icu-data-env-setter');
// set environment specific variables
@@ -24,8 +16,6 @@ process.env.NODE_ENV = 'test';
setICUEnvVariable();
global.logger = pino({ base: null, level: process.env.NODE_ENV === 'test' ? 'fatal' : 'info' }, pino.destination({ sync: false }));
// Utility function to compress & encode LZMA
function lzmaCompressToBase64 (payload, mode, callback) {
lzmaWorker.compress(payload, mode,
+7 -13
View File
@@ -5,7 +5,7 @@ var assert = require('assert');
var CdbRequest = require('../../lib/models/cdb-request');
describe('req2params', function () {
describe('username in host header (CdbRequest)', function () {
function createRequest (host, userParam) {
var req = {
params: {},
@@ -47,39 +47,33 @@ describe('req2params', function () {
assert.strictEqual(user, 'development');
});
it('returns undefined when it cannot extract username', function () {
it('returns throw when it cannot extract username', function () {
var userFromHostConfig = global.environment.user_from_host;
global.environment.user_from_host = null;
var cdbRequest = new CdbRequest();
var user = cdbRequest.userByReq(createRequest('localhost'));
assert.throws(() => cdbRequest.userByReq(createRequest('localhost')));
global.environment.user_from_host = userFromHostConfig;
assert.strictEqual(user, undefined);
});
it('should not fail for undefined host header', function () {
it('should throw for undefined host header', function () {
var userFromHostConfig = global.environment.user_from_host;
global.environment.user_from_host = null;
var cdbRequest = new CdbRequest();
var user = cdbRequest.userByReq(createRequest(undefined));
assert.throws(() => cdbRequest.userByReq(createRequest(undefined)));
global.environment.user_from_host = userFromHostConfig;
assert.strictEqual(user, undefined);
});
it('should not fail for null host header', function () {
it('should throw for null host header', function () {
var userFromHostConfig = global.environment.user_from_host;
global.environment.user_from_host = null;
var cdbRequest = new CdbRequest();
var user = cdbRequest.userByReq(createRequest(null));
assert.throws(() => cdbRequest.userByReq(createRequest(null)));
global.environment.user_from_host = userFromHostConfig;
assert.strictEqual(user, undefined);
});
});
-167
View File
@@ -20,171 +20,4 @@ describe('error-middleware', function () {
'Error status code for multiline/PSQL does not match'
);
});
it('should return a header with errors', function (done) {
const error = new Error('error test');
error.label = 'test label';
error.type = 'test type';
error.subtype = 'test subtype';
const errors = [error, error];
const req = {};
const res = {
headers: {},
set (key, value) {
this.headers[key] = value;
},
statusCode: 0,
status (status) {
this.statusCode = status;
},
json () {},
send () {}
};
const errorHeader = {
mainError: {
statusCode: 400,
message: error.message,
name: error.name,
label: error.label,
type: error.type,
subtype: error.subtype
},
moreErrors: [{
message: error.message,
name: error.name,
label: error.label,
type: error.type,
subtype: error.subtype
}]
};
const errorFn = errorMiddleware();
errorFn(errors, req, res, (err) => {
if (err) {
return done(err);
}
assert.deepStrictEqual(res.headers, {
'X-Tiler-Errors': JSON.stringify(errorHeader)
});
return done();
});
});
it('JSONP should return a header with error status code', function (done) {
const error = new Error('error test');
error.label = 'test label';
error.type = 'test type';
error.subtype = 'test subtype';
const errors = [error, error];
const req = {
query: { callback: true }
};
const res = {
headers: {},
set (key, value) {
this.headers[key] = value;
},
statusCode: 0,
status (status) {
this.statusCode = status;
},
jsonp () {},
send () {}
};
const errorHeader = {
mainError: {
statusCode: 400,
message: error.message,
name: error.name,
label: error.label,
type: error.type,
subtype: error.subtype
},
moreErrors: [{
message: error.message,
name: error.name,
label: error.label,
type: error.type,
subtype: error.subtype
}]
};
const errorFn = errorMiddleware();
errorFn(errors, req, res, (err) => {
if (err) {
return done(err);
}
assert.deepStrictEqual(res.headers, {
'X-Tiler-Errors': JSON.stringify(errorHeader)
});
return done();
});
});
it('should escape chars that broke logs regex', function (done) {
const badString = 'error: ( ) = " \" \' * $ & |'; // eslint-disable-line no-useless-escape
const escapedString = 'error ';
const error = new Error(badString);
error.label = badString;
error.type = badString;
error.subtype = badString;
const errors = [error, error];
const req = {};
const res = {
headers: {},
set (key, value) {
this.headers[key] = value;
},
statusCode: 0,
status (status) {
this.statusCode = status;
},
json () {},
send () {}
};
const errorHeader = {
mainError: {
statusCode: 400,
message: escapedString,
name: error.name,
label: escapedString,
type: escapedString,
subtype: escapedString
},
moreErrors: [{
message: escapedString,
name: error.name,
label: escapedString,
type: escapedString,
subtype: escapedString
}]
};
const errorFn = errorMiddleware();
errorFn(errors, req, res, (err) => {
if (err) {
return done(err);
}
assert.deepStrictEqual(res.headers, {
'X-Tiler-Errors': JSON.stringify(errorHeader)
});
return done();
});
});
});