Beispiel #1
0
        public override void Format(ref TraceEntry traceEntry, FormatWriter formatWriter)
        {
            ColorCategory color = ColorCategory.None;

            if (formatWriter.IsColorEnabled)
            {
                color = TraceLevelToColorCategory(traceEntry.TraceLevel);
            }

            int entryIndentLevel = formatWriter.IndentLevel + RelativeIndentLevel;

            entryIndentLevel = Math.Min(entryIndentLevel, MaxIndentLevel);

            formatWriter.BeginEntry(entryIndentLevel);

            if (IncludeDate)
            {
                formatWriter.WriteDate(traceEntry.TimestampUtc, ColorCategory.Debug);
            }
            if (IncludeTimestamp)
            {
                formatWriter.WriteTimestamp(traceEntry.TimestampUtc, ColorCategory.Detail);
            }
            formatWriter.WriteField(TraceLevelToLabel(traceEntry.TraceLevel), color, 7);
            formatWriter.WriteAbbreviatedTypeName(traceEntry.TracerName, ColorCategory.Debug, 36);
            formatWriter.WriteField(traceEntry.Message.Trim(), color);
            if (traceEntry.Details != null)
            {
                ColorCategory detailColor = color == ColorCategory.Debug ? ColorCategory.Debug : ColorCategory.Detail;
                formatWriter.WriteLines(traceEntry.Details.ToString(), detailColor, 1);
            }

            formatWriter.EndEntry();
        }
Beispiel #2
0
        /// <summary>
        /// Configures the logging of error messages.
        /// </summary>
        private static void CreateErrorLogger()
        {
            string directory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            ArchiveWriter archiveWriter = new ArchiveWriter(directory + @"\logs", "error");
            LevelWriter levelWriter = new LevelWriter(archiveWriter, new[] {Logger.eLEVEL.ERROR});
            FormatWriter formatWriter = new FormatWriter(levelWriter, new DetailFormat());

            Logger.Add(formatWriter);
        }
Beispiel #3
0
        /// <summary>
        /// Configures the logging of messages by thread.
        /// </summary>
        private static void CreateThreadLogger(string pName, int pThreadID)
        {
            string directory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

            ArchiveWriter archiveWriter = new ArchiveWriter(directory + @"\logs", pName.ToLower().Replace(' ','-'));
            ThreadWriter threadWriter = new ThreadWriter(archiveWriter, pThreadID);
            FormatWriter formatWriter = new FormatWriter(threadWriter, new DetailFormat());

            Logger.Add(formatWriter);
        }
        /// <summary>
        /// Formats <paramref name="enumerable"/> as an array.
        /// </summary>
        /// <param name="enumerable"></param>
        /// <param name="formatWriter"></param>
        /// <param name="recursionLevel"></param>
        /// <param name="lineage"></param>
        /// <returns>The max <paramref name="recursionLevel"/> reached when <paramref name="enumerable"/> was formatted.</returns>
        private int FormatAsEnumerable(IEnumerable enumerable, FormatWriter formatWriter, int recursionLevel, Stack <object> lineage)
        {
            int  maxRecursionLevel = recursionLevel;
            bool isEmpty           = true;
            bool enumerableContainsAllPrimitives = true;

            // Determine if there are any non-primitive elements
            foreach (object element in enumerable)
            {
                isEmpty = false;
                if (!ShouldFormatAsPrimitive(element))
                {
                    enumerableContainsAllPrimitives = false;
                    break;
                }
            }

            if (isEmpty)
            {
                formatWriter.WriteField("[]", ColorCategory.Markup);
                return(recursionLevel);
            }
            else
            {
                formatWriter.WriteField("[", ColorCategory.Markup);
                formatWriter.IndentLevel += 1;

                bool onFirstElement = true;
                foreach (object element in enumerable)
                {
                    if (!onFirstElement)
                    {
                        formatWriter.WriteText(",", ColorCategory.Markup);
                    }
                    if (!enumerableContainsAllPrimitives)
                    {
                        formatWriter.WriteEndLine();
                    }
                    onFirstElement = false;

                    // Format as a sub-object (indented, on a newline)
                    int propertyMaxRecursionLevel = InnerFormatObject(element, formatWriter, recursionLevel + 1, lineage, null);
                    maxRecursionLevel = Math.Max(maxRecursionLevel, propertyMaxRecursionLevel);
                }

                formatWriter.IndentLevel -= 1;
                if (!enumerableContainsAllPrimitives)
                {
                    formatWriter.WriteEndLine();
                }
                formatWriter.WriteField("]", ColorCategory.Markup);
            }

            return(maxRecursionLevel);
        }
