简体   繁体   English

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

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

I heard that using System.out.println for logging purposes is a very bad practice and this may force the server to fail. 我听说使用System.out.println进行日志记录是一种非常糟糕的做法,这可能会迫使服务器失败。

I don't use this approach but I am very interested in knowing why System.out.println could make so trash things when used in backend code. 我不使用这种方法,但我非常有兴趣知道为什么System.out.println在后端代码中使用时会产生垃圾。

System.out.println is an IO-operation and therefor is time consuming. System.out.println是一个IO操作,因此非常耗时。 The Problem with using it in your code is, that your program will wait until the println has finished. 在代码中使用它的问题是,程序将等到println完成。 This may not be a problem with small sites but as soon as you get load or many iterations, you'll feel the pain. 对于小型网站来说这可能不是问题,但是只要你加载或多次迭代,你就会感受到痛苦。

The better approach is to use a logging framework. 更好的方法是使用日志框架。 They use a message queue and write only if no other output is going on. 它们使用消息队列并仅在没有其他输出的情况下写入。

And another benefit is that you can configure separate log files for different purposes. 另一个好处是您可以为不同目的配置单独的日志文件。 Something your Ops team will love you for. 你的Ops团队会爱你的东西。

Read more here: 在这里阅读更多:

Check out Adam Biens article in the Java Magazine edition November/Dezember about stress testing JEE6 applications - it's free online , you only have to subscribe to it. 查看关于压力测试JEE6应用程序的Java杂志11月/ Dezember的Adam Biens 文章 - 它是免费在线的 ,你只需订阅它。

On page 43 he shows, that a server applications which manages to handle 1700 transactions per second falls down to only 800 when inserting a single System.out.println with fix String in each. 在第43页上,他显示,当插入单个System.out.println并在每个事件中添加了修复字符串时,设法处理每秒1700个事务的服务器应用程序仅降至800。

It's a bad practice because when your application goes in Production, you can't separate application logs from server logs. 这是一种不好的做法,因为当您的应用程序进入生产时,您无法将应用程序日志与服务器日志分开。

Prod teams want that you separate logs produced by your application from the ones from the app server (tomcat, websphere, etc...) : they want to be able to monitor the app server diffrently from the application itself. Prod团队希望您将应用程序生成的日志与应用程序服务器(tomcat,websphere等)中生成的日志分开:他们希望能够从应用程序本身监视应用程序服务器。

Moreover, using System.out, you can't define the log level : in Production, you don't want to print debug information. 而且,使用System.out,您无法定义日志级别:在生产中,您不希望打印调试信息。

It is considered to be bad because System.out.println(); 它被认为是坏的,因为System.out.println(); eats more cpu and thus output comes slow means hurts the performance. 吃更多的CPU,因此输出变慢意味着损害性能。 (Actually every I/O operation eats cpu). (实际上每个I / O操作都会占用cpu)。

The reason is not that the server might fail but it might be hard to find such output on the server. 原因不是服务器可能会失败,但可能很难在服务器上找到这样的输出。 You should always use some kind of logging framework with a defined behaviour and output file. 您应该始终使用某种带有已定义行为和输出文件的日志记录框架。

  1. Program will wait until the println has finished. 程序将一直等到println完成。 Loggers use message queue and write only if no other output is going on. 记录器仅在没有其他输出的情况下使用消息队列并进行写入。
  2. System.out.println (SOPs) are not thread safe (ie asynchronous) Loggers are thread safe (ie synchronous) System.out.println(SOP)不是线程安全的(即异步)记录器是线程安全的(即同步)
  3. Loggers are highly configurable a. 记录器是高度可配置a. Formatting, Limiting log content achievable by loggers b. 格式化,限制记录器可实现的日志内容b. Multiple destination logging –file, console, DB 多个目标logging -file,console,DB
  4. SOPs write logs into Server log files. SOP将日志写入服务器日志文件。 We need to keep application logs separate from Server logs as it may lead to Server Failure 我们需要将应用程序日志与服务器日志分开,因为它可能导致服务器故障
  5. Server applications which manages to handle 1700 transactions per second falls down to only 800 when inserting a single SOPs with fix String in each 当插入每个具有修复字符串的单个SOP时,设法每秒处理1700个事务的服务器应用程序降至仅800

For one, having multiple requests hitting your server and printing the log on System.out isn't good practice. 首先,有多个请求命中您的服务器并在System.out上打印日志不是一个好习惯。

  1. All the logs gets printed on screen (file descriptor). 所有日志都打印在屏幕上(文件描述符)。 There's no way to scroll back and read the log. 没有办法向后滚动并阅读日志。
  2. System.out isn't synchronized. System.out未同步。 There must be a concurrency management to manage printing via System.out 必须有并发管理才能通过System.out管理打印
  3. You can't determine log levels through System.out . 您无法通过System.out确定日志级别。 You can't separate your log levels to separate outputs on the fly. 您无法动态将日志级别分离为单独的输出。

I hope this helps. 我希望这有帮助。

One more reason is that System.out and err are PrintStreams, which are consuming all underlying IOExceptions. 另一个原因是System.out和err是PrintStreams,它们消耗所有底层IOExceptions。 See this methods of PrintStreams: 请参阅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;
}

So an IOException from the underlying stream is ALWAYS consumed, and usually the people never call checkError on System out, so they are not even knowing that something happened. 因此,总是消耗来自底层流的IOException,并且通常人们从不在System out上调用checkError,因此他们甚至不知道发生了什么。

Using standard out is bad practice. 使用标准输出是不好的做法。 However if you have a library, or code which uses System.out and System.err you can write your own PrintStream which logs the thread name and info() and error() the text instead. 但是,如果您有一个库或使用System.out和System.err的代码,您可以编写自己的PrintStream,它会记录线程名称和info()以及error()文本。 Once you have done this, you may be more relaxed about using System.out as it will write to the logs eg log4j. 完成此操作后,您可能会更放松地使用System.out,因为它会写入日志,例如log4j。

Ideally you will use the proper logs directly esp for debug level logging. 理想情况下,您将直接使用正确的日志esp进行调试级别日志记录。 IMHO its doesn't have to matter that much, provided you don use the built-in System.out/err! 恕我直言,如果你不使用内置的System.out / err,它就没那么重要了! (A big assumption admittedly) (一个很大的假设)

Whether you use System.out which is re-directed to a file or use log4j or Java Logger to write to a file, the performance is almost exactly the same. 无论您使用重定向到文件的System.out还是使用log4j或Java Logger写入文件,性能几乎都是一样的。

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

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