寻找代码中system.out.println的位置

6

假设我正在开发一个非常大的项目,我注意到有一行空白打印,因此我猜测在代码中有一个System.out.println("");。除了搜索整个项目中所有的System.out.println出现位置之外,我该如何找出它的实际位置呢?


1
在整个项目中进行 System.out.println 的搜索...你是否在使用像 Eclipse 这样的 IDE? - ErstwhileIII
我是,但我正在尝试找出更好的方法,因为这种情况似乎经常发生,并且代码库中有大量的syso。 - Lexxicon
听起来你需要一个项目范围的“调试”机制..并且你想要完全删除System.out.println(在你实现的“调试”类或“输出”类之外)。 - ErstwhileIII
6个回答

6
如果您正在使用Java 8+,则Durian有一个StackDumper类,可以轻松找到打印给定行的位置。
StackDumper.dumpWhenSysOutContains("SomeTrigger")

当打印出“SomeTrigger”时,这将被转储到System.err中:
+----------\
| Triggered by SomeTrigger
| at package.MyClass.myMethod(MyClass.java:62)
| (the rest of the stacktrace)
+----------/

针对您的情况(寻找空字符串),它会稍微复杂一些:
PrintStream sysOutClean = System.out;
StringPrinter sysOutReplacement = new StringPrinter(StringPrinter.stringsToLines(line -> {
    if (line.isEmpty()) {
        StackDumper.dump("Found empty line");
    }
    sysOutClean.println(line);
}));
System.setOut(sysOutReplacement.toPrintStream());

现在如果有这样的东西:
System.out.println("ABC");
System.out.println("123");
System.out.println("");
System.out.println("DEF");

然后你的控制台会看起来像这样:
ABC
123
+----------\
| Found empty line
| at package.MyClass.myMethod(MyClass.java:62)
| (the rest of the stacktrace)
+----------/

DEF

1
这对于查找其他人不必要添加的打印行并且没有任何我可以搜索的文本(只传递了一个对象toString)非常有效。无耻地插入一下,我如何在不使用Maven的情况下使用Durian:http://stackoverflow.com/questions/37171460/use-maven-library-without-drinking-maven-koolaid/37171461#37171461 - Eric

5
您可以实现自己的PrintStream并使用System.setOut替换默认的标准输出。然后,如果打印了空字符串,请在类中放置调试标记,或通过调用堆栈打印出方法名称(抛出和捕获异常并获取堆栈信息)。

有没有一种方法可以在不抛出异常的情况下获取它? - Lexxicon
异常只是用来获取堆栈跟踪信息的(虽然应该有更直接的方法来获取它)。 - Kayaman
这里介绍了一种不需要异常的方法。谢谢! - Lexxicon

2

例子:

/** Control sysout prints */
public static void main(String[] arg) throws Exception {
     System.out.println("Default"); //print normally

     SysOutController.setSysOutLocationAddressor();
     System.out.println("With Address"); //prints with calling location, and on click location cursor directly focus when System.out.**() called

     SysOutController.ignoreSysout();
     System.out.println("Ignored"); //this line will never prints

     SysOutController.resetSysOut();
     System.out.println("Default"); //print normally as it is (reset)
}

只需调用以下类的方法,即可帮助开发人员控制sysout。
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;

/** 
 * Class which controls System.out prints in console <br/>
 * this class will helps developers to control prints in console
 * @implSpec
 * <pre><code>
 * System.out.println("Default"); //print normally
 * 
 * SysOutController.setSysOutLocationAddressor();
 * System.out.println("With Address"); //prints with calling location
 * 
 * SysOutController.ignoreSysout();
 * System.out.println("Ignored"); //this line will never prints
 * 
 * SysOutController.resetSysOut();
 * System.out.println("Default"); //print normally as it is (reset)
 * </code></pre>
 * @author Dharmendrasinh Chudasama
 */
public class SysOutController {

    private static void setOut(OutputStream out){
        System.setOut(new PrintStream(out));
    }

    private static final OutputStream CONSOLE = new FileOutputStream(FileDescriptor.out);

    /**
     * Reset System.out.print* method
     * @author Dharmendrasinh Chudasama
     */
    public static void resetSysOut() { setOut(CONSOLE); }

    /**
     * System.out.print* will not print anything in console
     * @author Dharmendrasinh Chudasama
     */
    public static void ignoreSysout() {
        setOut(new OutputStream() {
            @Override public void write(int b) throws IOException {}
        });
    }

    /**
     * Address/location of calling System.out.* method will append in console
     * @author Dharmendrasinh Chudasama
     */
    public static void setSysOutLocationAddressor() {
        setOut(new OutputStream() {
            @Override
            public void write(int b) throws IOException {
                if(b=='\n'){ //if newLine
                    final StackTraceElement callerStEl = new Throwable().getStackTrace()[9];
                    String pathData =
                        "\u001B[37m"    //low-visibality
                        + "\t :: ("+callerStEl.getFileName()+":"+callerStEl.getLineNumber()+") ["+callerStEl+"]"  //code path
                        + "\u001B[0m ";  //reset
                    CONSOLE.write(pathData.getBytes());

                }

                CONSOLE.write(b);
            }
        });
    }
}

1
这可能是由于某些库的原因,如果您认为这仅是由于System.out.println,则可以尝试以下解决方案之一: 解决方案1: 下面的代码片段应该能帮助您找到它执行的位置。
        import java.io.FileNotFoundException;
        import java.io.PrintStream;

        public class CustomPrintStream extends PrintStream {

        public CustomPrintStream(String fileName) throws FileNotFoundException {
            super(fileName);
        }

            @Override
            public void print(String s) {

                try{
                    if(s == null || s.equals("")){
                        throw new Exception("Invalid print message");
                    }
                    super.print(s);
                }catch(Exception e){
                    //TODO Change to your logger framework and leave it as same 
                    e.printStackTrace();
                }
            }

            public static void main(String[] args) {
                try {
 //TODO : Change to your favorite path and make sure mentioned
//file is available
                    CustomPrintStream customPrintStream = new CustomPrintStream
    ("/home/prem/Desktop/test.log");
                    System.setOut(customPrintStream);
                    System.out.println("");

                } catch (FileNotFoundException e) {
                    //TODO Change to your logger framework and leave it as same 
                    e.printStackTrace();
                }
            }
        }

解决方案2: 由于有IDE可用,请从中获取帮助。如果您使用的是eclipse 菜单 -> 搜索 - > 文件搜索-> 将System.out.println("");放在包含搜索中并搜索。

我宁愿说不要在任何代码中使用System.out.println,您可以使用checkstyle并确信以后没有开发人员使用它们。


0

定义一个类NewPrintStream,继承自PrintStream

import java.io.FileNotFoundException;
import java.io.PrintStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class NewPrintStream extends PrintStream {
  private static final Logger LOGGER = LoggerFactory.getLogger(NewPrintStream.class);

  public NewPrintStream(String fileName) throws FileNotFoundException {
    super(fileName);
  }

  @Override
  public void println(String x) {
    LOGGER.info("xxxxxxx", new Exception("xxxx"));
  }
}

然后在主类中设置标准输出/错误打印流

System.setOut(new NewPrintStream("aaa"));
System.setErr(new NewPrintStream("aaa"));

0
PrintStream.println(String x)中设置一个条件断点,条件为x.equals("")或者你的字符串可能是什么。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接