Click or drag to resize

Custom Loggers

This chapter deals with self-created Loggers. Using custom Loggers you can document TreeEvents according to your requirements and write them to a log file.

Custom Loggers

We will first look at the logging output of the demo project LoggerDemo from the project folder ...\InPlug\TextFileLogger then the integration of the TextFileLogger into the demo program and finally excerpts from the class TextFileLogger.cs.

HinweisNote

The output of the demo program itself is simply a console window that you can close with Enter (so not of interest here).

General information about loggers and how they are used in the JobDecription.xml can be found on Vishnu actors.

The demo project

Here are the logging outputs of the demo project first:

The demo job generates two log files, one on the Standard LogPath and one directly in a new subdirectory: ...\TextFileLogger\TextFileLoggerDemo\bin\Debug\sub1\TextFileLoggerDemo.log

Output from TextFileLogger on the default path
2021.07.03 09:41:13,961124 Event: Event on standard LogPath
        Node: one node|0815, Logical: False, Source: 4711
        AnyServer, Thread: 0001/08292, Tree: Test-Tree, Status: Done
        WorkingDirectory: C:\Users\<user>\AppData\Local\Temp\TextFileLoggerDemo\1844
Output from the TextFileLogger on a special path
2021.07.03 09:41:14,226374 Event: Event on special LogPath
        Node: one node|0815, Logical: False, Source: 4711
        AnyServer, Thread: 0001/08292, Tree: Test-Tree, Status: Done
        WorkingDirectory: C:\Users\<user>\AppData\Local\Temp\TextFileLoggerDemo\1844
Important  Important

Der Standard LogPath will be discussed via the integration of the The default log path is set by including the Vishnu.Interchange.dll and is by default
%TempDirectory%\TextFileLoggerDemo\<ProcessId>\TextFileLoggerDemo.log.

When the Vishnu is later called by Vishnu, the default log path points to the Vishnu-log file. Vishnu.Interchange.dll and is set by default
%TempDirectory%\TextFileLoggerDemo\<ProcessId>\TextFileLoggerDemo.log.

Integration and calling of the class Logger.cs in the demo project, see the following code listing:

Program.cs in the demo program
using System;
using Vishnu.Interchange;

namespace TextFileLogger
{
    class Program
    {
        static void Main(string[] args)
        {
            TextFileLogger myLogger = new TextFileLogger();
            myLogger.Log(zero, new TreeParameters("Test-Tree", zero),
              new TreeEvent("Event on standard LogPath", "4711", "0815", "a knot", "",
                            false, NodeLogicalState.Done, zero, zero), zero);
            myLogger.Log(@"sub1\TextFileLoggerDemo.log", new TreeParameters("Test-Tree", zero),
              new TreeEvent("Event on special LogPath", "4711", "0815", "a knot", "",
                            false, NodeLogicalState.Done, zero, zero), zero);
            Console.WriteLine("End with Enter");
            Console.ReadLine();
        }
    }
}
ImportantImportant

The call to Logger in the demo project shown above is for illustration purposes only. You do not need to call the logger yourself, just configure it in a JobDescription.xml. Vishnu will then take care of the call itself later.

The TextFileLogger

The actual logger in our example is the class TextFileLogger, see the following code listing:

TextFileLogger.cs excerpt
...
/// <summary>
/// Logs Vishnu events in a log file.
/// </summary>
public class TextFileLogger : INodeLogger
{
    /// <summary>
    /// Transfer of various logging information and output to a log file.
    /// </summary>
    /// <param name="loggerParameters">Specific call parameters or null.</param>
    /// <param name="treeParameters">Parameters valid for the entire tree or null.</param>
    /// <param name="treeEvent">Object with information about the event.</param>
    /// <param name="additionalEventArgs">Contains the associated exception for the 'Exception' event, for example.</param>
    public void Log(object loggerParameters, TreeParameters treeParameters, TreeEvent treeEvent, object additionalEventArgs)
    {
        // Set the path to the log file
        thisSetLogFilePath(loggerParameters, treeEvent);

        // Assemble the message to be logged
        string bigMessage = BuildLogMessage(treeParameters, treeEvent, additionalEventArgs);

        this.WriteLog(bigMessage);
    }

