/// <summary> /// Return a new logger instance named as the first parameter using /// <paramref name="factory"/>. /// </summary> /// <param name="name">The name of the logger to retrieve</param> /// <param name="factory">The factory that will make the new logger instance</param> /// <returns>The logger object with the name specified</returns> /// <remarks> /// <para> /// If a logger of that name already exists, then it will be /// returned. Otherwise, a new logger will be instantiated by the /// <paramref name="factory"/> parameter and linked with its existing /// ancestors as well as children. /// </para> /// </remarks> public Logger GetLogger(string name, ILoggerFactory factory) { if (name == null) { throw new ArgumentNullException("name"); } if (factory == null) { throw new ArgumentNullException("factory"); } LoggerKey key = new LoggerKey(name); // Synchronize to prevent write conflicts. Read conflicts (in // GetEffectiveLevel() method) are possible only if variable // assignments are non-atomic. Logger logger; lock (m_ht) { Object node = m_ht[key]; if (node == null) { logger = factory.CreateLogger(name); logger.Hierarchy = this; m_ht[key] = logger; UpdateParents(logger); OnLoggerCreationEvent(logger); return(logger); } Logger nodeLogger = node as Logger; if (nodeLogger != null) { return(nodeLogger); } ProvisionNode nodeProvisionNode = node as ProvisionNode; if (nodeProvisionNode != null) { logger = factory.CreateLogger(name); logger.Hierarchy = this; m_ht[key] = logger; UpdateChildren(nodeProvisionNode, logger); UpdateParents(logger); OnLoggerCreationEvent(logger); return(logger); } // It should be impossible to arrive here but let's keep the compiler happy. return(null); } }
/// <summary> /// Updates all the parents of the specified logger /// </summary> /// <param name="log">The logger to update the parents for</param> /// <remarks> /// <para> /// This method loops through all the <i>potential</i> parents of /// <paramref name="log"/>. There 3 possible cases: /// </para> /// <list type="number"> /// <item> /// <term>No entry for the potential parent of <paramref name="log"/> exists</term> /// <description> /// We create a ProvisionNode for this potential /// parent and insert <paramref name="log"/> in that provision node. /// </description> /// </item> /// <item> /// <term>The entry is of type Logger for the potential parent.</term> /// <description> /// The entry is <paramref name="log"/>'s nearest existing parent. We /// update <paramref name="log"/>'s parent field with this entry. We also break from /// he loop because updating our parent's parent is our parent's /// responsibility. /// </description> /// </item> /// <item> /// <term>The entry is of type ProvisionNode for this potential parent.</term> /// <description> /// We add <paramref name="log"/> to the list of children for this /// potential parent. /// </description> /// </item> /// </list> /// </remarks> private void UpdateParents(Logger log) { string name = log.Name; int length = name.Length; bool parentFound = false; // if name = "w.x.y.z", loop through "w.x.y", "w.x" and "w", but not "w.x.y.z" for (int i = name.LastIndexOf('.', length - 1); i >= 0; i = name.LastIndexOf('.', i - 1)) { string substr = name.Substring(0, i); LoggerKey key = new LoggerKey(substr); // simple constructor Object node = m_ht[key]; // Create a provision node for a future parent. if (node == null) { ProvisionNode pn = new ProvisionNode(log); m_ht[key] = pn; } else { Logger nodeLogger = node as Logger; if (nodeLogger != null) { parentFound = true; log.Parent = nodeLogger; break; // no need to update the ancestors of the closest ancestor } else { ProvisionNode nodeProvisionNode = node as ProvisionNode; if (nodeProvisionNode != null) { nodeProvisionNode.Add(log); } else { LogLog.Error("Hierarchy: Unexpected object type [" + node.GetType() + "] in ht.", new LogException()); } } } } // If we could not find any existing parents, then link with root. if (!parentFound) { log.Parent = this.Root; } }
/// <summary> /// Determines whether two <see cref="LoggerKey" /> instances /// are equal. /// </summary> /// <param name="obj">The <see cref="object" /> to compare with the current <see cref="LoggerKey" />.</param> /// <returns> /// <c>true</c> if the specified <see cref="object" /> is equal to the current <see cref="LoggerKey" />; otherwise, <c>false</c>. /// </returns> /// <remarks> /// <para> /// Compares the references of the interned strings. /// </para> /// </remarks> override public bool Equals(object obj) { // Compare reference type of this against argument if (((object)this) == obj) { return(true); } LoggerKey objKey = obj as LoggerKey; if (objKey != null) { #if NETCF return(m_name == objKey.m_name); #else // Compare reference types rather than string's overloaded == return(((object)m_name) == ((object)objKey.m_name)); #endif } return(false); }