不要在服务器端代码中使用System.out.println
我听说使用System.out.println
进行logging是非常糟糕的做法,这可能会强制服务器失败。
我不使用这种方法,但我非常有兴趣知道为什么System.out.println在后端代码中使用时可能会产生垃圾。
System.out.println是一个IO操作,因此非常耗时。 在你的代码中使用它的问题是,你的程序将等到println完成。 这可能不是一个小网站的问题,但只要你得到负载或许多迭代,你会感到痛苦。
更好的方法是使用日志框架。 它们使用消息队列,只有在没有其他输出正在进行时才写入。
另一个好处是你可以为不同的目的configuration不同的日志文件。 你的行动团队会爱你的东西。
在这里阅读更多:
- http://logging.apache.org/log4j/1.2/manual.html
- logging器与System.out.println
这是一个不好的做法,因为当您的应用程序进入生产时,您不能将应用程序日志与服务器日志分开。
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
上打印日志不是很好的做法。
- 所有日志都打印在屏幕上(文件描述符)。 没有办法回滚并阅读日志。
-
System.out
不同步。 必须有一个并发pipe理来通过System.out
来pipe理打印 - 您无法通过
System.out
来确定日志级别。 您不能将您的日志级别分开运行,以单独的输出。
我希望这有帮助。
- 程序将等到println完成。 logging器使用消息队列,只有在没有其他输出正在进行时才写入。
- System.out.println(SOPs)不是线程安全的(即asynchronous的)logging器是线程安全的(即同步的)
- logging器是高度可configuration
a.
格式化,限制日志logging器可以实现的日志内容b.
多个目标日志logging文件,控制台,数据库 - SOP将日志写入服务器日志文件。 我们需要将应用程序日志与服务器日志分开,否则可能会导致服务器故障
- 当每个插入一个带有固定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写入文件,性能几乎都是一样的。