Entwicklung_BLAZOR/InterneDLLs/LambertzLogger/LambertzLogger/Logger.cs
2025-08-23 19:30:21 +02:00

999 lines
36 KiB
C#

using Microsoft.Data.SqlClient;
using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.Diagnostics.Eventing.Reader;
using System.IO;
using System.Linq;
using System.Net.Http.Headers;
using System.Reflection;
using System.Reflection.Emit;
using System.Security.Cryptography;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using static System.Net.Mime.MediaTypeNames;
namespace De.Lambertz.Logger
{
public class Logger
{
private static Logger? me = null;
static readonly object padlock0 = new object(); //Threadsafe!!
//
private String? iniPath = null;
private bool weiterCyclischIniLaden = true;
private string? insertSql = null;
private string? sender = null;
//
private int logLevel = 0;
private bool iniRefresh = true;
private string? logDestination = null;
private DateTime lastModified = DateTime.MinValue;
private string? connectionString = null;
private string? tableName = null;
private string? fieldTimeStamp = null;
private string? fieldId = null;
private string? fieldSender = null;
private string? fieldStep = null;
private string? fieldInfo = null;
private string? fieldLogLevel = null;
private string? fieldUser = null;
private string? fieldMachine = null;
private string? fieldProgram = null;
private int fieldIdLength = 50;
private int fieldSenderLength = 50;
private int fieldStepLength = 50;
private int fieldInfoLength = 500;
private int fieldUserLength = 20;
private int fieldMachineLength = 50;
private int fieldProgramLength = 50;
private string? pathLogFile = null;
private string eventSource = "Application";
private Logger()
{
loadIni(true);
//
if (iniRefresh)
{
Thread t1 = new Thread(cyclischIniLaden);
t1.Start();
}
}
/// <summary>
/// Entfernt die interne Referenz auf sich selber.
/// Erneutes Aufrufen einer Log-Funktion erstellt die Referenz neu (Ini wird auch neu geladen)
/// </summary>
public static void Close()
{
if (me != null)
{
me.weiterCyclischIniLaden = false;
lock (padlock0)
{
me = null;
}
}
}
/// <summary>
/// Interne Endlosschleife
/// Prüfte alle 30 Sekunden die INI-Datei
/// ob sie geändert wurde. Falls ja wird sie neu geladen.
/// </summary>
private void cyclischIniLaden()
{
while (weiterCyclischIniLaden)
{
int counter = 0;
while (counter < 30)
{
counter++;
Thread.Sleep(999);
if (me == null || !me.weiterCyclischIniLaden)
{
weiterCyclischIniLaden = false;
break;
}
}
if (weiterCyclischIniLaden)
{
if (File.GetLastWriteTime(iniPath) != lastModified)
{
lock (padlock0)
{
if (me != null)
{
loadIni(false);
}
}
}
}
}
}
/// <summary>
/// Loggen auf Log-level Error
/// </summary>
/// <param name="machine"></param>
/// <param name="program"></param>
/// <param name="itemId"></param>
/// <param name="step"></param>
/// <param name="info"></param>
public static void Error(string machine, string program, string itemId, string step, string info, string? user = null)
{
lock (padlock0)
{
if (me == null)
{
me = new Logger();
}
me.write(Konstanten.LogLevel.Fehler, string.Empty, machine, program, itemId, step, info, user);
}
}
/// <summary>
/// Loggen auf Log-level Error
/// </summary>
/// <param name="sender"></param>
/// <param name="itemId"></param>
/// <param name="step"></param>
/// <param name="info"></param>
public static void Error(string sender, string itemId, string step, string info, string? user = null)
{
lock (padlock0)
{
if (me == null)
{
me = new Logger();
}
if (me.logLevel >= (int)Konstanten.LogLevel.Fehler)
{
me.write(Konstanten.LogLevel.Fehler, sender, string.Empty, string.Empty, itemId, step, info, user);
}
}
}
/// <summary>
/// Loggen auf Log-level Debug
/// </summary>
/// <param name="machine"></param>
/// <param name="program"></param>
/// <param name="itemId"></param>
/// <param name="step"></param>
/// <param name="info"></param>
public static void Debug(string machine, string program, string itemId, string step, string info, string? user = null)
{
lock (padlock0)
{
if (me == null)
{
me = new Logger();
}
if (me.logLevel >= (int)Konstanten.LogLevel.Debug)
{
me.write(Konstanten.LogLevel.Debug, string.Empty, machine, program, itemId, step, info, user);
}
}
}
/// <summary>
/// Loggen auf Log-level Debug
/// </summary>
/// <param name="sender"></param>
/// <param name="itemId"></param>
/// <param name="step"></param>
/// <param name="info"></param>
public static void Debug(string sender, string itemId, string step, string info, string? user = null)
{
lock (padlock0)
{
if (me == null)
{
me = new Logger();
}
if (me.logLevel >= (int)Konstanten.LogLevel.Debug)
{
me.write(Konstanten.LogLevel.Debug, sender, string.Empty, string.Empty, itemId, step, info, user);
}
}
}
/// <summary>
/// Loggen auf Log-level Information
/// </summary>
/// <param name="machine"></param>
/// <param name="program"></param>
/// <param name="itemId"></param>
/// <param name="step"></param>
/// <param name="info"></param>
public static void Information(string machine, string program, string itemId, string step, string info, string? user = null)
{
lock (padlock0)
{
if (me == null)
{
me = new Logger();
}
if (me.logLevel >= (int)Konstanten.LogLevel.Information)
{
me.write(Konstanten.LogLevel.Information, string.Empty, machine, program, itemId, step, info, user);
}
}
}/// <summary>
/// Loggen auf Log-level Information
/// </summary>
/// <param name="sender"></param>
/// <param name="itemId"></param>
/// <param name="step"></param>
/// <param name="info"></param>
public static void Information(string sender, string itemId, string step, string info, string? user = null)
{
lock (padlock0)
{
if (me == null)
{
me = new Logger();
}
if (me.logLevel >= (int)Konstanten.LogLevel.Information)
{
me.write(Konstanten.LogLevel.Information, sender, string.Empty, string.Empty, itemId, step, info, user);
}
}
}
/// <summary>
/// Loggen auf Log-level Status
/// Gedacht für Statusmeldungen die immer ausgegeben werden sollen
/// </summary>
/// <param name="machine"></param>
/// <param name="program"></param>
/// <param name="itemId"></param>
/// <param name="step"></param>
/// <param name="info"></param>
public static void Status(string machine, string program, string itemId, string step, string info, string user = null)
{
lock (padlock0)
{
if (me == null)
{
me = new Logger();
}
if (me.logLevel >= (int)Konstanten.LogLevel.Status)
{
me.write(Konstanten.LogLevel.Status, string.Empty, machine, program, itemId, step, info, user);
}
}
}/// <summary>
/// Loggen auf Log-level Status
/// Gedacht für Statusmeldungen die immer ausgegeben werden sollen
/// </summary>
/// <param name="sender"></param>
/// <param name="itemId"></param>
/// <param name="step"></param>
/// <param name="info"></param>
public static void Status(string sender, string itemId, string step, string info, string user = null)
{
lock (padlock0)
{
if (me == null)
{
me = new Logger();
}
if (me.logLevel >= (int)Konstanten.LogLevel.Status)
{
me.write(Konstanten.LogLevel.Status, sender, string.Empty, string.Empty, itemId, step, info, user);
}
}
}
/// <summary>
/// Falls vom loggenden Programm selber die ini noch nicht angelegt wurde wird hiermit die Ini angelegt
/// </summary>
private static void creatLoggerIni(string path)
{
if (!File.Exists(path))
{
using (StreamWriter sr = new StreamWriter(path))
{
sr.WriteLine(@"LogLevel=0");
sr.WriteLine(@"LogDestination=FILE");
sr.WriteLine(@"PathLogFile=LambertzLogger.log");
sr.WriteLine(@"EventSource=Lambertz");
sr.WriteLine(@"ConnectionString=Data Source=SQL01AC; Initial Catalog=Lambertz; User Id=@p1; Password=@p2;encrypt=false;");
sr.WriteLine(@"Table=[LA].[EDVLog]");
sr.WriteLine(@"Field_TimeStamp=DATUM");
sr.WriteLine(@"Field_Sender=");
sr.WriteLine(@"Field_LogLevel=LOGLEVEL");
sr.WriteLine(@"Field_ItemId=ITEMID");
sr.WriteLine(@"Field_Step=BEFEHL");
sr.WriteLine(@"Field_Info=TEXT");
sr.WriteLine(@"Field_User=USERNAME");
sr.WriteLine(@"Field_Program=PROGRAMM");
sr.WriteLine(@"Field_Machine=MASCHINE");
}
}
}
/// <summary>
/// Lädt die INI-Datei und liest die Konfigurationswerte.
/// </summary>
/// <param name="initial">Gibt an, ob es sich um den initialen Ladevorgang handelt.</param>
private void loadIni(bool initial)
{
this.iniPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LambertzLogger.ini");
//Zur Not hier Ini anlegen (Wird nur angelegt falls noch nicht da)
creatLoggerIni(iniPath);
lastModified = File.GetLastWriteTime(iniPath);
StringBuilder infoText = new StringBuilder();
String token = "";
using (StreamReader reader = new StreamReader(iniPath))
{
String? line = reader.ReadLine();
while (line != null)
{
String key = line.Substring(0, line.IndexOf('='));
String value = line.Substring(line.IndexOf('=') + 1);
infoText.Append(token);
infoText.Append(key);
infoText.Append("=");
infoText.Append(value);
if (token == "")
{
token = ", ";
}
switch (key)
{
case "LogDestination":
logDestination = value.ToUpper();
break;
case "PathLogFile":
pathLogFile = value;
if (!value.ToUpper().EndsWith(".LOG"))
{
value += ".log";
}
if(pathLogFile.IndexOf("\\")<0)
{
pathLogFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, pathLogFile);
}
break;
case "ConnectionString":
connectionString = value.Replace("@p1", "LambertzLogger").Replace("@p2", "LambertzLogger24!");
break;
case "Table":
tableName = value;
break;
case "Field_TimeStamp":
fieldTimeStamp = value;
break;
case "Field_Sender":
fieldSender = value;
break;
case "Field_LogLevel":
fieldLogLevel = value;
break;
case "Field_ItemId":
fieldId = value;
break;
case "Field_Step":
fieldStep = value;
break;
case "Field_Info":
fieldInfo = value;
break;
case "Field_User":
fieldUser = value;
break;
case "Field_Machine":
fieldMachine = value;
break;
case "Field_Program":
fieldProgram = value;
break;
case "LogLevel":
Int32.TryParse(value, out logLevel);
break;
case "IniRefresh":
iniRefresh = value == "1";
break;
case "EventSource":
eventSource = value;
break;
}
line = reader.ReadLine();
}
if (logDestination == Konstanten.LOG_DESTINATION_DB)
{
sqlErstellen();
feldLängenBestimmen();
}
else if(logDestination == Konstanten.LOG_DESTINATION_FILE)
{
//Anlegen des LOG-Directorys, falls noch nicht vorhanden
string? nurPath = Path.GetDirectoryName(pathLogFile);
if (!String.IsNullOrWhiteSpace(nurPath))
{
if (!Directory.Exists(nurPath))
{
Directory.CreateDirectory(nurPath);
}
}
}
}
if (logLevel >= (int)Konstanten.LogLevel.Information)
{
if (sender == null)
{
sender = Assembly.GetCallingAssembly().FullName;
sender = sender.Substring(0, sender.IndexOf(", Culture"));
}
}
//Falls der Logger mit Administrationsrechten gestartet wurde,
//Wird geprüft ob die eventSource im Ereignisprotokoll von Windows bereits registriert ist.
//Falls nein, wird sie registriert
if (new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator))
{
if (!String.IsNullOrEmpty(eventSource))
{
if (!EventLog.SourceExists(eventSource))
{
EventLog.CreateEventSource(eventSource, "Application");
}
}
}
if (!iniRefresh)
{
weiterCyclischIniLaden = false;
}
}
/// <summary>
/// Hier werden die Byte größen der Datenbankfelder ausgelesen.
/// Dies erlaubt die Änderung der Feldlängen in der Datenbank ohne Anpassungen
/// am Logger
/// </summary>
private void feldLängenBestimmen()
{
using (SqlConnection con = new SqlConnection(connectionString))
{
StringBuilder temp = new StringBuilder();
temp.Append("Select ");
if(String.IsNullOrWhiteSpace(fieldSender))
{
temp.Append(" COL_LENGTH('");
temp.Append(tableName);
temp.Append("', '");
temp.Append(fieldMachine);
temp.Append("') as ");
temp.Append(fieldMachine);
temp.Append(",");
temp.Append(" COL_LENGTH('");
temp.Append(tableName);
temp.Append("', '");
temp.Append(fieldProgram);
temp.Append("') as ");
temp.Append(fieldProgram);
temp.Append(",");
}
else
{
temp.Append(" COL_LENGTH('");
temp.Append(tableName);
temp.Append("', '");
temp.Append(fieldSender);
temp.Append("') as ");
temp.Append(fieldSender);
temp.Append(",");
}
temp.Append(" COL_LENGTH('");
temp.Append(tableName);
temp.Append("', '");
temp.Append(fieldStep);
temp.Append("') as ");
temp.Append(fieldStep);
temp.Append(",");
temp.Append(" COL_LENGTH('");
temp.Append(tableName);
temp.Append("', '");
temp.Append(fieldId);
temp.Append("') as ");
temp.Append(fieldId);
temp.Append(",");
temp.Append(" COL_LENGTH('");
temp.Append(tableName);
temp.Append("', '");
temp.Append(fieldInfo);
temp.Append("') as ");
temp.Append(fieldInfo);
temp.Append(",");
temp.Append(" COL_LENGTH('");
temp.Append(tableName);
temp.Append("', '");
temp.Append(fieldUser);
temp.Append("') as ");
temp.Append(fieldUser);
con.Open();
SqlCommand cmd = new SqlCommand(temp.ToString(), con);
using (SqlDataReader reader = cmd.ExecuteReader())
{
Dictionary<String, int> fi = GetFelderIndex(reader);
if (reader.Read())
{
foreach (String feldName in fi.Keys)
{
int länge = reader.GetInt16(fi[feldName]);
if(feldName == fieldSender)
{
fieldSenderLength = länge;
}
else if (feldName == fieldId)
{
fieldIdLength = länge;
}
else if (feldName == fieldStep)
{
fieldStepLength = länge;
}
else if (feldName == fieldInfo)
{
fieldInfoLength = länge;
}
else if (feldName == fieldUser)
{
fieldUserLength = länge;
}
else if (feldName == fieldMachine)
{
fieldMachineLength = länge;
}
else if (feldName == fieldProgram)
{
fieldProgramLength = länge;
}
}
}
}
}
}
public Dictionary<String, int> GetFelderIndex(SqlDataReader reader)
{
Dictionary<String, int> result = new Dictionary<string, int>();
for (int i = 0; i < reader.FieldCount; i++)
{
String name = reader.GetName(i);
result.Add(name, i);
}
return result;
}
/// <summary>
/// Das sql zum Schreiben in die Datenbank wird dynamisch aus den in der Ini angegebenen Feldnamen erstellt.
/// </summary>
private void sqlErstellen()
{
String token;
StringBuilder temp = new StringBuilder();
temp.Append("INSERT INTO ");
temp.Append(tableName);
temp.Append(" (");
temp.Append(fieldTimeStamp);
temp.Append(", ");
temp.Append(fieldLogLevel);
temp.Append(", ");
temp.Append(fieldStep);
temp.Append(", ");
temp.Append(fieldId);
temp.Append(", ");
temp.Append(fieldInfo);
temp.Append(", ");
temp.Append(fieldUser);
if (String.IsNullOrWhiteSpace(fieldSender))
{
temp.Append(", ");
temp.Append(fieldMachine);
temp.Append(", ");
temp.Append(fieldProgram);
token = ", @p8)";
}
else
{
temp.Append(", ");
temp.Append(fieldSender);
token = ")";
}
temp.Append(") values (@p1, @p2, @p3, @p4, @p5, @p6, @p7");
temp.Append(token);
insertSql = temp.ToString();
}
private void write(Konstanten.LogLevel logLevel, string sender, string machine, string program, string itemId, string step, string info, string user)
{
switch(logDestination)
{
case Konstanten.LOG_DESTINATION_DB:
writeDB(logLevel, sender, machine, program, itemId, step, info, user);
break;
case Konstanten.LOG_DESTINATION_FILE:
case Konstanten.LOG_DESTINATION_FILEC:
writeFile(logLevel, sender, machine, program, itemId, step, info, user, logDestination == Konstanten.LOG_DESTINATION_FILEC);
break;
case Konstanten.LOG_DESTINATION_EVENT_LOG:
writeEventLog(logLevel, sender, machine, program, itemId, step, info, user);
break;
}
////Fehler werden immer auch in des EventLog geschrieben
//if(logDestination != Konstanten.LOG_DESTINATION_EVENT_LOG && logLevel == Konstanten.LogLevel.Fehler)
//{
// EventLogError(sender, machine, program, itemId, step, info, user);
//}
}
public static void EventLogError(string sender, string machine, string program, string itemId, string step, string info, string user)
{
lock (padlock0)
{
if (me == null)
{
me = new Logger();
}
me.writeEventLog(Konstanten.LogLevel.Fehler, sender, machine, program, itemId, step, info, user);
}
}
public static void EventLogInformation(string sender, string machine, string program, string itemId, string step, string info, string user, bool ignoreLogLevel = false)
{
lock (padlock0)
{
if (me == null)
{
me = new Logger();
}
if (ignoreLogLevel || me.logLevel >= (int)Konstanten.LogLevel.Information)
{
me.writeEventLog(Konstanten.LogLevel.Information, sender, machine, program, itemId, step, info, user);
}
}
}
public static void EventLogWrite(string sender, string machine, string program, string itemId, string step, string info, string user)
{
lock (padlock0)
{
if (me == null)
{
me = new Logger();
}
me.writeEventLog(Konstanten.LogLevel.Information, sender, machine, program, itemId, step, info, user);
}
}
public static void EventLogDebug(string sender, string machine, string program, string itemId, string step, string info, string user)
{
lock (padlock0)
{
if (me == null)
{
me = new Logger();
}
if (me.logLevel >= (int)Konstanten.LogLevel.Debug)
{
me.writeEventLog(Konstanten.LogLevel.Debug, sender, machine, program, itemId, step, info, user);
}
}
}
private void writeEventLog(Konstanten.LogLevel logLevel, string sender, string machine, string program, string itemId, string step, string info, string user)
{
if (sender == null)
{
sender = String.Empty;
}
if (itemId == null)
{
itemId = String.Empty;
}
if (step == null)
{
step = String.Empty;
}
if (info == null)
{
info = String.Empty;
}
if (machine == null)
{
machine = String.Empty;
}
if (program == null)
{
program = String.Empty;
}
if (user == null)
{
user = Environment.UserName;
}
string line;
if (String.IsNullOrEmpty(sender))
{
line = $"{DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss.fff")}; {machine}; {program}; {user}; {logLevel}; {step}; {itemId}; {info}";
}
else
{
line = $"{DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss.fff")}; {sender}; {user}; {logLevel}; {step}; {itemId}; {info}";
}
string source = eventSource;
try
{
try
{
if (!EventLog.SourceExists(source))
{
source = "Application";
}
}
catch (Exception)
{
source = "Application";
}
using (EventLog eventLog = new EventLog("Application"))
{
eventLog.Source = source;
EventLogEntryType type;
switch(logLevel)
{
case Konstanten.LogLevel.Information:
type = EventLogEntryType.Information;
break;
case Konstanten.LogLevel.Fehler:
type = EventLogEntryType.Error;
break;
default:
type = EventLogEntryType.Information;
break;
}
eventLog.WriteEntry(line, type, 9999);
}
} catch (Exception) { }
}
/// <summary>
/// Schreibt in Datei die mit PathLogFile angegegen ist
/// </summary>
/// <param name="logLevel"></param>
/// <param name="sender"></param>
/// <param name="itemId"></param>
/// <param name="step"></param>
/// <param name="info"></param>
private void writeFile(Konstanten.LogLevel logLevel, string sender, string machine, string program, string itemId, string step, string info, string? user = null, bool logAlsoOnConsole = false)
{
if (sender == null)
{
sender = String.Empty;
}
if (itemId == null)
{
itemId = String.Empty;
}
if (step == null)
{
step = String.Empty;
}
if (info == null)
{
info = String.Empty;
}
if (machine == null)
{
machine = String.Empty;
}
if (program == null)
{
program = String.Empty;
}
if (user == null)
{
user = Environment.UserName;
}
string line;
if (String.IsNullOrEmpty(sender))
{
line = $"{DateTime.Now:dd.MM.yyyy HH:mm:ss}; {machine}; {program}; {user}; {logLevel}; {step}; {itemId}; {info}";
}
else
{
line = $"{DateTime.Now:dd.MM.yyyy HH:mm:ss}; {sender}; {user}; {logLevel}; {step}; {itemId}; {info}";
}
if (logAlsoOnConsole)
{
Console.Write(line);
}
while (true)
{
try
{
File.AppendAllText(pathLogFile, $"{line}\r\n", System.Text.Encoding.Default);
}
catch (IOException)
{
//Datei ist gesperrt, passiert schonmal, nochmal versuchen
continue; //Neue Iteration der Schleife sofort starten
}
break;
}
}
/// <summary>
/// Schreib in die DB
/// </summary>
/// <param name="logLevel"></param>
/// <param name="sender"></param>
/// <param name="itemId"></param>
/// <param name="step"></param>
/// <param name="info"></param>
private void writeDB(Konstanten.LogLevel logLevel, string sender, string machine, string programm, string itemId, string step, string info, string? user = null)
{
//Prüfen der Längen der übergebenen Werte
if (itemId == null)
{
itemId = String.Empty;
}
else if (itemId.Length > fieldIdLength)
{
itemId = itemId.Substring(0, fieldIdLength);
}
if (step == null)
{
step = String.Empty;
}
else if (step.Length > fieldStepLength)
{
step = step.Substring(0, fieldStepLength);
}
if (info == null)
{
info = String.Empty;
}
else if (info.Length > fieldInfoLength)
{
info = info.Substring(0, fieldInfoLength);
}
if (sender == null)
{
sender = String.Empty;
}
else if (sender.Length > fieldSenderLength)
{
sender = sender.Substring(0, fieldSenderLength);
}
if (programm == null)
{
programm = String.Empty;
}
else if (programm.Length > fieldProgramLength)
{
sender = sender.Substring(0, fieldProgramLength);
}
if (machine == null)
{
machine = String.Empty;
}
else if (machine.Length > fieldMachineLength)
{
sender = sender.Substring(0, fieldMachineLength);
}
if (user == null)
{
user = Environment.UserName;
}
else if (user.Length > fieldUserLength)
{
user = user.Substring(0, fieldUserLength);
}
try
{
//Schreiben in DB
using (SqlConnection con = new SqlConnection(connectionString))
{
con.Open();
SqlCommand cmd = new SqlCommand(insertSql, con);
cmd.Parameters.AddWithValue("@p1", DateTime.Now);
cmd.Parameters.AddWithValue("@p2", logLevel);
cmd.Parameters.AddWithValue("@p3", step);
cmd.Parameters.AddWithValue("@p4", itemId);
cmd.Parameters.AddWithValue("@p5", info);
cmd.Parameters.AddWithValue("@p6", user);
if (String.IsNullOrEmpty(fieldSender))
{
cmd.Parameters.AddWithValue("@p7", machine);
cmd.Parameters.AddWithValue("@p8", programm);
}
else
{
cmd.Parameters.AddWithValue("@p7", sender);
}
cmd.ExecuteNonQuery();
}
}
catch (IOException ex)
{
//Datenbank nicht erreichbar.. Notfall-Log in Datei wenn Pfad für Datei angegeben
if(!String.IsNullOrWhiteSpace(pathLogFile))
{
if (String.IsNullOrWhiteSpace(fieldSender))
{
writeFile(Konstanten.LogLevel.Fehler, String.Empty, Environment.MachineName, this.sender, itemId, step, info, user);
}
else
{
writeFile(Konstanten.LogLevel.Fehler, this.sender + " auf " + Environment.MachineName, string.Empty, string.Empty, string.Empty, "Fehler DB-Log", ex.Message);
}
}
}
}
}
}