Rusty Full Stack

El blog para los amantes de Rust, Ionic y Vuejs

Jaime Blandón
Jaime Blandón Desarrollador de software desde 2009, entusiasta de Rust, Vuejs y Ionic!. Fundador de este blog, espero que las publicaciones te sean de utilidad y si tienes comentarios para mejorar, son bienvenidos.

Logs Con Rust

En este artículo vamos a aprender a crear logs con Rust ya sea imprimiéndolos en pantalla, o enviándolos a algún archivo, también vamos a hablar un poco sobre los diferentes niveles de logs que puede tener nuestra aplicación y cómo se configuran.

Antes que nada debemos preguntarnos qué son los logs y para que sirven en una aplicación.

¿Qué son logs?

Los logs son trazas o mensajes que nuestra aplicación puede generar y que nos ayuda a poder rastrear que es lo que está sucediendo, si ha existido algún error nos ayudan a identificar el punto donde se originó al igual que el momento en el tiempo que se ha originado. También nos puede servir para saber si nuestra aplicación está funcionando de manera normal o si existe alguna anomalía distinta a un error, pero que nos debe llamar la atención y analizarlo.

Leyendo lo anterior, podríamos preguntarnos el por qué crear logs cuando simplemente podemos hacer println! e imprimir lo que está ocurriendo. La verdad que aunque los prints en pantalla ya son de utilidad, por si mismos no nos pueden alertar del momento en el tiempo que ha ocurrido algo o el nivel de impacto en nuestra aplicación, algo que con los logs es bastante natural.

¿Cuál es la estructura de los logs?

Los logs pueden tener cualquier estructura, tú puedes decidir como mostrarlos, una estructura que a mi me gusta mucho y es bastante utilizada es la siguiente:

[fecha y hora, nivel del log, ubicación] mensaje

Por ejemplo:

[2023-05-03 16:51:27 INFO main] Hola soy un info

En donde:

2023-05-03 16:51:27, es la fecha

INFO, es el nivel de log

main, es la ubicación (o archivo)

Hola soy un info, es el mensaje

¿Dónde debemos mostrar los logs?

Esto también depende de tu caso de uso o como tu lo quieras configurar, los logs pueden mostrarse en pantalla, enviarlos a un archivo, enviarlos a algun tipo de storage externo como una base de datos, aunque esto último no es muy recomendado porque puede presentarse problemas de rendimiento o que la BD falle y nos quedemos sin logs!

Lo más común es simplemente mostrarlos "en pantalla" en nuestra terminal, aunque lo en verdad ocurre es que estaremos utilizando ya sea el stdout o el stderr, los cuales nos hacen ver los mensajes en pantalla en una terminal por ejemplo.

Para el caso no Rust, no es muy diferente, podemos hacer uso ya sea de los streams stdout, stderr o los podemos enviar a algún archivo, en este artículo aprenderemos ambas formas 😎

¿Cómo creamos logs con Rust?

Existe un crate llamado log el cual es utilizado para crear logs, veamos como crearlos con un ejemplo 😊

Empecemos creando un nuevo proyecto utilizando cargo, en una carpeta de tu preferencia ejecuta el siguiente comando:

cargo new crear_logs_con_rust

Ahora nos movemos al proyecto

cd crear_logs_con_rust

Puedes ver el código completo del ejemplo desde el repositorio en github dando click acá.

Ahora vamos a agregar el crate de log, esto puedes hacerlo directamente en el archivo Cargo.toml o utilizando cargo-edit. Si no sabes que es cargo edit puedes leer este artículo, te lo recomiendo 😉

En este caso lo haremos directamente en el archivo Cargo.toml para que veas como queda.

        
        
            // Cargo.toml

[package]
name = "crear_logs_con_rust"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
log = "0.4.17"

        
        
    

Ahora con nuestra dependencia creada, vamos a abrir nuestro archivo src/main.rs e intentar crear algunos logs, para ello, es importante comentar sobre los niveles de los logs.

