Logging in Standard ML

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

(* The Standard ML Basis Library provides basic functionality for
   outputting logs from SML programs, primarily through the TextIO
   structure for free-form output. For structured logging, we'll
   need to implement our own solution. *)

(* Import necessary modules *)
open TextIO;
open Date;

(* Helper function to get current timestamp *)
fun getCurrentTimestamp () =
    let
        val now = Date.fromTimeLocal (Time.now())
        val date = Date.fmt "%Y/%m/%d" now
        val time = Date.fmt "%H:%M:%S" now
    in
        date ^ " " ^ time
    end;

(* Simple logging function *)
fun log message =
    print (getCurrentTimestamp() ^ " " ^ message ^ "\n");

(* Main function *)
fun main () =
    let
        (* Simple logging *)
        val _ = log "standard logger"

        (* Custom logger with microsecond precision *)
        fun logWithMicro message =
            let
                val now = Time.now()
                val {sec, usec} = Time.toMicroseconds now
            in
                print (getCurrentTimestamp() ^ "." ^ 
                       Int.toString usec ^ " " ^ 
                       message ^ "\n")
            end

        (* Custom logger with file and line information *)
        fun logWithFileInfo filename line message =
            print (getCurrentTimestamp() ^ " " ^ 
                   filename ^ ":" ^ Int.toString line ^ 
                   ": " ^ message ^ "\n")

        (* Logging to a string *)
        val logBuffer = ref ""
        fun logToBuffer message =
            logBuffer := !logBuffer ^ getCurrentTimestamp() ^ 
                         " " ^ message ^ "\n"

        (* Simple JSON-like structured logging *)
        fun logJSON message fields =
            let
                fun fieldToString (key, value) = 
                    "\"" ^ key ^ "\":\"" ^ value ^ "\""
                val fieldsStr = String.concatWith "," 
                                (map fieldToString fields)
            in
                print ("{\"time\":\"" ^ getCurrentTimestamp() ^ 
                       "\",\"message\":\"" ^ message ^ "\"" ^ 
                       (if null fields then "" else "," ^ fieldsStr) ^ 
                       "}\n")
            end
    in
        log "standard logger";
        logWithMicro "with micro";
        logWithFileInfo "logging.sml" 54 "with file/line";
        logToBuffer "hello";
        print ("from buflog:" ^ !logBuffer);
        logJSON "hi there" [];
        logJSON "hello again" [("key", "val"), ("age", "25")]
    end;

(* Run the main function *)
val _ = main();

This Standard ML code demonstrates logging functionality similar to the original Go example. Here’s a breakdown of the translation:

  1. We use the TextIO module for basic I/O operations.
  2. A getCurrentTimestamp function is implemented to mimic the timestamp functionality.
  3. A simple log function is created for basic logging.
  4. The logWithMicro function demonstrates logging with microsecond precision.
  5. The logWithFileInfo function shows how to include file and line information.
  6. logToBuffer demonstrates logging to a string buffer.
  7. The logJSON function provides a basic implementation of structured logging in a JSON-like format.

To run this program, save it as logging.sml and use your Standard ML interpreter. For example, with MLton:

$ mlton logging.sml
$ ./logging

Sample output (the date and time will depend on when the example is run):

2023/08/22 10:45:16 standard logger
2023/08/22 10:45:16.904141 with micro
2023/08/22 10:45:16 logging.sml:54: with file/line
from buflog:2023/08/22 10:45:16 hello
{"time":"2023-08-22 10:45:16","message":"hi there"}
{"time":"2023-08-22 10:45:16","message":"hello again","key":"val","age":"25"}

Note that Standard ML doesn’t have built-in support for structured logging or JSON output, so we’ve implemented a basic version. In a real-world scenario, you might want to use or create a more robust logging library.