Click here to Skip to main content
15,897,518 members
Articles / Web Development / HTML

Transformalizing NorthWind

Rate me:
Please Sign up or sign in to vote.
4.95/5 (29 votes)
24 Jul 2014GPL37 min read 57.9K   341   53  
Combining de-normalization, transformation, replication, and awesome-ness.
#region License
// /*
// See license included in this library folder.
// */
#endregion

using System;
using System.Collections.ObjectModel;
using System.Text;
using Transformalize.Libs.NLog.Common;
using Transformalize.Libs.NLog.Config;
using Transformalize.Libs.NLog.Internal;
using Transformalize.Libs.NLog.LayoutRenderers;

namespace Transformalize.Libs.NLog.Layouts
{
    /// <summary>
    ///     Represents a string with embedded placeholders that can render contextual information.
    /// </summary>
    /// <remarks>
    ///     This layout is not meant to be used explicitly. Instead you can just use a string containing layout
    ///     renderers everywhere the layout is required.
    /// </remarks>
    [Layout("SimpleLayout")]
    [ThreadAgnostic]
    [AppDomainFixedOutput]
    public class SimpleLayout : Layout
    {
        private const int MaxInitialRenderBufferLength = 16384;
        private readonly ConfigurationItemFactory configurationItemFactory;

        private string fixedText;
        private string layoutText;
        private int maxRenderedLength;

        /// <summary>
        ///     Initializes a new instance of the <see cref="SimpleLayout" /> class.
        /// </summary>
        public SimpleLayout()
            : this(string.Empty)
        {
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="SimpleLayout" /> class.
        /// </summary>
        /// <param name="txt">The layout string to parse.</param>
        public SimpleLayout(string txt)
            : this(txt, ConfigurationItemFactory.Default)
        {
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="SimpleLayout" /> class.
        /// </summary>
        /// <param name="txt">The layout string to parse.</param>
        /// <param name="configurationItemFactory">The NLog factories to use when creating references to layout renderers.</param>
        public SimpleLayout(string txt, ConfigurationItemFactory configurationItemFactory)
        {
            this.configurationItemFactory = configurationItemFactory;
            Text = txt;
        }

        internal SimpleLayout(LayoutRenderer[] renderers, string text, ConfigurationItemFactory configurationItemFactory)
        {
            this.configurationItemFactory = configurationItemFactory;
            SetRenderers(renderers, text);
        }

        /// <summary>
        ///     Gets or sets the layout text.
        /// </summary>
        /// <docgen category='Layout Options' order='10' />
        public string Text
        {
            get { return layoutText; }

            set
            {
                LayoutRenderer[] renderers;
                string txt;

                renderers = LayoutParser.CompileLayout(
                    configurationItemFactory,
                    new SimpleStringReader(value),
                    false,
                    out txt);

                SetRenderers(renderers, txt);
            }
        }

        /// <summary>
        ///     Gets a collection of <see cref="LayoutRenderer" /> objects that make up this layout.
        /// </summary>
        public ReadOnlyCollection<LayoutRenderer> Renderers { get; private set; }

        /// <summary>
        ///     Converts a text to a simple layout.
        /// </summary>
        /// <param name="text">Text to be converted.</param>
        /// <returns>
        ///     A <see cref="SimpleLayout" /> object.
        /// </returns>
        public static implicit operator SimpleLayout(string text)
        {
            return new SimpleLayout(text);
        }

        /// <summary>
        ///     Escapes the passed text so that it can
        ///     be used literally in all places where
        ///     layout is normally expected without being
        ///     treated as layout.
        /// </summary>
        /// <param name="text">The text to be escaped.</param>
        /// <returns>The escaped text.</returns>
        /// <remarks>
        ///     Escaping is done by replacing all occurences of
        ///     '${' with '${literal:text=${}'
        /// </remarks>
        public static string Escape(string text)
        {
            return text.Replace("${", "${literal:text=${}");
        }

        /// <summary>
        ///     Evaluates the specified text by expadinging all layout renderers.
        /// </summary>
        /// <param name="text">The text to be evaluated.</param>
        /// <param name="logEvent">Log event to be used for evaluation.</param>
        /// <returns>
        ///     The input text with all occurences of ${} replaced with
        ///     values provided by the appropriate layout renderers.
        /// </returns>
        public static string Evaluate(string text, LogEventInfo logEvent)
        {
            var l = new SimpleLayout(text);
            return l.Render(logEvent);
        }

        /// <summary>
        ///     Evaluates the specified text by expadinging all layout renderers
        ///     in new <see cref="LogEventInfo" /> context.
        /// </summary>
        /// <param name="text">The text to be evaluated.</param>
        /// <returns>
        ///     The input text with all occurences of ${} replaced with
        ///     values provided by the appropriate layout renderers.
        /// </returns>
        public static string Evaluate(string text)
        {
            return Evaluate(text, LogEventInfo.CreateNullEvent());
        }

        /// <summary>
        ///     Returns a <see cref="T:System.String"></see> that represents the current object.
        /// </summary>
        /// <returns>
        ///     A <see cref="T:System.String"></see> that represents the current object.
        /// </returns>
        public override string ToString()
        {
            return "'" + Text + "'";
        }

        internal void SetRenderers(LayoutRenderer[] renderers, string text)
        {
            Renderers = new ReadOnlyCollection<LayoutRenderer>(renderers);
            if (Renderers.Count == 1 && Renderers[0] is LiteralLayoutRenderer)
            {
                fixedText = ((LiteralLayoutRenderer) Renderers[0]).Text;
            }
            else
            {
                fixedText = null;
            }

            layoutText = text;
        }

        /// <summary>
        ///     Renders the layout for the specified logging event by invoking layout renderers
        ///     that make up the event.
        /// </summary>
        /// <param name="logEvent">The logging event.</param>
        /// <returns>The rendered layout.</returns>
        protected override string GetFormattedMessage(LogEventInfo logEvent)
        {
            if (fixedText != null)
            {
                return fixedText;
            }

            string cachedValue;

            if (logEvent.TryGetCachedLayoutValue(this, out cachedValue))
            {
                return cachedValue;
            }

            var initialSize = maxRenderedLength;
            if (initialSize > MaxInitialRenderBufferLength)
            {
                initialSize = MaxInitialRenderBufferLength;
            }

            var builder = new StringBuilder(initialSize);

            foreach (var renderer in Renderers)
            {
                try
                {
                    renderer.Render(builder, logEvent);
                }
                catch (Exception exception)
                {
                    if (exception.MustBeRethrown())
                    {
                        throw;
                    }

                    if (InternalLogger.IsWarnEnabled)
                    {
                        InternalLogger.Warn("Exception in {0}.Append(): {1}.", renderer.GetType().FullName, exception);
                    }
                }
            }

            if (builder.Length > maxRenderedLength)
            {
                maxRenderedLength = builder.Length;
            }

            var value = builder.ToString();
            logEvent.AddCachedLayoutValue(this, value);
            return value;
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Software Developer (Senior)
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions