在Java中创建日志或异常消息的最佳实践:

huangapple go评论78阅读模式
英文:

Best Practices to create Message for Logging or Exception in Java

问题

以下是翻译好的内容:

在Java 6中,我找到了这段代码。

String mensajeExcluido = ArqSpringContext.getPropiedad("MENSAJE.EXCLUIDO");
LOG.warn("ERROR: Servicio: " + mensajeExcluido + ":" + someDTO.getProperty() +
        ",\tsomeValue:" + someDTO.getValue() + "'.");
throw new Exception(mensajeExcluido);

这段代码:

String mensajeExcluido = ArqSpringContext.getPropiedad("REGLA.MENSAJE");
String mensajeWarn = "ALERTA: Otro Servicio: " + mensajeExcluido + ":" +
        someDTO.getProperty() + ",\tsomeValue:" + someDTO.getValue() + "'.";
LOG.warn(mensajeWarn);

boolean exclusionVisible = Boolean.valueOf(ArqSpringContext.getPropiedad("EXCLUSION.VISIBLE"));
if (exclusionVisible) {
    mensajeWarn = "<br></br>" + mensajeWarn;
} else {
    mensajeWarn = "";
}
throw new Exception(mensajeExcluido + mensajeWarn);

以及这段代码:

LOG.warn("No se pudo validar Client Service. Code: " +
        someDTO.getStatusCode() + ".");
return "No se pudo validar Client Service. Code: " +
        someDTO.getStatusCode() + ".";

为了遵循最佳实践...

适用的建议是什么?

这些建议会对代码产生什么改变?

如何处理文本?

英文:

I found this code in Java 6.