Los logs, en cualquier lenguaje de programación pueden tener los siguientes logs, ordenados en orden de prioridad (los que debes atender primero):

  • Error: Cuando existe un error
  • Warning: Describen anomalías que no necesariamente son errores
  • Info: Para dar algún tipo de información útil como si la aplicación se ha conectado a la base de datos o alguna que creas conveniente
  • Debug: Sirve para cuando quieres enviar mensajes solo en modo debug.
  • Trace: Es el de más bajo nivel de prioridad y puede utilizarse para mensajes que ayuden a verificar por ejemplo el valor de alguna variable

El crate log, cuenta con una macro para cada tipo de log level:

  • Error: el macro es error!
  • Warning: el macro es warn!
  • Info: el macro es info!
  • Debug: el macro es debug!
  • Trace: el macro es trace!

Abramos nuestro archivo src/main.rs y coloquemos un ejemplo de cada nivel de log! 😌

        
        
            //src/main.rs

use log::{debug, error, info, trace, warn};

fn main() {
    error!("Este es un error");

    warn!("Hola soy un warning!");

    info!("Yo soy un info");

    debug!("Mensaje de debug");

    trace!("El de prioridad bajita");
}

        
        
    

En el código anterior la línea:

use log::{debug, error, info, trace, warn};

indica que queremos hacer uso de todos los niveles de log, también pudimos hacer use log::*, pero por motivos didácticos los colocamos todos.

luego en la función main, estamos haciendo uso de cada uno de los niveles de log por lo que deberíamos esperar muestre en nuestra terminal los niveles de log que hemos descrito, hagamos una prueba para verificar que ocurre si corremos nuestro programa. En tu terminal ejecuta el comando:

cargo run

Si todo sale bien, veremos el siguiente mensaje:

Pero, ¿dónde están los mensajes de logs? parece que nuestro programa no los muestra en pantalla 😵‍💫

No te preocupes, algo que no te había comentado es que el crate log es únicamente un crate que provee una abstracción de los logs, es decir, que debemos implementarlos y configurarlos, esto podría sonar complicado, pero lo cierto es que ya existen muchas implementaciones de las cuales podemos echar mano.

En la documentación oficial del crate log ya nos presentan algunas sugerencias, desde aquellas implementaciones más sencillas y que simplemente echamos mano, a algunos frameworks que nos permitirán hacer acciones o configuraciones más específicas.

Nuevamente podrías pensar que crear logs con Rust es complicado, pero simplemente agreguemos una de las implementaciones a nuestro archivo Cargo.toml y verás que es mucho más simple.

Puedes escoger el minimal logger que te parezca, pero el que me gustaría recomendarte es env_logger, el motivo es porque a parte de generar los logs, puedes controlar una configuración o filtrado mínimo utilizando variables de entorno.

Agreguemos env_logger a nuestro archivo Cargo.toml:

        
        
            // Cargo.toml

[package]
name = "crear_logs_con_rust"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
env_logger = "0.10.0"
log = "0.4.17"

        
        
    

Ahora con la nueva dependencia, modifiquemos nuestro archivo src/main.rs para indicar que queremos utilizar la implementación de env_logger:

        
        
            // src/main.rs

use log::{debug, error, info, trace, warn};

fn main() {
    env_logger::init();

    error!("Este es un error");

    warn!("Hola soy un warning!");

    info!("Yo soy un info");

    debug!("Mensaje de debug");

    trace!("El de prioridad bajita");
}

        
        
    

la línea dentro de la función main:

env_logger::init();

Es la encargada de realizar toda la implementación de los logs por nosotros 🥳

Volvamos a ejecutar nuestro programa, pero vamos a pasarle la variable de entorno RUST_LOG y vamos a decirle a través de esa variable de entorno que queremos mostrar todos los mensajes de log de nuestro programa, para ello debemos asignarle el nombre de nuestro proyecto y ejecutar en tu terminal el siguiente comando:

RUST_LOG=crear_logs_con_rust cargo run

Ahora debemos ver que en nuestra terminal se imprimen nuestros mensajes 🥹

Como puedes ver, sin hacer mayores esfuerzos, env_logger ha agregado por nosotros un formato a nuestros logs, que por coincidencia es el mismo que hablamos en la sección de ¿Cuál es la estructura de los logs? un poco más arriba 😋

Si somos observadores, vamos a notar que la fecha y hora la colocará en el timezone UTC, por el momento lo vamos a dejar así y luego lo vamos a cambiar por nuestra propia zona horaria.

