Just in Chronicles

Life as a Voyage

How to Add External Error Log to Umbraco with Razor Macro Scripts

leave a comment »

Umbraco Razor macro script is very powerful and handy solution for developers to implement websites quite easily, while XSLT scripts are very hard to read and understand. However, using Razor macro scripts in Umbraco calls error log functions internally, which saves the logs to the database, rather than specific files.

That sometimes gets developers bothered as they have to append “umbDebutShotTrace=true” query string to its URL to debug an error when it occurs. Besides using the “umbDebugShowTrace=true” option, developers want to save that error details to a specific location other than the database. In order to achieve this, Umbraco core needs to be modified and recompiled. The key method is “umbraco.MacroEngines.RazorMacroEngine.Execute()” which is coded in “/umbraco.MacroEngines.Juno/RazorCore/RazorMacroEngine.cs“. Let’s see the code.

public string Execute(MacroModel macro, INode currentPage)
{
	try
	{
		Success = true;
		return ExecuteRazor(macro, currentPage);
	}
	catch (Exception exception)
	{
		Success = false;
		ResultException = exception;
		HttpContext.Current.Trace.Warn("umbracoMacro", string.Format("Error Loading Razor Script (file: {0}) {1} {2}", macro.Name, exception.Message, exception.StackTrace));
		var loading = string.Format("<div style=\"border: 1px solid #990000\">Error loading Razor Script {0}</br/>", macro.ScriptName);
		if (GlobalSettings.DebugMode)
			loading = loading + exception.Message;
		loading = loading + "</div>";

		// Adds the exception to the current HttpContext.Items.
		// Option #1: Using Dictionary<T>
		List<Dictionary<string, string>> logs = (List<Dictionary<string, string>>)HttpContext.Current.Items["umbracoErrorLogItems"];
		if (logs == null)
			logs = new List<Dictionary<string, string>>();
		logs.Add(new Dictionary<string, string>() { { "message", exception.Message }, { "source", exception.Source }, { "stackTrace", exception.StackTrace } });

		// Option #2: Using general Object
		List<object> logs = (List<object>)HttpContext.Current.Items["umbracoErrorLogItems"];
		if (logs == null)
			logs = new List<object>();
		logs.Add(new { Message = exception.Message, Source = exception.Source, StackTrace = exception.StackTrace });

		HttpContext.Current.Items["umbracoErrorLogItems"] = logs;
		return loading;
	}
}

The lines highlighted between 18 and 29 are newly added for the external log saving mechanism. When an exception occurs, HttpContext.Current.Items[“umbracoErrorLogItems”] stores the error details. Option #1 uses Dictionary<T> while Option #2 uses general object.

Then, open the /default.aspx page of the website’s root directory and put the following code bits.

<script runat="server">
	protected void Page_Load(object sender, EventArgs e)
	{
		var logs = Context.Items["umbracoErrorLogItems"];
		if (logs != null)
		{
			foreach (var log in logs)
			YourLogHelper.SaveLog(log);
			Context.Items["umbracoErrorLogItems"] = null;
		}
	}
</script>

Once the page is loaded, if there is any error log details found from HttpContext.Current.Items[“umbracoErrorLogItems”], the highlighted log saving method will be executed. Once all the error log details are saved, the Context.Items[“umbracoErrorLogItems”] has to be cleared for further use.

That’s what I’ve found so far. I know modifying the core source code is not the ideal solution, but it this case might be excused.

Advertisements

Written by Justin Yoo

06/03/2012 at 18:01

Posted in For .NET

Tagged with , ,

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s