#Writing any thrown/runtime exception to a '.log' file

82 messages · Page 1 of 1 (latest)

median dagger
#

I have created my own logging class for handling writes to a ".log" file and want to print out any exceptions that are thrown outside my own "try-catch" statements or throw new calls. For example, if an image file in specified URL is not found, it throws a NullPointerExceptionat runtime, which is not handled by me, but by Java itself.

I want to log those runtime exceptions to my logfile, but it does not seem to write them (or perhaps recognise them)

Here is the code to my method that writes to a log file:

  public void writeLog(String message, Throwable t) {
    File logDirectory = FileHelper.createDirectory(FileHelper.workingDirectory, "logs");
    File logFile = new File(logDirectory, this.logFileName);
    if (!logFile.exists()) {
      try {
        boolean created = logFile.createNewFile();
        if (!created) {
          throw new IOException("Failed to create log file");
        }
      } catch (IOException ioe) {
        ioe.printStackTrace();
      }
    }

    try (FileWriter fw = new FileWriter(logFile, true)) {
      if (!this.isSystemMessageWritten(logFile)) {
        this.writeSystemMessage(fw);
      }
      fw.write(String.format("%s%n", message));

      try (PrintWriter pw = new PrintWriter(fw)) {
        t.printStackTrace(pw);
      }
    } catch (IOException ioe) {
      ioe.printStackTrace();
    }
  }
upper stirrupBOT
#

This post has been reserved for your question.

Hey @median dagger! Please use /close or the Close Post button above when you're finished. Please remember to follow the help guidelines. This post will be automatically closed after 300 minutes of inactivity.

TIP: Narrow down your issue to simple and precise questions to maximize the chance that others will reply in here.

median dagger
#

For testing purposes, I decided to intentionally set the wrong filename for the following method:

  public static Image readImageFile(Class<?> clazz, String name) {
    try {
      URL input = clazz.getClassLoader().getResource(name);
      Objects.requireNonNull(input, "input == null!");
      return ImageIO.read(input);
    } catch (IOException ioe) {
      LoggerHelper.logError("Failed to read image", ioe, true);
      return new ImageIcon(new byte[768]).getImage();
    }
  }
#

And so when I run the application through a debugger, I get this:

