// --------------------------------

        public void ProcessDummyAppender(XmlElement xe, string parentName, Dictionary<string, string> appenderNames, Sequence sequence,
            IEnumerable<AttributeInfo> appenderAttributes, StringBuilder sb)
        {
            // Ensure no child xml elements have been used with the appender element
            // by passing in an empty list.
            var childTagInfos = new List<XmlHelpers.TagInfo>();

            ProcessAppender(xe, parentName, appenderNames, sequence,
                appenderAttributes, "createDummyAppender", childTagInfos, sb);
        }
        protected void ProcessAppender(XmlElement xe, string parentName, Dictionary<string, string> appenderNames, Sequence sequence,
            IEnumerable<AttributeInfo> appenderAttributes, string jsCreateMethodName, List<XmlHelpers.TagInfo> childTagInfos, StringBuilder sb)
        {
            if (xe == null) { return; }

            string appenderName = XmlHelpers.RequiredAttribute(xe, "name");

            string appenderVariableName = string.Format("{0}{1}", Constants.JsAppenderVariablePrefix, sequence.Next());
            appenderNames[appenderName] = appenderVariableName;

            JavaScriptHelpers.GenerateCreate(appenderVariableName, jsCreateMethodName, appenderName, sb);
            Utils.ProcessOptionAttributes(
                appenderVariableName, xe, appenderAttributes, null, sb, (attributeValues) => { Validate(appenderName, attributeValues); });

            XmlHelpers.ProcessNodeList(
                xe.ChildNodes,
                childTagInfos,
                appenderVariableName, appenderNames, sequence, sb);
        }
