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

我听说使用System.out.println进行logging是非常糟糕的做法,这可能会强制服务器失败。

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

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

更好的方法是使用日志框架。 它们使用消息队列,只有在没有其他输出正在进行时才写入。

另一个好处是你可以为不同的目的configuration不同的日志文件。 你的行动团队会爱你的东西。

在这里阅读更多:

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

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

此外,使用System.out,您不能定义日志级别:在生产中,您不想打印debugging信息。

请参阅Java杂志11月/ 12月的Adam Biens关于压力testingJEE6应用程序的文章 – 它是免费的在线 ,您只需订阅它。

他在第43页上显示,每次插入带有固定string的单个System.out.println时,每秒处理1700个事务的服务器应用程序只有800个。

它被认为是坏的,因为System.out.println(); 吃更多的CPU,从而输出速度慢意味着伤害性能。 (实际上每个I / O操作吃cpu)。

原因不是服务器可能会失败,但可能很难在服务器上find这样的输出。 您应该总是使用某种具有定义的行为和输出文件的日志框架。

例如,有多个请求打到你的服务器上,并在System.out上打印日志不是很好的做法。

  1. 所有日志都打印在屏幕上(文件描述符)。 没有办法回滚并阅读日志。
  2. System.out不同步。 必须有一个并发pipe理来通过System.out来pipe理打印
  3. 您无法通过System.out来确定日志级别。 您不能将您的日志级别分开运行,以单独的输出。

我希望这有帮助。

  1. 程序将等到println完成。 logging器使用消息队列,只有在没有其他输出正在进行时才写入。
  2. System.out.println(SOPs)不是线程安全的(即asynchronous的)logging器是线程安全的(即同步的)
  3. logging器是高度可configurationa. 格式化,限制日志logging器可以实现的日志内容b. 多个目标日志logging文件,控制台,数据库
  4. SOP将日志写入服务器日志文件。 我们需要将应用程序日志与服务器日志分开,否则可能会导致服务器故障
  5. 当每个插入一个带有固定string的单个SOP时,每秒处理1700个事务的服务器应用程序只能降到800个

还有一个原因是System.out和err是PrintStreams,它们正在消耗所有底层的IOException。 看到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; } 

因此,底层stream的IOException总是被占用,通常人们从不在系统调用checkError,所以他们甚至不知道发生了什么事情。

使用标准是不好的做法。 但是,如果你有一个库,或者使用System.out和System.err的代码,你可以编写自己的PrintStream来代替线程名和info()和error()。 一旦你这样做了,你可能会更放松使用System.out,因为它会写入日志,例如log4j。

理想情况下,您将直接使用适当的日志来进行debugging级别的日志logging。 恕我直言,它不必重要,只要你不使用内置的System.out / err! (承认一个大的假设)

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