Logging parametrizado
Formateo eficiente de mensajes
Logging parametrizado es una lección gratuita de Java Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Java Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Java Academy incluye 4 lecciones en total.
El problema de concatenar cadenas
Concatenar un mensaje de log construye la cadena completa antes de la llamada, incluso si el nivel está desactivado.
log.debug("id=" + id + " name=" + name) desperdicia CPU cuando DEBUG está desactivado, porque la cadena se construye de todos modos.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
String name = "Ada"; int id = 7;
// Bad: string is built even if DEBUG is disabled
log.debug("id=" + id + " name=" + name);
}
}Marcadores de posición con {}
SLF4J utiliza {} como marcador de posición. Pase los valores como argumentos adicionales.
El mensaje solo se ensambla si el nivel está habilitado, por lo que los logs desactivados apenas tienen coste.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
String name = "Ada"; int id = 7;
// Good: no string built unless DEBUG is on
log.debug("id={} name={}", id, name);
}
}Varios marcadores de posición
Los marcadores de posición se rellenan en orden. El primer {} toma el primer argumento, el segundo toma el segundo, y así sucesivamente.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
log.info("order {} for user {} totaling {} cents", "A-1", 42, 1599);
}
}Por qué es eficiente
El framework comprueba primero el nivel. Si está desactivado, retorna inmediatamente sin llamar a toString() en ningún argumento.
La parte costosa, el formateo, se realiza de forma diferida solo cuando el mensaje realmente se va a emitir.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
static String describe(Object o) { System.out.println("toString called"); return o.toString(); }
public static void main(String[] args) {
// Note: passing describe(...) still evaluates eagerly; pass the raw object instead
log.trace("value={}", new int[]{1, 2, 3});
}
}Pase objetos sin procesar, no cadenas con formato previo
Para aprovechar la evaluación diferida, pase el objeto sin procesar, no una llamada a un método que lo formatee.
Si escribe log.debug("{}", buildReport()), buildReport() aún se ejecuta de forma inmediata. Pase argumentos que el logger pueda formatear por sí mismo.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
Object user = new Object();
// Logger calls user.toString() only if DEBUG is enabled
log.debug("current user: {}", user);
}
}Suppliers diferidos para trabajo costoso
Cuando el formateo es realmente costoso, utilice la fluent API de SLF4J 2.x con un Supplier para diferir el trabajo.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
static String heavyReport() { return "...expensive..."; }
public static void main(String[] args) {
log.atDebug()
.setMessage("report: {}")
.addArgument(() -> heavyReport())
.log();
}
}Escapar una llave literal
Si necesita incluir un {} literal en el mensaje, escápelo con una barra inversa: \\{}.
Es poco frecuente, pero resulta útil al registrar texto similar a JSON.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
// Logs a literal {} then the value
log.info("empty object is \\{} and id is {}", 7);
}
}Excepción y marcadores de posición
Puede combinar marcadores de posición con una excepción al final. SLF4J detecta que el último argumento es un Throwable e imprime su stack trace.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
int id = 99;
try {
throw new RuntimeException("db down");
} catch (Exception e) {
log.error("failed processing record {}", id, e);
}
}
}Evitar demasiados argumentos
Si el número de marcadores de posición y el número de argumentos no coinciden, SLF4J hace lo posible, pero la salida puede verse incorrecta.
Manténgalos sincronizados. Para más de un par de valores, considere utilizar contexto estructurado (MDC).
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
// Two placeholders, two arguments: correct
log.info("user {} did {}", "ada", "login");
}
}Añadir contexto con MDC
Para los valores compartidos entre muchas líneas, como un identificador de solicitud, colóquelos en el MDC en lugar de repetirlos en cada mensaje.
De este modo, el patrón de salida puede imprimir automáticamente el valor del MDC en cada línea.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
MDC.put("requestId", "req-1234");
try {
log.info("handling request");
log.info("request done");
} finally {
MDC.clear();
}
}
}Resumen de buenas prácticas
Reglas para un registro eficiente:
- Utilice siempre marcadores de posición
{}, nunca concatenación con+. - Pase objetos sin procesar, no cadenas creadas previamente.
- Utilice suppliers o
isXEnabled()para trabajos realmente costosos. - Utilice MDC para el contexto transversal.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
log.info("processed {} items in {} ms", 1000, 42);
}
}Comprobación rápida
Compruebe sus conocimientos sobre el registro parametrizado.
Repaso
Ha aprendido a utilizar el registro parametrizado:
- Utilice marcadores de posición
{}con argumentos adicionales. - Los mensajes se construyen de forma diferida, solo cuando el nivel está activado.
- Pase objetos sin procesar; utilice suppliers para trabajos costosos.
- Utilice MDC para valores contextuales compartidos.
A continuación, la configuración del backend Logback.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
log.info("Parameterized logging recap: {}", "done");
}
}Preguntas frecuentes
¿La lección «Logging parametrizado» es gratis?
Sí — el texto completo de «Logging parametrizado» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Java Academy, actualiza a CoddyKit PRO. El curso de Java Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Logging parametrizado»?
Formateo eficiente de mensajes Practicas Java Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Java Academy?
No se requiere experiencia previa. Java Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.
¿Cuánto tiempo toma la lección «Logging parametrizado»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Java Academy?
Sí. Cada lección de Java Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Por qué usar logging estructurado
- Fachada y loggers de SLF4J
- Logging parametrizado
- Configuración de Logback