El registro, las métricas y el rastreo distribuido son tres herramientas vitales para observar los servicios de Node.js. En esta charla consideraremos los diferentes escenarios en los que cada herramienta prospera, analizaremos paneles y visualizaciones, e incluso examinaremos el código necesario para instrumentar estas herramientas en un servicio de Node.js.
Registro, Métricas y Rastreo con Nodejs
Video Summary and Transcription
Esta charla cubre el registro, las métricas y el rastreo con Node.js. Explora la configuración de registro con Winston y las convenciones y soluciones de registro. La charla también discute los paneles de registro y las métricas, así como las métricas y el rastreo distribuido. Se abordan las herramientas de rastreo y visualizaciones, async-await y el registro en Node.js, y el registro específico de solicitudes y el rastreo distribuido. Además, se cubren los middleware de registro y las funciones sin servidor, y la diferencia entre la instrumentación automática y manual.
1. Introducción al registro
Hola. Soy Thomas Hunter y bienvenidos a mi charla sobre Registro, Métricas y Rastreo con Node. Primero, vamos a hablar sobre el registro. El registro es una forma de extraer el estado granular de un programa. Los registros a menudo tienen un nivel de gravedad asociado, que se utiliza para filtrar. Puede configurar una aplicación para escribir registros en la salida estándar, el sistema de archivos o enviarlos directamente a través de la red. El servicio central de registro captura estos registros globalmente en todas sus aplicaciones.
Hola. Soy Thomas Hunter y bienvenidos a mi charla sobre Registro, Métricas y Rastreo con Node. Todo el contenido de esta charla está adaptado de un capítulo de mi libro recientemente publicado, Sistemas Distribuidos con Node. Primero, vamos a hablar sobre el registro. Puedes pensar en el registro como el console.log de la nube. ¿Qué es exactamente el registro? Es una forma de extraer el estado granular de un programa. Por lo general, el estado termina pareciendo datos JSON bien estructurados en lugar de las palabras o objetos aleatorios que tú o yo podríamos registrar localmente. Estos registros a menudo tienen un nivel de gravedad asociado, que se utiliza para filtrar. Por ejemplo, los niveles de gravedad que se hicieron populares gracias a NPM son error, warn, info, HTTP, verbose, debug y silly. Puedes configurar una aplicación para que, tal vez, en producción solo recibas mensajes que tengan un nivel de gravedad mayor que debug, mientras que localmente recibas todos los mensajes. Por lo tanto, estos registros se pueden escribir en la salida estándar, en el sistema de archivos o incluso enviarse directamente a través de la red por la aplicación. Si decides enviarlos desde la aplicación directamente a través de la red, eso aumentaría la complejidad de la aplicación, sin embargo, también podría agilizar la entrega de esos registros. La razón por la que necesita funcionar de esta manera es que tenemos un servicio central de registro que captura
2. Configuración de registro con Winston
Uno de los paquetes populares para el registro en Node.js es Winston. Te permite crear una instancia de Winston y exportarla como una representación Singleton. Puedes configurar la instancia para capturar niveles de registro específicos y mostrarlos en formato JSON. Se pueden establecer propiedades meta predeterminadas para todos los registros, como el entorno de Node y el nombre de la aplicación. Se pueden configurar transportes para escribir los registros en un archivo e imprimirlos en la consola.
3. Convenciones y Soluciones de Registro
Podemos crear un registro global o un registro específico de la solicitud. Un patrón común es crear un ID de solicitud asociado con cada registro. En el ejemplo, requerimos el registro global, generamos un ID de solicitud para cada solicitud y creamos un registro secundario. El registro secundario incluye el ID de solicitud como propiedad predeterminada. Podemos usar el registro secundario para generar registros con información contextual, como la URL y el método. Otro ejemplo muestra cómo manejar errores y registrar trazas de pila. Las soluciones populares de registro incluyen Elk Stack, Splunk, Datadog y Sumo Logic.
4. Panel de Control de Registro y Métricas
Este panel de control muestra registros que coinciden con la consulta, junto con los registros en bruto. La consulta se escribe en KQL, que significa Kibana Query Language. Por otro lado, las métricas proporcionan datos numéricos agregados y ayudan a comprender la salud de la aplicación. Las métricas incluyen nombres y etiquetas asociadas para consultas. Proporcionan mediciones del mundo real que los puntos de referencia no pueden. Las métricas pueden rastrear el rendimiento de las solicitudes, el tiempo, el uso de memoria, los códigos de estado e incluso datos relacionados con el negocio. Las métricas suelen ser más económicas que los registros. El código de ejemplo demuestra el uso del paquete cliente StatsD para crear y rastrear métricas de tiempo de solicitud, códigos de estado y métodos.
5. Métricas y Tracing Distribuido
Entonces, existen diferentes soluciones de métricas como statsd, graphite y grafana o prometheus y grafana. La empresa Datadog también tiene un producto de métricas. Las métricas se pueden representar en gráficos, mostrando las solicitudes salientes, el tiempo de las solicitudes y los códigos de estado entrantes. El tracing distribuido permite rastrear las comunicaciones entre servicios, asociar solicitudes relacionadas y visualizar la jerarquía de solicitudes.
6. Tracing Distribuido e Instrumentación
Puedes proporcionar el UUID de solicitud generado a tu registro para asociar registros en todos tus servicios. Se muestra un ejemplo utilizando el paquete zipkin lite con Fastify y node fetch. La aplicación se instrumenta agregando una ruta para obtener un widget. El ID de solicitud se registra y se puede acceder en toda la solicitud. El código también establece el nombre de la solicitud y prepara la solicitud de Zipkin para una solicitud saliente. Soluciones de tracing como Zipkin y Jaeger son populares y se pueden alojar en tu propio servidor.
Aquí tienes un ejemplo de implementación de tracing. Esto utiliza el paquete zipkin lite. Y nuevamente, estamos usando Fastify. También se utilizará el paquete node fetch. Creamos una conexión de zipkin. Y especificamos el host al que vamos a enviar esta información de zipkin, siendo zipkin una implementación de tracing. También tenemos que nombrar el servicio, llevar un registro del puerto del servicio y la IP del servicio. Finalmente, instanciamos el servidor Fastify y luego agregamos dos hooks a él. El primero ocurre cuando se recibe una solicitud y el segundo ocurre cuando se envía la respuesta. Estos dos middlewares realizan tareas como llevar un registro del tiempo de inicio de la solicitud, generar un ID de solicitud, y finalmente transmitir toda esa información al servidor central de zipkin.
Ahora, aquí tienes un ejemplo de cómo instrumentar la aplicación en sí misma. Lo que estamos haciendo es agregar una ruta en la aplicación. Entonces, cuando el usuario obtiene un widget, se llama a esta ruta. Lo primero que sucede aquí es que se registra el ID de solicitud. Y esto es solo una forma de mostrar cómo se puede acceder a ese ID de solicitud. Idealmente, tendrías un middleware que luego toma ese ID de solicitud y lo adjunta al registro de solicitud para que puedas usarlo en toda la solicitud. Y este código también genera o establece el nombre de la solicitud, en este caso, para obtener el widget y se usa más adelante para informes. Y finalmente, tal vez haya mucho otro código que ocurre dentro de la aplicación a lo largo de la solicitud, pero llegamos a un punto en el que estamos listos para hacer una solicitud saliente. Lo primero que hacemos es preparar la solicitud de Zipkin. También tenemos acceso a esta URL. Y luego hacemos una llamada fetch. Entonces, la llamada fetch es en su mayoría la misma, excepto que específicamente tenemos que proporcionar los encabezados que se generan a partir de esta preparación de solicitud de Zipkin. Una vez que se completa la solicitud, llamamos a este método complete y pasamos el método HTTP y una URL. Y finalmente, terminamos la solicitud.
Entonces, hay varias soluciones de tracing disponibles. La que acabamos de ver es Zipkin. Otra alternativa popular de código abierto es Jaeger. Estas son dos opciones que puedes alojar en tu propio servidor.
7. Herramientas de Tracing y Visualizaciones
Tanto Zipkin como data.dog.apm ofrecen formas excelentes de rastrear y monitorear tus aplicaciones. Zipkin ofrece una vista jerárquica de los servicios y su información de tiempo, mientras que data.dog.apm proporciona una línea de tiempo de rendimiento similar a las herramientas del navegador. Estas herramientas capturan automáticamente metadatos y pueden modificar tu aplicación para pasar encabezados para un rastreo de servicios más profundo. Si deseas obtener más información, puedes seguirme en Twitter o consultar la presentación sobre sistemas distribuidos con Node.
Y ambas herramientas pueden seguir algo llamado especificación OpenTelemetry, que es una forma de definir, ¿sabes?, ¿qué son los encabezados que se pasan? ¿Qué tipo de información de tiempo estás rastreando? ¿Cómo se envía al servidor central, etc.? La compañía Datadog también tiene un producto APM. Y New Relic es otra solución de rastreo popular.
Entonces, ¿cómo se ve realmente el rastreo? Bueno, con Zipkin, terminas obteniendo una jerarquía bastante agradable. Esta es una captura de pantalla tomada del sitio web de Zipkin. Podemos ver a la izquierda que tenemos una jerarquía de los servicios. Tenemos, por ejemplo, el servicio de enrutamiento. Debajo de eso está Memcached, Yelp, Main, etc. Junto a eso, tenemos una línea de tiempo agradable que muestra el tiempo real que lleva. Y utilizando esa línea de tiempo, podemos ver que la solicitud general ocurre en la parte superior, tardó aproximadamente 131 milisegundos. Luego, las diferentes operaciones debajo de eso tomaron más tiempo. Y así, la profundidad de este gráfico representa la profundidad de la cadena de solicitudes dentro de tu aplicación. A la derecha, vemos algunas anotaciones de metadatos que también se rastrean.
data.dog.apm es otra herramienta alternativa. Esta se parece un poco más a la línea de tiempo de rendimiento que podrías ver en el navegador mientras mides la eficiencia de tu JavaScript. En este caso, el eje X también representa el tiempo, pero el eje Y representa de manera aproximada diferentes cosas que están sucediendo dentro de la aplicación. data.dog.apm es una forma agradable de instrumentar automáticamente tu base de código. Todas estas cosas diferentes que se muestran aquí se capturan automáticamente desde la aplicación. Y aquí tienes una captura de pantalla en vivo real de una solicitud en lob.com. Ves que tardó aproximadamente 850 milisegundos. Y así, he ampliado este gráfico, pero antes de esto, estábamos haciendo cosas como descargar un recurso de una postal de un cliente. También podemos ver cosas como las solicitudes a Postgres, una llamada a AWS, etc. Y así, el APM de Datadog modifica automáticamente la aplicación y pasa cosas como encabezados, que luego se envían a servicios más profundos. Bien, eso es todo. Siéntete libre de seguirme en Twitter. La presentación está disponible en esta URL. Por supuesto, este contenido fue tomado de sistemas distribuidos con Node. Si deseas obtener más información, no dudes en visitar esa URL.
QnA
Async-Await and Logging in Node.js
La sintaxis de async-await es agradable. También es la más nueva. Aún tienes ese problema de anidamiento y eso se resuelve con async-await. El papel del registro en las funciones de Node.js es tan útil como en cualquier otra aplicación. Quieres saber la salud de tu aplicación, si las cosas siguen funcionando, si hay retrasos. La mejor manera de organizar los registros de series temporales de los dispositivos IoT es estableciendo métricas utilizando una jerarquía. Asígnalos según el componente IoT y las regiones donde se ejecuta el equipo. El enfoque de registro mostrado en la presentación utiliza dos registradores, uno de ellos siendo un registrador universal.
Creo que eso es de esperar, sí. La sintaxis de async-await es agradable. También es la más nueva. Sí, es bastante común en este momento usar async-await. Y las promesas siguen siendo bastante populares, creo. Pero sí, aún tienes ese problema de anidamiento y eso se resuelve con async-await. Así que eso es agradable. Así que la sesión de preguntas y respuestas es bastante emocionante ahora, porque vas a regalar tu gran libro. Así que vamos a las preguntas. Y espero que podamos responder a todas ellas. La primera es de Brian Howe. Hugh, ¿qué papel desempeña el registro para las funciones de Node.js? Supongo que por funciones se refieren a funciones lambda, cosas así. Así que quiero decir que es tan útil como en cualquier otra aplicación. Quieres saber la salud de tu aplicación, quieres saber si las cosas siguen funcionando, si hay retrasos. Así que definitivamente es útil al enviar, tal vez, métricas mientras invocas funciones, luego puedes construir un panel que te muestre, tal vez, cuántas funciones simultáneas tienes en ejecución, cosas así. Creo que mucha de esta información probablemente la puedas obtener de quien aloja las funciones como AWS, pero también puedes extraer tus propios datos de eso.
Ok. La siguiente pregunta es de chshirendra2010. ¿Cuál es la mejor manera de organizar los registros de series temporales que provienen de los dispositivos IoT? Bueno, supongo que primero admitiré que nunca he trabajado con IoT. Sabes, gran parte de todos los datos de los que hablé en esta charla se trata de datos de series temporales. Datos que están vinculados a un cierto punto en el tiempo. Y así, sabes, creo que con las aplicaciones quieres organizar tus métricas utilizando una jerarquía donde el nivel superior sea tu aplicación. Entonces, por ejemplo, tal vez tengas una aplicación de vista de perfil, como una aplicación de galería, una aplicación de autenticación, pero con IoT, tal vez quieras asignarles un espacio de nombres basado en el componente IoT que tengas. Y luego, tal vez, si tienes regiones donde se ejecuta el equipo IoT, creo que podrías tener, por ejemplo, temperatura de la cama en América del Norte, sabes, creo que solo quieres crear una jerarquía que se ajuste a tu caso de uso. Sí, exactamente, sí. Bien. La siguiente pregunta es de Alexey. ¿Has creado en el ejemplo inicial un registrador de instancia de solicitud? ¿Cómo puedes recomendar proporcionar dos niveles que están por debajo del servidor web, como la lógica empresarial o los repositorios de bases de datos? Sí, supongo que lo complicado con eso es que con el enfoque de registro que mostré en la presentación, tienes los dos registradores,
Request-specific Logging and Distributed Tracing
El contexto dentro de un script de PHP representa la solicitud que se está realizando. En el seguimiento distribuido, puedes adjuntar el ID de solicitud al registrador específico de la solicitud. Para aplicaciones sin servidor, es difícil pasar encabezados de solicitud, pero puedes insertar el ID de solicitud en la carga útil. Existen formas de enviar estos datos a una herramienta de seguimiento distribuido. También existen herramientas o middleware que evitan el registro de información confidencial.
Genial. Otra pregunta de Java task. ¿Cuál es la mejor manera de correlacionar los registros con los rastreos en DT? ¿En DT? No sé qué... Oh, en seguimiento distribuido. Por ejemplo, en la presentación, mostré cómo un... creas un middleware que crea el registrador específico de la solicitud. Entonces, en ese momento, si estás utilizando una herramienta de seguimiento distribuido y recibes una solicitud entrante con un ID de solicitud, puedes adjuntarlo al registrador. Sin embargo, si eres la aplicación más superficial dentro de la pila, sabes, la que recibe la primera solicitud en ese momento, entonces generarías el ID de solicitud para pasarlo a los servicios más profundos. Así que, al adjuntar ese ID de solicitud al registrador específico de la solicitud, luego puedes buscar todos esos registros usando tus herramientas de registro como Kibana. Genial. La siguiente pregunta es de Brian H. Yoo nuevamente. Cuando hablas de seguimiento distribuido, ¿cómo funciona el registro o cómo se vería en la nube para aplicaciones sin servidor? Sí, ¿cómo funciona con sin servidor? Entonces, sí, supongo que, nuevamente, cosas como Lambda. Sí. Creo que cuando invocas una Lambda, no necesariamente tienes una solicitud HTTP visible con ella. Por lo tanto, es difícil pasar estos encabezados de solicitud. Dicho esto, cuando invocas una Lambda, proporcionas algún tipo de solicitud como carga útil. Y luego podrías hacer cosas como tomar ese ID de solicitud y simplemente insertarlo en esa carga útil. Y luego hay formas de tomar esos datos y enviarlos a una herramienta de seguimiento distribuido. La versión más larga de esta presentación mostró un desglose de todos los paquetes y mensajes reales que se envían. Y así, es posible, sabes, reconstruir estas representaciones de tramos HTTP y luego enviarlas al servicio de seguimiento distribuido. De acuerdo. Otra pregunta de Alexey. ¿Conoces alguna herramienta o middleware que evite que la aplicación registre información confidencial como contraseñas y tokens?
Logging Middleware and Serverless Functions
En lob.com, utilizamos un middleware para crear una lista de denegación de campos que no deben registrarse. Hay herramientas disponibles para eliminar automáticamente o permitir listas de denegación manuales. Para funciones sin servidor, puedes instanciar un registrador que envíe registros a un servicio diferente, como una instancia de Logstash. Puedes medir aspectos internos de Node.js, como los retrasos del bucle de eventos o la frecuencia de recolección de basura, accediendo a las métricas expuestas dentro de Node mismo. Las métricas suelen tener menos sobrecarga, mientras que el seguimiento puede ser más pesado, especialmente con soluciones de seguimiento automático.
Instrumentación Automática vs Manual
Si estás utilizando una herramienta automática, como una herramienta de estilo APM, puede ser más pesada. Pero si estás instrumentando manualmente y pasando encabezados, tendrá un impacto mínimo. Console.log y process.stdout/process.write tienen un rendimiento similar. Console.log es más fácil de usar y ampliamente compatible. Thomas eligió la pregunta de David Lane como la mejor y se pondrá en contacto con él para el libro.
Entonces, si estás utilizando una herramienta automática, como una herramienta de estilo APM, se va a instrumentar básicamente todo. Y por lo tanto, inyecta código que se sitúa entre una llamada entre la aplicación y la biblioteca. Y esto puede volverse un poco más pesado. Pero si estás instrumentando manualmente y pasando manualmente solo algunos encabezados en tu aplicación, como en el ejemplo que utilicé en la sección de seguimiento distribuido, eso probablemente tendrá un impacto en el rendimiento más mínimo.
Muy bien. Gracias. Otra pregunta de André Calasanz. ¿Hay algún impacto/sobrecarga en el uso de console.log en comparación con process.stdout/process.write? ¿O cuál recomiendas para el registro? Si estás haciendo algo como, ya sabes, dentro de un camino de código activo, si estás registrando, podrías encontrar una diferencia entre ellos. Pero si estás registrando un mensaje como parte de una solicitud HTTP o si hay muchas cosas asíncronas sucediendo, básicamente si no estás simplemente enviando estos mensajes, probablemente no verás una diferencia de rendimiento. Personalmente, me encanta console.log porque puedo usarlo en el front-end de JavaScript, en el back-end de JavaScript, y es más fácil de recordar. Eso es generalmente lo primero que haces y luego cuando dices, bien, ahora tengo 20 registros. Ahora necesito usar las herramientas de depuración.
Entonces, Thomas, nos quedan solo unos momentos. Pero en lugar de hacer una pregunta, me gustaría que leas las preguntas que se han hecho en el canal de preguntas y respuestas de Notalk. Así puedes elegir la mejor pregunta para el ganador, para tu libro. Y mientras Thomas hace eso, te informaré cómo funcionará este proceso. Entonces Thomas va a leer las preguntas ahora y tomará una decisión informada sobre cuál es la mejor, la pregunta más profunda que se haya hecho. Y luego Thomas anunciará al ganador y se pondrá en contacto con esa persona en Discord para compartir su correo electrónico y él se encargará de enviar el libro a tu lugar lo antes posible. Entonces, Thomas, ¿estás listo? ¿Has leído el resto de las preguntas? Sí. Creo que... Sí, disfruté más la pregunta de David. David Lane. Entonces la pregunta fue, ¿puedes recomendar formas de instrumentar los aspectos internos de Node.js, como los retrasos del bucle de eventos o la frecuencia de recolección de basura, para enviar a estos servicios? Entonces, David, Thomas se pondrá en contacto contigo, así que revisa tu bandeja de entrada en Discord y disfruta de tu libro. Asegúrate, cuando lo hayas leído, de enviar un tweet en nuestro camino en Node congress, y también, por supuesto, hazle saber a Thomas porque siempre es agradable recibir comentarios, ¿verdad? Absolutamente. Muy bien, Thomas. Bueno, muchas gracias por unirte a nosotros. Y para las personas que quieran hacer sus preguntas a Thomas que no tuvieron la oportunidad de responder, Thomas estará en su sala de altavoces de chat espacial si quieren unirse a él. Thomas, muchas gracias. Espero verte de nuevo pronto. Gracias. Adiós.