Logging in D Programming Language

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

import std.stdio;
import std.datetime;
import std.json;

void main()
{
    // Simply invoking functions like writeln from the
    // std.stdio module uses the standard output, which
    // is already pre-configured for reasonable logging
    // output to stdout.
    writeln("standard logger");

    // D doesn't have a built-in logging library like Go's log package,
    // but we can create a simple logging function that includes
    // timestamps and other information.
    void log(string message)
    {
        auto now = Clock.currTime();
        writefln("%s %s", now.toISOExtString(), message);
    }

    log("with timestamp");

    // We can also include file and line information
    void logWithFile(string file = __FILE__, int line = __LINE__)(string message)
    {
        auto now = Clock.currTime();
        writefln("%s %s:%d: %s", now.toISOExtString(), file, line, message);
    }

    logWithFile("with file/line");

    // In D, we can create custom logger classes for more flexibility
    class MyLogger
    {
        private string prefix;

        this(string prefix)
        {
            this.prefix = prefix;
        }

        void log(string message)
        {
            auto now = Clock.currTime();
            writefln("%s%s %s", prefix, now.toISOExtString(), message);
        }
    }

    auto mylog = new MyLogger("my:");
    mylog.log("from mylog");

    // We can change the prefix of our custom logger
    mylog.prefix = "ohmy:";
    mylog.log("from mylog");

    // D doesn't have a direct equivalent to Go's bytes.Buffer,
    // but we can use an array of char to achieve similar functionality
    char[] buf;
    void bufLog(string message)
    {
        import std.array : appender;
        auto app = appender(&buf);
        app.put("buf:");
        app.put(Clock.currTime().toISOExtString());
        app.put(" ");
        app.put(message);
        app.put("\n");
    }

    bufLog("hello");

    // This will actually show it on standard output.
    write("from buflog:", buf);

    // D doesn't have a built-in structured logging package like slog,
    // but we can create JSON-formatted log messages using std.json
    void jsonLog(string message, JSONValue[string] attrs = null)
    {
        JSONValue log = ["time": Clock.currTime().toISOExtString(),
                         "level": "INFO",
                         "msg": message];
        foreach (key, value; attrs)
        {
            log[key] = value;
        }
        writeln(log.toString());
    }

    jsonLog("hi there");
    jsonLog("hello again", ["key": "val", "age": JSONValue(25)]);
}

This D code provides similar functionality to the Go logging example. Here’s a breakdown of the changes and explanations:

  1. We use std.stdio for basic output functions and std.datetime for timestamp generation.

  2. D doesn’t have a built-in logging library like Go’s log package, so we create simple logging functions to mimic similar functionality.

  3. We create a custom MyLogger class to demonstrate how to implement logger objects with prefixes.

  4. Instead of bytes.Buffer, we use a char[] array to accumulate log messages.

  5. For structured logging, we use D’s std.json module to create JSON-formatted log messages.

  6. D uses __FILE__ and __LINE__ compile-time functions to get file and line information, similar to Go’s runtime.Caller().

  7. The main() function demonstrates the usage of these logging methods.

When you run this program, you’ll see output similar to the Go example, with timestamps and structured JSON logs. The exact output will depend on when you run the program.

standard logger
2023-08-22T10:45:16.904141Z with timestamp
2023-08-22T10:45:16.904141Z logging.d:40: with file/line
my:2023-08-22T10:45:16.904141Z from mylog
ohmy:2023-08-22T10:45:16.904141Z from mylog
from buflog:buf:2023-08-22T10:45:16.904141Z hello
{"time":"2023-08-22T10:45:16.904141Z","level":"INFO","msg":"hi there"}
{"time":"2023-08-22T10:45:16.904141Z","level":"INFO","msg":"hello again","key":"val","age":25}

This D code provides a similar logging experience to the Go example, demonstrating various logging techniques and structured logging using JSON.