{"id":6771,"date":"2020-05-16T19:16:46","date_gmt":"2020-05-16T17:16:46","guid":{"rendered":"https:\/\/u-labs.de\/portal\/?p=6771"},"modified":"2020-05-16T22:17:04","modified_gmt":"2020-05-16T20:17:04","slug":"zeitstempel-in-asp-net-core-anwendungen-auf-der-konsole-anzeigen","status":"publish","type":"post","link":"https:\/\/u-labs.de\/portal\/zeitstempel-in-asp-net-core-anwendungen-auf-der-konsole-anzeigen\/","title":{"rendered":"Zeitstempel in (ASP) .NET Core Anwendungen auf der Konsole anzeigen"},"content":{"rendered":"<p>Die ILogger Schnittstelle erm\u00f6glicht das einfache Injizieren eines Loggers in jegliche Klasse. Durch das Protokollieren des Namespace ist stets klar, von welcher Komponente die Informationen stammen. In der appsettings.json k\u00f6nnen wir f\u00fcr jeden Namespace den Detailgrad einstellen. Dies geht bis hin zu Debug- und Tracelogs, die uns z.B. beim EntityFramework die SQL-Abfragen protokollieren. <\/p>\n<p>Das standardm\u00e4\u00dfig verf\u00fcgbare Logging-Komponente ist also recht m\u00e4chtig. Drittanbieter-Alternativen wie Log4j (die auch nach .NET portiert wurden) m\u00fcssen daher nicht zwingend eingebunden werden. Doch leider fehlt zumindest bisher noch eine entscheidende Funktion: Zeitstempel. S\u00e4mtliche Logeintr\u00e4ge erhalten keinerlei Datums- oder Zeitangaben. Gerade bei l\u00e4ngeren Protokollen ist daher nicht mehr nachvollziehbar, wann ein bestimmtes Ereignis geschehen ist. Zur L\u00f6sung dieses Problemes gibt es leider auch noch keine Konfigurationseinstellung<\/p>\n<p>Auf den ersten Blick bleibt daher nur der manuelle Weg: Den aktuellen Zeitstempel h\u00e4ndisch in den zu protokollierenden Text einf\u00fcgen<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-cs\" data-line=\"\">logger.LogInformation($&quot;{DateTime.Now.ToString()} Index-Action aufgerufen&quot;);<\/code><\/pre>\n<h2 class=\"wp-block-heading\">Automatisierte Zeistempel durch Vererbung<\/h2>\n<p>Der h\u00e4ndische Weg ist aber umst\u00e4ndlich, wenig flexibel und fehleranf\u00e4llig. Au\u00dferdem verschlechtert sich die Lesbarkeit des Codes. Das Problem l\u00e4sst sich recht einfach, aber nachhaltig durch Vererbung l\u00f6sen. Wir erstellen eine Klasse <strong>TimedLogger&lt;T&gt;<\/strong>, die von <strong>ILogger&lt;T&gt;<\/strong> erbt. Hier f\u00fcgen wir in der generischsten Log-Methode den Zeitstempel ein. Alles andere wird an eine Instanz der Basisklasse weitergegeben.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-cs\" data-line=\"\">using System;\nusing Microsoft.Extensions.Logging;\n\npublic class TimedLogger&lt;T&gt; : ILogger&lt;T&gt; {\n    private readonly ILogger logger;\n\n    public TimedLogger(ILogger logger) =&gt; this.logger = logger;\n\n    public TimedLogger(ILoggerFactory loggerFactory) : this(new Logger&lt;T&gt;(loggerFactory)) { }\n\n    public void Log&lt;TState&gt;(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func&lt;TState, Exception, string&gt; formatter) =&gt;\n        logger.Log(logLevel, eventId, state, exception, (s, ex) =&gt; $&quot;[{DateTime.UtcNow:HH:mm:ss.fff}] {formatter(s, ex)}&quot;);\n\n    public bool IsEnabled(LogLevel logLevel) =&gt; logger.IsEnabled(logLevel);\n\n    public IDisposable BeginScope&lt;TState&gt;(TState state) =&gt; logger.BeginScope(state);\n}<\/code><\/pre>\n<p>Das Format kann man nat\u00fcrlich <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/standard\/base-types\/custom-date-and-time-format-strings\" class=\"aioseop-link\" target=\"_blank\" rel=\"nofollow\">frei anpassen<\/a> und auf Wunsch auch die Zeitzone des Zielsystemes statt UTC verwenden. M\u00f6chte man beispielsweise das Datum im Format 16.05.20 vor der Uhrzeit sehen und die lokale Zeitzone nutzen, kann folgende Formatierung genutzt werden:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-cs\" data-line=\"\">DateTime.Now:dd.MM.y, HH:mm:ss.fff<\/code><\/pre>\n<p>Unsere modifizierte <strong>TimedLogger&lt;T&gt;<\/strong> ist nun Einsatzbereit. Allerdings wird sie noch nicht geladen. Wie injizieren wir <strong>TimedLogger&lt;T&gt;<\/strong> per Dependency Injection, statt des standardm\u00e4\u00dfigen <strong>Logger&lt;T&gt;<\/strong>? Hierf\u00fcr gibt es die praktische <strong>IServiceCollection <\/strong>Erweiterungsmethode <strong>Replace<\/strong>: Sie ersetzt eine bereits registrierte Dienstklasse anhand des Types und erlaubt diese zu Ersetzen.<\/p>\n<p>In S<strong>tartup.ConfigureServices<\/strong> f\u00fchren wir damit die Ersetzung durch:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-cs\" data-line=\"\">services.Replace(ServiceDescriptor.Singleton(typeof(ILogger&lt;&gt;), typeof(TimedLogger&lt;&gt;)));<\/code><\/pre>\n<p>Die Erweiterungsmethode befindet sich im Namensraum <strong>Microsoft.Extensions.DependencyInjection.Extensions.<\/strong> Nun erhalten <strong>alle<\/strong> Klassen, die <strong>ILogger&lt;T&gt;<\/strong> referenzieren, unsere eigene Klasse mit den Zeitangaben. Ein weiterer Vorteil dieser L\u00f6sung gegen\u00fcber anderen Frameworks wie Log4 ist: Bestehender Code muss nicht ge\u00e4ndert werden. Haben wir den integrierten <strong>Ilogger&lt;T&gt;<\/strong> zuvor bereits genutzt, beispielsweise in einem Controller<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-cs\" data-line=\"\">public class HomeController : Controller {\n    readonly ILogger&lt;HomeController&gt; logger;\n    public HomeController(ILogger&lt;HomeController&gt; logger) {\n        this.logger = logger;\n    }\n\t\n    public IActionResult Index() {\n        logger.LogInformation(&quot;Index-Action aufgerufen&quot;);\n        return View();\n    }\n}<\/code><\/pre>\n<p>Funktioniert dies aufgrund der Vererbung weiterhin. Nun allerdings mit Zeitstempel.<\/p>\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"457\" height=\"176\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2020\/05\/VsDebugConsole_2020-05-16_19-04-44.png\" alt=\"\" class=\"wp-image-6777\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2020\/05\/VsDebugConsole_2020-05-16_19-04-44.png 457w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2020\/05\/VsDebugConsole_2020-05-16_19-04-44-441x170.png 441w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2020\/05\/VsDebugConsole_2020-05-16_19-04-44-300x116.png 300w\" sizes=\"auto, (max-width: 457px) 100vw, 457px\" \/><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>Die ILogger Schnittstelle erm\u00f6glicht das einfache Injizieren eines Loggers in jegliche Klasse. Durch das Protokollieren des Namespace ist stets klar, von welcher Komponente die Informationen stammen. In der appsettings.json k\u00f6nnen wir f\u00fcr jeden Namespace den Detailgrad einstellen. Dies geht bis hin zu Debug- und Tracelogs, die uns z.B. beim EntityFramework die SQL-Abfragen protokollieren. Das standardm\u00e4\u00dfig &#8230;<\/p>\n","protected":false},"author":5,"featured_media":6777,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[61,1],"tags":[590,805,330],"class_list":["post-6771","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-softwareentwicklung","category-technik-news","tag-net-core","tag-asp-net-core-2-1","tag-c"],"_links":{"self":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/6771","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/comments?post=6771"}],"version-history":[{"count":7,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/6771\/revisions"}],"predecessor-version":[{"id":6779,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/6771\/revisions\/6779"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/media\/6777"}],"wp:attachment":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/media?parent=6771"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/categories?post=6771"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/tags?post=6771"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}