如何为Serilog自定义Sink实现outputTemplate参数并支持通用模板配置
Great question! Adding outputTemplate support to your custom Serilog sink is totally doable, and you can reuse Serilog's built-in template rendering logic to keep behavior consistent with official sinks like the Console sink. Here's how to implement it step by step:
First, include these Serilog namespaces to access the template parsing and formatting utilities:
using Serilog; using Serilog.Core; using Serilog.Events; using Serilog.Formatting.Display; using System.IO;
MySink Class Instead of manually parsing the template string, use Serilog's MessageTemplateTextFormatter—this is the same class the official Console sink uses, so it handles all standard template syntax (like {Timestamp}, {Exception}, and format modifiers) out of the box.
Here's the revised sink code:
public class MySink : ILogEventSink { private readonly MessageTemplateTextFormatter _templateFormatter; // Constructor accepts the output template and format provider public MySink(string outputTemplate, IFormatProvider formatProvider = null) { // Initialize the built-in formatter to handle template rendering _templateFormatter = new MessageTemplateTextFormatter(outputTemplate, formatProvider); } public void Emit(LogEvent logEvent) { // Use a StringWriter to capture the formatted log output using var stringWriter = new StringWriter(); // Let the formatter render the log event into the writer _templateFormatter.Format(logEvent, stringWriter); // Get the final formatted string string formattedLogEntry = stringWriter.ToString(); // Replace this with your sink's actual output logic (e.g., write to file, API, etc.) Console.WriteLine(formattedLogEntry); } }
What's Changed?
- We replaced the raw
outputTemplatestring with a pre-initializedMessageTemplateTextFormatter—this parses the template once at sink creation (instead of every log event) for better performance. - The formatter handles all Serilog template rules, so your sink will behave consistently with official sinks.
- In
Emit, we use aStringWriterto capture the formatted log, then pass that string to your custom output logic.
LoggerConfiguration To enable the clean .WriteTo.MySink(outputTemplate: "...") syntax users expect, add an extension method for LoggerConfiguration:
public static class MySinkExtensions { // Use the same default template as Serilog's Console sink for consistency private const string DefaultOutputTemplate = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}"; public static LoggerConfiguration MySink( this LoggerSinkConfiguration sinkConfiguration, string outputTemplate = DefaultOutputTemplate, IFormatProvider formatProvider = null) { // Validate input parameters if (sinkConfiguration == null) throw new ArgumentNullException(nameof(sinkConfiguration)); if (string.IsNullOrWhiteSpace(outputTemplate)) throw new ArgumentNullException(nameof(outputTemplate)); // Create the sink instance and add it to the logger configuration var sink = new MySink(outputTemplate, formatProvider); return sinkConfiguration.Sink(sink); } }
This method:
- Provides a sensible default template (matching the Console sink) so users don't have to specify one.
- Validates inputs to avoid common errors.
- Wires up your custom sink to Serilog's configuration pipeline.
Now you can use your sink exactly like the official Console sink:
var logger = new LoggerConfiguration() .WriteTo.MySink(outputTemplate: "{Timestamp:HH:mm:ss} [{Level}] {Message}{NewLine}{Exception}") .CreateLogger(); logger.Information("Hello from my custom sink!"); logger.Error(new InvalidOperationException("Test error"), "Something went wrong");
- Consistency: Reusing
MessageTemplateTextFormatterensures your sink follows Serilog's standard template rules—users won't need to learn new syntax. - Performance: Parsing the template once at initialization is far more efficient than parsing it for every log event.
- Flexibility: You can add custom logic (like filtering, enrichment, or sending to a unique destination) after rendering the formatted log string.
内容的提问来源于stack exchange,提问作者Daniel Portugal

