Estirando algunos músculos técnicos.
Los tiempos ociosos en los que intento hacer algo relacionado con la tecnología se vuelven cada vez más escasos con el paso del tiempo. Antes lamentaba esto pensando que me estaba estancando en cuanto a habilidades. Me llevó bastante tiempo y muchos intercambios con gente interesante darme cuenta de que lo que realmente había pasado es que me moví en una dirección profesional que ahora me permite hacer las cosas que me gustan en mi trabajo, dejando algo de espacio para la vida personal, algo muy importante y cada vez más ignorado en la gente de tecnología. De todos modos, de vez en cuando todavía me doy el gusto de juguetear con la tecnología como hobby, y este fue uno de esos casos.
Un poco de contexto
Vivo en Argentina, actualmente tenemos una plataforma de e-commerce dominante que intenta cubrir el espacio que tanto e-bay como amazon ocupan en otras partes; se llama Mercado Libre. Entre sus servicios tiene una publicación gratuita de artículos para vender, que queda selectivamente relegada frente a otros artículos en venta que pagaron por una publicación más premium (esto es, por supuesto, completamente justo), pero hay una condición bastante nueva del servicio que no me gusta: obligan a usar su procesador de pagos, llamado Mercado Pago. Tuve experiencias pasadas bastante desagradables con él (me hicieron perder mucha plata hace algunos años) y las reseñas de su mediación de resolución de conflictos no han mejorado con los años. Con este problema en mente, decidí que prefería publicar el artículo en mi propio blog, que es un sitio estático hecho con hugo. Quería que la gente pudiera contactarme con consultas y tal vez enviarme ofertas, pero definitivamente no tenía ganas de hacerlos loguearse en disqus para esto, así que acá va mi solución.
Aprovechando la infraestructura existente.
Mi regla para esto es: tiene que ser corto. Lo hice una tarde después del trabajo. No tiene que requerir servicios nuevos en mi servidor, no quería agregarle más trabajo al yo del futuro. No tiene que sumar nuevos vectores de ataque a mi servidor, lo último que necesito es otra cosa de la que preocuparme.
Resulta que ya tengo una línea de comunicación con quienes visitan mi sitio, se llama el access.log (sí, ya sabés hacia dónde va esto). Mi servidor web actual (nginx) soporta access.log por ruta y formato personalizado para cada una.
Recuperando los “mensajes de los usuarios”
Lo primero que necesitaba era una forma fácil de recorrer mis logs para una ruta en particular; digamos que elegí /getmessages.
Un formato razonable para los logs
Iba a necesitar que mis logs estuvieran estructurados para esto, no tengo ganas de escribir invocaciones a cthulu en regexp solo para obtener el mensaje, así que tomé una muestra de este blog y elegí un formato que sería útil para logstash (lo que es bueno para ellos, es bueno para mí)
log_format logstash_json '{ "@timestamp": "$time_iso8601", '
'"@fields": { '
'"remote_addr": "$remote_addr", '
'"remote_user": "$remote_user", '
'"body_bytes_sent": "$body_bytes_sent", '
'"request_time": "$request_time", '
'"status": "$status", '
'"request": "$request", '
'"request_method": "$request_method", '
'"http_referrer": "$http_referer", '
'"http_user_agent": "$http_user_agent" } }';
La salida de esto se ve más o menos así:
{
"@timestamp": "2018-02-01T18:23:48+00:00",
"@fields": {
"remote_addr": "xxx.xxx.xxx.xxx",
"remote_user": "-",
"body_bytes_sent": "220",
"request_time": "0.000",
"status": "404",
"request": "GET /getmessages/hello HTTP/2.0",
"request_method": "GET",
"http_referrer": "-",
"http_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:58.0) Gecko/20100101 Firefox/58.0"
}
}
Parece bastante cómodo, podría prescindir de las particularidades del formato, pero como dije, cuanto menos trabaje en las partes aburridas de esto, mejor, ya que fue una ocurrencia rápida.
Ahora solo hace falta configurar algunas cosas personalizadas en nginx, como el access log para esa ruta en particular y un 404 personalizado que muestre un agradecimiento por el mensaje para evitar confusiones (podrías ponerte más creativo con algo de javascript y tal vez reglas de redirect, supongo, pero esto era solo para jugar).
ACLARACIÓN la página 404 personalizada está impidiendo que se registren los logs, así que estoy tratando de determinar qué está pasando.
[...]
location /getmessage {
access_log /var/log/nginx/your_access.json logstash_json;
error_page 404 /messages404.html;
}
[...]
Definiendo convenciones.
Aunque cualquier cosa que pasara por ahí sería o un mensaje o spam, necesitaba decidir cómo saber qué mensaje era para qué.
Me decidí por /getmessage/<topic_code>?<messagefields>, así la url contendría un código de tema, una cadena arbitraria que me diría de qué post/tema se trataba, y los campos de los mensajes serían simplemente formularios codificados con GET; esto da flexibilidad en cuanto a los datos enviados y uniformidad para poder filtrar los temas que no me interesan.
Parseando y visualizando los logs.
Para esto creé un pequeño binario en go que corro con un cron todas las noches; se puede encontrar al final.
Entre bambalinas
Tengo algunas protecciones extra para evitar el spam y otras intenciones maliciosas.
Lectura.
Esto es un buzón de correo, simplemente uso mutt.
Dejá un comentario :p
<form action="/messaging/blogpost-greetings" method="GET">
<div>
<label for="name">Name:</label>
<input type="text" name="name" id="name"> </input>
</div>
<div>
<label for="email">Email:</label>
<input type="email" name="email" id="email"> </input>
</div>
<div>
<label for="message">Message:</label>
<textarea type="textarea" name="message" id="message"> </textarea>
</div>
<div class="button">
<button type="submit">Talk to the nginx</button>
</div>
</form>