Document Solutions for Excel, .NET Edition | Document Solutions
Features / Logging
In This Topic
    Logging
    In This Topic

    DsExcel supports logging which allows you to capture logs and resolve issues by finding out their root cause. You can store different log levels like debug, error, warning or information based on the configuration in JSON file.

    Along with other external libraries, DsExcel uses Microsoft.Extensions.Logging library to implement the logging system. The logging information is supported for Json and Excel I/O and PDF exporting. Logging is disabled by default. To enable it, Workbook.LoggerFactory property needs to be set while initializing the application or website which is explained in detail in the next section.

    Enable Logging

    Follow the below steps to enable logging in DsExcel. The logs will be printed to console and saved to a file.

    1. Create a new console app and install the following nuget packages:
      • Microsoft.Extensions.Logging.Console
      • Microsoft.Extensions.Configuration.Json
      • Serilog.Extensions.Logging.File
      • If your project targets .NET Framework, Microsoft.Extensions.Logging.Abstractions also needs be installed.

    2. Write a method for creating logger factory as shown below:       
      C#
      Copy Code
      private static ILoggerFactory CreateLoggerFactory()
      {
          var builder = new ConfigurationBuilder().
              SetBasePath(Directory.GetCurrentDirectory()).
              AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
          var cfgRoot = builder.Build();
          var loggingCfg = cfgRoot.GetSection("Logging");
          var factory = LoggerFactory.Create(
              logBuilder => logBuilder.AddConfiguration(loggingCfg).AddConsole());
          factory.AddFile(loggingCfg);
          return factory;
      }

    3. Attach the logger factory to workbook as shown below:
      C#
      Copy Code
      static void Main(string[] args)
      {
          using (var loggerFactory = CreateLoggerFactory())
          {
              Workbook.LoggerFactory = loggerFactory;
              var wb = new Workbook();
              try
              {
                  wb.Save("test.pdf");
              }
              catch (Exception)
              { }
          }
      }

    4. Create a new json file in your project and name it as 'appsettings.json'. Set "Copy to output directory" to "Copy if newer" in properties window. If the file exists already, merge its content with existing file and appsettings.development.json. You can also refer Configure Serilog File Logs for more information about it.

         
    5. Add the following setting to appsettings.json file. 
      JSON
      Copy Code
      {
        "Logging": {
          "LogLevel": {
            "Default": "Information"
          },
          "PathFormat": "log-{Date}.txt"
        }
      }

    6. Run the project to observe that logs are printed to console and saved to log file 'log-yyyyMMdd.txt'.


    Set Log Level

    DsExcel allows you to capture four log levels, namely, debug, info, warn and error. Their priority order is:

    debug < info < warn < error

    You can configure which log level needs to be printed to the log file. After setting the log level, the logs with higher or equal priority are included in the printed logs while the logs with lower priority are ignored. For example, If you set the log level to "info", the info, warn and error logs are printed, while the "debug" logs are ignored.

    The following setting in appsettings.json sets the default log level to "warning" and DsExcel log level to "Information".

    JSON
    Copy Code
    {
      "Logging": {
        "LogLevel": {
          "Default": "Warning",
          "GrapeCity.Documents.Excel": "Information"
        }
      }
    }

    Similarly, the following setting in appsettings.json sets the DsExcel log level of console output to "Information".

    JSON
    Copy Code
    {
      "Logging": {
        "LogLevel": {
          "Default": "Warning"
        },
        "Console": {
          "LogLevel": {
            "GrapeCity.Documents.Excel": "Information"
          }
        }
      }
    }

     For more information, you can also refer to Logging in .NET Core and ASP.NET Core.


    Save Log Records with Thread ID

    You can also choose to print thread ID along with the logs in log files. This is particularly helpful to analyse the specific process or thread creating an issue. The appsettings file uses Microsoft.Extensions.Logging format to generate the logs.

    Note: This example does not use serilog-settings-configuration because it usually reports type load errors.

    Follow the below steps to save logs with thread ID:

    1. Install the following nuget packages:
      • Microsoft.Extensions.Configuration.Json
      • Microsoft.Extensions.Logging
      • Microsoft.Extensions.Logging.Configuration
      • Serilog.Enrichers.Thread
      • Serilog.Extensions.Logging
      • Serilog.Sinks.RollingFil
      • If your project targets .NET Framework, Microsoft.Extensions.Logging.Abstractions also needs to be installed

    2. Write methods for creating a logger factory as shown below:
      C#
      Copy Code
      private static ILoggerFactory CreateLoggerFactory()
      {
          var appSettings = new ConfigurationBuilder().
          SetBasePath(Directory.GetCurrentDirectory()).
          AddJsonFile("appsettings.json", optional: true, reloadOnChange: true).
          Build();
          var loggingSection = appSettings.GetSection("Logging");
          var serilogConfig = new LoggerConfiguration();
          ConfigureSerilog(loggingSection, serilogConfig);
          var factory = new LoggerFactory();
          factory.AddSerilog(serilogConfig.CreateLogger());
          return factory;
      }
       
      private static void ConfigureSerilog(IConfigurationSection loggingSection,
                                           LoggerConfiguration loggerCfg)
      {
          loggerCfg.Enrich.WithThreadId();
          string pathFormat = loggingSection["PathFormat"];
          string outputTemplate = loggingSection["OutputTemplate"];
          loggerCfg.WriteTo.RollingFile(pathFormat, outputTemplate: outputTemplate);
          ConfigureMinLevel(loggerCfg.MinimumLevel, loggingSection);
      }
       
      private static void ConfigureMinLevel(LoggerMinimumLevelConfiguration minimumLevel,
                                            IConfigurationSection loggingCfgSection)
      {
          var logLevelSection = loggingCfgSection.GetSection("LogLevel");
          int pathLength = logLevelSection.Path.Length;
          foreach (var logItem in logLevelSection.AsEnumerable())
          {
              if (logItem.Key.Length <= pathLength)
              {
                  continue;
              }
              string name = logItem.Key.Substring(pathLength + 1);
              if (Enum.TryParse(logItem.Value, ignoreCase: true, out LogLevel level))
              {
                  var serilogLevel = (LogEventLevel)level;
                  if (name == "Default")
                  {
                      minimumLevel.Is(serilogLevel);
                  }
                  else
                  {
                      minimumLevel.Override(name, serilogLevel);
                  }
              }
          }
      }

    3. Attach the logger factory to workbook as shown below:
      C#
      Copy Code
              static void Main(string[] args)
              {
                 static void Main()
      {
                  using (ILoggerFactory loggerFactory = CreateLoggerFactory())
                  {
                      Workbook.LoggerFactory = loggerFactory;
                      Workbook wb = new Workbook();
                      try
                      {
                          wb.Save("test.pdf")
                      }
                      catch(Exception)
                      { }
                  }
      }
              }

    4. Create a new json file in your project and name it as 'appsettings.json'. Set "Copy to output directory" to "Copy if newer" in properties window. If the file exists already, merge its content with existing file and appsettings.development.json.
      C#
      Copy Code
      {
        "Logging": {
          "LogLevel": {
            "Default": "Warning",
            "GrapeCity.Documents.Excel": "Debug"
          },
          "PathFormat": "log-{Date}.txt",
          "OutputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} (Thread {ThreadId}) [{Level}] {Message}{NewLine}{Exception}"
        }
      }

      Here,
      "LogLevel" section has the same schema as Microsoft.Extensions.Logging.
      "PathFormat" section specifies the name of log file.
      "OutputTemplate" section specifies the format of each log record.

    5. Run the project. Logs will be saved to log-yyyyMMdd.txt and the sample output will look like below:
      Text
      Copy Code
      2020-09-10 11:44:30.566 +08:00 (Thread 1) [Debug] Save pdf of the workbook.
       2020-09-10 11:44:30.615 +08:00 (Thread 1) [Debug] Paginate Start(Workbook)
       2020-09-10 11:44:31.104 +08:00 (Thread 1) [Debug] GetDigitWidthOfDefaultStyle GraphicsType: Pdf
       2020-09-10 11:44:31.108 +08:00 (Thread 1) [Debug] GetDigitWidthOfDefaultStyle DefaultFont: "FontName = Calibri
       FontSize = 11
       Bold = False
       Italic = False
       ScreenWidth = 0
       PDFWidth = 5.5751953125
       "
       2020-09-10 11:44:31.161 +08:00 (Thread 1) [Debug] Count of print ranges: 0
       2020-09-10 11:44:31.161 +08:00 (Thread 1) [Debug] Paginate End(Workbook)
       2020-09-10 11:44:31.164 +08:00 (Thread 1) [Error] There is no content to print.