String mensajeExcluido = ArqSpringContext.getPropiedad(&quot;MENSAJE.EXCLUIDO&quot;);
LOG.warn(&quot;ERROR: Servicio: &quot; + mensajeExcluido + &quot;:&quot; + someDTO.getProperty() +
        &quot;,\tsomeValue:&quot; + someDTO.getValue() + &quot;&#39;.&quot;);
throw new Exception(mensajeExcluido);

this code

String mensajeExcluido = ArqSpringContext.getPropiedad(&quot;REGLA.MENSAJE&quot;);
String mensajeWarn = &quot;ALERTA: Otro Servicio: &quot; + mensajeExcluido + &quot;:&quot; +
        someDTO.getProperty() + &quot;,\tsomeValue:&quot; + someDTO.getValue() + &quot;&#39;.&quot;;
LOG.warn(mensajeWarn);

boolean exclusionVisible = Boolean.valueOf(ArqSpringContext.getPropiedad(&quot;EXCLUSION.VISIBLE&quot;));
if (exclusionVisible) {
    mensajeWarn = &quot;&lt;br&gt;&lt;/br&gt;&quot; + mensajeWarn;
} else {
    mensajeWarn = &quot;&quot;;
}
throw new Exception(mensajeExcluido + mensajeWarn);

an this code

LOG.warn(&quot;No se pudo validar Client Service. Code: &quot; +
        someDTO.getStatusCode() + &quot;.&quot;);
return &quot;No se pudo validar Client Service. Code: &quot; +
        someDTO.getStatusCode() + &quot;.&quot;;

In order to follow best practices...

What recommendations are applicable?

What changes would they make to the code?

How should texts be handled?

答案1

得分: 1

First, try to avoid message creation processing before checking if the log statement should be printed (I.e.: don't concatenate the messages strings before checking the log level.

// Better this
if (LOG.isDebugEnabled())
    LOG.debug("This is a message with " + variable + " inside");

// Than this
final String message = "This is a message with " + variable + " inside";
if (LOG.isDebugEnabled())
    LOG.debug(message);

Most Java logging frameworks allow a check to know in advance if a log statement is going to be printed based on the given settings.

If you want to save you the burden of writting those checks for each log statement, you can take advantage of Java 8 lambdas and code an utility like this:

import java.util.function.Supplier;
import java.util.logging.Logger;
import static java.util.logging.Level.FINE;

class MyLogger {
    public static MyLogger of(final Class<?> loggerClass) {
        return new MyLogger(loggerClass);
    }
    private final Logger logger;
    private MyLogger(final Class<?> loggerClass) {
        logger = Logger.getLogger(loggerClass.getName());
    }
    // Supplier will be evaluated AFTER checking if log statement must be executed
    public void fine(final Supplier<?> message) {
        if (logger.isLoggable(FINE))
            logger.log(FINE, message.get().toString());
    }
}

static final LOG = MyLogger.of(String.class);

public void example() {
    LOG.fine(() -> "This is a message with a system property: " + System.getProperty("property"));
}

And finally, you can take advantage of Java string formatting to format log messages using String.format. I.e.:

final String message = String.format("Print %s string and %d digit", "str", 42);

Those good practices applied to the examples you provided would be:

/*
 * Using java.util.logging in JDK8+
 */

import java.util.logging.Level;
import java.util.logging.Logger;
import static java.lang.String.format;

class Dto {
    String getProperty() { return "property"; }
    String getValue() { return "property"; }
    String getStatusCode() { return "statusCode"; }
}

final Logger LOG = Logger.getGlobal();
final Dto someDTO = new Dto();

void example1() throws Exception {
    String mensajeExcluido = System.getProperty("MENSAJE.EXCLUIDO");

    // Check if log will be printed before composing the log message
    if (LOG.isLoggable(Level.WARNING)) {
        // Using String.format usually is clearer and gives you more formatting options
        final String messageFormat = "ERROR: Servicio: %s:%s,\tsomeValue:%s'.";
        LOG.warning(format(messageFormat, mensajeExcluido, someDTO.getProperty(), someDTO.getValue()));
    }

    // Or using lambdas
    LOG.warning(() -> {
        final String message = "ERROR: Servicio: %s:%s,\tsomeValue:%s'.";
        return format(message, mensajeExcluido, someDTO.getProperty(), someDTO.getValue());
    });

    throw new Exception(mensajeExcluido);
}

void example2() throws Exception {
    String mensajeExcluido = System.getProperty("REGLA.MENSAJE");
    String mensajeWarn = format(
        // The concatenated message is probably missing a single quote at 'someValue'
        "ALERTA: Otro Servicio: %s:%s,\tsomeValue:%s'.",
        mensajeExcluido,
        someDTO.getProperty(),
        someDTO.getValue()
    );

    LOG.warning(mensajeWarn);

    boolean exclusionVisible = Boolean.parseBoolean(System.getProperty("EXCLUSION.VISIBLE"));
    String exceptionMessage = exclusionVisible ?
            mensajeExcluido + "<br></br>" + mensajeWarn : mensajeExcluido;

    throw new Exception(exceptionMessage);
}

String example3() {
    // You can compose the message only once and use it for the log and the result
    String message =
        format("No se pudo validar Client Service. Code: %s.", someDTO.getStatusCode());
    LOG.warning(message);
    return message;
}
英文:

First, try to avoid message creation processing before checking if the log statement should be printed (I.e.: don't concatenate the messages strings before checking the log level.

// Better this
if (LOG.isDebugEnabled())
    LOG.debug(&quot;This is a message with &quot; + variable + &quot; inside&quot;);

// Than this
final String message = &quot;This is a message with &quot; + variable + &quot; inside&quot;;
if (LOG.isDebugEnabled())
    LOG.debug(message);

Most Java logging frameworks allow a check to know in advance if a log statement is going to be printed based on the given settings.

If you want to save you the burden of writting those checks for each log statement, you can take advantage of Java 8 lambdas and code an utility like this:


import java.util.function.Supplier;
import java.util.logging.Logger;

import static java.util.logging.Level.FINE;

class MyLogger {

    public static MyLogger of(final Class&lt;?&gt; loggerClass) {
        return new MyLogger(loggerClass);
    }

    private final Logger logger;

    private MyLogger(final Class&lt;?&gt; loggerClass) {
        logger = Logger.getLogger(loggerClass.getName());
    }

    // Supplier will be evaluated AFTER checking if log statement must be executed
    public void fine(final Supplier&lt;?&gt; message) {
        if (logger.isLoggable(FINE))
            logger.log(FINE, message.get().toString());
    }
}

static final LOG = MyLogger.of(String.class);

public void example() {
    LOG.fine(() -&gt; &quot;This is a message with a system property: &quot; + System.getProperty(&quot;property&quot;));
}

And finally, you can take advantage of Java string formatting to format log messages using String.format. I.e.:

final String message = String.format(&quot;Print %s string and %d digit&quot;, &quot;str&quot;, 42);

Those good practices applied to the examples you provided would be:

/*
 * Using java.util.logging in JDK8+
 */

import java.util.logging.Level;
import java.util.logging.Logger;

import static java.lang.String.format;

class Dto {
    String getProperty() { return &quot;property&quot;; }
    String getValue() { return &quot;property&quot;; }
    String getStatusCode() { return &quot;statusCode&quot;; }
}

final Logger LOG = Logger.getGlobal();
final Dto someDTO = new Dto();

void example1() throws Exception {
    String mensajeExcluido = System.getProperty(&quot;MENSAJE.EXCLUIDO&quot;);

    // Check if log will be printed before composing the log message
    if (LOG.isLoggable(Level.WARNING)) {
        // Using String.format usually is clearer and gives you more formatting options
        final String messageFormat = &quot;ERROR: Servicio: %s:%s,\tsomeValue:%s&#39;.&quot;;
        LOG.warning(format(messageFormat, mensajeExcluido, someDTO.getProperty(), someDTO.getValue()));
    }

    // Or using lambdas
    LOG.warning(() -&gt; {
        final String message = &quot;ERROR: Servicio: %s:%s,\tsomeValue:%s&#39;.&quot;;
        return format(message, mensajeExcluido, someDTO.getProperty(), someDTO.getValue());
    });

    throw new Exception(mensajeExcluido);
}

void example2() throws Exception {
    String mensajeExcluido = System.getProperty(&quot;REGLA.MENSAJE&quot;);
    String mensajeWarn = format(
        // The concatenated message is probably missing a single quote at &#39;someValue&#39;
        &quot;ALERTA: Otro Servicio: %s:%s,\tsomeValue:%s&#39;.&quot;,
        mensajeExcluido,
        someDTO.getProperty(),
        someDTO.getValue()
    );

    LOG.warning(mensajeWarn);

    boolean exclusionVisible = Boolean.parseBoolean(System.getProperty(&quot;EXCLUSION.VISIBLE&quot;));
    String exceptionMessage = exclusionVisible ?
            mensajeExcluido + &quot;&lt;br&gt;&lt;/br&gt;&quot; + mensajeWarn : mensajeExcluido;

    throw new Exception(exceptionMessage);
}

String example3() {
    // You can compose the message only once and use it for the log and the result
    String message =
        format(&quot;No se pudo validar Client Service. Code: %s.&quot;, someDTO.getStatusCode());
    LOG.warning(message);
    return message;
}

huangapple
  • 本文由 发表于 2020年4月8日 07:24:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/61090990.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定