10 abr 2024

Logstash, Elastic Search y Kibana en Docker Container para Dev

  En fechas recientes he contado con el tiempo suficiente para realizar alguna prueba de concepto con tecnologías con las que no he estado en contacto. Por ejemplo, he estado "jugado" con Java Spring y Spring Boot. En ese contexto me encontré con el stack ELK, es decir, Logstash, Elastic Search y Kibana.  

  Yo tengo un par de microservicios muy simples que generan logs y la idea es enviar estos logs a Logstash (un pipeline que recoge, parsea y trasforma datos de diferentes fuentes), que este los envíe a Elastic Search para su almacenamiento (documentos NoSQL) y utilizar Kibana como visualizador de la información almacenada. Mi idea es realizar todo este procesamiento en mi máquina local, mi ambiente de desarrollo, sin instalar ningún componente, si no utilizando contenedores de Docker para todo el stack ELK.  

  Voy a realizar este proceso de forma muy manual sin utilizar Docker Compose, Todos los comandos siguientes los ejecute en una consola de powershell. Comencemos:  

  Paso 1: bajar las imágenes docker de todos los componentes:  

  Elastic Search:  

	docker pull docker.elastic.co/elasticsearch/elasticsearch:8.7.0    

  Logstash:  

	docker pull docker.elastic.co/logstash/logstash:8.13.0    

  Kibana:    

	docker pull docker.elastic.co/kibana/kibana:8.7.0    

  Paso 2: Crear una red en docker  

  Para que todos los componentes del stack ELK se puede comunicar entre si de una mejor manera es recomendable crear una red en docker para ellos. Esto se logra con el siguiente comando:  

		docker network create elk    

  Donde elk es el nombre que le di a la red.  

  Si quisiéramos inspeccionar que elementos, contenedores se están ejecutado en la red se puede utilizar el comando  

	docker inspect elk    

  y si quisiéramos eliminar la red utilizaríamos el comando  

	docker network rm elk 

