Logging in Modelica

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

The Java standard library provides various tools for outputting logs from Java programs. We'll use the `java.util.logging` package for free-form output and the `org.json.JSONObject` for structured output (simulating the `slog` package in Go).

```java
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 {
        // 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 properties to set their output format.
        // We can change its format to emit time with microsecond accuracy.
        System.setProperty("java.util.logging.SimpleFormatter.format",
                "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL %4$s %2$s %5$s%6$s%n");
        Logger.getGlobal().info("with micro");

        // It also supports emitting the class name and
        // line from which the log function is called.
        Logger logger = Logger.getLogger(LoggingExample.class.getName());
        logger.info("with class/line");

        // It may be useful to create a custom logger and
        // pass it around. When creating a new logger, we
        // can set a handler to customize its output.
        Logger mylog = Logger.getLogger("MyLogger");
        ConsoleHandler handler = new ConsoleHandler();
        handler.setFormatter(new SimpleFormatter() {
            private static final String format = "my: %1$tF %1$tT %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()
                );
            }
        });
        mylog.setUseParentHandlers(false);
        mylog.addHandler(handler);
        mylog.info("from mylog");

        // We can change the format of existing loggers
        handler.setFormatter(new SimpleFormatter() {
            private static final String format = "ohmy: %1$tF %1$tT %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()
                );
            }
        });
        mylog.info("from mylog");

        // Loggers can have custom output targets;
        // any OutputStream works.
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        Logger buflog = Logger.getLogger("BufferLogger");
        StreamHandler streamHandler = new StreamHandler(out, new SimpleFormatter() {
            private static final String format = "buf: %1$tF %1$tT %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()
                );
            }
        });
        buflog.setUseParentHandlers(false);
        buflog.addHandler(streamHandler);

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

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

        // For structured log output, we can use JSONObject.
        // This simulates the slog package's JSON output.
        JSONObject jsonLog = new JSONObject();
        jsonLog.put("time", Instant.now().toString());
        jsonLog.put("level", "INFO");
        jsonLog.put("msg", "hi there");
        System.out.println(jsonLog.toString());

        // In addition to the message, we can include
        // an arbitrary number of 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());
    }
}

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 LoggingExample main with micro
May 30, 2023 3:45:16 PM LoggingExample main
INFO: with class/line
my: 2023-05-30 15:45:16 INFO from mylog
ohmy: 2023-05-30 15:45:16 INFO from mylog
from buflog:buf: 2023-05-30 15:45:16 INFO hello

{"level":"INFO","msg":"hi there","time":"2023-05-30T15:45:16.904166391Z"}
{"level":"INFO","msg":"hello again","time":"2023-05-30T15:45:16.904178985Z","key":"val","age":25}

These are wrapped for clarity of presentation; in reality, they are emitted on a single line.

Note: This example uses the org.json.JSONObject class for JSON formatting, which may require adding an external dependency to your project.