diff --git a/src/NLog.Extensions.Logging/LayoutRenderers/MicrosoftConsoleLayoutRenderer.cs b/src/NLog.Extensions.Logging/LayoutRenderers/MicrosoftConsoleLayoutRenderer.cs
new file mode 100644
index 00000000..79b7edb7
--- /dev/null
+++ b/src/NLog.Extensions.Logging/LayoutRenderers/MicrosoftConsoleLayoutRenderer.cs
@@ -0,0 +1,76 @@
+using System.Linq;
+using System.Text;
+using NLog.Config;
+using NLog.LayoutRenderers;
+
+namespace NLog.Extensions.Logging
+{
+ ///
+ /// Renders output that simulates simple Microsoft Console Logger. Useful for Hosting Lifetime Startup Messages.
+ ///
+ [LayoutRenderer("MicrosoftConsoleLayout")]
+ [ThreadSafe]
+ [ThreadAgnostic]
+ class MicrosoftConsoleLayoutRenderer : LayoutRenderer
+ {
+ private static readonly string[] EventIdMapper = Enumerable.Range(0, 50).Select(id => id.ToString()).ToArray();
+
+ ///
+ protected override void Append(StringBuilder builder, LogEventInfo logEvent)
+ {
+ var microsoftLogLevel = ConvertLogLevel(logEvent.Level);
+ builder.Append(microsoftLogLevel);
+ builder.Append(": ");
+ builder.Append(logEvent.LoggerName);
+ builder.Append("[");
+ int eventId = 0;
+ if (logEvent.HasProperties && logEvent.Properties.TryGetValue("EventId_Id", out var eventIdValue))
+ {
+ if (eventIdValue is int)
+ eventId = (int)eventIdValue;
+ else if (!int.TryParse(eventIdValue?.ToString() ?? string.Empty, out eventId))
+ eventId = 0;
+ }
+ else
+ {
+ eventId = 0;
+ }
+ builder.Append(ConvertEventId(eventId));
+ builder.Append("]");
+ builder.Append(System.Environment.NewLine);
+ builder.Append(" ");
+ builder.Append(logEvent.FormattedMessage);
+ if (logEvent.Exception != null)
+ {
+ builder.Append(System.Environment.NewLine);
+ builder.Append(logEvent.Exception.ToString());
+ }
+ }
+
+ static string ConvertEventId(int eventId)
+ {
+ if (eventId == 0)
+ return "0";
+ else if (eventId > 0 || eventId < EventIdMapper.Length)
+ return EventIdMapper[eventId];
+ else
+ return eventId.ToString();
+ }
+
+ string ConvertLogLevel(LogLevel logLevel)
+ {
+ if (logLevel == LogLevel.Trace)
+ return "trce";
+ else if (logLevel == LogLevel.Debug)
+ return "dbug";
+ else if (logLevel == LogLevel.Info)
+ return "info";
+ else if (logLevel == LogLevel.Warn)
+ return "warn";
+ else if (logLevel == LogLevel.Error)
+ return "fail";
+ else
+ return "crit"; // Fatal
+ }
+ }
+}
diff --git a/test/NLog.Extensions.Logging.Tests/MicrosoftConsoleLayoutRendererTest.cs b/test/NLog.Extensions.Logging.Tests/MicrosoftConsoleLayoutRendererTest.cs
new file mode 100644
index 00000000..fa56e033
--- /dev/null
+++ b/test/NLog.Extensions.Logging.Tests/MicrosoftConsoleLayoutRendererTest.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Xunit;
+
+namespace NLog.Extensions.Logging.Tests
+{
+ public class MicrosoftConsoleLayoutRendererTest
+ {
+ [Fact]
+ public void MicrosoftConsoleLayoutRenderer_NullEvent()
+ {
+ var layoutRenderer = new MicrosoftConsoleLayoutRenderer();
+ var result = layoutRenderer.Render(LogEventInfo.CreateNullEvent());
+ Assert.Contains("crit: [0]", result);
+ }
+
+ [Fact]
+ public void MicrosoftConsoleLayoutRenderer_ExceptionEvent()
+ {
+ var layoutRenderer = new MicrosoftConsoleLayoutRenderer();
+ var exception = new ArgumentException("Test");
+ var eventId = 42;
+ var result = layoutRenderer.Render(new LogEventInfo(LogLevel.Error, "MyLogger", null, "Alert {EventId_Id}", new object[] { eventId }, exception));
+ Assert.Equal($"fail: MyLogger[{eventId}]{Environment.NewLine} Alert 42{Environment.NewLine}{exception}", result);
+ }
+ }
+}