Errors not printing using custom PrintStream even after setting System.setErr() - java

Basically, I wanted console to do 2 things:
I wanted console to color code errors and general info messages (which errors being red and everything else green).
I wanted to save all console messages to a log file.
So, I created a print stream that looked something like this:
public static class GeneralStream extends PrintStream {
public GeneralStream(OutputStream out) {
super(out);
}
#Override
public void println(String string) {
String time = DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalDateTime.now());
String output = "["+time+"] ["+type.n()+"] "+string;
Logs.logToFile(output);
String coloredOutput = ANSI_RESET+ANSI_WHITE+"["+ANSI_CYAN+time+ANSI_WHITE+"] "+
ANSI_WHITE+"["+ANSI_RESET+type.c()+type.n()+ANSI_WHITE+"] "+type.c()+string+ANSI_RESET;
super.println(coloredOutput);
}
}
Great. Then I set this print stream at the start of my program as the default PrintStream using:
// Set console output settings
System.setOut(new Console.GeneralStream(System.out));
System.setErr(new Console.GeneraStream(System.err));
Awesome. Finally, upon doing System.out.println("Hello World"), I get the result I expected. My messages are colored. They are logged to a file. Great! In fact even if I do System.err.println("Error!"), I still get a result as expected. However, "automatic" exceptions do not print through the System.err that I set.
Here is an example:
// Set console output settings
System.setOut(new Console.GeneralStream(System.out));
System.setErr(new Console.ErrorStream(System.err));
System.out.println("Hello world!");
System.err.println("Printing an error!");
// Real exception (NPE)
Integer nullInteger = null;
System.out.println(nullInteger.toString()); // won't print and will produce a NullPointException
Here is the result:
As you can see, my System.out and System.err print fine but as soon as there is a real exception, it prints regularly.
So my question is how can I set a custom PrintStream for errors like this so they are logged to a file (and preferably follow my custom message formating).

If you dig into how the Throwable class prints the stack trace, you'll see it uses the println(Object) method, so you'll need to add this method to your custom ErrorStream class:
#Override
public void println(Object object) {
println(String.valueOf(object));
}
Even then, you may want to change the "uncaught exception handler" to change how it logs exceptions. It seems that the default handler calls first System.err.print to output Exception in thread "{ThreadName}" followed by Throwable.printStackTrace, so you end up with the time stamp and other stuff in the middle of the message. For example:
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
System.err.println("Uncaught exception in thread " + thread.getName());
throwable.printStackTrace(System.err);
});

Related

How to test a print method in Java using Junit [duplicate]

