You can add an in-app diagnostic log viewer to a CodeDress-based MDriven Turnkey application when you need to capture OCL, EAL, SQL, and execution trace output while testing a ViewModel.
What this logging does
This implementation uses the same ECO listener and log switches used by the logging shown in Documentation:Logging what MDriven does. It collects trace messages in memory and makes them available through a model class, so a ViewModel can display them in the Turnkey user interface.
Use this for interactive diagnosis while you reproduce a problem. It is different from LogEntry, which writes a message to the application log files under /logs.
| Operation | Result |
|---|---|
StartLogging()
|
Stops any current listener subscription, applies the selected log switches, subscribes to trace messages, and starts listening. |
GetLog()
|
Returns the accumulated trace text and then clears the in-memory buffer. |
StopLogging()
|
Removes this class's trace handler and stops the ECO listener. |
GetUsageStats()
|
Returns collected association-usage statistics, or No stats in log when none are available.
|
Create the logging class
Create a transient singleton class named SysLogging. The singleton gives the ViewModel one shared object to use; the generated singleton shortcut is SysLogging.oclSingleton. In an action, SO() can be used as a shortcut for SysLogging.oclSingleton.
Add Boolean attributes to the class for the switches read by StartLogging():
LogOclLogEALLogPMapperLogSqlLogSqlMetaLogActionExecuteLogActionEnableLogMethodsCollectAssociationUsageStatsLogWecpof
For example, set LogOcl and LogEAL to true when investigating an expression or action, then start logging, repeat the failing UI operation, and retrieve the log.
Add the CodeDress implementation
Add the following code to the generated partial class methods for SysLogging:
public partial class SysLogging
{
StringBuilder sb = new StringBuilder(100000);
void Singleton_OnTraceLog(object sender, Eco.Logging.TraceEventArgs e)
{
if (sb.Length > 5000000)
sb.Clear();
sb.AppendLine(e.Message);
}
[UmlElement(Id = "ee54deb5-3024-47c2-be01-7c93faa6638a")]
public void StartLogging()
{
this.StopLogging();
EcoLogSwitches.LogOcl = this.LogOcl;
EcoLogSwitches.LogEAL = this.LogEAL;
EcoLogSwitches.LogPMapper = this.LogPMapper;
EcoLogSwitches.LogSql = this.LogSql;
EcoLogSwitches.LogSqlMeta = this.LogSqlMeta;
EcoLogSwitches.LogActionExecute = this.LogActionExecute;
EcoLogSwitches.LogActionEnable = this.LogActionEnable;
EcoLogSwitches.LogMethods = this.LogMethods;
EcoLogSwitches.CollectAssociationUsageStats = this.CollectAssociationUsageStats;
EcoLogSwitches.LogWecpof = this.LogWecpof;
EcoListener.Singleton.OnTraceLog += Singleton_OnTraceLog;
EcoListener.StartListening();
}
[UmlElement(Id = "ace10ea6-8793-4205-a2eb-9f22b9391701")]
public string GetLog()
{
string text = sb.ToString();
sb.Clear();
return text;
}
[UmlElement(Id = "3d2941f2-75ca-4a41-a5e8-465ddcfa2904")]
public void StopLogging()
{
EcoListener.Singleton.OnTraceLog -= Singleton_OnTraceLog;
Eco.Logging.EcoListener.StopListening();
}
[UmlElement(Id = "a4e7d189-a056-4be4-8e07-ea42d72505ac")]
public string GetUsageStats()
{
StringBuilder stats = new StringBuilder();
lock (EcoSupport.AssociationUsageStats)
{
if (EcoSupport.AssociationUsageStats.Count > 0)
{
foreach (KeyValuePair<string, int> x in EcoSupport.AssociationUsageStats)
{
stats.AppendLine(x.Key + " = " + x.Value.ToString());
}
}
else
stats.AppendLine("No stats in log");
}
return stats.ToString();
}
}
Understand the buffer limit
The trace handler clears the whole buffer when its length exceeds 5,000,000 characters. GetLog() also clears the buffer after it returns its contents. Copy the displayed text before requesting it again if you need to retain it.
Add a ViewModel log viewer
Create a ViewModel that works with the SysLogging singleton. Add a variable or view field named vLogText to hold the returned text. Expose the Boolean switch attributes so that the person diagnosing the issue can select the trace categories before starting the listener.
Add actions with the following EAL assignments. OCL is the query language used throughout MDriven; EAL (Extended Action Language) uses related syntax for actions that change state.
| Action | EAL | Example use |
|---|---|---|
| Start logging | SysLogging.oclSingleton.StartLogging
|
Select LogOcl, then start logging before opening or running the ViewModel action you want to inspect.
|
| Get log | vLogText := self.GetLog
|
Display the captured trace in the field bound to vLogText.
|
| Get usage statistics | vLogText := self.GetUsageStats
|
Display association-usage counts after logging with CollectAssociationUsageStats enabled.
|
| Stop logging | SysLogging.oclSingleton.StopLogging
|
Stop trace capture when the diagnostic session is complete. |
If the action context is the SysLogging object itself, the existing GetLog and GetUsageStats expressions can use self as shown. If the action has another context, call the singleton explicitly instead.
Recommended diagnostic workflow
- Open the diagnostic ViewModel and choose only the switch or switches relevant to the issue. For example, choose
LogSqlwhen examining SQL trace output, orLogActionExecutewhen examining action execution. - Run the Start logging action.
- Reproduce the behavior in the application.
- Run Get log and inspect
vLogText. This consumes the current buffer. - If association usage is being investigated, run Get usage statistics.
- Run Stop logging when finished.
The switches and listener are shared by this singleton. Starting logging changes the selected ECO log switches, and stopping logging stops the listener. Treat the diagnostic ViewModel as an administrator/developer tool and stop it when you are done.
Log files and server diagnostics
For persisted Turnkey and MDrivenServer log files, log locations, and the Turnkey Serverinfo page, see Documentation:Serverinfo. For an application action that records a deliberate message in the log file, use LogEntry instead of this in-memory trace viewer.