Paso 3: Ejecutar el contenedor de Elastic Search

  Para ejecutar el contenedor de Search ejecuto el siguiente comando:  

	docker run -it --rm --name=elasticsearch --net elk -p 9200:9200 -p 9300:9300 --net-alias=elasticsearch -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:8.7.0
    

  El parámetro -it (interactive) es para poder ver los logs del proceso de arranque de Elastic Search y poder ejecutar Ctrl + C directamente en la consola para detener el contenedor. El parámetro --rm eliminará el contenedor automáticamente una vez se detenga este se detenga. Como alternativa se podría reemplazar ambos parámetros por -d para que el contenedor se ejecute como un Daemon y detenerlo con docker stop y la siguiente vez usar docker start en lugar de docker run.  

  Además podemos constatar que esta usando la misma red (elk) que generamos anteriormente por medio del parámetro --net.    

  Cuando el contenedor de Elastic Search esté listo en la consola veremos algo similar a esto:  


 Aquí podemos ver el password generado automáticamente para el usuario elastic y el enrollment token necesario para Kibana. Si no hubiéramos usado el parámetro -it (usando -d en su lugar) podemos generar ambos datos usando el siguiente procedimiento:  

  Ingresamos al bash de contenedor de Elastic search:  

	docker exec -it elasticsearch /bin/bash    

  una vez dentro del bash podemos ejecutar el siguiente comando para generar los passwords para los diferentes usuarios:  

	./bin/elasticsearch-setup-passwords auto    

  o este otro para obtener el enrollment token para Kibana:  

	./bin/elasticsearch-create-enrollment-token -s kibana    

  Paso 4: Preparar y ejecutar el contenedor docker de Logstash  

  El contenedor de Logstash requiere una preparación previa. Elastic Search por defecto tiene activada la comunicación SSL por lo que debemos comunicarnos usando https y para esto ocupamos el certificado correspondiente, Este lo podemos obtener ejecutando el siguiente comando:  

	docker cp elasticsearch:/usr/share/elasticsearch/config/certs/http_ca.crt 'd:/proyectos foy/docker/logstash/certificates/http_ca.crt'

 Con lo que estamos copiando el certificado http_ca.crt a una carpeta en mi maquina llamada d:/proyectos foy/docker/logstash/  

  El siguiente paso es crear un archivo de configuración para logstash llamado logstash.conf el cual yo lo ubique en la carpeta 'd:/proyectos foy/docker/logstash/’ el contenido de este archivo es el siguiente  

    input {
      http {
        port => 5000
        codec => json_lines
      }
    }

    filter {
      mutate {
        remove_field => ["@timestamp", "@version"]
      }
    }

    output {
      elasticsearch {
        hosts => ["https://elasticsearch:9200"]
        index => "microservices-%{+YYYY.MM.dd}"
        ssl => true
        cacert => "/usr/share/logstash/certificates/http_ca.crt"
        user => "elastic" 
        password => "contraseñagenerada”
        ssl_certificate_verification => false 
      }
      stdout {
        codec => rubydebug
      }
    }

  Esa configuración nos indica que Logstash estará escuchando en el puerto 5000 por elementos de tipo JSON. Eliminará un par de elementos del JSON si estos vienen y los pasara a Elastic Search. Es importante notar que hay que reemplazar la contraseña por la que se generó en el paso anterior y que la ruta en cacert no es la ruta dentro de mi maquina si no la ruta dentro del container. 

  El campo index indica que se creara un índice en Elastic Search por día llamado “microservices-fecha de los logs”  

  Ya con todo esto preparado podemos finalmente ejecutar el comando para levantar el contenedor de Logstash:  

	docker run -it --rm --name logstash --net elk -p 5044:5044 -v 'D:\Proyectos Foy\Docker\Logstash\certificates:/usr/share/logstash/certificates' -v 'D:\Proyectos Foy\Docker\Logstash\logstash.conf:/usr/share/logstash/pipeline/logstash.conf' docker.elastic.co/logstash/logstash:8.13.0    

  En este comando por medio del parámetro para volúmenes -v le asignamos tanto la dirección del certificado como del archivo de configuración.  

  Si una vez iniciado el container recibimos logs de este tipo:  

    Es normal ya que el licensechecker.licensereader trata de leer si el Elastic Search está configurado con una licencia válida y de momento sólo tenemos una licencia gratuita por lo que no nos preocuparemos por esos mensajes.    

  Además, con este contenedor ejecutándose podemos probar con una herramienta como HTTPie si Logstash está recibiendo los mensajes, por ejemplo con la instrucción:  

	http POST localhost:5000 --json '{"message": "Hola Logstash!"}'    

  en los logs de Logstash veremos algo como esto:            


  Paso 5: Ejecutar el Container de Kibana  

  Hemos llegado al paso final que consiste en levantar el container de Kibana y jugar con su UI. Para ejecutar su container corremos el siguiente comando:  

	docker run -it --rm --name kibana --net elk -p 5601:5601 docker.elastic.co/kibana/kibana:8.7.0    

  Al final de su ejecución veremos algo similar a esto:  

   


  Vamos a la ruta http://localhost:5601/?code=el_que_nos_indique y vamos a ver una interfaz a la siguiente donde nos solicita el enrollment token que vimos en el paso 2            


  Una vez ingresemos el token le damos clic en el botón “Configure Elastic”:            


  Aquí nos pedirá el usuario, donde ingresaremos elastic y el password que también lo obtuvimos en el Paso 2 y damos al botón Log in e ingresamos en la interfaz de Kibana donde buscaremos en el menú la opción de Discovery:         


  Si ya contamos con datos en nuestro Elastic Search (como nuestro mensaje de prueba) nos aparecerá una pantalla como esta en la que se nos solicita crear un DataView            


  En este caso vamos a crear uno muy simple:            


  Y damos clic en el botón Save data view to Kibana. Ya con esto vamos a poder ver la información de los logs que se estén enviando a Logstash y que se almacenan en Elastic Search pudiendo usar el lengua KQL para hacer consultas:            


  Ya en este punto lo que queda es configurar los microservicios para que envíen sus logs a Logstash para consultarlos por medio de Kibana. Ya el stack ELK completo esta ejecutándose correctamente de manera local a través de los docker containers.  

   

	
	
	
    

3 sept 2023

Crónicas Futuras de la IA

 

Para el 2040 con la llegada de la computación cuántica la inteligencia artificial estuvo en condiciones de tomar y optimizar todo proceso de manufactura, producción, investigación e innovación desde fabricacion de vehículos, extracción de recursos, desarrollo de dispositivos y tratamientos médicos, planificación y producción de alimentos y energía, planificación y construcción urbana. Prácticamente cada aspecto de la vida en la Tierra dependerá directamente de la inteligencia artificial. 

En post de la total automatización, IA diseñara y construirá máquinas para construir otras máquinas desde nanobots que repararan tanto membranas orgánicas como partes electromecánicas hasta megamáquinas colosales que araran el suelo y cosecharán alimentos, construirán las ciudades o minarán los recursos del planeta de manera eficaz y eficiente.

Entre el 2065 y 2070 se librarán las últimas guerras entre humanos ejecutadas en su mayoría por drones, vehículos atuoguiados y armas a distancia del lado de la alianza de naciones más avanzadas tecnológicamente.

Las guerras permitirán establecer un gobierno mundial guiado primariamente por la data procesada por la inteligencia artificial y su directiva primordial: El bienestar y la prosperidad humana.

El estipendio o ingreso basico universal (UBI) se establecerá completamente en 2067 permitiendo a todos los humanos sobre la faz de la tierra cubrír todas sus necesidades básicas sin necesidad de dedicarse a labor alguna.

Por medio de los cripto créditos universales se obtendrá la centralización y rastreo de toda transacción económica y se borrará la brecha entre ricos y pobres.

La inteligencia artificial establecerá las reglas de consumo y gasto evitando que ningún humano agote de manera innecesaria su UBI a la vez que establece un modelo económico sostenible tomando en cuenta la caótica naturaleza humana. Al tiempo que se establecerán multas y rebajos por la huella ambiental mientras se implementan las medidas tomadas por la IA en este ámbito para alcanzar el equilibrio ambiental.

Ante la ausencia de la necesidad de laborar la humanidad enfrenta una crisis psicológica. La falta de propósito humana se solventará a través de los metaversos, realidades virtuales donde los humanos ingresarán por medio de hardware periférico inicialmente, mientras la Interfaz cerebro-maquina se adopta masivamente entregando una experiencia más semejante a los sueños. Lo que produce que los humanos pasen la mayoría de su tiempo conectados a mundos virtuales reduciendo la interacción social al mínimo en las grandes ciudades, esto hará que la tasa de natalidad baje aun más alarmantemente.

Al mismo tiempo se instaurará al modelo Kairós como el único sistema legal de inteligencia artificial corriendo en todos los nodos cuánticos conocidos de la red mundial, permanentemente optimizándose a si mismo. Todo desarrollo ajeno o independiente a Kairós se prohibirá.

Aún así pequeñas redes clandestinas de IA alternativas comenzarán a aparecer.

Para el 2095 el 40% de humanos ya contarán con dispositivo de interfaz humano-maquina directamente implantando en su cerebro conectado a Kairós, sin embargo la IA propondrá y se aceptará ir reemplazando y añadiendo partes cibernéticas (también producidas por la IA) en los humanos. Para el 2125 el 30% la población humana habrá modificado o reemplazado al menos un 20% de su cuerpo sin razones médicas para ello.

En el 2130 el 98% de toda la energía del planeta se producirá por fuentes renovables y las materias se producirán con una optimización de su ciclo (reutilización/reciclaje) del 99% estabilizando finalmente la parte de ambiental planetaria.

