Friday, 16 June 2017

Tracing

The Trace class allows you to attach a listener to a stream to implement rudimentary logging. in the following example we do just that, we create a TextWriterTraceListener when we instantiate it we connect it with our stream which is used to interact with a file. We then attach our listener to our trace class and now whenever we call an output method on our trace class we pass our data into memory which is then written via our stream to a file when the Trace.Flush() method is called.

for tracing to work, either #TRACE or #DEBUG must be set to true, which is why it's good practice to wrap your trace statements in #if DEBUG  #endif. if you try to run the trace in release mode nothing will be logged.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;

namespace pc.TraceExample
{
    class Person {
        static int runningID = 0;
        public int id { get; private set; } = runningID++;
        public string Name { get; set; }
        public Person(string Name) { this.Name = Name; }
        public override string ToString() { return $"{id}) {Name}"; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var people = new SortedList<int, Person>();
            int selection = -1;
#if DEBUG
    var fs = File.Open("TraceFile.txt", FileMode.Append,
                                FileAccess.Write, FileShare.Read);
           
    // Create a TextWriterTraceListener for the trace output stream.
    var traceListener = new TextWriterTraceListener(fs);
    Trace.Listeners.Add(traceListener);

    Trace.WriteLine("Trace started " + DateTime.Now.ToString());
    Trace.Indent();
#endif
            do
            {
                do
                {
                    Console.WriteLine("1) create a person\n" +
                        "2) delete a person\n4) List\n0) exit");
                } while (!int.TryParse(Console.ReadLine(), out selection));

                switch (selection)
                {
                    case 1:
                        var p = createPerson();
                        people.Add(p.id, p);
                        break;
                    case 2:
                        deletePerson(ref people);
                        break;
                    case 4:
                        foreach (var per in people)
                            Console.WriteLine(per.Value.ToString());
                        break;
                }

            } while (selection != 0);

#if DEBUG
    // Flush the trace output.

    Trace.Unindent();
    Trace.WriteLine($"Trace stopped {DateTime.Now.ToString()}");
    Trace.Close();

    traceListener.Dispose();

    fs.Close();
    fs.Dispose();
#endif
        }

        static Person createPerson()
        {
            Console.WriteLine("Enter in a name");
            var p = new Person(Console.ReadLine());
#if DEBUG
    Trace.WriteLine("Added [" + p.ToString() + "] " + DateTime.Now.ToString());
#endif
            return p;
        }

        static void deletePerson(ref SortedList<int, Person> people)
        {
            foreach (var per in people)
                Console.WriteLine(per.Value.ToString());
            Console.WriteLine("Id of person to delete");

            int id;
            if (int.TryParse(Console.ReadLine(), out id)) {
#if DEBUG
    var d = $"removed {people[people.IndexOfKey(id)].ToString()} { DateTime.Now.ToString()}";
    Trace.WriteLine(d);
#endif
                people.RemoveAt(people.IndexOfKey(id));
            }
        }
    }

}

Once we run our program


we result with the following trace file



and we have very rudimentary logging that only really works with applications in debug mode.