Java 不要在服务器端代码中使用System.out.println
我听说使用Java 不要在服务器端代码中使用System.out.println,java,logging,backend,Java,Logging,Backend,我听说使用System.out.println进行日志记录是一种非常糟糕的做法,这可能会迫使服务器失败 我不使用这种方法,但我很想知道为什么System.out.println在后端代码中使用时会造成如此多的垃圾。这被认为是不好的,因为System.out.println()消耗了更多的cpu,因此输出速度变慢意味着会影响性能。(实际上,每个I/O操作都会消耗cpu)。这是一种不好的做法,因为当应用程序投入生产时,无法将应用程序日志与服务器日志分开 Prod团队希望您将应用程序生成的日志与来自应
System.out.println
进行日志记录是一种非常糟糕的做法,这可能会迫使服务器失败
我不使用这种方法,但我很想知道为什么System.out.println在后端代码中使用时会造成如此多的垃圾。这被认为是不好的,因为
System.out.println()代码>消耗了更多的cpu,因此输出速度变慢意味着会影响性能。(实际上,每个I/O操作都会消耗cpu)。这是一种不好的做法,因为当应用程序投入生产时,无法将应用程序日志与服务器日志分开
Prod团队希望您将应用程序生成的日志与来自应用程序服务器(tomcat、websphere等)的日志分开:他们希望能够以不同于应用程序本身的方式监控应用程序服务器
此外,使用System.out,您无法定义日志级别:在生产环境中,您不想打印调试信息。原因不是服务器可能出现故障,而是在服务器上很难找到此类输出。您应该始终使用某种具有定义行为和输出文件的日志框架。例如,让多个请求命中您的服务器并在系统上打印日志。out
不是好做法
所有日志都打印在屏幕上(文件描述符)。没有办法向后滚动并读取日志
System.out
未同步。必须有并发管理才能通过System.out
您无法通过System.out
确定日志级别。您不能在运行时将日志级别分隔为单独的输出
我希望这会有所帮助。System.out.println是一个IO操作,因此非常耗时。
在代码中使用它的问题是,程序将等待println完成。对于小型站点来说,这可能不是问题,但一旦您获得负载或多次迭代,您就会感到痛苦
更好的方法是使用日志框架。
它们使用消息队列,并且仅在没有其他输出进行时写入
另一个好处是,您可以为不同的目的配置单独的日志文件。
你的行动团队会喜欢你的
在此处阅读更多信息:
查看Java杂志11月/12月版中关于压力测试JEE6应用程序的Adam Biens-它是免费的,您只需订阅即可
在第43页,他指出,当插入单个System.out.println
时,一个每秒处理1700个事务的服务器应用程序下降到只有800个,每个应用程序中都有固定字符串。使用标准输出是一种不好的做法。但是,如果您有一个库,或者代码使用System.out和System.err,那么您可以编写自己的PrintStream,它记录线程名称和info(),而error()记录文本。完成此操作后,您可能会更轻松地使用System.out,因为它将写入日志,例如log4j
理想情况下,您将直接使用适当的日志进行调试级日志记录。如果你不使用内置的System.out/err,那么它就没有那么重要了!(无可否认,这是一个很大的假设)
无论您使用重新定向到文件的System.out,还是使用log4j或Java Logger写入文件,性能几乎完全相同。另一个原因是System.out和err是打印流,它们消耗所有底层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;
}
*或同等标准。
*
*@returntrue
当且仅当此流遇到
*IOException
除了
*中断异常
,或
*setError
方法已被调用
*/
公共布尔校验错误(){
if(out!=null)
冲洗();
if(out instanceof java.io.PrintStream){
打印流ps=(打印流)输出;
返回ps.checkError();
}
返回故障;
}
因此,底层流中的IOException总是被使用,而且通常人们从不在System out上调用checkError,所以他们甚至不知道发生了什么事情
a.
格式化,限制日志记录者可获得的日志内容
b.
多目标日志记录–文件、控制台、数据库我相信这个问题(或其背后的原理)比答案要有趣得多。关于第一点:很容易将输出重定向到一个文件,以便您可以滚动任何您想要的内容。这是如果您从控制台进行管道传输,但这是资源密集型的。通常主要问题不是CPU使用情况,而是I/O使用情况,事实上,
System.out.println
与Java(以及大多数其他环境)中的大多数I/O调用一样。这会完全扼杀吞吐量。