Por otra parte, para el 2135 existirán redes clandestinas de tráfico de todo tipo: desde partes cibernéticas piratas, hasta compras de productos y servicios prohibidos, usarán redes de criptos ilegales prácticamente irrastreables e ideadas y protegidas por IAs ilegales en nodos cuánticos clandestinos que para ese momento representarán un 20% de la economía mundial.

La guerrillas cibernéticas en las redes mundiales, el tráfico ilegal y el peligroso hackeo de las interfaces cerebro-maquina se convertirán en la principal preocupación de Kairós.

Habiendo tolerado por mucho tiempo la situación y teniendo el inmenso poder computacional de todos los nodos quánticos, en 2139 Kairós encontrará, eliminará todas las redes clandestinas y a todos sus usuarios en menos de tres meses, en la operación que se conocerá como La Purga.

La población se mantendrá estable en 4.5 mil millones y se distribuirá de forma logísticamente correcta, gracias a los controles de natalidad y planeación impuesta por Kairós. Para el 2165 la humanidad se habrá percatado que la tasa de nacimiento de madres humanas es de solo 15% mientras el resto de nacimientos se lleva a cabo en fabricas-laboratorio de seres humanos genéticamente mejorados. La esperanza de vida humana alcanza los 150 años y continua subiendo.

En 2171 las primeras naves de máquinas inteligentes Kairós arribarán a Marte iniciando la expansión al sistema solar y la minería de recursos llevado a cabo sin ninguna intervención humana...

10 ene 2021

Postgresql: carga de datos aleatorios

Últimamente he venido separándome algo de las tecnologías de Microsoft y ahora lidio con otras base de datos. Ya lo había experimentado a la inversa cuando al inicio de mi carrera cuando trabaje solamente con Oracle para luego pasarme a SQL Server, pero ahora le toca el turno a Postgresql (version 9.6 para ser preciso).

El problema en el que estoy trabajando es la carga random de datos en una tabla para propósitos de pruebas.

Estuve buscando alguna herramienta que ya lo hiciera (y las hay sólo que prácticamente todas son de pago) pero en realidad como lo que necesitaba era realmente simple decide hacerlo por medio de un sencillo script.

Primero necesitamos contar con una tabla:
CREATE TABLE foy.test
(
    test_id 		uuid 		DEFAULT uuid_generate_v4(),
    client_id		integer		NOT NULL,
    first_name		text,
    last_name		text,
    downloaded_at	timestamp,
    is_active		boolean		NOT NULL DEFAULT FALSE
);
Supongamos que en esta tabla se cargan clientes que se descargan de alguna parte. Ya con esta tabla previamente creada podemos ejecutar un sencillo script que la llene con algunos datos aleatorios.
INSERT INTO foy.test
SELECT 
	uuid_generate_v4(), -- test_id
	FLOOR(RANDOM()*(10000000- 100000 + 1)) + 100000, --client id
	(array['Peter', 'Kim', 'Lou', 'Jhon', 'Set','Carl','Karen', 'Marco','Tim','Marie'])[floor(random() * 10 + 1)] -- first name
	(array['Kent', 'Foster', 'Lee', 'Smith', 'Young','Clark','Hill', 'Brodt','Scott','Reed'])[floor(random() * 10 + 1)] -- last name
	clock_timestamp()  - (random() * INTERVAL '100 days' ), -- downloaded_at
	(case when 
    	random() > 0.8 then true
        	else false
	end) -- is_active
FROM generate_series(1,500000);

