gologging

How to pass a struct and use its field automatically in slog logger?


I'm using slog package. I'm facing the problem that I have to pass too much parameters to it while I have most of these parameters in a struct.

Is there a way to modify the handler to make use of this struct? Something like what you can do in python, sending a dict or object as extra and then extracting needed parameters from it.

now I have this:

g.l.Log(
    context.TODO(),
    slog.LevelInfo,
    "Sending request to server.",
    "Destination", m.route.destination,
    "Protocol", m.route.protocol,
    "Service Identifier", m.route.serID,
    "Session ID", m.GetIdentifier(),
    "Client Connection", client.RemoteAddr().String(),
    "Server Connection", destination.RemoteAddr().String(),
)

And I want to do something like:

g.l.Log(
    context.TODO(),
    slog.LevelInfo,
    "Sending request to server.",
    "message", m,
    "Client Connection", client.RemoteAddr().String(),
    "Server Connection", destination.RemoteAddr().String(),
)

How should I do this?


Solution

  • I've found an answer to this question.

    I embedded the slog logger into a custom logger of mine.

    type Logger struct {
        *slog.Logger
    }
    

    I also, write export functions for my struct like this:

    
    func (m *GatewayMessage) LoggableData() *xlog.RequestData {
        return &xlog.RequestData{
            Request:             m.Request.String(),
            OriginalRequest:     m.OriginalRequest,
        }
    }
    
    func (m *GatewayMessage) PopulateGeneralLogData() []any {
        logData := m.LoggableData()
        return []any{
            "Request", logData.Request,
            "OriginalRequest", logData.OriginalRequest,
        }
    }
    
    

    Then I write a helper function that gets this GatewayMessage as a parameter and any number of arguments like the Log function of the slog Logger. This is the debug function for example:

    func LogDebug(l *xlog.Logger, ctx context.Context, msg string, m *GatewayMessage, args ...any) {
        var generalLogData []any = make([]any, 0)
        if m != nil {
            generalLogData = m.PopulateGeneralLogData()
        }
        args = append(args, generalLogData...)
        l.RuntimeDebug(
            ctx,
            msg,
            args...,
        )
    }
    
    

    I'm also using a receiver called RuntimeDebug to inject a parameter named Scope in all logs.

    func (l *Logger) RuntimeDebug(ctx context.Context, msg string, args ...any) {
        args = append(args, "Scope", "Runtime")
        l.Logger.Log(
            ctx,
            slog.LevelDebug,
            msg,
            args...,
        )
    }