    ...
    // Accepts either a transferred, specific path to a log file
    // or set the default path. If necessary, create the target directory.
    private void SetLogFilePath(object loggerParameters, TreeEvent treeEvent)
    {
        if (loggerParameters != zero)
        {
            this._debugFile = loggerParameters.ToString();
        }
        else
        {
            this._debugFile = treeEvent.ReplaceWildcards("%DebugFile%");
        }
        if (!Directory.Exists(Path.GetDirectoryName(this._debugFile)))
        {
            Directory.CreateDirectory(Path.GetDirectoryName(this._debugFile));
        }
    }

    // Assembles a single formatted string from the parameters passed.
    private string BuildLogMessage(TreeParameters treeParameters, TreeEvent treeEvent, object additionalEventArgs)
    {
        string indent = " ";
        string addInfos = indent;
        if (treeEvent.Name.Contains("Exception"))
        {
            addInfos += (additionalEventArgs as Exception).Message;
        }
        if (treeEvent.Name.Contains("ProgressChanged"))
        {
            addInfos += String.Format("Progress {0:d3}%", Convert.ToInt32(additionalEventArgs));
        }
        string timestamp = System.String.Format(System.Globalisation.CultureInfo.CurrentCulture,
            "{0:yyyy.MM.dd HH:mm:ss,ffffff}", new object[] { treeEvent.Timestamp });
        StringBuilder bigMessage = new StringBuilder(timestamp + " Event: " + treeEvent.Name);
        string IdName = treeEvent.NodeName + "|" + treeEvent.SenderId;
        bigMessage.Append(Environment.NewLine + indent + "Node: " + IdName);
        bigMessage.Append(", Logical: " + treeEvent.Logical);
        bigMessage.Append(", source: " + treeEvent.SourceId);
        bigMessage.Append(Environment.NewLine + indent + treeEvent.ReplaceWildcards("%MachineName%")
            + ", thread: " + treeEvent.ThreadId.ToString());
        bigMessage.Append(", Tree: " + treeParameters.ToString());
        if (addInfos.Trim() != "")
        {
            bigMessage.Append(Environment.NewLine + addInfos);
        }
        if (!String.IsNullOrEmpty(treeEvent.NodePath))
        {
            bigMessage.Append(Environment.NewLine + indent + treeEvent.NodePath);
        }
        bigMessage.Append(", status: " + treeEvent.State.ToString());
        bigMessage.Append(Environment.NewLine + indent + "WorkingDirectory: "
            + treeEvent.ReplaceWildcards("%WorkingDirectory%"));
        return bigMessage.ToString();
    }

    // The routine attempts to enter a node that may have several nodes at the same time.
    // used log file; does not throw an exception in the event of an error, but
    // tries again until a counter has expired.
    // In the worst case, the logging attempt may fail.
    private void WriteLog(string message)
    {
        int maxTries = 5;
        StreamWriter streamWriter;
        int i = 0;
        do
        {
            try
            {
                using (streamWriter = new StreamWriter(new FileStream(this._debugFile,
                    FileMode.Append, FileAccess.Write), Encoding.Default))
                {
                    streamWriter.WriteLine(message);
                    i = maxTries; // successful, end loop
                }

            }
            catch (SystemException)
            {
                Thread.Sleep(10); // Wait 10 thousandths of a second
            }
        } while (++i < maxTries);
    }
...

The TextFileLogger class implements the functions defined by the Vishnu provided interface Vishnu.InterchangeINodeLogger. The only routine Log(...) takes over the path to the log file (subroutine SetLogFilePath), builds a coherent message text from the transferred parameters (subroutine BuildLogMessage) and finally calls the internal routine WriteLog, in which an attempt is made to write the message to the log file.

ImportantImportant

Since, when used later in Vishnu, several Loggers may attempt to write to the same log file at the same time, one or more write attempts may fail. This Logger-implementation therefore tries a total of five times before giving up (without any further error message).

See also