También, otra cosa a observar es que todos los logs se encuentran en src/main.rs por lo que la ubicación donde están ocurriendo los mensajes, env_logger los coloca como crear_logs_con_rust, pero ¿que pasaría si hemos creado módulos?

Hagamos la prueba de agregar un módulo y ver como cambian los mensajes de log. Si quires conocer más a detalle como se manejan los módulos en Rust, puedes referirte a nuestro propio artículo acá.

empecemos creando dentro de la carpeta src una nueva carpeta y le ponemos por nombre mi_modulo, dentro del folder mi_modulo, creemos un archivo al que llamaremos mensajes.rs y colocamos el siguiente código:

        
        
            // src/mi_modulo/mensajes.rs

use log::info;

pub fn info_desde_un_modulo() {
    info!("Soy un mensaje desde un modulo");
}

        
        
    

Únicamente estamos creando una función que deberá de crear un log de nivel INFO para que veamos que ocurre, recuerda que para que nuestro módulo sea encontrado por nuestro archivo src/main. rs debemos crear un archivo mod.rs dentro de la carpeta src/mi_modulo y colocamos mensajes.rs como un módulo público.

        
        
            // src/mi_modulo/mod.rs

pub mod mensajes;
        
        
    

Ahora creemos dentro de la carpeta src un archivo lib.rs y colocamos el siguiente código.

        
        
            // src/lib.rs

mod mi_modulo;

use mi_modulo::mensajes::info_desde_un_modulo;

pub fn mostrar_un_info() {
    info_desde_un_modulo();
}

        
        
    

En el código anterior simplemente estamos creando una librería con una única función que invocará el info_desde_un_modulo que creamos anteriormente, ahora modifiquemos nuestro archivo src/main.rs para colocar el nuevo mensaje al final de nuestra función main.

        
        
            // src/main.rs

use crear_logs_con_rust::mostrar_un_info;
use log::{debug, error, info, trace, warn};

fn main() {
    env_logger::init();

    error!("Este es un error");

    warn!("Hola soy un warning!");

    info!("Yo soy un info");

    debug!("Mensaje de debug");

    trace!("El de prioridad bajita");

    mostrar_un_info();
}

        
        
    

Ahora volvamos a ejecutar nuestro programa, recuerda que para mostrar todos los logs del programa debemos pasar la variable RUST_LOG con el nombre de nuestro proyecto de la siguiente manera:

RUST_LOG=crear_logs_con_rust cargo run

Si todo sale bien, veremos el siguiente resultado:

Si miras la última línea de log, verás que justamente imprimió un mensaje de nivel INFO, pero la ubicación es desde nuestro módulo, lo cual nos facilita identificar el archivo donde están ocurriendo los eventos 😃

Puedes ver el código completo del ejemplo desde el repositorio en github dando click acá.

Filtrando logs con env_logger.

Algo de lo que no hemos hablado mucho es sobre la variable de entorno RUST_LOG, hasta el momento solamente le hemos asignado como valor el nombre de nuestro proyecto para que muestre todos los logs, pero podemos hacer más que ello, por ejemplo si queremos filtrar los mensajes de cierto módulo, podemos asignar la ubicación como valor, por ejemplo si queremos mostrar solo los logs del archivo mensajes.rs que creamos anteriormente, podemos ejecutar el siguiente comando:

        
        
            

RUST_LOG=crear_logs_con_rust::mi_modulo::mensajes cargo run
        
        
    

y veremos que únicamente muestra el mensaje que colocamos en el módulo:

También podemos filtrar por niveles de logs, env_logger nos permite especificar el nivel de log mínimo que queremos mostrar, por ejemplo si queremos imprimir solo los warning y error, podemos filtrar asi:

RUST_LOG=warn cargo run

y mostrará solo los warning y error

Si queremos imprimir desde los niveles de INFO a ERROR, podemos filtrar asi:

RUST_LOG=info cargo run

muestra desde info hasta error, sin mostrar debug y trace porque tienen un menor nivel de prioridad.

Guardando logs en un archivo con Rust.