Esempio n. 3
0
        // --------------------------------

        public void ProcessLogger(XmlElement xe, string parentName, Dictionary<string, string> appenderNames, Sequence sequence,
            IEnumerable<AttributeInfo> loggerAttributes, StringBuilder sb)
        {
            if (xe == null) { return; }

            var appendersValue = new AppendersValue(appenderNames);
            string appenders = XmlHelpers.OptionalAttribute(xe, "appenders", null, appendersValue.ValidValueRegex);
            string loggerName = XmlHelpers.OptionalAttribute(xe, "name", "");

            JavaScriptHelpers.GenerateLogger(Constants.JsLoggerVariable, loggerName, sb);

            AttributeValueCollection attributeValues = new AttributeValueCollection();
            if (appenders != null)
            {
                attributeValues[Constants.JsLoggerAppendersOption] = new Value(appenders, appendersValue);
            }

            Utils.ProcessOptionAttributes(Constants.JsLoggerVariable, xe, loggerAttributes, attributeValues, sb);
        }
        // This version is not reliant on sitting in a web site, so can be unit tested.
        // generateClosure - if false, no function closure is generated around the generated JS code. Only set to false when unit testing.
        // Doing this assumes that jsnlog.js has loaded before the code generated by the method is executed.
        //
        // You want to set this to false during unit testing, because then you need direct access outside the closure of variables
        // that are private to the closure, specifically dummyappenders that store the log messages you receive, so you can unit test them.
        public void ProcessRootExec(XmlElement xe, StringBuilder sb, Func<string, string> virtualToAbsoluteFunc, string userIp, string requestId, bool generateClosure)
        {
            string loggerProductionLibraryVirtualPath = XmlHelpers.OptionalAttribute(xe, "productionLibraryPath", "");
            bool loggerEnabled = bool.Parse(XmlHelpers.OptionalAttribute(xe, "enabled", "true", Constants.RegexBool));

            string loggerProductionLibraryPath = null;
            if (!string.IsNullOrEmpty(loggerProductionLibraryVirtualPath))
            {
                // Every hard coded path must be resolved. See the declaration of DefaultDefaultAjaxUrl
                loggerProductionLibraryPath = virtualToAbsoluteFunc(loggerProductionLibraryVirtualPath);
            }

            if (!loggerEnabled)
            {
                if (!string.IsNullOrWhiteSpace(loggerProductionLibraryPath))
                {
                    JavaScriptHelpers.WriteScriptTag(loggerProductionLibraryPath, sb);
                }

                JavaScriptHelpers.WriteJavaScriptBeginTag(sb);
                Utils.ProcessOptionAttributes(Constants.JsLogObjectName, xe, Constants.JSNLogAttributes, null, sb);
                JavaScriptHelpers.WriteJavaScriptEndTag(sb);

                return;
            }

            JavaScriptHelpers.WriteJavaScriptBeginTag(sb);
            if (generateClosure) 
            {
                JavaScriptHelpers.WriteLine(string.Format("var {0} = function () {{", Constants.GlobalMethodCalledAfterJsnlogJsLoaded), sb); 
            }

            // Generate setOptions for JSNLog object itself

            AttributeValueCollection attributeValues = new AttributeValueCollection();

            attributeValues[Constants.JsLogObjectClientIpOption] = new Value(userIp, new StringValue());
            attributeValues[Constants.JsLogObjectRequestIdOption] = new Value(requestId, new StringValue());

            // Set default value for defaultAjaxUrl attribute
            attributeValues[Constants.JsLogObjectDefaultAjaxUrlOption] = 
                new Value(virtualToAbsoluteFunc(Constants.DefaultDefaultAjaxUrl), new StringValue());

            Utils.ProcessOptionAttributes(Constants.JsLogObjectName, xe, Constants.JSNLogAttributes,
                attributeValues, sb);

            // Process all loggers and appenders

            Dictionary<string, string> appenderNames = new Dictionary<string, string>();
            Sequence sequence = new Sequence();

            // -----------------
            // First process all assembly tags

            topLeveltagInfos =
                new List<XmlHelpers.TagInfo>(
                    new[] {
                            new XmlHelpers.TagInfo(Constants.TagAssembly, ProcessAssembly, Constants.AssemblyAttributes, (int)Constants.OrderNbr.Assembly)
                        });

            XmlHelpers.ProcessNodeList(
                xe.ChildNodes,
                topLeveltagInfos.Where(t => t.Tag == Constants.TagAssembly).ToList(),
                null, appenderNames, sequence, sb,
                string.Format("^{0}*", Constants.TagAssembly));

            // -----------------
            // The elements (if any) from external assemblies have now been loaded (with the assembly elements).
            // Now add the elements from the executing assembly after the external ones. 
            // This way, logger elements are processed last - after any new appenders.

            AddAssemblyTagInfos(Assembly.GetExecutingAssembly());

            // Now process the external and internal elements, but not the assembly elements.

            XmlHelpers.ProcessNodeList(
                xe.ChildNodes,
                topLeveltagInfos,
                null, appenderNames, sequence, sb,
                string.Format("^((?!{0}).)*$", Constants.TagAssembly));

            // -------------

            if (generateClosure) 
            {
                // Generate code to execute the function, in case jsnlog.js has already been loaded.
                // Wrap in try catch, so if jsnlog.js hasn't been loaded, the resulting exception will be swallowed.
                JavaScriptHelpers.WriteLine(string.Format("}}; try {{ {0}(); }} catch(e) {{}};", Constants.GlobalMethodCalledAfterJsnlogJsLoaded), sb); 
            }
            JavaScriptHelpers.WriteJavaScriptEndTag(sb);

            // Write the script tag that loads jsnlog.js after the code generated from the web.config.
            // When using jsnlog.js as an AMD module or in a bundle, jsnlog.js will be loaded after that code as well,
            // and creating a similar situation in the default out of the box loading option makes it more likely
            // you pick up bugs during testing.
            if (!string.IsNullOrWhiteSpace(loggerProductionLibraryPath))
            {
                JavaScriptHelpers.WriteScriptTag(loggerProductionLibraryPath, sb);
            }
        }
        private void ProcessAssembly(XmlElement xe, string parentName, Dictionary<string, string> appenderNames, Sequence sequence,
            IEnumerable<AttributeInfo> assemblyAttributes, StringBuilder sb)
        {
            if (xe == null) { return; }

            string assemblyName = XmlHelpers.RequiredAttribute(xe, "name");
            AddAssemblyTagInfos(Assembly.Load(assemblyName));
        }