This question already has answers here:
JUnit test for System.out.println()
(14 answers)
Closed 6 years ago.
I have written a method that is printing output to a console. How should I test it?
public class PrinterForConsole implements Printer<Item>{
public void printResult(List<Item> items) {
for (Item item: items){
System.out.println("Name: " + item.getName());
System.out.println("Number: " + item.getNumber());
}
}
}
currently, my test looks like this
public class TestPrinter{
#Test
public void printResultTest() throws Exception {
(am figuring out what to put here)
}
}
I have read the solution at this post (thanks #Codebender and #KDM for highlighting this) but don't quite understand it. How does the solution there test the print(List items) method? Hence, asking it afresh here.
Since you have put you don't get what the duplicate question says, I will try to explain a little.
When you do, System.setOut(OutputStream), whatever the application writes to the console (using System.out.printX()) statements, instead get written to the outputStream you pass.
So, you can do something like,
public void printTest() throws Exception {
ByteArrayOutputStream outContent = new ByteArrayOutputStream();
System.setOut(new PrintStream(outContent));
// After this all System.out.println() statements will come to outContent stream.
// So, you can normally call,
print(items); // I will assume items is already initialized properly.
//Now you have to validate the output. Let's say items had 1 element.
// With name as FirstElement and number as 1.
String expectedOutput = "Name: FirstElement\nNumber: 1" // Notice the \n for new line.
// Do the actual assertion.
assertEquals(expectedOutput, outContent.toString());
}
The best way to test it is by refactoring it to accept a PrintStream as a parameter and you can pass another PrintStream constructed out of ByteArrayOutputStream and check what is printed into the baos.
Otherwise, you can use System.setOut to set your standard output to another stream. You can verify what is written into it after the method returns.
A simplified version with comments is below:
#Test
public void printTest() throws Exception {
// Create our test list of items
ArrayList<Item> items = new ArrayList<Item>();
items.add(new Item("KDM", 1810));
items.add(new Item("Roy", 2010));
// Keep current System.out with us
PrintStream oldOut = System.out;
// Create a ByteArrayOutputStream so that we can get the output
// from the call to print
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// Change System.out to point out to our stream
System.setOut(new PrintStream(baos));
print(items);
// Reset the System.out
System.setOut(oldOut);
// Our baos has the content from the print statement
String output = new String(baos.toByteArray());
// Add some assertions out output
assertTrue(output.contains("Name: KDM"));
assertTrue(output.contains("Name: Roy"));
System.out.println(output);
}
Note that if the print method throws an exception, the System.out is not reset. It is better to use setup and teardown methods to set and reset this.
How about something like this.
#Test
public void printTest() throws Exception {
OutputStream os = new ByteArrayOutputStream();
System.setOut(os);
objectInTest.print(items);
String actualOutput = os.toString("UTF-8");
assertEquals(expectedOutput, actualOutput);
}
This is the Simple Test Code :-
#Test
public void out() {
System.out.print("hello");
assertEquals("helloworld", outContent.toString());
}
#Test
public void err() {
System.err.print("helloworld 1 ");
assertEquals("helloworld 1", errContent.toString());
}
For more :JUnit test for System.out.println()
Eventually, what I came up with is this (after going through all the answers and links to possible duplicates above).
import org.junit.Test;
#Test
public void shouldPrintToConsole() throws Exception {
Item testItem = new Item("Name", "Number");
List<Item> items = Arrays.asList(testItem);
Printer print = new Printer();
printer.printOutput(items);
}
Read up on naming convention (shouldPrintToConsole()) for testing too. Wondering if this is the convention because I see many sites that follow and many that don't.

where I could find documentation on verification methods?

I use Assert class to check if some text is on the page, this command stop test executing if text is not present. I want use verification. Could someone tell where I could find documentation on such methods?
I mean WebDriver, junit. For example such code
String text=("Terms");
List<WebElement> list = driver.findElements(By.xpath("//*[contains(text(),'" + text + "')]"));
Assert.assertEquals("Text not found!", "Terms", list);
If there isn't text "Term" on page junit test will interrupt test, but I need just take error message and continue test.
If you want to continue execution of your test cases even if some some result you are expecting fails and get to see the results at the end of complete execution.
You can do something like this -
Declare a variable to store all the test case results which fail during execution and then in the tearDown method you can call Assert.fail(String message)
StringBuffer errors = new StringBuffer();
#Test
public void testSomething(){
if(!"data".equals(text)){
addErrors(text +"not equal to data");
}
// add any number of if statements to check anything else
}
#After()
public void tearDown(){
if(errors.length()!=0){
Assert.fail(errors.toString());
}
}
public String addErrors(String message){
errors = errors.append(message+"\n");
}
Now in the testSomething() method you can check or test any number of WebElements on the webpage and all you have to do is have a simple if statement to check if some thing is correct and if not then call the addErrors() method. Hope this helps you.
Sounds like you just need to catch and handle AssertionError thrown by the various methods of Assert (documented here). Something like this:
try {
Assert.assertEquals("Text not found!", "Terms", list);
} catch (AssertionError e) {
System.err.println("Assertion failed: " + e.getMessage());
}

How System.out.println('teststring') prints the value on console? which native method is doing the actual job?

I was searching java source code that prints the System.out.println() parameter values on the console. I checked PrintStream, FilterOutputStream and OutputStream classes, none of them have complete implementation of the method nor any reference to native code.
How does the System.out.println value getting printed on the console, which native method is doing the actual job ?
You have to drill down through the decorator-pattern wrappers. At the bottom you'll find FileOutputStream, specifically this method:
private native void writeBytes(byte b[], int off, int len) throws IOException;
Use this code to play with it:
public static void main(String[] args) throws Exception {
nav(nav(System.out));
}
static Object nav(Object o) throws Exception {
final Field[] fs = o.getClass().getSuperclass().getDeclaredFields();
for (Field f : fs) {
f.setAccessible(true);
final Object r = f.get(o);
System.out.println(r);
return r;
}
return null;
}
public static final PrintStream out
The "standard" output stream. This stream is already open and ready to accept output data. Typically this stream corresponds to display output or another output destination specified by the host environment or user.
For simple stand-alone Java applications, a typical way to write a line of output data is:
System.out.println(data)
where:
void println(String x)
Prints a String and then terminates the line.

Access Java Exception Objects's detailed message

I am debugging my application, I have added exception.getMessage() in logger, but exception.getMessage() prints Null, but , when I debug I could see my Exception String in exception object's detailed message, how can I get the exception message that is coming as detailed message? Note - getMessage returns Null.
P.S - I am not using PrintStackTrace or stacktraceElement, my logger should return the string from exception.getmessage(), that is the requirement.
From comment:
DBException dbExe = new DBException(sqlExe);
DBException objDbEx = (DBException) ExceptionUtil.populateSuperException(dbExe, strTraceMesg, ConstantsIF.SEVERE_LEVEL, false, null, null, null);
throw objDbEx;
public static SuperException populateSuperException (SuperException exSuperException, String strTraceMsg, char chTraceLevel, ) {
if (strTraceMsg != null) {
switch (chTraceLevel) {
case Con.IN:
case Con.S:
//log
}
}
return exSuperException;
}
You can print out the full stack trace:
exception.printStackTrace();
Try:
switch (chTraceLevel) {
case Con.IN:
case Con.S:
String msg = exSuperException.getCause().getMessage();
// LOG msg
}
That is pretty strange. The message that you see with debugging is usually created through Throwable#toString and that calls getLocalizedMessage() internally.
So if the exception does have a message, then it should be returned through getMessage() and be part of the toString() result.
An exception/throwable does not need to have a detailed message. Please double check, if you've created your exceptions with a message.
After making your code readable: your DBException is created without a message, so dbExe.getMessage() will return null. Either look the the cause or add a message while creating:
DBException dbExe = new DBException(sqlExe.toString(), sqlExe);// just an example
You are creating your exception object without any message (you're only specifying the chained exception):
DBException dbExe = new DBException(sqlExe);
hence calling dbExe.getMessage() may (correctly) return null (with the details depending on what your constructor does in this situation). The reason you can see a message in the stacktrace, incidentally, is because the generation of the stacktrace recurses to the underlying exception, and sqlExe.getMessage() will be what you're seeing.
The solution is simply to provide a message as well as the underlying exception when constructing your exception. The general wisdom is that this should reflect the level at which the exception is thrown, so perhaps something like the following:
DBException dbExe = new DBException("Unable to persist widgets", sqlExe);
If your unspecified "requirement about the existing code flow" means that you need the actual database exception to be the message in dbExe, you could construct this like the following:
DBException dbExe = new DBException(sqlExe.getMessage(), sqlExe);
though on the whole that duplication of the message isn't very nice, and the former option is the more "correct" one.
From the discussion in the comments, it is my conclusion that the root cause of your problem is in the implementation of the DBException constructor or its hierarchy. For a valid reason or not, I think it's not calling the exception class hierarchy (e.g. super(reason);) and therefore, you are not getting the expected behaviour from the call to dbException.getMessage(). Note that a call to new Exception(anotherException) will always populate the field backing the getMessage() call in the base Throwable class through this call chain: (only relevant bits shown)
public Throwable(Throwable cause) {
...
detailMessage = (cause==null ? null : cause.toString());
...
}
public String toString() {
...
String message = getLocalizedMessage();
...
}
public String getLocalizedMessage() {
return getMessage();
}
Check the implementation of DBException as the root cause of the problem discussed.

Hide Java Output

I am using an external library. When a call a method of this library then it outputs some text on console. I want to hide this text from console. How is it possible?
Thanks in Advance
You can redefine system.out (I believe it is System.setOut()) I believe you can set it to NULL (Corrected--you can NOT set it to NULL), but you can set it to ANY output stream.
I did something interesting with this once. I saved "System.out" then redirected it to my own output stream with code in the "print" method--that method is called whenever anyone prints to the stream.
Every time a line of input came in to this class, I'd create a stack trace, grab the trace and dig down to the method that called the System.out.println() method. At this point I could prepend the line and have instant logger functionality--it even shows the line number.
This was probably quite slow but it could be turned on and off very easily.
I could also do all the filtering you'd like without touching the source code. Sometimes I'd filter on a single package, sometimes I'd filter on a class and sometimes it would be strings starting with "BK:" which would only print out my messages.
Overall it was a lot of fun and trivial to remove ALL debug output for production.
(I do not recommend the get stack trace thing for production code, it really should be quite slow even though I didn't notice it)
// class variable
public static final OutputStream out;
{
out=System.getOutputStream();// I may have the actual name wrong, but it's close
System.setOutputStream(new OutputStreamThatDoesNothing());
}
at this point any calls to:
Redirect.out("Hello");
Should act just as calls to System.out did.
Since there is no magic with this, you can also do something like this if you really want to:
OutputStream tmp=System.getOutputStream();
System.setOutpuatStream(nullStream);
callOffensiveLibraryMethod();
System.setOutputStream(tmp);
This would only eliminate output within that call BUT would be Very Bad if your application was multi-threaded.
private PrintStream realSystemOut = System.out;
private static class NullOutputStream extends OutputStream {
#Override
public void write(int b){
return;
}
#Override
public void write(byte[] b){
return;
}
#Override
public void write(byte[] b, int off, int len){
return;
}
public NullOutputStream(){
}
}
void someMethod(){
System.setOut(new PrintStream(new NullOutputStream());
realSystemOut.println("Hello World!"); //prints Hello World!
System.out.println("Hello World!"); //nothing!
System.setOut(realSystemOut);
System.out.println("Hello World!"); //prints Hello World!
}
For those looking for a 2020 version that also does not require external libraries for the null stream:
PrintStream out = System.out;
System.setOut(new PrintStream(OutputStream.nullOutputStream()));
//
//do stuff with library...
//
System.setOut(out);
Available since Java 11.
Set the System.out to a NullOutputStream. apacahe.commons has one available.
If you want to print it out accordingly you could write a fun hack.
private static final PrintStream SYSTEM_OUT = System.out();
public static void debug(String debug){
SYSTEM_OUT.println(debug);
}
Somehwere else in the code
System.setOut(new PrintStream(new NullOutputStream()));

Categories

Resources