Aunque las implementaciones simples de logs como env_logger ya es casi suficiente para trabajar o para lanzar algo a producción, hay algunas limitantes por si se nos presentan casos de usos para acciones más "complejas" como enviar log logs a un archivo de texto o utilizar nuestra hora local en lugar de UTC (aunque no es tan mala idea utilizar UTC) no son muy adecuados, por lo cual debemos utilizar frameworks de logs que nos permiten hacer configuraciones más adhoc a lo que buscamos.

En este caso vamos a utilizar el framework llamado fern, que nos ayudará a configurar el enviar los logs no únicamente a nuestra terminal, sino, también a un archivo de texto.

Aunque hoy en día existen muchas herramientas para monitorear los logs sin necesidad de archivos, pueda que sea un caso con el cual nos encontremos en nuestra carrera y no está demás el saber como se hace.

Para nuestro ejemplo creemos un proyecto nuevo, ejecutemos en nuestra terminal el comando en la carpeta de tu preferencia:

cargo new enviar_logs_a_archivos

Ahora nos movemos a la carpeta de nuestro proyecto:

cd enviar_logs_a_archivos

Puedes ver el código de este ejemplo en este repositorio en github.

Lo primero que vamos a hacer es agregar las dependencias que utilizaremos, en este caso fern y log, recuerda que puedes hacerlo directamente en el archivo Cargo.toml o con cargo-edit, pero también vamos a agregar un crate para mostrar la fecha y hora en la que pasa una acción, en este caso utilizaremos el crate llamado humantime. Tu archivo Cargo.toml debería verse así:

        
        
            // Cargo.toml

[package]
name = "enviar_logs_a_archivos"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
fern = "0.6.2"
humantime = "2.1.0"
log = "0.4.17"

        
        
    

Ahora vamos a abrir nuestro archivo src/main.rs y antes de modificar la función main, vamos a crear una función en la cual vamos a configurar la estructura de nuestros logs, puedes abrir src/main.rs y colocar el siguiente código:

        
        
            // src/main.rs

use log::{debug, error, info, trace, warn};
use std::time::SystemTime;

fn setup_logs() -> Result<(), fern::InitError> {
    fern::Dispatch::new()
        .format(|out, message, record| {
            // Aca definimos la estructura de nuestros logs
            // practicametne puedes hacerlo como creas conveniente.
            out.finish(format_args!(
                "[{} {} {}] {}", // Aca definimos la estructura de nuestro log, en este caso tendremos {hora y fecha} {nivel del log} {ubicacion} {mensaje}
                humantime::format_rfc3339_seconds(SystemTime::now()), // Este es el primer argumento, la hora local
                record.level(), // El segundo element de la estructura de los logs es el nivel
                record.target(), // El tercer elemento es la ubicacion
                message         // por ultimo agregamos el mensaje
            ))
        })
        .level(log::LevelFilter::Trace) // Definimos que el nivel minimo de logs que queremos registrar es Trace
        .chain(std::io::stdout()) // Aca indicamos que queremos que los logs se muestren en la terminal mediante el stdout
        .chain(fern::log_file("logs.log")?) // Aca tambien indicamos que queremos los mismos logs pero en un archivo llamado logs.log
        .apply()?;
    Ok(())
}

fn main() {
    println!("Hello, world!");
}

        
        
    

En el bloque anterior de código estamos definiendo una función que llamamos setup_logs, la cual servirá para configurar como queremos nuestros logs, aunque la función se ve grande y complicada, en realidad, es bastante sencilla de entender, puedes guiarte por los comentarios del código, pero acá está el desglose de como es que funciona:

este bloque de código:

        
        
            

.format(|out, message, record| {
            // Aca definimos la estructura de nuestros logs
            // practicametne puedes hacerlo como creas conveniente.
            out.finish(format_args!(
                "[{} {} {}] {}", // Aca definimos la estructura de nuestro log, en este caso tendremos {hora y fecha} {nivel del log} {ubicacion} {mensaje}
                humantime::format_rfc3339_seconds(SystemTime::now()), // Este es el primer argumento, la hora local
                record.level(), // El segundo element de la estructura de los logs es el nivel
                record.target(), // El tercer elemento es la ubicacion
                message         // por ultimo agregamos el mensaje
            ))
        })
        
        
    