Esempio n. 6
0
        /// <summary>
        /// Processes a list of nodes. All XmlElements among the nodes are processed,
        /// any other types of nodes (comments, etc.) are ignored.
        /// </summary>
        /// <param name="xmlNodeList">
        /// The list of nodes
        /// </param>
        /// <param name="tagInfos">
        /// Specifies all tags (= node names) that are permissable. You get an exception if there is a node
        /// that is not listed here.
        /// 
        /// The nodes are not listed in the order in which they appear in the list. Instead, first all nodes
        /// with the name listed in the first TagInfo in tagInfos are processed. Then those in the second TagInfo, etc.
        /// 
        /// This way, you can for example first process all appenders, and then all loggers.
        /// 
        /// If there are no nodes at all for a tag name given in tagInfo, the 
        /// XmlElementProcessor given in the tagInfo is called once with a null XmlElement.
        /// </param>
        /// <param name="context">parentName, appenderNames, sequence and sb get passed to the processor method that is listed for each tag in tagInfos.</param>
        /// <param name="sequence"></param>
        /// <param name="sb"></param>
        public static void ProcessNodeList(
            XmlNodeList xmlNodeList, IEnumerable<TagInfo> tagInfos, string parentName, Dictionary<string,string> appenderNames, 
            Sequence sequence, StringBuilder sb)
        {
            // Ensure there are no child nodes with names that are unknown - that is, not listed in tagInfos

            foreach (XmlNode xmlNode in xmlNodeList)
            {
                XmlElement xe = xmlNode as XmlElement;
                if (xe != null)
                {
                    if (!(tagInfos.Any(t => t.Tag == xe.Name)))
                    {
                        throw new UnknownTagException(xe.Name);
                    }
                }
            }

            // Process each child node

            foreach (TagInfo tagInfo in tagInfos)
            {
                int nbrTagsFound = 0;
                foreach (XmlNode xmlNode in xmlNodeList)
                {
                    XmlElement xe = xmlNode as XmlElement;
                    if (xe != null)
                    {
                        if (xe.Name == tagInfo.Tag)
                        {
                            // Check that all attributes are valid

                            foreach (XmlAttribute xa in xe.Attributes)
                            {
                                if ((tagInfo.ValidAttributeName == null) || (!tagInfo.ValidAttributeName.IsMatch(xa.Name)))
                                {
                                    throw new UnknownAttributeException(xe.Name, xa.Name);
                                }
                            }

                            nbrTagsFound++;

                            tagInfo.XmlElementProcessor(xe, parentName, appenderNames, sequence, sb);
                        }
                    }
                }

                if (nbrTagsFound > tagInfo.MaxNbrTags)
                {
                    throw new TooManyTagsException(tagInfo.Tag, tagInfo.MaxNbrTags, nbrTagsFound);
                }

                if (nbrTagsFound == 0)
                {
                    tagInfo.XmlElementProcessor(null, parentName, appenderNames, sequence, sb);
                }
            }
        }
        /// <summary>
        /// Processes a list of nodes. All XmlElements among the nodes are processed,
        /// any other types of nodes (comments, etc.) are ignored.
        /// </summary>
        /// <param name="xmlNodeList">
        /// The list of nodes
        /// </param>
        /// <param name="tagInfos">
        /// Specifies all tags (= node names) that are permissable. You get an exception if there is a node
        /// that is not listed here. However, see childNodeNameRegex.
        /// 
        /// The nodes are not listed in the order in which they appear in the list. Instead, first all nodes
        /// with the name listed in the first TagInfo in tagInfos are processed. Then those in the second TagInfo, etc.
        /// 
        /// This way, you can for example first process all appenders, and then all loggers.
        /// 
        /// If there are no nodes at all for a tag name given in tagInfo, the 
        /// XmlElementProcessor given in the tagInfo is called once with a null XmlElement.
        /// </param>
        /// <param name="context">parentName, appenderNames, sequence and sb get passed to the processor method that is listed for each tag in tagInfos.</param>
        /// <param name="sequence"></param>
        /// <param name="sb"></param>
        /// <param name="childNodeNameRegex">
        /// If this is given, then only those nodes in xmlNodeList whose name matches childNodeNameRegex will be processed.
        /// The other nodes will be completely ignored.
        /// 
        /// If this is not given, no filtering takes place and all nodes are processed.
        /// </param>
        public static void ProcessNodeList(
            XmlNodeList xmlNodeList, List<TagInfo> tagInfos, string parentName, Dictionary<string,string> appenderNames, 
            Sequence sequence, StringBuilder sb, string childNodeNameRegex = ".*")
        {
            // Ensure there are no child nodes with names that are unknown - that is, not listed in tagInfos

            foreach (XmlNode xmlNode in xmlNodeList)
            {
                XmlElement xe = xmlNode as XmlElement;
                if (xe != null)
                {
                    if (!Regex.IsMatch(xe.Name, childNodeNameRegex)) { continue; }

                    if (!(tagInfos.Any(t => t.Tag == xe.Name)))
                    {
                        throw new UnknownTagException(xe.Name);
                    }
                }
            }

            // Process each child node
            //
            // Note that the tagInfo list may be added to when tagInfo.XmlElementProcessor is called.
            // Because of this, use for, not foreach

            for (int i = 0; i < tagInfos.Count; i++ )
            {
                TagInfo tagInfo = tagInfos[i];

                int nbrTagsFound = 0;
                foreach (XmlNode xmlNode in xmlNodeList)
                {
                    XmlElement xe = xmlNode as XmlElement;

                    // If xmlNode is not an XmlElement, ignore it.
                    // This will be the case when xmlNode is a comment.
                    if (xe == null) { continue; }

                    if (!Regex.IsMatch(xe.Name, childNodeNameRegex)) { continue; }

                    if (xe.Name == tagInfo.Tag)
                    {
                        // Check that all attributes are valid

                        EnsureAllAttributesKnown(xe, tagInfo.AttributeInfos);

                        nbrTagsFound++;

                        tagInfo.XmlElementProcessor(xe, parentName, appenderNames, sequence, tagInfo.AttributeInfos, sb);
                    }
                }

                if (nbrTagsFound > tagInfo.MaxNbrTags)
                {
                    throw new TooManyTagsException(tagInfo.Tag, tagInfo.MaxNbrTags, nbrTagsFound);
                }

                if (nbrTagsFound == 0)
                {
                    tagInfo.XmlElementProcessor(null, parentName, appenderNames, sequence, tagInfo.AttributeInfos, sb);
                }
            }
        }
Esempio n. 8
0
 private void ProcessTimerInterval(XmlElement xe, string parentName, Dictionary<string, string> appenderNames, Sequence sequence, StringBuilder sb)
 {
     JavaScriptHelpers.ProcessTagWithValue(
         xe, parentName, Constants.RegexIntegerGreaterZero, "{0}.setTimerInterval({1}); {0}.setTimed(true);", sb);
 }
Esempio n. 9
0
        /// <summary>
        /// Processes a configuration (such as the contents of the jsnlog element in web.config).
        /// 
        /// The configuration is processed into JavaScript, which configures the jsnlog client side library.
        /// </summary>
        /// <param name="xe">
        /// XmlElement to be processed
        /// </param>
        /// <param name="sb">
        /// All JavaScript needs to be written to this string builder.
        /// </param>
        public void ProcessRoot(XmlElement xe, StringBuilder sb)
        {
            string loggerProductionLibraryVirtualPath = XmlHelpers.OptionalAttribute(xe, "productionLibraryPath", "");
            string loggerStubLibraryVirtualPath = XmlHelpers.OptionalAttribute(xe, "stubPath", "");
            bool loggerEnabled = bool.Parse(XmlHelpers.OptionalAttribute(xe, "enabled", "true", Constants.RegexBool));

            string loggerProductionLibraryPath = null;
            if (!string.IsNullOrEmpty(loggerProductionLibraryVirtualPath))
            {
                loggerProductionLibraryPath = VirtualPathUtility.ToAbsolute(loggerProductionLibraryVirtualPath);
            }

            string loggerStubLibraryPath = null;
            if (!string.IsNullOrEmpty(loggerStubLibraryVirtualPath))
            {
                loggerStubLibraryPath = VirtualPathUtility.ToAbsolute(loggerStubLibraryVirtualPath);
            }

            if (!loggerEnabled)
            {
                if (!string.IsNullOrWhiteSpace(loggerStubLibraryPath))
                {
                    JavaScriptHelpers.WriteScriptTag(loggerStubLibraryPath, sb);
                }
                else if (!string.IsNullOrWhiteSpace(loggerProductionLibraryPath))
                {
                    JavaScriptHelpers.WriteScriptTag(loggerProductionLibraryPath, sb);
                }

                JavaScriptHelpers.WriteJavaScriptBeginTag(sb);
                JavaScriptHelpers.WriteLine("var jsnlog_disabled = true;", sb);
                JavaScriptHelpers.WriteJavaScriptEndTag(sb);

                return;
            }

            if (!string.IsNullOrWhiteSpace(loggerProductionLibraryPath))
            {
                JavaScriptHelpers.WriteScriptTag(loggerProductionLibraryPath, sb);
            }

            JavaScriptHelpers.WriteJavaScriptBeginTag(sb);
            JavaScriptHelpers.WriteLine("(function () {", sb);

            Dictionary<string, string> appenderNames = new Dictionary<string, string>();
            Sequence sequence = new Sequence();

            XmlHelpers.ProcessNodeList(
                xe.ChildNodes,
                new[] {
                    new XmlHelpers.TagInfo("appender", ProcessAppender, new Regex("^(name|url)$")),
                    new XmlHelpers.TagInfo("root", ProcessRoot, null, 1),
                    new XmlHelpers.TagInfo("logger", ProcessLogger, new Regex("^(name|additivity)$"))
                },
                null, appenderNames, sequence, sb);

            JavaScriptHelpers.WriteLine("}());", sb);
            JavaScriptHelpers.WriteJavaScriptEndTag(sb);
        }