[main] INFO ee.twentyten.config.LauncherConfig - load: "C:\Users\Kasutaja\AppData\Roaming\.twentyten\twentyten.properties"
[main] INFO ee.twentyten.request.HttpsConnectionResponse - getJsonResponse: 204 No Content (https://authserver.mojang.com/validate)
[main] INFO com.mojang.util.YggdrasilHelper - validate: {}
Exception in thread "AWT-EventQueue-0" Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException: input == null!
    at java.util.Objects.requireNonNull(Objects.java:226)
    at ee.twentyten.util.FileHelper.readImageFile(FileHelper.java:34)
    at ee.twentyten.ui.LauncherFrame.<init>(LauncherFrame.java:52)
    at ee.twentyten.ui.LauncherFrame$2.run(LauncherFrame.java:114)
    at java.awt.event.InvocationEvent.dispatch$$$capture(InvocationEvent.java:312)<14 internal lines>
#

but it doesn't log the exception

south knot
#

Why not add a second catch block for a generic exception and log it there?

median dagger
#

this is outside a catch block though

#

this is the JVM runtime exception

south knot
#

You can still catch null pointer exceptions

median dagger
#

yeah, but what if some other runtime exception happens?

#

i can't just manually try adding each and every one of 'em

#

that produces boilerplate

#

i'm already handling various try-catch exceptions manually.

#

runtime should be based on whichever is being thrown

south knot
#

all exceptions (usually) are a subclass of Exception (or getting even more generic, Throwable) so a single catch block for exception handles every single kind of exception

median dagger
#

ooooooooooooooh

#

hmmmm

south knot
#

So if there’s any specific exceptions you care about, you can catch those, and then have a catch Exception at the end as a catch all.

median dagger
#

i have caught any exception i could think of that is needed in any of my try-catch statements

#

i have yet to test if those work

#

but the runtime ones i can't seem to figure out

south knot
#

It’s not super best practice, since someone reading your code might not know what exceptions to expect, but it’ll work.

#

All runtime exceptions extend RuntimeExceptiom, so same basic principle

median dagger
#

For example, this code manually handles these:

  public static void setLookAndFeel() {
    try {
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    } catch (UnsupportedLookAndFeelException ulafe) {
      LoggerHelper.logError(ulafe.getMessage(), ulafe, true);
    } catch (ClassNotFoundException cnfe) {
      LoggerHelper.logError("Can't find look and feel class", cnfe, true);
    } catch (InstantiationException ie) {
      LoggerHelper.logError("Can't instantiate look and feel class", ie, true);
    } catch (IllegalAccessException iae) {
      LoggerHelper.logError("Can't access look and feel class", iae, true);
    }
  }

I have yet to try if manual try-catch variants work, but that's beside the main problem

#

i need a way to report any thrown exception that's outside my control (e.g. JVM runtime)

#

and write it onto the file

south knot
#

If you want to handle an exception, it needs to be in a try catch

median dagger
#

my logger takes a throwable

south knot
#

But it works it’s way up the stack trace

median dagger
#

so "exception instanceof throwable" ?

south knot
#

Exceptions are Throwable

median dagger
#

ah

south knot
#

It might be worth looking a bit into inheritance and how to use the java api documentation, since it’ll help you solve similar problems a bit better.

median dagger
#

well, it seems that wrapping anything in my main class in a throwable does not work

south knot
#

Wrapping with a throwable?

median dagger
#

try-catch and catch a Throwable

south knot
#

That’s weird. You should be able to catch a throwable

#

What’s your syntax?

median dagger
#

I don't get it

#

what syntax?

south knot
#

What’s your code

median dagger
#

where?

south knot
#

Main

median dagger
#
  public static void main(String[] args) {
    if (RuntimeHelper.MAX_MEMORY < RuntimeHelper.MIN_MEMORY) {
      List<String> arguments = new ArrayList<>();
      arguments.add(EPlatform.getPlatform() == EPlatform.WINDOWS ? "javaw" : "java");
      arguments.add("-Xmx1024m");
      arguments.add("-Dsun.java2d.d3d=false");
      arguments.add("-Dsun.java2d.opengl=false");
      arguments.add("-Dsun.java2d.pmoffscreen=false");
      arguments.add("-cp");
      arguments.add(System.getProperty("java.class.path"));
      arguments.add(String.valueOf(Launcher.class));

      ProcessBuilder pb = new ProcessBuilder(arguments);
      try {
        Process process = pb.start();

        LoggerHelper.logInfo(pb.command().toString(), true);
        if (process.waitFor() != 0) {
          System.exit(process.exitValue());
        }
      } catch (IOException ioe) {
        JOptionPane.showMessageDialog(null,
            String.format("An error occurred while starting the process:%n%s", ioe.getMessage()),
            "Error", JOptionPane.ERROR_MESSAGE);

        LoggerHelper.logError("Failed to start the process", ioe, true);
      } catch (InterruptedException ie) {
        JOptionPane.showMessageDialog(null,
            String.format("An error occurred while waiting for the process to terminate:%n%s",
                ie.getMessage()), "Error", JOptionPane.ERROR_MESSAGE);

        LoggerHelper.logError("Failed to wait for process to terminate", ie, true);
      }
    } else {
      LauncherFrame.main(args);
    }
  }

I removed the try-catch because it did nothing

south knot
#

I’m trying to see the try catch

median dagger
#

it would just be wrapped around

south knot
#

Since you said it doesn’t work

median dagger
#

and it makes no difference

south knot
#

It should, and that’s why I’d like to see why it doesn’t

median dagger
#

perhaps voice channel for real-time edits while chatting here?

south knot
#

Can’t right now

median dagger
#

okay.

#

i meant muted but yes

#
  public static void main(String[] args) {
    try {
      if (RuntimeHelper.MAX_MEMORY < RuntimeHelper.MIN_MEMORY) {
        List<String> arguments = new ArrayList<>();
        arguments.add(EPlatform.getPlatform() == EPlatform.WINDOWS ? "javaw" : "java");
        arguments.add("-Xmx1024m");
        arguments.add("-Dsun.java2d.d3d=false");
        arguments.add("-Dsun.java2d.opengl=false");
        arguments.add("-Dsun.java2d.pmoffscreen=false");
        arguments.add("-cp");
        arguments.add(System.getProperty("java.class.path"));
        arguments.add(String.valueOf(Launcher.class));

        ProcessBuilder pb = new ProcessBuilder(arguments);
        try {
          Process process = pb.start();

          LoggerHelper.logInfo(pb.command().toString(), true);
          if (process.waitFor() != 0) {
            System.exit(process.exitValue());
          }
        } catch (IOException ioe) {
          JOptionPane.showMessageDialog(null,
              String.format("An error occurred while starting the process:%n%s", ioe.getMessage()),
              "Error", JOptionPane.ERROR_MESSAGE);

          LoggerHelper.logError("Failed to start the process", ioe, true);
        } catch (InterruptedException ie) {
          JOptionPane.showMessageDialog(null,
              String.format("An error occurred while waiting for the process to terminate:%n%s",
                  ie.getMessage()), "Error", JOptionPane.ERROR_MESSAGE);

          LoggerHelper.logError("Failed to wait for process to terminate", ie, true);
        }
      } else {
        LauncherFrame.main(args);
      }
    } catch (Throwable t) {
      JOptionPane.showMessageDialog(null,
          String.format("An error occurred while starting the launcher:%n%s", t.getMessage()),
          "Error", JOptionPane.ERROR_MESSAGE);

      LoggerHelper.logError("Failed to start launcher", t, true);
    }
  }
#

it doesn't catch anything

south knot
#

How did you test that? Is it possible you already have a catch block somewhere catching your test case before it can be caught here?

median dagger
#

by running the same code

soft hornet
#

where do you expect the exception to be thrown?

median dagger
#

well, for testing purposes, it's thrown at exactly here

#

well, i partially fixed an issue, and it's got a new problem

#

in the log area

#

the throwable is null...?

median dagger
#

ok, i'll try testing it in another way

#

not from image input, but in other way

median dagger
#

Well, I got the main method's throwable working, but the logging is still thinking that the throwable is null

#

i don't get it

#

Now when doing something, it shows this:

[ERROR] ee.twentyten.request.HttpsConnectionImpl - Failed to write to output stream
java.lang.NullPointerException: t == null!
    at ee.twentyten.log.LauncherLogger.writeLog(LauncherLogger.java:181)
    at ee.twentyten.util.LoggerHelper.logError(LoggerHelper.java:83)
    at ee.twentyten.request.HttpsConnectionImpl.performJsonRequest(HttpsConnectionImpl.java:178)
    at ee.twentyten.util.RequestHelper.performJsonRequest(RequestHelper.java:65)
    at com.mojang.YggdrasilAuthenticationImpl.validate(YggdrasilAuthenticationImpl.java:38)
    at com.mojang.util.YggdrasilHelper.validate(YggdrasilHelper.java:32)
    at com.mojang.util.YggdrasilHelper.isSessionExpired(YggdrasilHelper.java:54)
    at ee.twentyten.ui.LauncherFrame.main(LauncherFrame.java:106)
    at ee.twentyten.Launcher.main(Launcher.java:48)
#

I did adjust this just to see if it's null or not:

   try (FileWriter fw = new FileWriter(logFile, true)) {
      if (this.isSystemMessageWritten(logFile)) {
        this.writeSystemMessage(fw);
      }
      fw.write(String.format("%s%n", message));

      try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)) {
        if (t == null) {
          t = new NullPointerException("t == null!");
          t.printStackTrace(pw);
        }
        fw.write(String.format("%s%n", sw));
      }
    } catch (IOException ioe) {
      ioe.printStackTrace();
    }
#

and I don't get it

#

why is it null when I'm passing it over?

#

I'm literally trying to catch whatever is being thrown

#

so why this?

#

It's supposed to throw an IOException for [ERROR] ee.twentyten.request.HttpsConnectionImpl - Failed to write to output stream

#

I FIXED IT!

#

Let me tell you how

#

I went back to my logError code...

#
  public static void logError(String message, Throwable t, boolean written) {
    Throwable cause = t.getCause() != null ? t.getCause() : t;
    if (DEBUG_MODE) {
      Logger logger = LoggerFactory.getLogger(LoggerHelper.getCallerClassName());
      logger.error(String.format("%s: %s", LoggerHelper.getCallerMethodName(), message), cause);
    }

    if (written) {
      String outputMessage = String.format("[ERROR] %s - %s", LoggerHelper.getCallerClassName(),
          message);
      LOGGER.writeLog(outputMessage, cause);
    }
  }

And added a ternary condition for the cause

#

also moved the "printStackTrace" outside the "if null" statement in the other file