Beispiel #5
0
 internal string SerializeFormatter(JToken formatterToken, out int indents)
 {
     using (var sw = new StringWriter())
         using (var jwr = new FormatWriter(sw))
         {
             jwr.Formatting = Indented;
             Serializer.Serialize(jwr, formatterToken);
             indents = jwr.Depth;
             return(sw.ToString());
         }
 }
        /// <summary>
        /// Constructor
        /// </summary>
        public LoggerControl()
        {
            InitializeComponent();

            FormatWriter format = new FormatWriter(new ListBoxWriter(lbLog), new DetailFormat());

            _threadWriter = new ThreadWriter(format);
            _writer = new MultiWriter
                      {
                          new ContainsWriter(_threadWriter, _MARKER, true), 
                          new ContainsWriter(format, _MARKER, false)
                      };
        }
        private void FormatAsPrimitive(object o, FormatWriter formatWriter)
        {
            var s = o.ToString();

            if (s.Any(c => (c == '"') || char.IsWhiteSpace(c)))
            {
                formatWriter.WriteText("\"", ColorCategory.Markup);
                formatWriter.WriteText(s.Replace("\"", "\"\""), ColorCategory.Detail);
                formatWriter.WriteText("\"", ColorCategory.Markup);
            }
            else
            {
                formatWriter.WriteText(s, ColorCategory.Detail);
            }
        }
Beispiel #8
0
    public Format(string format, FormatWriter writer)
    {
        if (format.StartsWith(Final.at))
        {
            var indent = Final.tabs.Substring(0, writer.Level());
            format = format.Replace(Final.line, indent);
            format = format.Replace(Final.at, indent);
        }
        var first = format.IndexOf(Final.arg);
        var sub   = format.Substring(0, first);

        writer.Write(sub);
        index       = first + Final.arg.Length;
        this.format = format;
        this.writer = writer;
    }
Beispiel #9
0
        internal static void FormatHeaders(FormatWriter formatWriter, KeyValuePair <string, string[]>[] headers)
        {
            StringBuilder buf = formatWriter.FieldBuffer;

            foreach (var header in headers)
            {
                foreach (string value in header.Value)
                {
                    buf.Clear();
                    buf.Append("  ");
                    buf.Append(header.Key);
                    buf.Append(": ");
                    buf.Append(value);
                    formatWriter.WriteLine(buf, ColorCategory.Debug);
                }
            }
        }
        /// <inheritdoc />
        public override void Format(ref LoggerEntry entry, FormatWriter formatWriter)
        {
            ColorCategory color = ColorCategory.None;

            if (formatWriter.IsColorEnabled)
            {
                color = LogLevelToColorCategory(entry.LogLevel);
            }

            int entryIndentLevel = formatWriter.IndentLevel + RelativeIndentLevel;

            entryIndentLevel = Math.Min(entryIndentLevel, MaxIndentLevel);

            formatWriter.BeginEntry(entryIndentLevel);

            if (IncludeDate)
            {
                formatWriter.WriteDate(entry.TimestampUtc, ColorCategory.Debug);
            }
            if (IncludeTimestamp)
            {
                formatWriter.WriteTimestamp(entry.TimestampUtc, ColorCategory.Detail);
            }

            formatWriter.WriteField(LogLevelToLabel(entry.LogLevel), color, 7);
            formatWriter.WriteAbbreviatedTypeName(entry.CategoryName, ColorCategory.Debug, 36);

            if (IncludeEventId)
            {
                formatWriter.WriteField(entry.EventId.ToString(), color, 6);
            }

            string message = entry.DefaultFormatter(entry.State, null);

            formatWriter.WriteField(message.Trim(), color);
            if (entry.Exception != null)
            {
                ColorCategory detailColor = color == ColorCategory.Debug ? ColorCategory.Debug : ColorCategory.Detail;
                formatWriter.WriteLines(entry.Exception.ToString(), detailColor, 1);
            }

            formatWriter.EndEntry();
        }
 /// <summary>
 /// Reflects object <paramref name="o"/>, writes its type and properties to <paramref name="formatWriter"/>.
 /// </summary>
 /// <param name="o"></param>
 /// <param name="formatWriter"></param>
 public void FormatObject(object o, FormatWriter formatWriter)
 {
     if (o == null)
     {
         // Top level object is not usually expected to be null, which is why it's formatted as a warning
         formatWriter.WriteField("(null)", ColorCategory.Warning);
     }
     else
     {
         // If o is a Primitive, don't format it as an object
         if (ShouldFormatAsPrimitive(o))
         {
             FormatAsPrimitive(o, formatWriter);
         }
         else
         {
             InnerFormatObject(o, formatWriter, 0, new Stack <object>(10), null);
         }
     }
 }
