Include NDC in view.

Aug 8, 2012 at 3:32 PM
Edited Aug 24, 2012 at 2:59 PM

I sometimes put context info into the NDC value and noticed you don't add this to the view.

 

Quick changes to implement this.

in MainWindowVM : InitDataGrid

IList<ColumnItem> dgColumns = new List<ColumnItem>()
                {
                    new ColumnItem("Id", 37, null, CellAlignment.CENTER),
                    new ColumnItem("TimeStamp", 120, null, CellAlignment.CENTER, "MMM d, HH:mm:ss.fff"),
                    new ColumnItem("Level", null, 50, CellAlignment.CENTER),
                    new ColumnItem("Message", null, 300),
                    new ColumnItem("NDC", null, 150),
                    new ColumnItem("Logger", 150, null),
                    new ColumnItem("MachineName", 110, null, CellAlignment.CENTER),
                    new ColumnItem("HostName", 110, null, CellAlignment.CENTER),
                    new ColumnItem("UserName", 110, null, CellAlignment.CENTER),
                    new ColumnItem("App", 150, null),
                    new ColumnItem("Thread", 44, null, CellAlignment.CENTER),
                    new ColumnItem("Class", null, 300),
                    new ColumnItem("Method", 200, null)
                    //new ColumnItem("Path", 50)
                };

 

In Domain/LogItem.cs add

public string NDC { get; set; }

In GlobalHelper.cs in ParseLogFile add to the switch statement in the default case on the second XmlTextReader.Read() loop

case ("log4j:NDC"):
        item.Message = xmlTextReader.ReadString();
        break;


Coordinator
Aug 9, 2012 at 2:02 PM

But how assign NDC property?

I did not understand how modify "ParseLogFile" method on GlobalHelper.cs

Aug 23, 2012 at 1:40 PM

In the common folder there is a GlobalHelper.cs file. In that file there is static method called ParseLogFile. In that method you will find a switch statement with a nested switch statement. Inside the nested switch statement you will add the case above.

To set the NDC for the Log file you use the NDC class of Log4Net. Example

 

In my App.cs file I have added my logger as a public variable.

 

public static readonly ILog Log = LogManager.GetLogger(typeof(App));

 

Then when I want to use the Logger I can set the NDC as a reference to the current object or list of objects in the call stack. The NDC class is basically a stack that you can push messages on to and then pop them off when finished.

In the example I have a multi-threaded foreach loop that creates a list of contracts.

 

foreach (var model in Contracts)
            {
                var thisModel = model;
                factory.StartNew(() =>
                    {
                        log4net.NDC.Push(thisModel.ContractName);
                        thisModel.LoadContractUnits();
                        thisModel.Load(ReportingStartDate, ReportingEndDate);
                        thisModel.LoadEnergyItems(ReportingStartDate, ReportingEndDate);
                        log4net.NDC.Pop();
                    }
            );

 

 

in the above statement I use the log4net namespace and NDC class to Push the contract name for that thread. Before the thread finishes I want to pop it off the stack. Now in the methods called I can log to the logger and it will include the contract name in the NDC as long as it is in the same thread.

 

public void LoadContractUnits()
        {
            LoadingState = LoadState.Loading;
            App.Log.DebugFormat("Loading Contract Units for {0}", _contractName);
            using (var odv = App.ODVDataStore.CreateProvider())
            {
                odv.ObjectTrackingEnabled = false;
                var units =
                    odv.ContractUnits.Where(unit => unit.ContractId == _contractId)
                        .Select(unit => new ContractUnitModel
                                            {
                                                ContractUnitId = unit.ContractUnitId,
                                                UnitId = unit.UnitId
                                            });

                foreach (ContractUnitModel model in units)
                {
                    model.UnitModel = ODVInstance.Current.Units.FirstOrDefault(x => x.UnitId == model.UnitId);
                    Units.Add(model);
                }
                App.Log.InfoFormat("Loaded {1} units for {0}", _contractName, units.Count());
            }
            App.Log.DebugFormat("Completed Loading Units for {0}", _contractName);
        }

 

 

The resulting log now shows the contract name for each interation.

<log4j:event logger="ODV.ODVTool.App" timestamp="1345728164458" level="INFO" thread="3">
	<log4j:message>LoadingState Changed to Loading for Contract Contract1</log4j:message>
	<log4j:NDC>Contract1</log4j:NDC>
	<log4j:locationInfo class="ODV.ODVTool.ViewModel.ContractViewModel" method="set_LoadingState" file="ContractViewModel.cs" line="52" />
</log4j:event>
<log4j:event logger="ODV.ODVTool.App" timestamp="1345728164458" level="INFO" thread="4">
	<log4j:message>LoadingState Changed to Loading for Contract Calhoun</log4j:message>
	<log4j:NDC>Calhoun</log4j:NDC>
	<log4j:locationInfo class="ODV.ODVTool.ViewModel.ContractViewModel" method="set_LoadingState" file="ContractViewModel.cs" line="52" />
</log4j:event>
<log4j:event logger="ODV.ODVTool.App" timestamp="1345728164473" level="DEBUG" thread="3">
	<log4j:message>Loading Contract Units for Contract1</log4j:message>
	<log4j:NDC>Contract1</log4j:NDC>
	<log4j:locationInfo class="ODV.ODVTool.ViewModel.ContractViewModel" method="LoadContractUnits" file="ContractViewModel.cs" line="291" />
</log4j:event>
<log4j:event logger="ODV.ODVTool.App" timestamp="1345728164473" level="DEBUG" thread="4">
	<log4j:message>Loading Contract Units for Calhoun</log4j:message>
	<log4j:NDC>Calhoun</log4j:NDC>
	<log4j:locationInfo class="ODV.ODVTool.ViewModel.ContractViewModel" method="LoadContractUnits" file="ContractViewModel.cs" line="291" />
</log4j:event>