Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Do Jul 03, 2025 17:23

Foren-Übersicht » Programmierung » Allgemein
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 12 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Wie loggt man richtig
BeitragVerfasst: Di Apr 27, 2010 09:05 
Offline
DGL Member

Registriert: Mi Okt 16, 2002 15:06
Beiträge: 1012
Eine frage an die Profis hier: Wie loggt man in komplexen Anwendungen richtig ?

Was für Loglevel benutzt man in welchen fällen ?
An welchen Stellen setzt man logging richtig ein ?
Wie verhindert man das das Programm durch logging unleserlich wird ?
Wie loggt man das man Fehler erkennen, falls es beim Kunden probleme gibt ?
Wie man mit Eingang (mit oder ohne Argumente) und Ausgang (mit oder ohne result) von Methoden umgeht ?

Ich frage deshalb weil ich Beruflich große Kommerziele Server Anwendungen schreibe,
die auf Windows-Dienste aufbauen und etwailige selbst entwickelte DLL´s nutzen und
mind 50k Zeilen Quellcode enthalten.

Solche Anwendung sauber zu logging erweisst sich immer als Schwierig,
allein schon deswegen wenn andere dran arbeiten und z.b. nur mit Debug loggen,
und ich somit nach Fehler riechen muss :(

Es geht aber nicht darum, welche Lib ich nehmen muss zum loggen.
Das Thema muss man hier nicht anschneiden und darum geht es mir nicht.


Ich will nur wissen wie man richtig loggt. Das ist alles.

Danke erstmal,
Final


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Wie loggt man richtig
BeitragVerfasst: Di Apr 27, 2010 09:17 
Offline
Guitar Hero
Benutzeravatar

Registriert: Do Sep 25, 2003 15:56
Beiträge: 7810
Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Bei uns im Projekt haben wir Templates (Eclipse-Codetemplates) welche

1. bei neuerstellten Funktionen automatisch ein
if (log.isTraceEnabled()) {
log.enter("Funktionsname");
}
Alternativ auch mit Parametern. Das sollte zumindest bei allen public methoden gemacht werden.

beim Verlassen gibt es das Gleiche mit log.exit().

Bei jeder Exception wird das Gleiche mit log.exception() gemacht.

Außerdem sollen entwickler an entscheidenden Stellen bzw. bei langen Funktionen immer mal wieder "checkpoint" trace-logs einbauen.

Somit kannst du beim Kunden im Problemfall trace-logging aktivieren und siehst wo dein Code durchläuft. Is natürlich nix für den dauerhaften produktiveinsatz.

Normalerweise läuft das Loggin bei der Entwicklung auf DEBUG und beim Kunden auf WARN.

ERRORs werden genutzt um Fachlich falsches Verhalten abzubilden bzw um zu zeigen, dass die Anwendung in einem Bereich inkonsistent werden könnte.
FATAL überhaupt nur selten und dann nur um zu zeigen, dass die Technik unvorhersehbar gestört ist. Hab ich noch nie benutzt.

Hoffe das geht in die Richtung von dem was du meinst.

_________________
Blog: kevin-fleischer.de und fbaingermany.com


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Wie loggt man richtig
BeitragVerfasst: Di Apr 27, 2010 10:19 
Offline
DGL Member

Registriert: Mi Okt 16, 2002 15:06
Beiträge: 1012
Das Enter/Leave prinzip kenn ich und nutze ich auch,
allerdings immer alles von hand.
Wüsste nicht wie ich das in C# Generalisieren könnte :(

Wie ist das denn mit Info Logging ? Wann benutzt man sowas ?

Wenn man Error/Warning/Fatal loggt, macht man das nur wenn eine Exception aufgetreten ist oder
auch wenn man im code schon einen Fehler erkannt hatte, z.b. Daten die reinkommen passen nicht.

Wäre sowas richtig ?

Code:
        /// <summary>
        /// Main entry point
        /// </summary>
        /// <param name="args">Command line arguments</param>
        /// <returns>Application result</returns>
        [STAThread]
        static int Main(string[] args)
        {
            Logger.Info(MethodInfo.GetCurrentMethod(), "Started Worker Queue V" + Assembly.GetExecutingAssembly().GetName().Version.ToString());
            Console.WriteLine("eRoom Business Reports Worker Queue V" + Assembly.GetExecutingAssembly().GetName().Version.ToString());

            // Prevent that this application can be started multiple times
            Logger.Debug(MethodInfo.GetCurrentMethod(), "Aquire application mutex state");
            Mutex singleInstanceMutex = null;
            try
            {
                singleInstanceMutex = Mutex.OpenExisting("EBRWorkerQueue");

                // application is already open
                Logger.Warn(MethodInfo.GetCurrentMethod(), "Application already opened, Exiting!");
                return ReturnCodes.ApplicationAlreadyOpened;
            }
            catch
            {
                // Mutex dont exists, create one
                Logger.Debug(MethodInfo.GetCurrentMethod(), "Create new application mutex");
                singleInstanceMutex = new Mutex(true, "EBRWorkerQueue");
            }

            // Get parameters
            Logger.Debug(MethodInfo.GetCurrentMethod(), String.Format("Parse arguments: {0}", ToString(args)));
            bool compabilityParam = HasArgument(args, "compability");

            // Print arguments
            Logger.Info(MethodInfo.GetCurrentMethod(), String.Format("Compability mode active: {0}", compabilityParam));

            // Run Queue Application
            int res = ReturnCodes.Success; // By default its successfully.
            try
            {
                // Init worker queue / eRoom application is created internally
                Logger.Debug(MethodInfo.GetCurrentMethod(), "Run worker queue");
                using (EBRWorkerQueue workerQueue = new EBRWorkerQueue())
                {
                    // Set compability parameter
                    workerQueue.Compability = compabilityParam;

                    // Run worker queue
                    res = workerQueue.Run();
                    Logger.Debug(MethodInfo.GetCurrentMethod(), "Finished worker queue, result: " + res.ToString());
                }
            }
            catch (Exception ex)
            {
                Logger.Error(MethodInfo.GetCurrentMethod(), "Unhandled exception while running worker queue!", ex);
            }
            finally
            {
                // Release mutex
                if (singleInstanceMutex != null)
                {
                    Logger.Debug(MethodInfo.GetCurrentMethod(), "Release application mutex");
                    singleInstanceMutex.ReleaseMutex();
                }
            }
            Logger.Info(MethodInfo.GetCurrentMethod(), "Finished Worker Queue with result: " + res.ToString());
            return res;
        }

        /// <summary>
        /// Runs the worker queue:
        ///   1.) Compability process (Only if mode is enabled)
        ///   2.) Clear memory job list
        ///   3.) Add jobs to memory job list
        ///   4.) Process jobs (Refresh all reports)
        /// </summary>
        /// <returns>Application result code</returns>
        public int Run()
        {
            Logger.Enter(MethodInfo.GetCurrentMethod());

            Logger.Debug(MethodInfo.GetCurrentMethod(), "Check application object...");
            if (!HasApplication)
            {
                Logger.Error(MethodInfo.GetCurrentMethod(), "Check application object failed!");
                return ReturnCodes.ApplicationObjectIsMissing;
            }
            else
                Logger.Debug(MethodInfo.GetCurrentMethod(), "Check application object ok");

            // Compability process (Only if mode is enabled)
            if (bCompability)
            {
                Logger.Debug(MethodInfo.GetCurrentMethod(), "Run compability process");
                CompabilityProcess();
                Logger.Debug(MethodInfo.GetCurrentMethod(), "Finished compability process");
            }

            // Clear memory job list
            Logger.Debug(MethodInfo.GetCurrentMethod(), "Clear memory job list");
            aJobs.Clear();

            // Start worker queue
            Logger.Debug(MethodInfo.GetCurrentMethod(), "Add jobs");
            AddJobs();
            Logger.Debug(MethodInfo.GetCurrentMethod(), "Finished adding jobs");

            // Process worker queue jobs
            Logger.Debug(MethodInfo.GetCurrentMethod(), "Run reports");
            ProcessJobs();
            Logger.Debug(MethodInfo.GetCurrentMethod(), "Finished reports");

            // Return
            int res = ReturnCodes.Success;
            Logger.Leave(MethodInfo.GetCurrentMethod(), res);
            return res;
        }


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Wie loggt man richtig
BeitragVerfasst: Di Apr 27, 2010 12:53 
Offline
DGL Member
Benutzeravatar

Registriert: Di Apr 29, 2008 18:56
Beiträge: 1213
Programmiersprache: Delphi/FPC
Hey,

ich mach das immer so: Ich schreib mir in der Datei, in der ich gerade arbeite ne CompilerDirektieve und wenn die definiert ist, dann schick ich den Log Test an die Konsole (oder halt an die Log-Klasse, wenn du sowas hast). So hab ich den Überblick über die Logs un kann die, die ich nich brauch abschalten...

MfG Bergmann

_________________
Aktuelle Projekte: BumpMapGenerator, Massive Universe Online
Auf meiner Homepage gibt auch noch paar Projekte und Infos von mir.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Wie loggt man richtig
BeitragVerfasst: Di Apr 27, 2010 16:29 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2623
Wohnort: Berlin
Programmiersprache: Go, C/C++
Richtig loggen tut man erstmal nicht auf die Console ^^, die ist einfach übelst lahm.
Ich arbeite ja auch Beruflich an Server allerdings für MMO und da geht richtig was an log über die Bühne.
Hierfür nutzen wir ein Netzwerk Log-Server, welcher TB an Festplattenspeicher hat, einige Kerne, 32GB Ram läuft.
Da schmeist du dann per TCP deine ganzen Messages rein, 3 Level Debug,Error,Info.
Error kommen von ErrorCode und von externen exception(vermeide sowas immer, wenn möglich), Info kommen von dein Programmcode, wie z.B. StartSession(.....) und Debug sind halt alle Messages in verbindung mit einem Error, also wenn du eine exception hast, wird der funktionsstack zurück gerollt und dabei kommen weitere folgefehler, dann Informationen die im catch zweig kommen, Dumps und ähnliches.
Logs für große Anwendungen sind sehr CPU und Speicherlastig, daher ein externer Server, welcher z.b. durch ein apache und xml/xslt prima live beobachtet werden kann.

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Wie loggt man richtig
BeitragVerfasst: Di Apr 27, 2010 23:29 
Offline
Guitar Hero
Benutzeravatar

Registriert: Do Sep 25, 2003 15:56
Beiträge: 7810
Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Also dein Codebeispiel ist schon ziemlich krass mit Log-Ausgaben durchsetzt.

Es geht m.M.n. nicht nur darum Sachen ins log zu schreiben, sondern hilfreiche Sachen ins Log zu schreiben.

Ich habe mal eine Anwendung Supporten müssen, deren Log übersäht war mit Meldungen ala "Fatal Exception - Main Queue Missing!!!!!" oder sowas in dieser Bedeutung. Als ich dann die Leute die das bis dahin Supportet hatten gefragt habe, was das sei kam als Antwort: "Ist nicht wichtig. Kommt immer."
DAS darf nicht sein.

Aussagen und Loglevel sowie Informationsgehalt muss zusammen passen.

Das Tracelogging macht man nur, damit man im Worstcase mal das Tracelogging für 5Minuten anschalten kann, wo der Code die Teile durchläuft die aller Wahrscheinlichkeit nach einen Bug haben. Ansonsten braucht man das nicht.
Debug-Logging ist für die Entwickler da.
Error und Warning sind wichtiger. Warnings sollten immer dann geworfen werden, wenn der Code einen Sonderfall der Spezifikation durchläuft, der eigentlich nicht üblich ist. z.B. das ein Config-File fehlt und man Default-Values verwendet. Oder wenn eine Importschnittstelle gerufen wird, und sie merkt, dass keine Daten vorliegen, obwohl laut Spec immer irgendwas kommen müsste. Das sind Warnings.
Errors sind Fehler wo wirklich Exceptions fliegen. Einige Exceptions werden zwar auch nur als Warning gelogt, aber das sind erstmal alles ERROR Kandidaten.
Errors innerhalb von Schleifen sollten die Werte der Schleife mitloggen.

Loggen in die Konsole direkt ist eher nicht sinnvoll, da alle Logausgaben zusammen an einem Ort sein sollten.

Man sollte nicht zuviel in ein Logfile schreiben. Erstens kostet es Zeit, dann Speicherplatz und zuletzt hilft einem "Blabla-Logs" nicht beim Fehlerfinden.

_________________
Blog: kevin-fleischer.de und fbaingermany.com


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Wie loggt man richtig
BeitragVerfasst: Di Mai 04, 2010 14:50 
Offline
DGL Member

Registriert: Mi Okt 16, 2002 15:06
Beiträge: 1012
Also habe ich das richtig verstanden:

Errors/Fatal werden geloggt bei jeder Exception.
Spielt dabei keine rolle ob diese Unhandled oder Handled ist.

Info werden dann Informationen sein wie z.b. "Berechne etwas"...

Debug ist das dann dazwischen Enter und Leave.

Beispiel:

Code:
int Addition(int a, int b)
{
  Log.Enter(a, b);

  Log.Debug("Initialize result with zero");
  int res = 0;

  Log.Info(String.Format("Calculate {0} and {1}", a, b));
  try
  {
    res = a+b;
    Log.Debug(String.Format("Calculation from {0} and {1} succeeded.", a, b));
  }
  catch (Exception ex)
  {
    Log.Error(String.Format("Failed calculating {0} and {1}!", a, b), ex);
  }
  Log.Leave(res);
  return res;
}


Da ist aber noch eine Frage, bzw. eine Anforderung:

Ein Kunde macht eine Migration mit einem Tool das ich entwickelt habe.
Der Kunde will unbedingt im Log erkennen welches Element grad migriert wird.
Info ist aber vom Loglevel her zu hoch, da der Kunde keine unnötigen Enter/Leave... sehen will.

Macht man da dann ein Neues Loglevel für den Kunden oder bleibt man beim Info ?


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Wie loggt man richtig
BeitragVerfasst: Di Mai 04, 2010 16:12 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2623
Wohnort: Berlin
Programmiersprache: Go, C/C++
Jupp
Jupp
Jupp

Code:
int Addition(int a, int b)
{
  int res = 0;
  Log::FunctionScopeEnter FunctionScopeDebugMessage(res,a, b);//generate enter message with init values and parameter(result,parameterlist)

  try
  {
    res = a+b;
  }
  catch (Exception ex)
  {
    Log.Error(String.Format("Failed calculating {0} + {1}!", a, b), ex);
  }
  return res;
}//FunctionScopeDebugMessage will bedesrtoyed and print all values again with leave message


Mein Vorschlag wäre dem Kunden ein Präfix an zu bieten, also dass vor jeder Message dann der Präfix steht z.B. "MyFramework->"+"Error:"+ErrorMsg() und "CustomerApplication->"+"Error:"+ErrorMsg(); .
Dies erlaubt eine einfache Log API und man kann sehr einfach zwischen eigenen Application und fremden Bibliotheks Code unterscheiden.

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Wie loggt man richtig
BeitragVerfasst: Di Mai 04, 2010 18:42 
Offline
Guitar Hero
Benutzeravatar

Registriert: Do Sep 25, 2003 15:56
Beiträge: 7810
Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Enter und Leave sind eins drunter auf Trace-Level.

Infos sind genau für sowas da wie dein Kunde will.

_________________
Blog: kevin-fleischer.de und fbaingermany.com


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Wie loggt man richtig
BeitragVerfasst: Mi Mai 05, 2010 10:46 
Offline
DGL Member

Registriert: Mi Okt 16, 2002 15:06
Beiträge: 1012
Flash hat geschrieben:
Enter und Leave sind eins drunter auf Trace-Level.

Infos sind genau für sowas da wie dein Kunde will.


Hmm ich glaube ich habe die ganze zeit ein wenig was falsch gemacht.
Enter und Leave gibt es ja als eigentliches Loglevel nicht, zumindest nicht in log4net.

Bisher habe ich immer Debug bei Enter und Leave benutzt, das ist natürlich nicht so toll :(

Code:
        public enum LogLevel
        {
            Off = -1,
            Fatal = 0,
            Error = 1,
            Warning = 2,
            Info = 3,
            Debug = 4
        }


Ich müsste also, Enter und Leave über Debug setzten.
Also debug auf 5 und Enter/Leave auf 4 richtig ?

Info würde man dann nur noch für Kundeninfos, bzw. Programinfos nutzen, z.b. auch Versionsnummer der Anwendung, User context, etc.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Wie loggt man richtig
BeitragVerfasst: Mi Mai 05, 2010 12:44 
Offline
Guitar Hero
Benutzeravatar

Registriert: Do Sep 25, 2003 15:56
Beiträge: 7810
Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Versuchs mal so:

ALL -> TRACE -> DEBUG -> INFO -> WARN -> ERROR -> FATAL

_________________
Blog: kevin-fleischer.de und fbaingermany.com


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Wie loggt man richtig
BeitragVerfasst: Do Mai 06, 2010 19:28 
Offline
Forenkatze
Benutzeravatar

Registriert: Mi Okt 22, 2003 18:30
Beiträge: 1945
Wohnort: Närnberch
Programmiersprache: Scala, Java, C*
Ahoi,

hab den Thread nur überflogen, aber zusätzlich zu dem, was Flash sagt, mag ich noch was hinzufügen wg. Loglevels:

Warning: Für alle Ausnahmen, die zwar potentiell unerwünscht sind, von denen sich das Programm aber "erholen" kann. Also alles, wo das Programm noch sinnvoll weiterlaufen kann.
Error: Für alles, was wirklich "WAaaaaaaaaaahh!" ist :D Darunter fallen die meisten Exceptions (Nicht alle, manche sind eher Kandidaten für Warnungen)
Fatal: Etwas, was das Programm gleich am Anfang schon abbricht. Wenn die VM z.B. verreckt, nicht starten kann, wenn irgendwelche Bibliotheken fehlen. Spich alles, was wirklich fatal ist für das Programm und das keine Chance hat, durch eine Fehlerbehandlung behandelt zu werden.

Das ist natürlich auch alles abhängig vom Programm, das du schreibst. Wenn du unerwartete Ausnahmen generell auch dem User anzeigt a la einem Dialog "OOoops! The following unexpected error occured: ..." ist das was anderes als wenn du z.B. eine Web-Anwendung schreibt, die jeden Fehler mit einem HTTP 500 (Internal Server Error) beantwortet und die Exception (und ihren Stacktrace freilich) in einer html-seite anzeigt...

Mal ein Beispiel an einem Klassiker: Eine FileNotFoundException wäre für mich z.B. sowohl ein Kandidat für Warning als auch für Error - eventuell auch für Fatal:
Warning
Beispielsweise dann, wenn eine Konfigurationsdatei nicht gefunden wurde, das Programm aber default-Werte für die Datei hat.
=> Normalerweise sollte die Datei da sein, die Anwendung kann sich jedoch von dem Fehlverhalten erholen, da sie Default-Werte hat

Error
Wenn das Programm eine Datei auslesen soll, die nicht da ist, aber da sein muss wie z.B. Data-Files für ein Spiel (Wenn z.B. ein Level geladen werden soll, von dem Level ist weit und breit auf der Platte aber nichts zu sehen).

Fatal
Wenn du z.B. eine Bibliothek laden musst, die du fürs Programm brauchst und die ist einfach nicht da. Dann ist das etwas, was deine komplette Anwendung nutzlos machst und damit ziemlich fatal ;)

Hoffe das hilft weiter,
~ Frase

_________________
"Für kein Tier wird so viel gearbeitet wie für die Katz'."


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 12 Beiträge ] 
Foren-Übersicht » Programmierung » Allgemein


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 4 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.008s | 14 Queries | GZIP : On ]