How do I debug Java networking issues using java.net logging and troubleshooting tools?

Debugging Java networking issues often involves using logging utilities provided by the java.net package, diagnostic tools, and third-party utilities. Here’s a detailed guide:

1. Enable Java Networking Logging

Java includes built-in logging capabilities for debugging networking issues. You can use the java.util.logging package to capture logs from the java.net classes.

Enable Debugging Logs for HTTP, HTTPS, and Networking

Add the following system properties when starting your application to enable verbose logging for networking:

-Djava.util.logging.config.file=logging.properties
-Djavax.net.debug=all
-Dhttp.keepAlive=false
-Dsun.net.www.http.HttpClient.level=ALL
-Djava.net.level=ALL

Steps:

  • logging.properties File: Create a logging.properties file if not already available. Configure the logger like this:
    handlers=java.util.logging.ConsoleHandler
    .level=ALL
    java.util.logging.ConsoleHandler.level=ALL
    java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
    sun.net.www.protocol.http.HttpURLConnection.level=ALL
    sun.net.www.http.HttpClient.level=ALL
    java.net.level=ALL
    
  • Run the JVM: Use the -Djava.util.logging.config.file property to point to this file when starting your Java application.

2. Use Debugging Logs from SSL/TLS

If your networking issue involves HTTPS, enable debug logs for SSL/TLS issues:

  • Add the -Djavax.net.debug=all property to your JVM options.

You can modify the scope by replacing all with specific values, such as:

  • ssl
  • ssl:handshake
  • ssl:keymanager
  • ssl:trustmanager

For example:

-Djavax.net.debug=ssl:handshake

The logs will display details, such as:

  • Certificate validation
  • Handshake details
  • Cipher suites used

3. Manually Add Logging in Application

Add custom logging to capture specific details about network connections in your Java application. For instance, log details about URLs, connections, and responses:

Example Code:

package org.kodejava.net;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;

public class NetworkDebugging {
    private static final Logger LOGGER = Logger.getLogger(NetworkDebugging.class.getName());

    public static void main(String[] args) {
        try {
            URL url = new URL("https://example.com");
            LOGGER.log(Level.INFO, "Connecting to URL: {0}", url);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();

            connection.setRequestMethod("GET");
            int responseCode = connection.getResponseCode();
            LOGGER.log(Level.INFO, "Response Code: {0}", responseCode);

            if (responseCode == HttpURLConnection.HTTP_OK) {
                BufferedReader in = new BufferedReader(
                        new InputStreamReader(connection.getInputStream()));
                String inputLine;
                StringBuilder response = new StringBuilder();

                while ((inputLine = in.readLine()) != null) {
                    response.append(inputLine);
                }
                in.close();
                LOGGER.log(Level.INFO, "Response: {0}", response.toString());
            } else {
                LOGGER.log(Level.WARNING, "Request failed with code: {0}", responseCode);
            }

        } catch (Exception e) {
            LOGGER.log(Level.SEVERE, "Error during connection", e);
        }
    }
}

Explanation:

  • Logs the URL connection.
  • Tracks HTTP methods and response codes.
  • Captures exceptions for troubleshooting.

4. Java Networking Debugging Techniques

Analyze Connection Configuration

  • Ensure you are using the correct protocol (http or https).
  • Check proxy settings if applicable:
    • Set system properties like:
System.setProperty("http.proxyHost", "your.proxy.host");
System.setProperty("http.proxyPort", "8080");

Test with a Simple Socket Connection

For low-level troubleshooting, test using a Socket connection:

package org.kodejava.net;

import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class SocketDebugging {
    public static void main(String[] args) {
        try (Socket socket = new Socket("example.com", 80)) {
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            Scanner in = new Scanner(socket.getInputStream());

            out.println("GET / HTTP/1.1");
            out.println("Host: example.com");
            out.println("Connection: close");
            out.println();

            while (in.hasNextLine()) {
                System.out.println(in.nextLine());
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Use Case:

  • This allows you to debug raw HTTP connections.
  • Analyze whether the issue originates from the server, DNS, or route.

5. External Tools for Troubleshooting

Use external tools for deeper investigation:

  • Wireshark: Monitor raw network traffic.
  • cURL: Test URLs outside Java to isolate application-specific issues.
  • Netcat (nc): Debug and test network connections.

Example cURL command to check an HTTP endpoint:

curl -v https://example.com

6. Check Logs for Common Issues

Inspect the logs generated by java.util.logging or javax.net.debug for patterns of common issues:

  1. Host Unreachable:
    • Possible causes: DNS resolution failure, incorrect URL.
  2. SSLHandshakeException:
    • Possible causes: Invalid certificates (verify truststore setup).
  3. Timeout Issues:
    • Check connection timeout and read timeout parameters:
connection.setConnectTimeout(5000); // 5 seconds
connection.setReadTimeout(5000); // 5 seconds

7. Verify SSL Certificates (If HTTPS)

For HTTPS issues:

  • Use keytool to inspect Java’s Keystore or Truststore:
keytool -list -v -keystore cacerts
  • Import missing certificates into the Truststore:
keytool -import -trustcacerts -file cert.pem -keystore cacerts

8. Monitor JVM Metrics

Use Java monitoring tools like:

  • JConsole
  • VisualVM

Attach these to your running Java application and monitor I/O or thread states.
By following these steps and analyzing the debug outputs, you can effectively diagnose and resolve Java networking issues.

How do I created tab delimited data file in Java?

The following code snippet show you how to create a tab delimited data file in Java. The tab character is represented using the \t sequence of characters, a backslash (\) character followed by the t letter. In the code below we start by defining some data that we are going to write to the file.

We create a PrintWriter object, passes a BufferedWritter created using the Files.newBufferedWriter() method. The countries.dat is the file name where the data will be written. Because we are using the try-with-resources the PrintWriter and the related object will be closed automatically when the file operation finishes.

package org.kodejava.io;

import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

public class TabDelimitedDataFile {
    public static void main(String[] args) throws IOException {
        List<String[]> data = new ArrayList<>();
        data.add(new String[]{"Afghanistan", "AF", "AFG", "004", "Asia"});
        data.add(new String[]{"Åland Islands", "AX", "ALA", "248", "Europe"});
        data.add(new String[]{"Albania", "AL", "ALB", "008", "Europe"});
        data.add(new String[]{"Algeria", "DZ", "DZA", "012", "Africa"});
        data.add(new String[]{"American Samoa", "AS", "ASM", "016", "Polynesia"});
        data.add(new String[]{"Andorra", "AD", "AND", "020", "South Europe"});
        data.add(new String[]{"Angola", "AO", "AGO", "024", "Africa"});
        data.add(new String[]{"Anguilla", "AI", "AIA", "660", "Americas"});
        data.add(new String[]{"Antarctica", "AQ", "ATA", "010", ""});
        data.add(new String[]{"Argentina", "AR", "ARG", "032", "Americas"});

        try (PrintWriter writer = new PrintWriter(
                Files.newBufferedWriter(Paths.get("countries.dat")))) {
            for (String[] row : data) {
                writer.printf("%1$20s\t%2$3s\t\t%3$3s\t\t%4$3s\t\t%5$s",
                        row[0], row[1], row[2], row[3], row[4]);
                writer.println();
            }
        }
    }
}

The output of the code snippet above are:

         Afghanistan     AF     AFG     004     Asia
       Åland Islands     AX     ALA     248     Europe
             Albania     AL     ALB     008     Europe
             Algeria     DZ     DZA     012     Africa
      American Samoa     AS     ASM     016     Polynesia
             Andorra     AD     AND     020     South Europe
              Angola     AO     AGO     024     Africa
            Anguilla     AI     AIA     660     Americas
          Antarctica     AQ     ATA     010     
           Argentina     AR     ARG     032     Americas

How do I get an exception stack trace message?

In this example we use the java.io.StringWriter and java.io.PrintWriter class to convert stack trace exception message to a string.

package org.kodejava.io;

import java.io.StringWriter;
import java.io.PrintWriter;

public class StackTraceToString {
    public static void main(String[] args) {
        try {
            int result = 10 / 0;
        } catch (Exception e) {
            // Create a StringWriter and a PrintWriter both of these object
            // will be used to convert the data in the stack trace to a string.
            StringWriter stringWriter = new StringWriter();
            PrintWriter printWriter = new PrintWriter(stringWriter);

            // Instead of writing the stack trace in the console we write it
            // to the PrintWriter, to get the stack trace message we then call
            // the toString() method of StringWriter.
            e.printStackTrace(printWriter);

            System.out.println("Error = " + stringWriter);
        }
    }
}

This code snippet print the following output:

Error = java.lang.ArithmeticException: / by zero
    at org.kodejava.io.StackTraceToString.main(StackTraceToString.java:9)