Рубрики
Uncategorized

Пошаговое руководство по добавлению идентификатора запроса на все журналы SQL с Async Local Storage

Регистрация важно для всей добываемой продукции. Это значительно повлияет на нашу производительность … Теги с узлом, журналом, застегивают, дежопта.

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

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

Поскольку 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»