Es el que sirve para definir los logs, como puedes ver no es más que macro format_args! y definir un string, en este caso "[{} {} {}] {}" donde cada {} no es más que un parámetro de lo que queremos mostrar, en las líneas siguientes vemos que hemos definido pasarle:

  1. Hora y fecha actual (lo colocamos en formato UTC)
  2. el nivel de log (ERROR, WARNING, INFO, etc)
  3. la ubicación donde ocurren las cosas.
  4. el mensaje de log

Luego esta línea:

.level(log::LevelFilter::Trace) sirve para indicar cual es el nivel de log mínimo que queremos mostrar, con Trace vamos a mostrar todos los niveles

.chain(std::io::stdout()) indica que queremos mostrar los mensajes de logs en el stream stdout, es decir, se verán reflejados en la consola.

.chain(fern::log_file("logs.log")?) indica que también queremos guardar los logs en un archivo con nombre logs.log, puedes cambiar el nombre si así lo deseas.

Antes de continuar con el ejemplo, vamos a incluir el mismo módulo del ejemplo anterior para que podamos ver como cambia la ubicación, recuerda que lo primero que hicimos fue crear un folder src/mi_modulo y dentro de ese módulo creamos dos archivos mod.rs y mensajes.rs con los siguientes códigos:

src/mi_modulo/mod.rs:

        
        
            // src/mi_modulo/mod.rs

pub mod mensajes;
        
        
    

src/mi_modulo/mensajes.rs:

        
        
            // src/mi_modulo/mensajes.rs

use log::info;

pub fn info_desde_un_modulo() {
    info!("Soy un mensaje desde un modulo");
}
        
        
    

Ahora creamos el archivo src/lib.rs en el cual colocamos el código para usar el módulo:

        
        
            // src/lib.rs

// src/lib.rs

mod mi_modulo;

use mi_modulo::mensajes::info_desde_un_modulo;

pub fn mostrar_un_info() {
    info_desde_un_modulo();
}
        
        
    

Por último vamos a modificar nuestro archivo src/main.rs para colocar los mensajes de logs, pero está vez, no vamos a inicializar nuestros logs utilizando env_logger como en los ejemplos anteriores, sino, nuestra propia función de configuración.

src/main.rs:

        
        
            // src/main.rs

 enviar_logs_a_archivos::mostrar_un_info;
use log::{debug, error, info, trace, warn};
use std::time::SystemTime;

fn setup_logs() -> Result<(), fern::InitError> {
    fern::Dispatch::new()
        .format(|out, message, record| {
            // Aca definimos la estructura de nuestros logs
            // practicametne puedes hacerlo como creas conveniente.
            out.finish(format_args!(
                "[{} {} {}] {}", // Aca definimos la estructura de nuestro log, en este caso tendremos {hora y fecha} {nivel del log} {ubicacion} {mensaje}
                humantime::format_rfc3339_seconds(SystemTime::now()), // Este es el primer argumento, la hora local
                record.level(), // El segundo element de la estructura de los logs es el nivel
                record.target(), // El tercer elemento es la ubicacion
                message         // por ultimo agregamos el mensaje
            ))
        })
        .level(log::LevelFilter::Trace) // Definimos que el nivel minimo de logs que queremos registrar es Trace
        .chain(std::io::stdout()) // Aca indicamos que queremos que los logs se muestren en la terminal mediante el stdout
        .chain(fern::log_file("logs.log")?) // Aca tambien indicamos que queremos los mismos logs pero en un archivo llamado logs.log
        .apply()?;
    Ok(())
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    setup_logs()?;

    error!("Este es un error");

    warn!("Hola soy un warning!");

    info!("Yo soy un info");

    debug!("Mensaje de debug");

    trace!("El de prioridad bajita");

    mostrar_un_info();

    Ok(())
}

        
        
    

algo importante a notar es que ahora la definición de la función main podemos regresar un resultado o un error:

fn main() -> Result<(), Box<dyn std::error::Error>>

el Box<dyn std::error::Error> podría reemplazarse perfectamente form fern::InitError, pero para dejarlo más general puse el Box, aunque lo ideal es que utilices tus propios tipos de errores (Si quieres saber como manejar errores en Rust deja tu comentario al final e este artículo 😎)

Ahora en lugar de usar env_logger::init() como lo hicimos anteriormente, estamos usando nuestra propia función de configuración:

setup_logs()?;

