Logging in Karel

Here’s the translation of the Go logging example to Java, formatted in Markdown suitable for Hugo:

Our logging example demonstrates how to use Java’s built-in logging capabilities, primarily focusing on the java.util.logging package for free-form output and the org.json.JSONObject for structured output (simulating the slog package’s JSON functionality).

import java.util.logging.*;
import java.io.*;
import org.json.JSONObject;
import java.time.Instant;

public class LoggingExample {
    public static void main(String[] args) throws IOException {
        // The default logger is already pre-configured for reasonable logging
        // output to System.err.
        Logger logger = Logger.getLogger(LoggingExample.class.getName());
        logger.info("standard logger");

        // We can configure the logger's output format
        System.setProperty("java.util.logging.SimpleFormatter.format",
                "%1$tF %1$tT.%1$tL %4$s %2$s %5$s%6$s%n");
        logger.info("with microseconds");

        // To include the class name and line number, we need to use a custom formatter
        class MyFormatter extends Formatter {
            @Override
            public String format(LogRecord record) {
                return String.format("%1$tF %1$tT %2$s:%3$s: %4$s\n",
                        new java.util.Date(record.getMillis()),
                        record.getSourceClassName(),
                        record.getSourceMethodName(),
                        record.getMessage());
            }
        }
        ConsoleHandler handler = new ConsoleHandler();
        handler.setFormatter(new MyFormatter());
        logger.setUseParentHandlers(false);
        logger.addHandler(handler);
        logger.info("with class/method");

        // We can create a custom logger with a specific name
        Logger mylog = Logger.getLogger("MyLogger");
        mylog.info("from mylog");

        // We can change the logger's name
        mylog.setLevel(Level.INFO);
        mylog.info("from renamed mylog");

        // Loggers can have custom output targets
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        Handler bufHandler = new StreamHandler(baos, new SimpleFormatter());
        Logger buflog = Logger.getLogger("BufferLogger");
        buflog.setUseParentHandlers(false);
        buflog.addHandler(bufHandler);

        // This call writes the log output into baos
        buflog.info("hello");
        bufHandler.flush();

        // This will actually show it on standard output
        System.out.print("from buflog:" + baos.toString());

        // For structured logging, we can use JSON
        JSONObject jsonLog = new JSONObject();
        jsonLog.put("time", Instant.now().toString());
        jsonLog.put("level", "INFO");
        jsonLog.put("msg", "hi there");
        System.out.println(jsonLog.toString());

        // We can add arbitrary key-value pairs
        jsonLog = new JSONObject();
        jsonLog.put("time", Instant.now().toString());
        jsonLog.put("level", "INFO");
        jsonLog.put("msg", "hello again");
        jsonLog.put("key", "val");
        jsonLog.put("age", 25);
        System.out.println(jsonLog.toString());
    }
}

To run this program, you’ll need to include the org.json library in your classpath. You can download it from JSON-java or use a dependency management tool like Maven or Gradle.

Sample output; the date and time emitted will depend on when the example ran:

2023-08-22 10:45:16 INFO LoggingExample main standard logger
2023-08-22 10:45:16.904 INFO LoggingExample main with microseconds
2023-08-22 10:45:16 LoggingExample:main: with class/method
Aug 22, 2023 10:45:16 AM LoggingExample main
INFO: from mylog
Aug 22, 2023 10:45:16 AM LoggingExample main
INFO: from renamed mylog
from buflog:Aug 22, 2023 10:45:16 AM LoggingExample main
INFO: hello

{"level":"INFO","msg":"hi there","time":"2023-08-22T10:45:16.904166391Z"}
{"level":"INFO","msg":"hello again","time":"2023-08-22T10:45:16.904178985Z","key":"val","age":25}

This Java example demonstrates various logging techniques, including:

  1. Using the standard logger
  2. Configuring log output format
  3. Creating custom loggers
  4. Writing logs to different outputs
  5. Structured logging using JSON

Note that Java’s built-in logging is not as feature-rich as Go’s slog package, so we’ve used a JSON library to simulate structured logging. In a real-world application, you might want to consider using a more robust logging framework like SLF4J with Logback or Log4j2, which offer more advanced features and better performance.