Inviare i log di un applicazione nodejs al Cockpit di Scaleway

250
0

Gestire i log di un applicazione, soprattutto se distribuita, può essere molto difficile, andiamo quindi ad analizzare il Cockpit di Scaleway!

Ma prima di tutto, cos’è questo Cockpit?

Il cockpit di Scaleway ti consente di monitorare le tue applicazioni e la loro infrastruttura fornendoti informazioni e contesto sul loro comportamento. Ti consente inoltre di visualizzare le tue metriche e i tuoi log attraverso una dashboard di grafana

https://www.scaleway.com/en/docs/observability/cockpit/quickstart/

Vediamo quindi come possiamo inviare dei log applicativi al Cockpit in Node.js!


L’applicazione

Prima di tutto creiamo una semplice applicazione con Fastify, il template di default proposto dalla sua documentazione va benissimo.

import fastify from "fastify";

// Require the framework and instantiate it
const server = fastify({ logger: true });

// Declare a route
server.get("/", async (request, reply) => {
  return { hello: "world" };
});

// Run the server!
const start = async () => {
  try {
    await server.listen({ port: 3000 });
  } catch (err) {
    server.log.error(err);
    process.exit(1);
  }
};

start();

Fastify usa Pino.js come logger, sfruttiamo quindi le sue funzionalità per inviare i nostri log al Cockpit di Scaleway!

Creiamo un nuovo file transport.mjs e creiamo un Pino.js Transport.

import build from "pino-abstract-transport";
import invariant from "tiny-invariant";
import axios from "axios";

export default async function (opts) {
  invariant(opts.url, "url is required for the transport");
  invariant(opts.labels.job, "job label is required for the transport");

  const labels = opts.labels;

  return build(
    async function (source) {
      for await (let obj of source) {
        const now = new Date();
        const unixEpochInNanoseconds = now.getTime() * 1000000;
        const values = [
          [unixEpochInNanoseconds.toString(), JSON.stringify(obj)],
        ];
        try {
          await axios.post(opts.url, {
            streams: [
              {
                stream: {
                  ...labels,
                },
                values,
              },
            ],
          });
        } catch (error) {
          console.error("loki transport error:", error);
        }
      }
    },
    {
      async close(err) {},
    }
  );
}

Analizziamo insieme questo file.

Prima di tutto, viene utilizzato (come consigliato dalla documentazione di Pino.js) il pacchetto npm pino-abstract-transport, che ci permette di ricevere i log uno alla volta e di elaborarli indipendentemente in un Thread a parte.

Il file controlla inoltre che vengano forniti in input i seguenti parametri:

  • URL: L’url di loki dove andare ad inviare i nostri log, nel formato https://api_key:your-api-key-here@hostname/loki/api/v1/push
  • LABELS.JOB: Una label che identifica univocamente la nostra applicazione (e.g. user-greeter-service)

Nel caso in cui uno di questi parametri fosse omesso, verrebbe generata un eccezione e la nostra applicazione non si avvierebbe.

Dopo aver controllato che i parametri richiesti siano stati inseriti, viene generato un payload così formato (reference):

{
  streams: [
    {
      stream: {
        ...labels,
      },
      values: [[unixEpochInNanoseconds.toString(), JSON.stringify(obj)]],
    },
  ];
}

E attraverso una chiamata POST viene inviato al nostro endpoint di LOKI, nel caso in cui ci fosse un errore per quello specifico log verrebbe stampato sulla stdout con un console.error.

Andiamo ora a modificare la nostra applicazione base per usare questo transport.

// Questa linea di codice va cambiata
const fastify = require('fastify')({ logger: true })

// ------------------------

import dotenv from "dotenv";
dotenv.config();

// In questo!
const fastify = fastify({
  logger: {
    transport: {
      targets: [
        {
          target: "./transport.mjs",
          options: {
            url: process.env.LOKI_API_URL,
            labels: {
              job: process.env.JOB_NAME,
            },
          },
        },
        {
          target: "pino-pretty",
        },
      ],
    }
  },
});

E questo è quanto per il nostro server Fastify!

Andiamo quindi a creare un file .env e forniamo le variabili LOKI_API_URL e JOB_NAME e avviamo l’applicazione.

Apriamo quindi la homepage del nostro cockpit e, dopo aver importato la dasboard qui riportata potremo vedere i log inviati!

Aggiungo inoltre che per ottenere il parsing dei log in formato JSON bisogna inoltre modificare il target dei log nella configurazione della dashboard e cambiare logfmt in json

E questo è quanto!

Grazie e alla prossima!


Reference:

Leave a Reply

Your email address will not be published. Required fields are marked *