initial commit

This commit is contained in:
Pedro Pérez 2025-10-08 23:17:23 +02:00
commit a7c436fe4c
9 changed files with 165 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
logs/

28
Makefile Normal file
View File

@ -0,0 +1,28 @@
GO ?= go
PG_VERSION := 17.6-alpine3.22
MOD_NAME := nats-app
DB_NAME := nats-db
NATS_NAME := nats-sv
NATS_VERSION := 2.12.0-alpine3.22
.PHONY: dockerize-db
# Remove and create a development database.
dockerize-db:
docker rm -f $(DB_NAME)
docker run --name $(DB_NAME) -e POSTGRES_PASSWORD=secret -e POSTGRES_USER=developer -e POSTGRES_DB=$(DB_NAME) -p 5432:5432 -d postgres:$(PG_VERSION)
.PHONY: dockerize-nats
# Remove and create a NATS server.
dockerize-nats:
docker rm -f $(NATS_NAME)
docker run --name $(NATS_NAME) -p 4222:4222 -d nats:$(NATS_VERSION)
.PHONY: run
# Start app in development environment
run:
go run ./app/.
.PHONY: run-prod
run-prod:
# Start app in production environment
go run ./app/. -env=prod

36
README.md Normal file
View File

@ -0,0 +1,36 @@
# NATS APP
Lectura de datos de sensores en un dispositivo IoT. Prueba técnica para optar
por el puesto de programador Go.
## Requisitos previos
- Docker
- NATS CLI
- Make, si prefieres la comodidad de usar Makefile
## Consideraciones
Hay partes de códigos que son _snippets_ extraídos de una librería de autoría
propia. [Repositorio GitHub](https://github.com/zepyrshut/gopher-toolbox). De
las cuales son:
- El _logger_ usando la _stdlib log/slog_.
## Bitácora
### Quickstart y toma de contacto con NATS
Lo primero que he hecho es un _quickstart_ del proyecto, con lo que siempre o
casi siempre pongo en mis experimentos. Y lo siguiente, en lugar de empezar a
construir el proyecto como loco he tratado de entender cómo funciona NATS. Al
final ha sido muy sencillo, siguiendo esos pasos:
1. Levantar el servidor NATS en Docker
2. Instalar el CLI de NATS
2. Abrir un puñado de terminales, y en un par de ellas escribir: `nats sub "hello"`
lo cual significa que se está suscribiendo al canal `hello`. Y en otra escribir:
`nats pub "hello" "Hola mundo!"`, lo cual significa que está escribiendo el
mensaje `Hola mundo!` en el canal `hello`.
![demo de NATS](./assets/nats-demo-1.png)

19
app/main.go Normal file
View File

@ -0,0 +1,19 @@
package main
import (
"flag"
"log/slog"
"nats-app/internal/app"
)
func main() {
environment := flag.String("env", "dev", "dev or prod")
flag.Parse()
_ = app.NewApp(*environment)
slog.Debug("hello world debug")
slog.Info("Hello world info")
slog.Warn("Hello world warn")
slog.Error("hello world error")
}

BIN
assets/nats-demo-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module nats-app
go 1.25.1

0
go.sum Normal file
View File

11
internal/app/app.go Normal file
View File

@ -0,0 +1,11 @@
package app
type App struct {
}
func NewApp(environment string) *App {
startRotativeLogger(environment)
return &App{}
}

67
internal/app/logger.go Normal file
View File

@ -0,0 +1,67 @@
package app
import (
"fmt"
"io"
"log/slog"
"os"
"strings"
"time"
)
var (
logFile *os.File
)
func newLogger(environment string) {
if err := os.MkdirAll("logs", 0755); err != nil {
fmt.Println("error creating logs directory:", err)
return
}
now := time.Now().Format("2006-01-02")
f, err := os.OpenFile(fmt.Sprintf("logs/log%s.log", now), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
fmt.Println("error opening log file:", err)
return
}
var level slog.Level
var addSource bool
switch strings.ToLower(environment) {
case "dev":
level = slog.LevelDebug // -4
addSource = true
case "prod":
level = slog.LevelInfo // 0
addSource = false
default:
level = slog.LevelInfo
addSource = false
}
mw := io.MultiWriter(os.Stdout, f)
logger := slog.New(slog.NewTextHandler(mw, &slog.HandlerOptions{
AddSource: addSource,
Level: level,
}))
if logFile != nil {
logFile.Close()
}
logFile = f
slog.SetDefault(logger)
}
func startRotativeLogger(environment string) {
newLogger(environment)
ticker := time.NewTicker(time.Hour * 24)
go func() {
for range ticker.C {
newLogger(environment)
}
}()
}