Esempio n. 10
0
        private void ProcessRoot(XmlElement xe, string parentName, Dictionary<string, string> appenderNames, Sequence sequence, StringBuilder sb)
        {
            JavaScriptHelpers.WriteLine(string.Format("var {0}=jsnlog.getRootLogger();", JsRootLoggerVariable), sb);

            if (xe == null)
            {
                // No root has been defined in the web.config.
                // But we must have a root with an AjaxAppender.
                // So create one with a default appender.

                AddDefaultAppenderToLogger(JsRootLoggerVariable, sb);
                return;
            }

            ProcessLoggerChildren(xe.ChildNodes, JsRootLoggerVariable, appenderNames, sb);
        }
Esempio n. 11
0
 // Normally used by version. But this method will override version.
 private void ProcessSessionId(XmlElement xe, string parentName, Dictionary<string, string> appenderNames, Sequence sequence, StringBuilder sb)
 {
     JavaScriptHelpers.ProcessTagWithValue(
         xe, parentName, null, "{0}.setSessionId(\"{1}\");", sb);
 }
Esempio n. 12
0
 private void ProcessLoggerUserAgentRegex(XmlElement xe, string parentName, Dictionary<string, string> appenderNames, Sequence sequence, StringBuilder sb)
 {
     JavaScriptHelpers.ProcessTagWithValue(
         xe, parentName, null, "{0}.setUserAgentRegex('{1}');", sb);
 }
