Logs y archivos de configuración: qué son y cuáles usa cada lenguaje

Todo programa que funciona en serio necesita dos cosas que no son código: una forma de contar lo que hace mientras funciona y una forma de cambiar cómo se comporta sin tener que reescribirlo. La primera son los logs (en español, registros); la segunda, los archivos de configuración, que en el mundo Java se llaman a menudo «archivos de propiedades». Esta guía explica qué son, para qué sirven, qué errores evitar y qué archivos concretos usa cada lenguaje y cada framework.

Qué es un log

Un log es el diario de a bordo de un programa: una lista de anotaciones, en orden, de lo que va pasando. «Se creó el pedido 1042», «queda poco stock del producto 15», «no se pudo conectar con el banco». Mientras todo va bien, nadie lo lee. Cuando algo falla, a las tres de la mañana y en un servidor al que nadie estaba mirando, el log es lo único que cuenta qué pasó.

Sirve para tres cosas:

  • Encontrar errores: qué falló, cuándo, con qué datos y qué pasó justo antes.
  • Vigilar: cuántos errores hay por minuto, qué tarda demasiado, quién intenta entrar sin permiso.
  • Dejar constancia: quién hizo qué y cuándo, para una auditoría o para resolver una reclamación.

Las partes de una línea

Una línea de log dividida en partes: la fecha y hora dicen cuándo, WARNING la gravedad, tienda.pedidos quién lo registró y el mensaje qué pasóLas partes de una línea de log2026-10-27 21:15:29cuándoWARNINGgravedadtienda.pedidosquiénStock bajo del producto 15: quedan 2qué pasóCon estas cuatro respuestas, cualquiera puede reconstruir qué pasó sin estar allí.

Una buena línea de log responde a cuatro preguntas. Esquema: decodigo.com.

Además de esas cuatro, los logs modernos añaden contexto: el identificador del pedido, del usuario o de la petición web. Con un identificador común se pueden seguir todos los pasos de una misma operación aunque pase por varios servidores.

Los niveles: no todo es igual de grave

Cada anotación lleva un nivel de gravedad. Los nombres cambian un poco entre lenguajes, pero la idea es la misma:

NivelPara quéEjemplo
TRACE y DEBUGdetalle para quien programa; apagados en producción«Consulta SQL con estos parámetros…»
INFOlo normal, lo que conviene saber que pasó«Pedido 1042 creado»
WARN o WARNINGalgo raro que todavía no es un error«Quedan 2 unidades del producto 15»
ERRORalgo falló y hay que mirarlo«No se pudo cobrar el pedido 1042»
FATAL o CRITICALel programa no puede seguir«No hay conexión con la base de datos al arrancar»

El nivel se usa para filtrar: en producción se suele registrar de INFO hacia arriba, y si hay un problema se baja a DEBUG durante un rato para ver el detalle. En los sistemas Linux, el estándar syslog tiene ocho niveles, de emerg a debug.

Así se ve un log en cada lenguaje

Los mismos dos mensajes, escritos con la herramienta que trae cada lenguaje, tal como salen de verdad:

Python (módulo logging)2026-10-27 21:15:29,324 INFO tienda.pedidos: Pedido 1042 creado para el cliente 77
2026-10-27 21:15:29,325 WARNING tienda.pedidos: Stock bajo del producto 15: quedan 2
2026-10-27 21:15:29,326 ERROR tienda.pedidos: No se pudo calcular el descuento del pedido 1042
Traceback (most recent call last):
  File "/p/log.py", line 8, in <module>
    1 / 0
    ~~^~~
ZeroDivisionError: division by zero
Java (java.util.logging)Oct 27, 2026 9:15:29 PM Log main
INFO: Pedido 1042 creado para el cliente 77
Oct 27, 2026 9:15:30 PM Log main
WARNING: Stock bajo del producto 15: quedan 2
Go (log/slog, en texto y en JSON)time=2026-10-27T21:15:33.589-06:00 level=INFO msg="pedido creado" pedido=1042 cliente=77
{"time":"2026-10-27T21:15:33.589789688-06:00","level":"WARN","msg":"stock bajo","producto":15,"quedan":2}
PHP (error_log y un aviso)[28-Oct-2026 03:15:33 UTC] Pedido 1042 creado para el cliente 77
[28-Oct-2026 03:15:33 UTC] PHP Warning:  Stock bajo del producto 15: quedan 2 in /p/log.php on line 3