Si ahora corremos nuestro programa con el siguiente comando (observa que no es necesario pasar una variable de entorno RUST_LOG)

cargo run

Veremos que el resultado es prácticamente el mismo que en nuestro ejemplo anterior, pero esta vez nosotros hemos realizado la configuración:

Y otra cosa importante a notar es que en la carpeta de nuestro proyecto ha creado un archivo de nombre logs.log el cual podemos abrir y revisar!

Abriendo el archivo vemos que los logs también están ahí:

Usar nuestra hora local en logs con Rust.

En todos nuestros ejemplos hemos estado creando logs utilizando UTC, hoy en día es muy común que las fechas se manejen de esa forma porque es bastante simple convertirlo a las diferentes zonas horarias (si quieres que escriba un artículo sobre manejo de fechas en Rust deja tu comentario al final de este artículo 😉), pueda que tengamos algún caso en que queramos crear logs en nuestra hora local.

Una forma bastante sencilla de hacerlo es mediante el crate chrono, el cual nos facilita el manejo de fechas con Rust, en nuestro ejemplo anterior vamos a reemplazar humantime por chrono de la siguiente forma en nuestro archivo Cargo.toml:

        
        
            // Cargo.toml

[package]
name = "enviar_logs_a_archivos"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
chrono = "0.4.24"
fern = "0.6.2"
# humantime = "2.1.0"
log = "0.4.17"

        
        
    

Ahora vamos a modificar un poco la configuración de nuestros logs de la siguiente forma en src/main.rs:

        
        
            // src/main.rs

use enviar_logs_a_archivos::mostrar_un_info;
use log::{debug, error, info, trace, warn};
// use std::time::SystemTime;
use chrono::prelude::*;

fn setup_logs() -> Result<(), fern::InitError> {
    fern::Dispatch::new()
        .format(|out, message, record| {
            // Aca definimos la estructura de nuestros logs
            // practicametne puedes hacerlo como creas conveniente.
            out.finish(format_args!(
                "[{} {} {}] {}", // Aca definimos la estructura de nuestro log, en este caso tendremos {hora y fecha} {nivel del log} {ubicacion} {mensaje}
                // humantime::format_rfc3339_seconds(SystemTime::now()),
                Local::now().format("%Y-%m-%d %H:%M:%S").to_string(), // Este es el primer argumento, la hora local
                record.level(), // El segundo element de la estructura de los logs es el nivel
                record.target(), // El tercer elemento es la ubicacion
                message         // por ultimo agregamos el mensaje
            ))
        })
        .level(log::LevelFilter::Trace) // Definimos que el nivel minimo de logs que queremos registrar es Trace
        .chain(std::io::stdout()) // Aca indicamos que queremos que los logs se muestren en la terminal mediante el stdout
        .chain(fern::log_file("logs.log")?) // Aca tambien indicamos que queremos los mismos logs pero en un archivo llamado logs.log
        .apply()?;
    Ok(())
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    setup_logs()?;

    error!("Este es un error");

    warn!("Hola soy un warning!");

    info!("Yo soy un info");

    debug!("Mensaje de debug");

    trace!("El de prioridad bajita");

    mostrar_un_info();

    Ok(())
}

        
        
    

Como puedes ver solo hemos incluido un nuevo use:

use chrono::prelude::*;

y hemos reemplazado la línea de humantime por esta:

Local::now().format("%Y-%m-%d %H:%M:%S").to_string()

también, puedes utilizar Utc::now() en lugar de Local::now() si siempre quieres utilizar utc

Ahora si ejecutamos nuestro programa con:

cargo run

veremos que ahora los los los muestra con nuestra hora local en lugar de UTC

Hemos aprendido en este artículo como poder crear y configurar logs con Rust 🥳

Recuerda que puedes ver el código de este ejemplo en este repositorio en github.

Si te ha gustado este artículo o te ha sido de utilidad, compártelo con tus amigos y en tus redes sociales. No te olvides de seguirme en twitter!

Si quieres que escriba sobre algún tema sobre Rust déjame un comentario al final de este artículo o desde el formulario de contacto.

println!("hasta la próxima!");


 Utilizamos cookies propias y de terceros para mejorar tu experiencia, mostrar publicidad y análisis de navegación, puedes encontrar el detalle en nuestra Política de Cookies