Skip to content

Custom sinks cannot render message templates - internal/parser is not accessible #64

@willibrandon

Description

@willibrandon

Version: Latest (main branch)

What happened?
Custom sinks cannot properly render message templates because internal/parser is not accessible outside the mtlog module. When implementing core.LogEventSink, there's no public API to render the MessageTemplate with Properties, forcing manual string replacement that breaks with capturing operators (@), scalar hints ($), and format specifiers.

Expected behavior
Custom sinks should be able to render message templates just like built-in sinks. Serilog provides LogEvent.RenderMessage() for this purpose. mtlog should provide equivalent functionality.

Minimal reproduction

package main

import (
    "fmt"
    "os"
    "strings"
    "github.com/willibrandon/mtlog"
    "github.com/willibrandon/mtlog/core"
)

// Custom sink per README documentation
type CustomSink struct{}

func (s *CustomSink) Emit(event *core.LogEvent) {
    // ❌ No way to properly render the message!
    // event.MessageTemplate = "Config: {@Config}"
    // event.Properties = {"Config": &config.Config{...}}
    
    // Can't do this (internal package):
    // tmpl, _ := parser.Parse(event.MessageTemplate)
    // message := tmpl.Render(event.Properties)
    
    // Only option: manual string replacement (broken):
    message := event.MessageTemplate
    for name, value := range event.Properties {
        // Doesn't handle {@Property}, {$Property}, {Property:format}, etc.
        placeholder := fmt.Sprintf("{%s}", name)
        message = strings.ReplaceAll(message, placeholder, fmt.Sprintf("%v", value))
    }
    
    fmt.Fprintln(os.Stderr, message)
}

func main() {
    logger := mtlog.New(mtlog.WithSink(&CustomSink{}))
    cfg := map[string]any{"debug": true, "port": 8080}
    
    // Outputs: "Config: {@Config}" (placeholder not replaced!)
    logger.Debug("Config: {@Config}", cfg)
}

Environment

  • Go version: go1.25.1
  • OS: darwin/arm64

Additional context
Serilog solves this by providing LogEvent.RenderMessage() and public MessageTemplateTextFormatter. Suggested solution:

Add RenderMessage() method to core.LogEvent (Serilog-style, cleanest)

Current workaround in use: Manual replacement of {Property}, {@Property}, and {$Property} with strings.ReplaceAll, but this doesn't support format specifiers or alignment.

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdocumentationImprovements or additions to documentationenhancementNew feature or requestsinksChanges to log event sinks (output destinations)

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions