繁体   English   中英

不要在服务器端代码中使用System.out.println

[英]Do not use System.out.println in server side code

我听说使用System.out.println进行日志记录是一种非常糟糕的做法,这可能会迫使服务器失败。

我不使用这种方法,但我非常有兴趣知道为什么System.out.println在后端代码中使用时会产生垃圾。

System.out.println是一个IO操作,因此非常耗时。 在代码中使用它的问题是,程序将等到println完成。 对于小型网站来说这可能不是问题,但是只要你加载或多次迭代,你就会感受到痛苦。

更好的方法是使用日志框架。 它们使用消息队列并仅在没有其他输出的情况下写入。

另一个好处是您可以为不同目的配置单独的日志文件。 你的Ops团队会爱你的东西。

在这里阅读更多:

查看关于压力测试JEE6应用程序的Java杂志11月/ Dezember的Adam Biens 文章 - 它是免费在线的 ,你只需订阅它。

在第43页上,他显示,当插入单个System.out.println并在每个事件中添加了修复字符串时,设法处理每秒1700个事务的服务器应用程序仅降至800。

这是一种不好的做法,因为当您的应用程序进入生产时,您无法将应用程序日志与服务器日志分开。

Prod团队希望您将应用程序生成的日志与应用程序服务器(tomcat,websphere等)中生成的日志分开:他们希望能够从应用程序本身监视应用程序服务器。

而且,使用System.out,您无法定义日志级别:在生产中,您不希望打印调试信息。

它被认为是坏的,因为System.out.println(); 吃更多的CPU,因此输出变慢意味着损害性能。 (实际上每个I / O操作都会占用cpu)。

原因不是服务器可能会失败,但可能很难在服务器上找到这样的输出。 您应该始终使用某种带有已定义行为和输出文件的日志记录框架。

  1. 程序将一直等到println完成。 记录器仅在没有其他输出的情况下使用消息队列并进行写入。
  2. System.out.println(SOP)不是线程安全的(即异步)记录器是线程安全的(即同步)
  3. 记录器是高度可配置a. 格式化,限制记录器可实现的日志内容b. 多个目标logging -file,console,DB
  4. SOP将日志写入服务器日志文件。 我们需要将应用程序日志与服务器日志分开,因为它可能导致服务器故障
  5. 当插入每个具有修复字符串的单个SOP时,设法每秒处理1700个事务的服务器应用程序降至仅800

首先,有多个请求命中您的服务器并在System.out上打印日志不是一个好习惯。

  1. 所有日志都打印在屏幕上(文件描述符)。 没有办法向后滚动并阅读日志。
  2. System.out未同步。 必须有并发管理才能通过System.out管理打印
  3. 您无法通过System.out确定日志级别。 您无法动态将日志级别分离为单独的输出。

我希望这有帮助。

另一个原因是System.out和err是PrintStreams,它们消耗所有底层IOExceptions。 请参阅PrintStreams的这种方法:

/**
 * Writes the specified byte to this stream.  If the byte is a newline and
 * automatic flushing is enabled then the <code>flush</code> method will be
 * invoked.
 *
 * <p> Note that the byte is written as given; to write a character that
 * will be translated according to the platform's default character
 * encoding, use the <code>print(char)</code> or <code>println(char)</code>
 * methods.
 *
 * @param  b  The byte to be written
 * @see #print(char)
 * @see #println(char)
 */
public void write(int b) {
    try {
        synchronized (this) {
            ensureOpen();
            out.write(b);
            if ((b == '\n') && autoFlush)
                out.flush();
        }
    }
    catch (InterruptedIOException x) {
        Thread.currentThread().interrupt();
    }
    catch (IOException x) {
        trouble = true;
    }
}

/**
 * Flushes the stream and checks its error state. The internal error state
 * is set to <code>true</code> when the underlying output stream throws an
 * <code>IOException</code> other than <code>InterruptedIOException</code>,
 * and when the <code>setError</code> method is invoked.  If an operation
 * on the underlying output stream throws an
 * <code>InterruptedIOException</code>, then the <code>PrintStream</code>
 * converts the exception back into an interrupt by doing:
 * <pre>
 *     Thread.currentThread().interrupt();
 * </pre>
 * or the equivalent.
 *
 * @return <code>true</code> if and only if this stream has encountered an
 *         <code>IOException</code> other than
 *         <code>InterruptedIOException</code>, or the
 *         <code>setError</code> method has been invoked
 */
public boolean checkError() {
    if (out != null)
        flush();
    if (out instanceof java.io.PrintStream) {
        PrintStream ps = (PrintStream) out;
        return ps.checkError();
    }
    return trouble;
}

因此,总是消耗来自底层流的IOException,并且通常人们从不在System out上调用checkError,因此他们甚至不知道发生了什么。

使用标准输出是不好的做法。 但是,如果您有一个库或使用System.out和System.err的代码,您可以编写自己的PrintStream,它会记录线程名称和info()以及error()文本。 完成此操作后,您可能会更放松地使用System.out,因为它会写入日志,例如log4j。

理想情况下,您将直接使用正确的日志esp进行调试级别日志记录。 恕我直言,如果你不使用内置的System.out / err,它就没那么重要了! (一个很大的假设)

无论您使用重定向到文件的System.out还是使用log4j或Java Logger写入文件,性能几乎都是一样的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM