Maison  >  Article  >  interface Web  >  Apprenez étape par étape à imprimer avec élégance les journaux de liens complets dans le nœud

Apprenez étape par étape à imprimer avec élégance les journaux de liens complets dans le nœud

青灯夜游
青灯夜游avant
2022-03-07 20:05:102608parcourir

Comment le nœud peut-il imprimer les journaux de liens complets avec élégance ? L'article suivant vous présentera comment imprimer avec élégance des journaux de liens complets dans node. J'espère qu'il vous sera utile !

Apprenez étape par étape à imprimer avec élégance les journaux de liens complets dans le nœud

Lorsqu'un utilisateur signale un problème : lorsqu'une erreur se produit lors de l'utilisation d'une certaine fonction en ligne, comment pouvez-vous la localiser rapidement et précisément ? Comment suivre efficacement l'optimisation lorsqu'une certaine interface de requête renvoie les données lentement ?

1. Principe et pratique

Comme nous le savons tous, lorsqu'une demande arrive, les journaux suivants seront probablement générés :

1. AceesLog : journal d'accès utilisateur

2. . SQL : journal des requêtes SQL

4. ThirdParty : journal des services tiers

Comment suivre tous les logs générés par une requête ?

L'approche générale consiste à utiliser un requestId comme identifiant unique,

puis à écrire un middleware, à injecter le requestId dans le contexte, et lorsque la journalisation est nécessaire, à le sortir du contexte et à l'imprimer,

Dans un tiers services et SQL Dans le journal, le requestId doit également être transmis à la fonction correspondante pour l'impression. Il est trop gênant de le transmettre couche par couche, et le code est également relativement intrusif.

Notre objectif est de réduire le caractère intrusif du code, de l'injecter une seule fois et de le suivre automatiquement.

Après la recherche, async_hooks peut suivre le cycle de vie du comportement asynchrone. Dans chaque ressource asynchrone (chaque requête est une ressource asynchrone), elle a 2 ID,

sont respectivement asyncId (l'ID du cycle de vie actuel de la ressource asynchrone) ) , trigerAsyncId (ID de ressource asynchrone parent).

async_hooks fournit les hooks de cycle de vie suivants pour surveiller les ressources asynchrones :

asyncHook = async_hook.createHook({
  // 监听异步资源的创建
  init(asyncId,type,triggerAsyncId,resource){},
  // 异步资源回调函数开始执行之前
  before(asyncId){},
  // 异步资源回调函数开始执行后
  after(asyncId){},
  // 监听异步资源的销毁
  destroy(asyncId){}
})

Ensuite, si nous effectuons un mappage, chaque asyncId est mappé à un stockage et le requestId correspondant est stocké dans le stockage, alors le requestId peut être facilement obtenu.

Il se trouve que la bibliothèque cls-hooked a été encapsulée sur la base de async_hooks. Elle conserve une copie des données dans la même ressource asynchrone et la stocke sous la forme de paires clé-valeur. (Remarque : async_hooked doit être utilisé dans la version supérieure node>=8.2.1) Bien sûr, il existe d'autres implémentations dans la communauté, telles que cls-session, node-continuation-local-storage, etc.

Ce qui suit est un exemple de la façon dont j'ai appliqué cls-hooked dans mon projet :

/session.js crée un espace de stockage nommé

const createNamespace = require('cls-hooked').createNamespace 
const session = createNamespace('requestId-store') 
module.exports = session

/logger.js imprime le journal

const session = require('./session') 
module.exports = { 
info: (message) => 
{ 
const requestId = session.get('requestId')
console.log(`requestId:${requestId}`, message) 
}, 
error: (message) => 
{ 
const requestId = session.get('requestId') 
console.error(`requestId:${requestId}`, message) 
} 
}

/sequelize.js sql appelle l'enregistreur pour imprimer le journal

const logger = require("./logger") 
new Sequelize( 
logging: function (sql, costtime) { 
logger.error( `sql exe : ${sql} | costtime ${costtime} ms` ); 
} )

/app.js Définissez le requestId, définissez le requestId pour renvoyer l'en-tête de réponse et imprimez le journal d'accès

const session = require('./session') 
const logger = require('./logger') 
async function accessHandler(ctx, next) 
{ 
const requestId = ctx.header['x-request-id'] || uuid()
const params = ctx.request.body ? JSON.stringify(ctx.request.body) : JSON.stringify(ctx.request.query)
// 设置requestId session.run(() => { session.set('requestId', requestId)
logger.info(`url:${ctx.request.path};params:${params}`) next()
// 设置返回响应头
ctx.res.setHeader('X-Request-Id',requestId)
}) }

Jetons un œil au journal lorsqu'un chemin de requête est /home?a=1 :

访问日志:
requestId:79f422a6-6151-4bfd-93ca-3c6f892fb9ac url:/home;params:{"a":"1"}

Sql日志:
requestId:79f422a6-6151-4bfd-93ca-3c6f892fb9ac sql exe :
Executed (default): SELECT `id` FROM t_user

Vous pouvez voir l'intégralité de la requête. Le journal requestId du lien est le même. Si une alarme est envoyée ultérieurement à la plateforme d'alarme, nous pouvons alors trouver l'intégralité du lien exécuté par cette requête en fonction du requestId.

Les étudiants prudents remarqueront peut-être que j'ai également défini le requestId dans l'en-tête de réponse renvoyé par l'interface. Le but est de connaître le requestId directement depuis le navigateur si une requête tarde à répondre ou présente des problèmes d'analyse.

2. Surcharge de performances

J'ai fait un test de stress localement,

Voici la comparaison de l'utilisation de la mémoire :

Apprenez étape par étape à imprimer avec élégance les journaux de liens complets dans le nœudC'est environ 10 % de plus que si async_hook n'est pas utilisé.

Pour notre système QPS qui est de niveau 100, ce n'est pas grave, mais s'il s'agit d'un service à haute concurrence, nous devrons peut-être y réfléchir attentivement.

ps : S'il y a des erreurs, veuillez les signaler, ne commentez pas si vous ne les aimez pas

Pour plus de connaissances sur les nœuds, veuillez visiter :

tutoriel nodejs

 !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer