public static void LogFileContentsStats(IList <FileWithContents> filesWithContents)
        {
            if (LogContentsStats && Logger.IsInfoEnabled)
            {
                var sectionSeparator = new string('=', 180);
                Logger.LogInfo("{0}", sectionSeparator);
                Logger.LogInfo("Index statistics");

                Logger.LogInfo("  {0}", sectionSeparator);
                Logger.LogInfo("  Part 1: Files larger than {0}", FormatSizeAsKb(LogContentsStats_LargeFile_Threshold_Bytes));

                var bigFiles = filesWithContents
                               .Where(x => x.Contents.ByteLength >= LogContentsStats_LargeFile_Threshold_Bytes)
                               .OrderBy(x => x.FileName);

                LogFileContentsByPath(bigFiles);

                Logger.LogInfo("  {0}", sectionSeparator);
                Logger.LogInfo("  Part 2: File extensions that occupy more than {0}",
                               FormatSizeAsKb(LogContentsStats_FilesByExtensions_Threshold_Bytes));
                var filesByExtensions = filesWithContents
                                        .GroupBy(x => x.FileName.RelativePath.Extension)
                                        .Select(g => {
                    var count = g.Count();
                    var size  = g.Aggregate(0L, (c, x) => c + x.Contents.ByteLength);
                    return(Tuple.Create(g.Key, count, size));
                })
                                        .Where(x => x.Item3 >= LogContentsStats_FilesByExtensions_Threshold_Bytes)
                                        .OrderByDescending(x => x.Item3)
                                        .ToList();

                var filesByExtensionsReport = new TextTableGenerator(text => Logger.LogInfo("    {0}", text));
                filesByExtensionsReport.AddColumn("Extension", 70, TextTableGenerator.Align.Left, TextTableGenerator.Stringifiers.RegularString);
                filesByExtensionsReport.AddColumn("File Count", 16, TextTableGenerator.Align.Right, TextTableGenerator.Stringifiers.DecimalGroupedInteger);
                filesByExtensionsReport.AddColumn("Size", 16, TextTableGenerator.Align.Right, FormatSizeAsKb);
                filesByExtensionsReport.GenerateReport(filesByExtensions.Select(g => new List <object> {
                    g.Item1, g.Item2, g.Item3
                }));

                for (var i = 0; i < Math.Min(LogContentsStats_ExtensionsList_Count, filesByExtensions.Count); i++)
                {
                    var extension = filesByExtensions[i].Item1;

                    Logger.LogInfo("  {0}", sectionSeparator);
                    Logger.LogInfo("  Part {0}: {1} largest files for file extension \"{2}\"", i + 3, LogContentsStats_ExtensionsList_File_Count, extension);
                    var extensionFiles = filesWithContents
                                         .Where(f => f.FileName.RelativePath.Extension == extension)
                                         .OrderByDescending(f => f.Contents.ByteLength)
                                         .Take(LogContentsStats_ExtensionsList_File_Count);
                    LogFileContentsByPath(extensionFiles);
                }
            }
        }
        private static void LogFileContentsByPath(IEnumerable <FileWithContents> bigFiles)
        {
            var table = new TextTableGenerator(text => Logger.LogInfo("    {0}", text));

            table.AddColumn("Path", 140, TextTableGenerator.Align.Left, TextTableGenerator.Stringifiers.EllipsisString);
            table.AddColumn("Size", 16, TextTableGenerator.Align.Right, FormatSizeAsKb);
            var files = bigFiles
                        .Select(file => new List <object> {
                file.FileName.FullPath,
                file.Contents.ByteLength
            });

            table.GenerateReport(files);
        }