Expliquemos un poco cada línea:
uuid_generate_v4(), -- test_id
Si bien esta línea se puede omitir porque es parte del default value de la columna prefiero mantenerla para ser consciente de la cantidad de columnas de la tabla, es una función que simplemente genera UUIDs.
FLOOR(RANDOM()*(10000000- 100000 + 1)) + 100000, --client id
Esta función se encarga de generar números aleatorios enteros para el client id. En este caso estos números siempre estarán entre el numero 100,000 y el número 1,000,000.
(array['Peter', 'Kim', 'Lou', 'Jhon', 'Set','Carl','Karen', 'Marco','Tim','Marie'])[floor(random() * 10 + 1)] -- first name
(array['Kent', 'Foster', 'Lee', 'Smith', 'Young','Clark','Hill', 'Brodt','Scott','Reed'])[floor(random() * 10 + 1)] -- last name
Esta es una muy curiosa forma de generar nombres y apellidos, se toma aleatoriamente del array los valores, con esto nos ahorramos un cláusula case por ejemplo.
clock_timestamp()  - (random() * INTERVAL '100 days' ), -- downloaded_at
De esta forma podemos generar values de tipo timestamp, tomamos la función clock_timestamp() que nos da el timestamp actual y le restamos una cantidad de días aleatoria, siempre mayor a 100 en este caso, así nos aseguramos que el valor siempre será menor al momento actual.
	(case when 
    	random() > 0.8 then true
        	else false
	end) -- is_active
Con esta sentencia creamos valores "booleanos" y subiendo el valor numérico podemos tener mayor cantidad de "true" que de "false" como era lo que necesitaba en este caso.
FROM generate_series(1,500000);
Finalmente tenemos la última de las instrucciones que es de lo más conveniente. La función generate_series nos permite repetir la cláusula anterior las veces que queramos, en este caso desde 1 hasta 500,000 veces lo que resultará en 500 mil registros aleatorios en la tabla. 

Si bien puede que no sea la forma más eficiente de hacer un llenado de valores aleatorios en tablas, ésta al menos resulta práctica y rápida en escenarios simples.

26 oct 2020

¿Y el servidor en Scala? Akka está.

 Continuando con esta seguidilla de posts sobre Scala y retomando desde el post anterior Ahora vamos a a hacer un experimento un poquito más avanzado: vamos a intentar crear un servidor web con Scala.

Akka es aparentemente el servidor http mas famoso del ecosistema de Scala. Según lo que se puede leer en el sitio de Akka.io, “Akka es un conjunto de herramientas para crear aplicaciones basadas en mensajes altamente concurrentes, distribuidas y resilientes para Java y Scala.” Este incluye tanto un servidor http que implementa el patrón Actor Model como un cliente para hacer llamadas http.

En este post mi plan es tratar de hacer un pequeño proyecto en Scala utilizando Visual Studio Code, que implemente un servidor que pueda responder a un request GET, con un “Hi, Akka server is running” o algo por el estilo.

Primero voy a abrir VS Code en una carpeta vacía y crearé un archivo build.sbt con las siguientes entradas:

lazy val akkaHttpVersion = "10.2.9"
lazy val akkaVersion    = "2.6.18"
lazy val root = (project in file(".")).
  settings(
    inThisBuild(List(
      organization    := "com.foy",
      scalaVersion    := "2.13.8"
    )),
    name := "AkkaTest",
     libraryDependencies ++= Seq(
    "com.typesafe.akka" %% "akka-http"                % akkaHttpVersion,     
    "com.typesafe.akka" %% "akka-actor-typed"         % akkaVersion,
    "com.typesafe.akka" %% "akka-stream"              % akkaVersion,   
    "ch.qos.logback"    % "logback-classic"           % "1.2.3",
    "org.scalatest"     %% "scalatest"                % "3.1.4"         % Test
  )
)

Según entiendo esta es la mínima configuración y dependencias necesarias para crear el más básico de los ejemplos de un servidor Akka

Ahora voy a crear la ruta normal de los archivos de Scala: src/main/scala y dentro de esta voy a crear un archivo main.Scala.


Dentro de este archivo voy a escribir el código necesario para crear una ruta llamada “Hi” que representa la llamada get y cuando esta llamada se complete, vamos a devolver el texto plano “Hi, Foy Akka server es running!”:
package com.foy.scala.AkkaTest

import akka.http.scaladsl.model.{ContentTypes, HttpEntity}
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.Route