Esempio n. 13
0
 private void ProcessLoggerLevel(XmlElement xe, string parentName, Dictionary<string, string> appenderNames, Sequence sequence, StringBuilder sb)
 {
     JavaScriptHelpers.ProcessTagWithValue(
         xe, parentName, Constants.RegexLevels, "{0}.setLevel(jsnlog.Level.{1});", sb);
 }
Esempio n. 14
0
        private void ProcessLogger(XmlElement xe, string parentName, Dictionary<string, string> appenderNames, Sequence sequence, StringBuilder sb)
        {
            if (xe == null) { return; }

            string loggerName = XmlHelpers.RequiredAttribute(xe, "name");
            string additivityEnabled = XmlHelpers.OptionalAttribute(xe, "additivity", AdditivityDefaultValue, Constants.RegexBool);

            JavaScriptHelpers.WriteLine(string.Format("{0}=jsnlog.getLogger('{1}');", JsLoggerVariable, loggerName), sb);
            if (additivityEnabled != AdditivityDefaultValue)
            {
                JavaScriptHelpers.WriteLine(string.Format("{0}.setAdditivity({1});", JsLoggerVariable, additivityEnabled), sb);
            }

            ProcessLoggerChildren(xe.ChildNodes, JsLoggerVariable, appenderNames, sb);
        }
Esempio n. 15
0
        private void ProcessAppenderRef(XmlElement xe, string parentName, Dictionary<string, string> appenderNames, Sequence sequence, StringBuilder sb)
        {
            if (xe == null)
            {
                if (parentName == JsRootLoggerVariable)
                {
                    // A root is being defined without an appender-ref.
                    // So attach a default appender.

                    AddDefaultAppenderToLogger(parentName, sb);
                }

                return;
            }

            string appenderRef = XmlHelpers.RequiredAttribute(xe, "ref");

            if (!appenderNames.ContainsKey(appenderRef))
            {
                throw new UnknownAppenderException(appenderRef);
            }

            string appenderVariableName = appenderNames[appenderRef];

            JavaScriptHelpers.AddAppenderToLogger(parentName, appenderVariableName, sb);
        }
Esempio n. 16
0
        // For the interface descriptions of these methods, see XmlHelpers.XmlElementProcessor delegate.
        // ---- Appender and its children
        private void ProcessAppender(XmlElement xe, string parentName, Dictionary<string, string> appenderNames, Sequence sequence, StringBuilder sb)
        {
            if (xe == null) { return; }

            string appenderName = XmlHelpers.RequiredAttribute(xe, "name");
            string appenderUrl = XmlHelpers.OptionalAttribute(
                xe, "url", AppenderDefaultUrl, @"^[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\-._~:/?#[\]@!$&'()*+,;=]+$");

            string appenderVariableName = string.Format("{0}{1}", JsAppenderVariablePrefix, sequence.Next());
            appenderNames[appenderName] = appenderVariableName;

            JavaScriptHelpers.GenerateAppender(appenderVariableName, appenderUrl, sb);

            XmlHelpers.ProcessNodeList(
                xe.ChildNodes,
                new[] {
                    new XmlHelpers.TagInfo("level", ProcessAppenderLevel, new Regex("^value$"), 1),
                    new XmlHelpers.TagInfo("userAgentRegex", ProcessAppenderUserAgentRegex, new Regex("^value$"), 1),
                    new XmlHelpers.TagInfo("ipRegex", ProcessAppenderIpRegex, new Regex("^value$"), 1),
                    new XmlHelpers.TagInfo("batchSize", ProcessBatchSize, new Regex("^value$"), 1),
                    new XmlHelpers.TagInfo("timerInterval", ProcessTimerInterval, new Regex("^value$"), 1),
                    new XmlHelpers.TagInfo("sessionId", ProcessSessionId, new Regex("^value$"), 1)
                },
                appenderVariableName, appenderNames, sequence, sb);
        }