Broken by Design: Wenn Software starr statt flexibel ist

Wenn es um Software (SOFT + ware) geht, liegt in ihrer Bezeichnung bereits eine grundlegende Erwartung: Sie sollte weich, verformbar, flexibel und anpassbar sein. Eine Software, die diese Eigenschaften vermissen lässt, gleicht eher einem starren Hardware-Produkt: Nicht einfach konfigurierbar und damit oft unbrauchbar, resultiert dies in kostspieligen Neuanschaffungen oder zeitaufwendigen Neuentwicklungen.

Als ich neulich zur Post ging, um eine Sendung abzuholen, fiel mir eine einfache, schnelle und praktische Lösung auf, die die Mitarbeiter der Post-Filiale gefunden hatten. Ich vermute, dass die (sogenannte) „Software“ des Info-Kiosks¹ entweder nicht lokal² konfigurierbar ist oder sich nicht schnell und einfach anpassen lässt. Andernfalls hätten die Mitarbeiter der Post-Filiale nicht zu Papier, Schere und Klebeband greifen müssen.

Höchstwahrscheinlich (meine persönliche Vermutung) wurde bereits in den frühen Phasen des Designs und der Entwicklung übersehen, das System konfigurierbar zu gestalten. Dies hätte es dem Personal vor Ort ermöglicht, Titel oder Text zu bearbeiten und Bilder auszutauschen.

1 Info-Kiosk: Auch bekannt als „digitales Kiosksystem“, „Touchscreen-Infostand“, „Self-Service-Terminal“, „interaktiver Informationsstand“ oder allgemein als Digital Signage bzw. Point-Of-Sale (kurz: POS) bezeichnet

2 Remote (von der Ferne über das Internet) durch dafür vorgesehene Personal zu konfigurieren bzw. aktualisieren

Logger log4Net installieren & konfigurieren

log4net ist mit über 113M Downloads (auf Nuget.org) einer der ältesten Hasen unter die Logger für .NET/C#. Ich verwende es seit 2011, und war damit zufrieden bis ich den neueren Logger NLog entdeckt hatte 🙂
Um log4net in eigene Anwendungen zu verwenden muss dies installiert werden:

Danach muss die Konfiguration des Projekts mit der Konfiguration für log4net erweitert werden:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
	<configSections>
		<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,Log4net"/>
	</configSections>

	<log4net>
		<root>
			<level value="DEBUG"/>
			<appender-ref ref="RollingFileAppender"/>
			<appender-ref ref="ColoredConsoleAppender"/>
		</root>

		<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
			<file value="T:\MyTemp\Logs\MyApplication\log.txt"/>
			<appendToFile value="true"/>
			<rollingStyle value="Size"/>
			<maxSizeRollBackups value="3"/>
			<maximumFileSize value="10MB"/>
			<staticLogFileName value="true"/>
			<layout type="log4net.Layout.PatternLayout">
				<!--<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />-->
        <conversionPattern value="%date{HH:mm:ss,fff} (%-2thread) [%-5level] %type.%method - %message%newline"/>
			</layout>
		</appender>

		<appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
			<mapping>
				<level value="ERROR"/>
				<foreColor value="Red, HighIntensity"/>
				<!-- backColor value="Black" / -->
			</mapping>
			<mapping>
				<level value="DEBUG"/>
				<foreColor value="Green, HighIntensity"/>
			</mapping>

			<mapping>
				<level value="WARN"/>
				<foreColor value="Yellow"/>
			</mapping>

			<mapping>
				<level value="INFO"/>
				<foreColor value="Cyan, HighIntensity"/>
			</mapping>

			<layout type="log4net.Layout.PatternLayout">
				<conversionPattern value="%date{HH:mm:ss,fff} (%-2thread) [%-5level] %type.%method - %message%newline"/>
        <!--<conversionPattern value="%date{HH:mm:ss,ffff} [%thread{2}] - %message%newline" />-->
			</layout>
		</appender>

	</log4net>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/></startup></configuration>

Nun kann der Logger im Code wie folgt verwendet werden:

public class Program
{
    // Create logger for this class ( = typeof(Program)).
    private static readonly ILog Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

    public void Main(string[] args)
    {
	Logger.Info("Starting application from console...");
	// more code...
    }
}

Logger NLog installieren & konfigurieren

Der Logger NLog ist mit über 250M Downloads (in Nuget.org) einer der Standard-Logger für .NET/C#.
Davor verwendete ich den log4net Logger.

Um NLog zu verwenden müssen zwei Nuget-Packages installiert werden:

  1. NLog
  2. NLog.Config

Danach muss die NLog.config Datei im Projekt konfiguriert werden.
Hier ist eine einfache Konfiguration um die Logs in einer Datei zu schreiben sowie diese auch in Console farbig auszugeben:

Die Konfiguration dazu:

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
      autoReload="true"
      throwExceptions="false"
      internalLogLevel="Off" internalLogFile="T:\MyTemp\Logs\PGH.AssemblyParser and Converter\${shortdate}.log">

  <targets>

    <target
	name="coloredConsole"
	xsi:type="ColoredConsole"
	useDefaultRowHighlightingRules="false"
	layout="${longdate} [${pad:padding=5:inner=${level:uppercase=true}}] ${logger} - ${message}" >
			
      <highlight-row condition="level == LogLevel.Debug" foregroundColor="Green"  />
      <highlight-row condition="level == LogLevel.Info"  foregroundColor="Blue"   />
      <highlight-row condition="level == LogLevel.Warn"  foregroundColor="Yellow" />
      <highlight-row condition="level == LogLevel.Error" foregroundColor="Red"    />
      <highlight-row condition="level == LogLevel.Fatal" foregroundColor="Red"    backgroundColor="White" />
    </target>

    <target
	name="logFile"
	xsi:type="File"
	layout="${longdate} [${pad:padding=5:inner=${level:uppercase=true}}] ${logger} - ${message}"
	fileName="T:\MyTemp\Logs\MyApplication\${shortdate}.log" 
	keepFileOpen="false" 
	encoding="utf-8" />
  </targets>
  
  <rules>
    <!-- add your logging rules here -->
    <logger name="*" minlevel="Trace" writeTo="coloredConsole" />
    <logger name="*" minlevel="Trace" writeTo="logFile" />

    <!--
    Write all events with minimal level of Debug (So Debug, Info, Warn, Error and Fatal, but not Trace)  to "f"
    <logger name="*" minlevel="Debug" writeTo="f" />
    -->
  </rules>
</nlog>

Nun kann der Logger wie folgt im Code verwendet werden:

class Program
{
    // Create the logger for current class ( = typeof(Program)).
    private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();

    static void Main(string[] args)
    {
        Logger.Info("Starting application from Console...");
        // more code...
    }
}