Enviar métricas y logs a CloudWatch AWS usando AWS-SDK de JAVASCRIPT

Introducción

Con CloudWatch y el AWS-SDK para Javascript y nuestra creatividad podemos lograr cosas bien interesantes y dar solución a múltiples problemas de forma sencilla.

Usualmente cuando se trabaja con servicios y plataformas que se despliegan en instancias EC2 o incluso en instancias locales, es necesario tener ciertos KPIs (o métricas) sobre lo que se espera de dicho servicio o plataforma.

Por ejemplo uno podría esperar que una plataforma transaccional en un estado de buena salud tenga una cantidad X de transacciones pasando segundo, por ejemplo, 10 trx/s (diez transacciones por segundo).

Estos tipos de métricas son muy útiles y en la mayoría de los casos, necesarios, para áreas se soporte u operaciones, dado que con esas métricas pueden determinar si la plataforma tiene un comportamiento o rendimiento adecuado o en línea a lo esperado.

Gracias al SDK de AWS, disponible en Javascript, podemos enviar métricas y LOGs directamente a CloudWatch, con lo que eventualmente se puede contar con dashboard, alertas y acciones automáticas en base a los datos que enviemos. A continuación en Octasquare te mostraremos cómo hacerlo

Entrando al código

Supongamos que queremos enviar una métrica de transacciones por segundo (en este caso las simularemos). Lo primero seria tener alguna función que obtenga o cuente las transacciones que pasan por nuestra plataforma. Dado que el objeto de este articulo no es contar transacciones, simularemos con números aleatorios la cantidad de transacciones, para eso esta función:

const getRandomInt = (min, max) => {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1)) + min;
}
const getTrx = (min,max) => { //remplazar aquí por lo que sea adecuado en cada caso
    return getRandomInt(min,max);
}

Ahora necesitamos generar el objeto de AWS para enviar los datos a CloudWatch, aqui se deben llenar los datos con las credenciales de un usuario con los privilegios adecuados para enviar data a CloudWatch.

AWS.config.update({
    region: 'xxxxxx', // por ejemplo'us-east-1',
    accessKeyId: 'xxxxxxxx', // el access Key del usuario programático 
    secretAccessKey: 'xxxxxxxx' // la secret key del usuario programático 
});

ahora generación del objeto con la data a enviar

// usamos una version fija del a API, para evitar problema de compatibilidad
var cw = new AWS.CloudWatch({ apiVersion: '2010-08-01' });
// creamos el JSON que tendrá la data 
const paramsCW = {
    MetricData: [
        {
            MetricName: 'TRX_PER_SECOND', // nombre: Transacciones por segundo
            Dimensions: [
                {
                    Name: 'TRX', // un nombre de dimension
                    Value: 'Plataforma A' // supongamos las trx/s de Plataforma A
                },
            ],
            Unit: 'Seconds', // en este caso, segundos, dado que medimos trx/s
            Value: getTrx(1, 100) // obtenemos un valor aleatorio entre 1 y 100 
        },
    ],
    Namespace: 'MIS_METRICAS' // un namespace que haga sentido
};

Finalmente el envío de la data, imprimimos en consola los resultados.

cw.putMetricData(paramsCW, function (err, data) {
    if (err) {
        console.log("Error", err);
    } else {
        console.log("Success", JSON.stringify(data));
    }
});

Y eso es todo, ahora si quisieramos enviar “LOGS” el proceso es similar, solo que la clase a utilizar es otra. Ej;

var cloudwatchlogs = new AWS.CloudWatchLogs({ apiVersion: '2014-03-28' });

let paramsPutLog = {
    logEvents: [ /* required */
        {
            message: '[Note] trx 1 df 2 rt 4 hh 5', // este es mi log
            timestamp: Date.now() // required, el timestamp, AWS lo necesita
        },
    ],
    logGroupName: 'testgroup', // un grupo para el log
    logStreamName: 'teststream', /un nombre del stream, deben existir ambos previamente
    //sequenceToken: ''
};
const paramsGetSeq = {
    logGroupName: 'testgroup', /* required */
    logStreamNamePrefix: 'teststream'
};

// envío el dato, pero validando si hay o no data previa,
// de existir data previa obtengo el ultimo sequence token. 
cloudwatchlogs.describeLogStreams(paramsGetSeq, function (err, data) {
    if (err) console.log(err, err.stack); // an error occurred
    else { // successful response
        if (data.logStreams[0].uploadSequenceToken) {
            paramsPutLog.sequenceToken = data.logStreams[0].uploadSequenceToken;
        }
        cloudwatchlogs.putLogEvents(paramsPutLog, function (err, data) {
            if (err) console.log(err, err.stack); // an error occurred
            else console.log("putlog", data);           // successful response
        });
    }
});

Resultados para cada caso:

cloudwatch metrics sample
cloudwatch logs sample

Leave a Reply