Fíjate en tres cosas. Python registra el error completo, con la línea donde ocurrió; por eso conviene registrar las excepciones con su traza. Java escribe la fecha en inglés y en dos líneas, un formato antiguo que se cambia con su configuración. Y PHP escribe la hora en UTC, mientras los demás usan la de México: si no se configura la zona horaria, cada programa elige la suya, y comparar logs de dos programas se vuelve un lío. Lo más práctico es registrar siempre en UTC o con la diferencia horaria incluida, como hace Go.

Texto o JSON

La segunda línea de Go es un log estructurado: en vez de una frase, un objeto JSON con campos. Para una persona es menos cómodo de leer, pero para una máquina es perfecto: se puede buscar «todos los avisos del producto 15» o contar errores por minuto sin trucos con expresiones regulares. Cuando los logs de muchos servidores se reúnen en un mismo sitio, lo habitual es JSON.

Dónde acaban

La aplicación escribe el evento en la consola o en un archivo; la rotación los separa por días y borra los viejos; y un sistema central reúne los de todos los servidores para buscarlos y lanzar alertasEl viaje de un log: de la aplicación a quien lo leeaplicaciónescribe el eventosalida o archivoconsola, app.logrotaciónuno por día; borra lo viejosistema centralbúsqueda y alertasEn un servidor pequeño, el viaje termina en el archivo. Con muchos servidores o contenedores,todos envían sus logs a un mismo sitio para buscarlos juntos y recibir avisos.

Del programa a la persona que lo lee. Esquema: decodigo.com.
  • En la consola (la salida estándar). Es lo recomendado en contenedores: Docker y Kubernetes recogen lo que el programa escribe ahí.
  • En archivos, normalmente en /var/log/ en Linux o en una carpeta logs de la aplicación. Un programa como logrotate los rota: cada día empieza un archivo nuevo, comprime los anteriores y borra los muy viejos, para que no llenen el disco.
  • En el diario del sistema, en los Linux con systemd, que se consulta con journalctl.
  • En un sistema central, como Elasticsearch u OpenSearch con Kibana, Grafana Loki, Graylog o el servicio de registros de cada nube, que permiten buscar en los de todos los servidores y avisar cuando algo pasa.

Los servidores web tienen los suyos: Nginx y Apache escriben un access log, una línea por cada visita, y un error log. Si quieres aprender a leerlos, en Cómo saber si atacaron tu WordPress lo explicamos paso a paso.

Lo que nunca debe ir en un log

Contraseñas, tokens, números de tarjeta y datos personales que no hagan falta. Los logs se copian, se envían a otros sistemas, los leen más personas que la base de datos y se guardan meses. Un log con contraseñas es una filtración esperando a ocurrir, y en muchos países guardar datos personales sin necesidad también es un problema legal. Registra el identificador del usuario, no su correo y su contraseña.
  • Cuidado con lo que escribe el usuario. Si un texto del usuario va tal cual al log, puede meter saltos de línea y fabricar líneas falsas que confundan a quien lo lea. Las bibliotecas de log estructurado lo evitan solas; con texto plano, hay que limpiar los saltos de línea.
  • La biblioteca de logs también se actualiza. En diciembre de 2021, un fallo en Log4j, la biblioteca de logs más usada de Java, permitía tomar el control de un servidor con solo conseguir que registrara un texto concreto. Se llamó Log4Shell (CVE-2021-44228) y afectó a miles de empresas. Las dependencias de logs se mantienen al día como cualquier otra.
  • Protege los archivos de log: que solo los lean quienes deben, y que no queden dentro de la carpeta pública de una web.

Qué es un archivo de configuración

Un archivo de configuración es el panel de ajustes de un programa: guarda lo que cambia de un sitio a otro sin cambiar el código. La dirección de la base de datos, el puerto en el que escucha, el nivel de log, el correo desde el que se envían avisos o si el modo de depuración está activado.

La idea clave es que el mismo programa funcione en tu ordenador, en el servidor de pruebas y en producción cambiando solo la configuración. Si la dirección de la base de datos estuviera escrita en el código, habría que tocar y volver a compilar el programa cada vez que se instala en un sitio distinto.

