Регистрация важно для всей добываемой продукции. Это значительно повлияет на нашу производительность, когда возникает проблема.
С удостоверением личности запроса мы можем отслеживать запрос пользователя, не греясь на все строки с нашими глазами. Просто фильтрация с уникальным удостоверением личности запроса и сделано. Почти все службы регистрации имеют функцию фильтрации, так что это довольно портативный путь.
Поскольку node.js обычно работает в одной резьбовой среде, требуется трюк для добавления идентификатора запроса для каждого журнала. Хитрость была Домен
API в течение длительного времени, но теперь вы можете использовать AsynclocalStorage
создать потокообразный контекст.
Я покажу тебе, как это сделать.
Примечание: AsynClocalStorage имеет эффект производительности, но я думаю, что легкая регистрация важнее производительности.
В этом примере я использую Застегивайте
и Находка
и Pino
С помощью текста, но идея должна использоваться с каждыми технологиями.
https://github.com/acro5piano/knex-fastify-async-local-storage-example
Ничего особенного.
yarn add fastify knex nanoid pino pino-pretty sqlite3 # For easy development yarn add -D esbuild-register @types/node @types/pino typescript
Это ключевая часть. AsynclocalStorage
Содержит данные, которые уникальны для каждого запроса.
// src/executionContext.ts import { AsyncLocalStorage } from 'async_hooks' type ContextKey = 'reqId' export const executionContext = new AsyncLocalStorage
Этот регистратор добавляет Reqid
на каждые записи. Вы должны войти все с помощью этого регистратора (не использовать console.log).
// src/logger.ts import pino from 'pino' import { executionContext } from './executionContext' export const logger = pino({ prettyPrint: true, mixin() { return { reqId: executionContext.getStore()?.get('reqId'), } }, })
Используйте наше Логин
для регистрации запросов. Он автоматически добавляет Reqid
Отказ
Отказ от ответственности: Для простоты я не добавляю настройки восстановления журнала. Если вы используете его на производственную службу, не забудьте скрыть конфиденциальную информацию от журналов.
// src/db.ts import createKnex from 'knex' import { logger } from './logger' export const db = createKnex({ client: 'sqlite3', connection: ':memory:', useNullAsDefault: false, }) // Log every query with our logger db.on('query', ({ sql, bindings }) => { logger.info({ sql, bindings }, 'SQL') })
Застегивание имеет функцию регистрации, указав Логин
вариант. request.log.info
Автоматически добавляет Reqid
которые могут быть достаточно для небольших услуг. Однако, используя наши ExecutionContext
Мы можем добавить Reqid
Для каждых записей журнала, включая журнал SQL!
Для этого создайте экземпляр постегивания сначала:
// src/app.ts import Fastify from 'fastify' import { nanoid } from 'nanoid' import { logger } from './logger' import { executionContext } from './executionContext' import { db } from './db' export const app = Fastify({ logger, genReqId: () => nanoid(), // the default is increment, but nanoid is easier for tracing disableRequestLogging: true, // we do it on our own }) // Create a database table for logging (just for example) app.addHook('onReady', async () => { await db.schema.createTable('logs', (t) => { t.bigIncrements() t.string('message').notNullable() t.string('req_id').notNullable() t.timestamp('created_at').notNullable().defaultTo(db.fn.now()) }) }) // ...
Затем зарегистрируйте крючок, который обернут запрос в контексте. Без этого мы не можем получить доступ к контексту!
// src/app.ts // ... // Add hook to run all operations on the request context app.addHook('preHandler', (_, __, next) => { executionContext.run(new Map(), next) }) // ...
Затем набор Reqid
к контексту. Это будет выделено в каждом запросе.
// src/app.ts // ... // Set request ID to the context app.addHook('preHandler', (request, _, next) => { executionContext.getStore()?.set('reqId', request.id) next() }) // ...
Хорошо, мы устанавливаем Reqid
к контексту! Давайте добавим функцию ведения журнала:
// src/app.ts // ... // Log request app.addHook('preHandler', (request, _, next) => { const { method, url, ip } = request logger.info({ method, url, ip }, 'incoming request') next() }) // ...
Добавляет Reqid
Отказ
Далее давайте подтвердим Reqid
появится в журналах SQL Query:
// src/app.ts // ... // Main routing app.get('/', async (_, reply) => { await db('logs').insert({ message: 'incoming request', req_id: executionContext.getStore()!.get('reqId'), }) reply.send('ok') }) // ...
Это выделяет следующий журнал.
Отслеживание ID запроса действительно важно расследовать ошибки.
Если у вас есть отзывы, пожалуйста, оставьте комментарий!
Оригинал: «https://dev.to/acro5piano/step-by-step-guide-to-add-request-id-to-all-sql-logs-with-async-local-storage-1al0»