Logging in Java

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

The Java standard library provides straightforward tools for outputting logs from Java programs, with the `java.util.logging` package for free-form output and the `org.slf4j` package (a popular third-party library) for more advanced logging capabilities.

```java
import java.util.logging.*;
import java.io.*;

public class LoggingExample {
    public static void main(String[] args) throws IOException {
        // Simply invoking methods like info() from the Logger class uses
        // the default logger, which is already pre-configured for reasonable
        // logging output to the console.
        Logger.getGlobal().info("standard logger");

        // Loggers can be configured with handlers and formatters to set
        // their output format. By default, the console handler uses a
        // SimpleFormatter. We can change its format to include microseconds.
        ConsoleHandler handler = new ConsoleHandler();
        handler.setFormatter(new SimpleFormatter() {
            private static final String format = "[%1$tF %1$tT.%1$tL] %2$s %3$s%n";
            @Override
            public synchronized String format(LogRecord lr) {
                return String.format(format,
                        new java.util.Date(lr.getMillis()),
                        lr.getLevel().getLocalizedName(),
                        lr.getMessage()
                );
            }
        });
        Logger logger = Logger.getLogger("MyLogger");
        logger.setUseParentHandlers(false);
        logger.addHandler(handler);
        logger.info("with micro");

        // It also supports emitting the class name and
        // method from which the log method is called.
        logger.logp(Level.INFO, LoggingExample.class.getName(), "main", "with class/method");

        // It may be useful to create a custom logger and
        // pass it around. When creating a new logger, we
        // can set a name to distinguish its output from other loggers.
        Logger mylog = Logger.getLogger("CustomLogger");
        mylog.info("from mylog");

        // We can change the logger's name
        mylog.setUseParentHandlers(false);
        mylog.addHandler(new ConsoleHandler());
        ((ConsoleHandler)mylog.getHandlers()[0]).setFormatter(new SimpleFormatter() {
            private static final String format = "mycustom: [%1$tF %1$tT] %2$s%n";
            @Override
            public synchronized String format(LogRecord lr) {
                return String.format(format,
                        new java.util.Date(lr.getMillis()),
                        lr.getMessage()
                );
            }
        });
        mylog.info("from custom mylog");

        // Loggers can have custom output targets;
        // any OutputStream works.
        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 a third-party library like SLF4J with Logback
        // Here's a basic example (Note: This requires additional dependencies)
        /*
        import org.slf4j.Logger;
        import org.slf4j.LoggerFactory;

        Logger slf4jLogger = LoggerFactory.getLogger(LoggingExample.class);
        slf4jLogger.info("hi there");
        
        // In addition to the message, structured logging can contain
        // an arbitrary number of key-value pairs.
        slf4jLogger.info("hello again", "key", "val", "age", 25);
        */
    }
}

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

May 30, 2023 3:45:16 PM LoggingExample main
INFO: standard logger
[2023-05-30 15:45:16.904] INFO with micro
May 30, 2023 3:45:16 PM LoggingExample main
INFO: with class/method
May 30, 2023 3:45:16 PM LoggingExample main
INFO: from mylog
mycustom: [2023-05-30 15:45:16] from custom mylog
from buflog: May 30, 2023 3:45:16 PM LoggingExample main
INFO: hello

Note that for structured logging, Java typically relies on third-party libraries like SLF4J with implementations like Logback or Log4j2. These provide more advanced features and better performance than the built-in java.util.logging package.