Los formatos más habituales

Esta es la misma configuración de «tutienda» en los formatos que verás con más frecuencia:

# application.properties (Java)
servidor.puerto=8080
basedatos.url=jdbc:postgresql://localhost/tutienda
log.nivel=INFO
# application.yml (YAML)
servidor:
  puerto: 8080
basedatos:
  url: jdbc:postgresql://localhost/tutienda
log:
  nivel: INFO
{
  "Servidor": { "Puerto": 8080 },
  "BaseDatos": { "Url": "Host=localhost;Database=tutienda" },
  "Logging": { "LogLevel": { "Default": "Information" } }
}
# .env (variables de entorno en un archivo)
PUERTO=8080
DATABASE_URL=postgres://localhost/tutienda
LOG_LEVEL=info
# config.toml (TOML)
[servidor]
puerto = 8080

[basedatos]
url = "postgres://localhost/tutienda"
FormatoCómo esDónde se ve
.propertieslíneas clave=valor, con puntos para agruparJava y Spring Boot
YAML (.yml, .yaml)jerárquico por sangría; legible, pero los espacios importanSpring Boot, Symfony, Rails, Docker Compose, Kubernetes
JSONjerárquico con llaves; estricto y sin comentarios.NET, Node.js (package.json), TypeScript (tsconfig.json)
TOMLsecciones entre corchetes; pensado para personasRust (Cargo.toml), Python (pyproject.toml), Go
INIsecciones y clave=valor; el más antiguoPHP (php.ini), Python, Windows
.envvariables de entorno en un archivo, una por líneaLaravel, Symfony, Node, Python, Docker
XMLetiquetas; muy detalladoMaven (pom.xml), .NET antiguo (web.config), Tomcat
códigoun archivo del propio lenguajeDjango (settings.py), Laravel (config/*.php), WordPress (wp-config.php)

Capas y entornos

Casi todos los frameworks leen la configuración de varios sitios a la vez, en un orden fijo, y lo que llega después sobrescribe lo anterior:

Cinco capas de configuración, de la que menos manda a la que más: valores por omisión, archivo general, archivo del entorno, variables de entorno y argumentos al arrancar. En el ejemplo, el puerto acaba siendo el 8443 que se pasó como argumentoLa configuración por capas: la de abajo mandavalores por omisiónlo que trae el programapuerto = 8080archivo generalapplication.properties, appsettings.json, .envpuerto = 8000archivo del entornoapplication-prod, appsettings.Productionpuerto = 80variables de entornolas que pone el servidor o el contenedorPUERTO=443argumentos al arrancarlo que se escribe en la orden–puerto=8443ejemploEl programa acaba escuchando en el 8443: cada capa sobrescribe lo que dijeron las anteriores.

El orden concreto cambia de un framework a otro, pero la idea es la misma en casi todos. Esquema: decodigo.com.

Gracias a eso, el archivo general lleva valores que sirven para todos, cada entorno (desarrollo, pruebas, producción) cambia solo lo suyo, y el servidor puede ajustar algo puntual con una variable de entorno sin tocar ningún archivo. Es la forma recomendada de trabajar en contenedores: la misma imagen en todas partes, y la configuración, fuera.

Los secretos, aparte

Las contraseñas y claves no van en el repositorio. Un archivo de configuración con la contraseña de la base de datos, subido a Git, queda en el historial para siempre aunque luego se borre. Los secretos van en variables de entorno, en un .env que está en .gitignore o en un gestor de secretos (los de cada nube, HashiCorp Vault, los secrets de Kubernetes). En el repositorio, solo un archivo de ejemplo con valores falsos.
  • Nunca dentro de la carpeta pública de una web. Un .env o una copia de wp-config.php que se puede descargar con una URL es una de las filtraciones más frecuentes.
  • El modo de depuración, apagado en producción (APP_DEBUG=false en Laravel, DEBUG = False en Django): si no, un error enseña al visitante la configuración y a veces las contraseñas.
  • Comprueba la configuración al arrancar: si falta un valor obligatorio, mejor que el programa no arranque a que falle a mitad de una compra.

Qué usa cada lenguaje y cada framework

Lo que sigue son los archivos y herramientas que encontrarás en cada caso, empezando por lo que trae el lenguaje y siguiendo por lo más usado.

Logs

Lenguaje o frameworkHerramienta de logsConfiguración de los logsDónde escribe por omisión
Javajava.util.logging (incluido); Log4j 2 y Logback, casi siempre detrás de SLF4Jlogging.properties, log4j2.xml, logback.xmlconsola
Spring BootLogback, a través de SLF4Japplication.properties (logging.level.*) o logback-spring.xmlconsola; a archivo con logging.file.name
Pythonmódulo logging (incluido); también structlog y loguruen código, o un archivo con logging.configconsola (salida de errores)
Djangomódulo loggingel diccionario LOGGING de settings.pyconsola
Node.jsconsole (incluido); pino y winstonen código o en la configuración de la bibliotecaconsola
PHPerror_log() (incluido); Monolog, el estándar de facto (PSR-3)php.ini (error_log, log_errors)el registro del servidor o la consola
LaravelMonologconfig/logging.php y LOG_CHANNEL en .envstorage/logs/laravel.log
SymfonyMonologconfig/packages/monolog.yamlvar/log/dev.log, var/log/prod.log…
C# y .NETILogger (incluido); Serilog y NLogsección Logging de appsettings.jsonconsola
Golog y log/slog (incluidos, slog desde Go 1.21); zap y zerologen códigoconsola (salida de errores para log)
Rustlog con env_logger, o tracingla variable de entorno RUST_LOGconsola
Ruby on RailsRails.loggerconfig/environments/*.rblog/development.log, log/production.log

Configuración

Lenguaje o frameworkArchivos de configuraciónProyecto y dependenciasPor entorno y secretos
Java.properties con java.util.Propertiespom.xml (Maven), build.gradle (Gradle)variables de entorno
Spring Bootapplication.properties o application.ymlpom.xml o build.gradleapplication-prod.properties con perfiles (spring.profiles.active)
PythonINI con configparser, TOML, .env con python-dotenvpyproject.tomlvariables de entorno; pydantic-settings
Djangosettings.pypyproject.toml o requirements.txtun settings por entorno, secretos de variables de entorno
Node.js.env (con dotenv o node --env-file, desde Node 20.6), JSONpackage.jsonNODE_ENV y variables de entorno
PHPphp.inicomposer.jsonvariables de entorno
Laravel.env y config/*.phpcomposer.jsonAPP_ENV; el .env nunca en Git
Symfony.env, .env.local y config/packages/*.yamlcomposer.jsonAPP_ENV y el gestor de secretos de Symfony
WordPresswp-config.php—fuera de la carpeta pública si se puede
C# y .NETappsettings.json; en proyectos antiguos, web.config o app.config.csprojappsettings.Production.json con ASPNETCORE_ENVIRONMENT; dotnet user-secrets en desarrollo
Gosin estándar: argumentos, variables de entorno, YAML o TOML (por ejemplo, con Viper)go.modvariables de entorno
RustTOML o variables de entorno (crates config y dotenvy)Cargo.tomlvariables de entorno
Ruby on Railsconfig/database.yml y config/environments/*.rbGemfileconfig/credentials.yml.enc, cifrado (desde Rails 5.2)
Docker y Kubernetescompose.yaml; ConfigMap y Secret—variables de entorno y secrets

Algunos casos con más detalle en el propio sitio: la configuración por entorno en Docker, tsconfig.json explicado y las variables de entorno en PHP, C# y Java.

Resumen

LogsConfiguración
Qué esel diario de lo que hace el programael panel de ajustes que cambia sin tocar el código
Lo escribeel programa, mientras funcionaquien lo instala, antes de arrancarlo
Lo leeuna persona o un sistema de vigilanciael programa, al arrancar
Formatotexto con fecha, nivel, origen y mensaje, o JSON.properties, YAML, JSON, TOML, INI, .env…
Lo que no puede llevarcontraseñas, tokens ni datos personales innecesariossecretos subidos al repositorio
Buena costumbreniveles bien usados, contexto y rotaciónun archivo por entorno y los secretos, aparte

Las líneas de log de Python 3.14, Java 21, Go 1.27 y PHP 8.5 se generaron el 27 de octubre de 2026 en contenedores, con la herramienta que trae cada lenguaje y su configuración por omisión. Niveles de syslog: RFC 5424. Log4Shell: CVE-2021-44228 en el NVD.