Node.js выражать запрос Id

Я пытаюсь создать какой-то идентификатор запроса для ведения журнала, который будет доступен мне через каждую функцию потока запросов. Я хочу регистрировать каждый шаг потока запросов с идентификатором, указывающим, какая строка журнала для какого запроса.

Я просмотрел некоторые идеи и столкнулся с двумя основными предложениями:

Первое - это создание промежуточного программного обеспечения, которое добавит поле в объект 'req', как это (как предложено здесь):

var logIdIterator = 0;

app.all('*', function(req, res, next) {
  req.log = {
    id: ++logIdIterator
  }
  return next();
});

И второй использует continuation-local-storage

Проблемы:

Для первого подхода - это означает, что мне придется передать дополнительный аргумент каждой функции в потоке, и это нелегкое решение для использования над зрелым приложением с бесчисленными API и потоками.

Второй выглядит многообещающим, но, к сожалению, он имеет некоторые проблемы, в которых государство теряется (см. здесь). Кроме того, это произошло несколько раз, когда мы использовали нашу библиотеку redis - что плохо, потому что запросы redis происходят в каждом из наших потоков.

Я думаю, если я не найду другого решения, мне придется использовать первый подход, просто я хочу избежать передачи дополнительного параметра тысячам существующих функций.

Мой вопрос: как вы предлагаете поддерживать идентификатор запроса через поток запросов?

Ответ 1

Вы могли бы сделать свою первоначальную рутину немного более сложной: (а) хранить информацию в виде файла cookie только для сервера и (б) помещать больше информации в файл cookie за пределы счетчика. Например, я использую следующее как трассировку всех вызовов в моем приложении:

console.log('['+count+'] at: '+format.asString('hh:mm:ss.SSS', new Date())+' Url is: ' + req.url);

где "count" увеличивается с начала приложения (да, лучше использовать постоянный синглтон). Это дает мне каждый вызов сервера (req.url) и точно, когда этот вызов был сделан. Это можно легко расширить, чтобы забрать sessionID, если ваше приложение выполняет управление уровнем сеанса.

Ответ 2

Вы можете использовать этот пакет: https://www.npmjs.com/package/express-request-id

Это промежуточное программное обеспечение, которое будет добавлять uuid для каждого запроса

var app = require('express')();
var addRequestId = require('express-request-id')();
 
app.use(addRequestId);
 
app.get('/', function (req, res, next) {
    res.send(req.id);
    next();
});
 
app.listen(3000, function() {
    console.log('Listening on port %d', server.address().port);
});
 
// curl localhost:3000 
// d7c32387-3feb-452b-8df1-2d8338b3ea22 

Ответ 3

У вас асинхронная связь, и вы хотите сохранить контекст без а) закрытия или b) передачи параметров. Я боюсь, что лучше всего передать что-то ко всем функциям, которые нужно знать - будь то объект req, идентификатор запроса, вызов функции curried log - что-то.

Независимо от того, что вы проходите, можно легко переделать в любой из других - простой идентификатор может искать объект из глобального хранилища (например, не хорошо, но возможно). Имея это в виду - у вас уже может быть что-то переданное методам, которые однозначно идентифицируют запрос; в этом случае, используя это как ключ и просматривая дополнительные данные из глобального хранилища (т.е. require файл с module.exports.cache = new Map(); или что-то не повод для загрязнения глобального пространства имен).

Как вы заметили, попытки делать неуловимые вещи с языком часто бывают хрупкими (особенно когда встречаются другие неуклюжие вещи). Тем не менее, вы можете понять, как continuation-local-storage работает внутри, отлаживает его вместе с вашими библиотеками и использует его или homebrew-решение.

Звучит неудобно со стоимостью поддержания этого кода. Это запах кода - и добавление неявного глобального продолжения локального состояния звучит как нечто, что только поможет понять и удержать код, более сложный, чем простой. Вы можете принять это как возможность обучения и спросить, почему вам нужен идентификатор запроса, и почему он не нужен, когда кто-нибудь написал код. Мне жаль, что, не зная самой кодовой базы, это лучший ответ, который я могу дать.