Beispiel #12
0
        /// <inheritdoc />
        public override void Format(ref LoggerBeginScopeEntry <object> entry, FormatWriter formatWriter)
        {
            formatWriter.BeginEntry();

            if (IncludeDate)
            {
                formatWriter.WriteDate(entry.TimestampUtc, ColorCategory.Debug);
            }
            if (IncludeTimestamp)
            {
                formatWriter.WriteTimestamp(entry.TimestampUtc, ColorCategory.Detail);
            }

            formatWriter.WriteField("Begin", ColorCategory.Detail, 7);
            formatWriter.WriteAbbreviatedTypeName(entry.CategoryName, ColorCategory.Debug, 36);

            _reflectionFormatter.FormatObject(entry.State, formatWriter);

            formatWriter.EndEntry();
        }
Beispiel #13
0
        /// <summary>
        /// Translate the unit into TypeScript.
        /// </summary>
        /// <returns></returns>
        public string Translate()
        {
            FormatWriter writer = new FormatWriter()
            {
                Formatter = this.Formatter
            };

            if (this.hasGet)
            {
                // Opening declaration: [<modifiers>] get <name>() : <type> {
                // TODO: Handle case of no visibility specified
                writer.WriteLine("{0}{1}{2} {3} {4}{5}",
                                 this.RenderedModifiers,
                                 this.RenderedGetterMethodName,
                                 Lexems.OpenRoundBracket + Lexems.CloseRoundBracket,
                                 Lexems.Colon,
                                 this.type.Translate(),
                                 this.hasSet ? Lexems.Semicolon : string.Empty); // TODO: Find a better way for this
            }

            if (this.hasSet)
            {
                var valueParameter = ArgumentDefinitionTranslationUnit.Create(
                    this.type, IdentifierTranslationUnit.Create("value"));

                // Opening declaration: [<modifiers>] set <name>(value : <type>) : void {
                // Emitting `void` in order to prevent errors in case of implicitAllowAny
                writer.WriteLine("{0}{1}{2}{3}{4} {5} {6}",
                                 this.RenderedModifiers,
                                 this.RenderedSetterMethodName,
                                 Lexems.OpenRoundBracket,
                                 valueParameter.Translate(),
                                 Lexems.CloseRoundBracket,
                                 Lexems.Colon,
                                 Lexems.VoidReturnType);
            }

            return(writer.ToString());
        }
Beispiel #14
0
            public override void Format(ref MessageEntry entry, FormatWriter formatWriter)
            {
                formatWriter.BeginEntry(0);
                formatWriter.WriteTimestamp(entry.Timestamp);

                var buf = formatWriter.FieldBuffer;

                buf.Clear();
                buf.Append('[');
                if (entry.MessageId.HasValue)
                {
                    buf.Append(entry.MessageId.Value);
                }
                else
                {
                    buf.Append('?');
                }
                buf.Append(']');
                formatWriter.WriteField(buf);

                formatWriter.WriteField(entry.Text);
                formatWriter.EndEntry();
            }
        /// <inheritdoc />
        public override void Format(ref HttpRequestEntry entry, FormatWriter formatWriter)
        {
            StringBuilder buf = formatWriter.FieldBuffer;

            formatWriter.BeginEntry(0);

            // RequestNumber
            buf.Clear();
            buf.Append(entry.RequestNumber);
            buf.Append('>');
            formatWriter.WriteField(buf, ColorCategory.Markup, 3);

            formatWriter.WriteTimestamp(entry.RequestStarted, ColorCategory.Detail);

            formatWriter.WriteField(entry.Method, ColorCategory.Info, 3);
            formatWriter.WriteField(entry.Uri, ColorCategory.Important);

            FormatterHelper.FormatHeaders(formatWriter, entry.RequestHeaders);

            formatWriter.WriteLine(); // Extra line break for readability
            formatWriter.EndEntry();

            formatWriter.IndentLevel++;
        }
Beispiel #16
0
            /// <summary>
            /// Following typical scheme.
            /// </summary>
            /// <returns></returns>
            public string Translate()
            {
                FormatWriter writer = new FormatWriter()
                {
                    Formatter = this.Formatter
                };

                // Opening
                writer.WriteLine("{0} {1}",
                                 HeaderLexem,
                                 Lexems.OpenCurlyBracket);

                foreach (var translationUnit in this.innerUnits)
                {
                    writer.WriteLine("{0}",
                                     translationUnit.Translate());
                }

                // Closing
                writer.WriteLine("{0}",
                                 Lexems.CloseCurlyBracket);

                return(writer.ToString());
            }
Beispiel #17
0
        /// <inheritdoc />
        public override void Format(ref HttpResponseEntry entry, FormatWriter formatWriter)
        {
            StringBuilder buf = formatWriter.FieldBuffer;

            formatWriter.IndentLevel--;
            formatWriter.BeginEntry(0);

            // RequestNumber
            buf.Clear();
            buf.Append(entry.RequestNumber);
            buf.Append('<');
            formatWriter.WriteField(buf, ColorCategory.Markup, 3);

            formatWriter.WriteTimestamp(entry.RequestCompleted, ColorCategory.Detail);

            // Ttfb
            buf.Clear();
            buf.AppendPadZeroes(entry.Ttfb.Seconds, 2);
            buf.Append('.');
            buf.AppendPadZeroes(entry.Ttfb.Milliseconds, 3);
            buf.Append('s');
            formatWriter.WriteField(buf, ColorCategory.Info);

            // Determine response color from HTTP status code
            ColorCategory responseColorCategory = ColorCategory.None;

            if (formatWriter.IsColorEnabled)
            {
                var statusCode = entry.HttpStatusCode;
                if ((statusCode >= 200) && (statusCode < 300))
                {
                    responseColorCategory = ColorCategory.Success;
                }
                else if ((statusCode >= 300) && (statusCode < 400))
                {
                    responseColorCategory = ColorCategory.Important;
                }
                else if (statusCode >= 500)
                {
                    responseColorCategory = ColorCategory.Error;
                }
                else
                {
                    responseColorCategory = ColorCategory.Warning;
                }
            }

            formatWriter.WriteField(entry.Method, ColorCategory.Info, 3);
            formatWriter.WriteField(entry.Uri, responseColorCategory);
            formatWriter.WriteLine();

            // HTTP status line
            formatWriter.WriteLinePrefix(formatWriter.IndentLevel + 1);
            formatWriter.WriteText("  HTTP/1.1 ", ColorCategory.Detail);
            buf.Clear();
            buf.Append(entry.HttpStatusCode);
            formatWriter.WriteText(buf, 0, buf.Length, responseColorCategory);
            formatWriter.WriteSpaces(1);
            formatWriter.WriteText(entry.HttpReasonPhrase, ColorCategory.Detail);
            formatWriter.WriteLine();

            FormatterHelper.FormatHeaders(formatWriter, entry.ResponseHeaders);

            formatWriter.WriteLine(); // Extra line break for readability
            formatWriter.EndEntry();
        }
Beispiel #18
0
 public Format(FormatWriter writer)
 {
     index       = 0;
     format      = null;
     this.writer = writer;
 }
        /// <summary>
        /// Formats <paramref name="o"/> and its sub-objects.
        /// </summary>
        /// <param name="o"></param>
        /// <param name="formatWriter"></param>
        /// <param name="recursionLevel"></param>
        /// <param name="lineage"></param>
        /// <param name="propertyType">The type of the property set to value <paramref name="o"/>. May be <c>null</c> if not applicable or unknown.</param>
        /// <returns>The max <paramref name="recursionLevel"/> reached when <paramref name="o"/> was formatted.</returns>
        private int InnerFormatObject(object o, FormatWriter formatWriter, int recursionLevel, Stack <object> lineage, Type propertyType)
        {
            if (o == null)
            {
                formatWriter.WriteText("(null)", ColorCategory.Debug);
                return(recursionLevel);
            }

            if (recursionLevel >= c_maxRecursion)
            {
                formatWriter.WriteText("(Recursion limit exceeded)", ColorCategory.Warning);
                return(recursionLevel);
            }

            int parentNumber = 0;

            foreach (var ancestor in lineage)
            {
                if (object.ReferenceEquals(ancestor, o))
                {
                    formatWriter.WriteText("(Parent " + parentNumber + ")", ColorCategory.Detail);
                    return(recursionLevel);
                }

                parentNumber++;
            }

            // If o is a Primitive, don't format it as an object, don't change indent, etc
            if (ShouldFormatAsPrimitive(o))
            {
                FormatAsPrimitive(o, formatWriter);
                return(recursionLevel);
            }

            int previousIndentLevel = formatWriter.IndentLevel;

            //formatWriter.IndentLevel += 1;
            lineage.Push(o);

            int maxRecursionLevel;

            if (o is IEnumerable)
            {
                if (IsDictionary(o, out var formatAsDictionaryFunc))
                {
                    // Handle IEnumerable<KeyValuePair>; don't reflect individual properties
                    maxRecursionLevel = formatAsDictionaryFunc(o, formatWriter, recursionLevel, lineage, propertyType);
                }
                else
                {
                    // Handle IEnumerable; don't reflect properties
                    maxRecursionLevel = FormatAsEnumerable((IEnumerable)o, formatWriter, recursionLevel, lineage);
                }
            }
            else
            {
                maxRecursionLevel = FormatAsObject(o, formatWriter, recursionLevel, lineage, propertyType);
            }

            formatWriter.IndentLevel = previousIndentLevel;
            lineage.Pop();
            return(maxRecursionLevel);
        }
        /// <summary>
        /// Formats <paramref name="o"/> as an object.
        /// </summary>
        /// <param name="o"></param>
        /// <param name="formatWriter"></param>
        /// <param name="recursionLevel"></param>
        /// <param name="lineage"></param>
        /// <param name="parentPropertyType">The type of the property set to value <paramref name="o"/>. May be <c>null</c> if not applicable or unknown.</param>
        /// <returns>The max <paramref name="recursionLevel"/> reached when <paramref name="o"/> was formatted.</returns>
        private int FormatAsObject(object o, FormatWriter formatWriter, int recursionLevel, Stack <object> lineage, Type parentPropertyType)
        {
            int maxRecursionLevel = recursionLevel;

            formatWriter.WriteField("{", ColorCategory.Markup);

            if (recursionLevel > 0)
            {
                formatWriter.WriteEndLine();
            }

            formatWriter.IndentLevel += 1;

            Type objectType = o.GetType();

            if (IncludeTypeNames && (parentPropertyType != objectType))
            {
                formatWriter.WriteField("type:", ColorCategory.Debug);
                formatWriter.WriteText(_typeNameFunc(objectType), ColorCategory.Debug);
                formatWriter.WriteLine();
            }

            // Write properties
            foreach (var property in objectType.GetReadablePublicProperties())
            {
                bool colonWritten = false;

                void WriteErrorAsPropertyValue(string errorMessage)
                {
                    if (!colonWritten)
                    {
                        formatWriter.WriteText(":", ColorCategory.Markup);
                    }

                    formatWriter.WriteText("!(", ColorCategory.Markup);
                    formatWriter.WriteText(errorMessage, ColorCategory.Warning);
                    formatWriter.WriteText(")!", ColorCategory.Markup);
                }

                try
                {
                    formatWriter.WriteField(property.Name, ColorCategory.Detail);
                    Type propertyType = property.PropertyType;

                    ParameterInfo[] propertyIndexParameters = property.GetIndexParameters();
                    if (propertyIndexParameters.Length > 0)
                    {
                        // Properties with index parameters are not formatted - they act like functions, it's not possible to enumerate all contained values.
                        WriteErrorAsPropertyValue("Properties with index parameters are not formatted");
                        continue;
                    }

                    // GetValue(object) throws if the property has index parameters
                    object propertyValue = property.GetValue(o);

                    if (IncludeTypeNames)
                    {
                        // Only write the propertyType if it doesn't equal the subobject type
                        bool writePropertyType = !object.ReferenceEquals(propertyValue?.GetType(), propertyType);
                        if (writePropertyType)
                        {
                            formatWriter.WriteText("(", ColorCategory.Markup);
                            formatWriter.WriteText(_typeNameFunc(propertyType), ColorCategory.Debug);
                            formatWriter.WriteText(")", ColorCategory.Markup);
                        }
                    }

                    formatWriter.WriteText(":", ColorCategory.Markup);
                    colonWritten = true;

                    int propertyMaxRecursionLevel = InnerFormatObject(propertyValue, formatWriter, recursionLevel + 1, lineage, propertyType);
                    maxRecursionLevel = Math.Max(maxRecursionLevel, propertyMaxRecursionLevel);
                }
                catch (Exception excp)
                {   // Exception reading or formatting the property value.
                    WriteErrorAsPropertyValue(excp.ToString());
                }
            }

            // No newline for simple objects with no sub-objects
            if (maxRecursionLevel > 1)
            {
                formatWriter.WriteEndLine();
            }

            formatWriter.IndentLevel -= 1;
            formatWriter.WriteField("}", ColorCategory.Markup);

            return(maxRecursionLevel);
        }
        /// <summary>
        /// Formats <paramref name="untypedDictionary"/> as dictionary with key type <typeparamref name="TKey"/> and value type <typeparamref name="TValue"/>.
        /// </summary>
        /// <param name="untypedDictionary"></param>
        /// <param name="formatWriter"></param>
        /// <param name="recursionLevel"></param>
        /// <param name="lineage"></param>
        /// <param name="parentPropertyType">The type of the property set to object <paramref name="untypedDictionary"/>. May be <c>null</c> if not applicable or unknown.</param>
        /// <returns>The max <paramref name="recursionLevel"/> reached when <paramref name="untypedDictionary"/> was formatted.</returns>
        // ReSharper disable once UnusedMember.Local
        private int FormatAsDictionary <TKey, TValue>(object untypedDictionary, FormatWriter formatWriter, int recursionLevel, Stack <object> lineage, Type parentPropertyType)
        {
            // OK that this throws on failure; this shouldn't happen
            var dictionary = (IEnumerable <KeyValuePair <TKey, TValue> >)untypedDictionary;

            int maxRecursionLevel = recursionLevel;

            if (!dictionary.Any())
            {
                formatWriter.WriteField("{}", ColorCategory.Markup);
                return(recursionLevel);
            }
            else
            {
                formatWriter.WriteField("{", ColorCategory.Markup);
                formatWriter.IndentLevel += 1;

                bool onFirstKvp = true;

                Type dictionaryType = dictionary.GetType();
                if (IncludeTypeNames && (parentPropertyType != dictionaryType))
                {
                    formatWriter.WriteField("type:", ColorCategory.Debug);
                    formatWriter.WriteText(_typeNameFunc(dictionaryType), ColorCategory.Debug);
                    onFirstKvp = false;
                }

                foreach (var kvp in dictionary)
                {
                    if (!onFirstKvp)
                    {
                        formatWriter.WriteText(",", ColorCategory.Markup);
                    }
                    formatWriter.WriteEndLine();
                    onFirstKvp = false;

                    formatWriter.WriteField("{", ColorCategory.Markup);
                    formatWriter.IndentLevel += 1;

                    // If key is primitive, format on single line
                    TKey   key   = kvp.Key;
                    TValue value = kvp.Value;
                    int    childMaxRecursionLevel;
                    if (ShouldFormatAsPrimitive(key))
                    {
                        formatWriter.WriteText(formatWriter.FieldDelimiter, ColorCategory.Markup);
                        FormatAsPrimitive(key, formatWriter);
                        formatWriter.WriteText(":", ColorCategory.Markup);
                        childMaxRecursionLevel = InnerFormatObject(value, formatWriter, recursionLevel + 1, lineage, typeof(TValue));
                    }
                    else
                    {
                        formatWriter.WriteField("Key", ColorCategory.Detail);
                        formatWriter.WriteText(":", ColorCategory.Markup);
                        childMaxRecursionLevel = InnerFormatObject(key, formatWriter, recursionLevel + 1, lineage, typeof(TKey));
                        maxRecursionLevel      = Math.Max(maxRecursionLevel, childMaxRecursionLevel);

                        formatWriter.WriteText(",", ColorCategory.Markup);
                        formatWriter.WriteEndLine();
                        formatWriter.WriteField("Value", ColorCategory.Detail);
                        formatWriter.WriteText(":", ColorCategory.Markup);
                        childMaxRecursionLevel = InnerFormatObject(value, formatWriter, recursionLevel + 1, lineage, typeof(TValue));
                    }
                    maxRecursionLevel = Math.Max(maxRecursionLevel, childMaxRecursionLevel);

                    if (!ShouldFormatAsPrimitive(value))
                    {
                        formatWriter.WriteLine();
                    }

                    formatWriter.IndentLevel -= 1;
                    formatWriter.WriteField("}", ColorCategory.Markup);
                }

                formatWriter.WriteEndLine();

                formatWriter.IndentLevel -= 1;
                formatWriter.WriteField("}", ColorCategory.Markup);
            }

            return(maxRecursionLevel);
        }