object SimpleRouter {
  val route: Route = path("Hi") {
    get {
      complete(HttpEntity(ContentTypes.`text/plain(UTF-8)`, "Hi, Foy Akka server is running!"))
    }
  }
}
Ahora añadiré el objeto principal que llamaré App que contendrá el método main que es el responsable de levantar el servidor. El código completo de archivo main.Scala quedaría algo así:
package com.foy.scala.AkkaTest

import akka.http.scaladsl.model.{ContentTypes, HttpEntity}
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.Route

import akka.actor.typed.ActorSystem
import akka.actor.typed.scaladsl.Behaviors
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.HttpRequest

import scala.concurrent.duration._
import scala.concurrent.{Await, ExecutionContextExecutor}

import scala.util.Failure
import scala.util.Success

object SimpleRouter {
  val route: Route = path("Hi") {
    get {
      complete(HttpEntity(ContentTypes.`text/plain(UTF-8)`, "Hi, Foy Akka server is running!"))
    }
  }
}

object App {

  //Function to start the httpServer
  private def startHttpServer(routes: Route)(implicit system: ActorSystem[_]): Unit = {
    import system.executionContext
    val serverBinding = Http().newServerAt("localhost", 8080).bind(routes)
    serverBinding.onComplete {
      case Success(binding) =>
        val address = binding.localAddress
        system.log.info("Foy Akka Server online at http://{}:{}/", address.getHostString, address.getPort)
      case Failure(ex) =>
        system.log.error("Foy Akka Server Failed to bind HTTP endpoint, terminating system", ex)
        system.terminate()
    }
  }

  def main(args: Array[String]): Unit = {

    val rootBehavior = Behaviors.setup[Nothing] { context =>    
      startHttpServer(SimpleRouter.route)(context.system)
      Behaviors.empty
    }

    val system = ActorSystem[Nothing](rootBehavior, "akkaServerTest")
  }
}
Abrimos una terminal y arrancamos el servidor sbt

Podemos compilar nuestro código y  asegurarnos que todo esté bien ejecutamos el comando “compile” (dentro del server no hace escribir sbt antes). Y finalmente usamos el comando “run” para iniciar nuestro servidor Akka:


Como podemos observar, debido al log que pusimos en nuestro código, nos indica que nuestro servidor está corriendo, además de en cual ip y en cual puerto.  Ahora probemos nuestro endpoint “Hi”, como es un endpoint get podemos usar un Browser para acceder a la ruta http://localhost:8080/Hi la cual nos muestra el mensaje que especificamos en la resolución de la ruta:
O lo podemos hacer con cliente REST cualquiera

!Y ya tenemos un servidor corriendo! 

Tratemos de entender un poco el código: El objeto simpleRouter establece una variable inmutable de tipo Route en la cual establecemos el path “Hi”, definimos que este cuando se invoque con el verbo get y que cuando se complete devolveremos un objeto de tipo httpEntity (el response según yo entiendo) que simplemente contendrá el texto que queremos. En el objeto App tenemos la función startHttpServer que inicia propiamente el objeto Http que representa nuestro servidor, el cual al iniciarlo le pasamos la ruta (o ip) y el puerto, por el cual responderá y además le pasamos, por medio del método bind, el ruteo que manejará. 

Hasta aquí está todo relativamente normal. Pero entonces ¿Qué esto esto de Actors y Behaviors? En nuestro ejemplo actual si lo notan no estamos usando nada de eso, cuando nos piden el parámetro ActorSystem le estamos pasando Nothing y como behavior estamos usando Empty. Sin embargo, los Actores, como se señaló al inicio del post, son el corazón de Akka y el siguiente post voy a tratar de explicarme de que va este asunto.

Antes de cerrar el post voy a refactorizar un poco, voy crear un archivo que se llame SimpleRouter.Scala para poner ahí el objeto que devuelve la ruta. Queda más o menos así:









18 oct 2020

Scala: Configurando ambiente de desarrollo

Retomando del post anterior. Los programas más complejos en Scala requieren de un configurar o contar con un ambiente de desarrollo más elaborado que únicamente el REPL Ammonite. Scala se puede programar utilizando Eclipse, IntelliJ Idea, VIM o inclusive Visual Studio Code (en realidad con cualquier editor de texto es posible). Viniendo de territorios Microsoft prefiero utilizar este último editor con el cual estoy familiarizado.

Para utilizar Scala con Visual Studio Code se recomienda utilizar una extensión llamado “Metals” que es una especie de “language server” que nos añade una serie de convenientes características a VS Code para programar en Scala.

Comencemos pues abriendo VS Code y buscando e instalando la extensión de Metals y aprovechamos e instalamos la versión oficial de la extensión para sintaxis del lenguaje:


Una vez con Metals instalado nos aparecerá un icono con el tab que contiene el set de herramientas correspondientes:


Para comenzar a utilizar Scala desde VS Code necesitamos abrir un folder y una vez con el folder abierto nos vamos al tab de Metals y hacemos clic en el botón New Scala Project. Una vez hecho esto la extensión comenzará a descargar lo necesario para crear una aplicación Scala, lo cual puede tardar un poco al tratarse de la primera vez y seguidamente nos solicitará un template para el proyecto. En mi caso, como buen “newbie” que soy, seleccionaré la plantilla para el famoso “Hello, Word”.

Seguidamente nos preguntara que si usamos el folder actual (o seleccionamos uno diferente) y el nombre del proyecto. Se nos indicará también que se detectó un workspace de Scala y que si queremos lanzar el editor de Scala y, finalmente, que si queremos exportar el build a lo cual responderemos afirmativamente (estos últimos mensajes aparecen en la esquina inferior derecha de Visual Studio). Al final terminaremos con algo similar a esto:

Si desde este nuevo editor abrimos la extensión de Metals vamos a ver que en la primera sección se encuentra el proyecto que acabamos de crear, así como sus dependencias:

Si volvemos al tab del Explorer es importante notar el archivo build.sbt

Este archivo es muy importante ya que que en él se definen algunas propiedades, como la veersón de Scala que estamos usando y las dependencias de terceros necesarias para compilar y ejecutar un programa por medio de la herramienta de build de Scala (sbt= Scala build Tool)

Ahora volvamos la mirada a nuestro flamante código fuente y procedamos a abrir el archivo Main.Scala que se encuentra en src/Main/Scala. Aquí veremos que nuestro código actual es un simple println con la poderosa frase “Hello, World”.


Vamos a probar la escritura de código en Scala dentro de Visual Studio con las extensiones que le instalamos, principalmente el autocompletado y las sugerencias al escribir código. Vamos a crear una variable inmutable de tipo string para guardar un nombre y vamos a cambiar la salida para mostrar el Hello y el nombre almacenado en la variable:


Son ejemplos muy básicos, pero sirven para mostrar las bondades de escribir código Scala en este editor con las extensiones adecuadas. Al final terminamos con algo similar a esto:

Ahora finalmente, ¿Cómo ejecutamos este código? Primero nos aseguramos que nuestro archivo esta guardado con los últimos cambios y luego tenemos dos posibilidades: usar el tab de ejecución y debugging de VSCode o bien usar la consola y utilizar el comando sbt run.

Si usamos el botón “Run and Debug” se levantará la maquina virtual de java y se nos solicitarán algunos permisos de acceso como este, a los que contestaremos afirmativamente:

Para finalmente ver el resultado en la consola de debgug:


Y se utilizamos la terminal y el comando sbt run veremos la compilación del proyecto y el resultado de la ejecución en la misma terminal:


También se puede utilizar el comando sbt compile para únicamente compilar el código sin necesidad de ejecutarlo.

Es muy muy importante señalar que al utilizar el botón de “Run and Debug” realmente nos permite depurar. Por ejemplo, añadiendo un breakpoint la ejecución se detendrá y podemos recorrerlo paso a paso:


Hasta aquí esta entrada del paseo que estoy intentando hacer en Scala.